1 module events.handler;
2 
3 import events.keyboard;
4 import events.mouse;
5 import kernel;
6 import old;
7 import config;
8 import types;
9 import gui.bar;
10 import cboxapp;
11 import window;
12 import monitor;
13 
14 import deimos.X11.X;
15 import deimos.X11.Xlib;
16 import deimos.X11.keysymdef;
17 import deimos.X11.Xutil;
18 import deimos.X11.Xatom;
19 import std.stdio;
20 import std.c.locale;
21 import std.c.string;
22 import std.c.stdlib;
23 
24 class EventHandler 
25 {
26 	KeyboardEvents keyboard;
27 	MouseEvents mouse;
28 
29 	this(KeyboardEvents keyboardEvents, MouseEvents mouseEvents)
30 	{
31 		keyboard = keyboardEvents;
32 		mouse = mouseEvents;
33 
34 	    handler[ClientMessage] = &clientmessage;
35 	    handler[ConfigureRequest] = &configurerequest;
36 	    handler[ConfigureNotify] = &configurenotify;
37 	    handler[DestroyNotify] = &destroynotify;
38 	    handler[Expose] = &expose;
39 	    handler[FocusIn] = &focusin;
40 	    handler[MappingNotify] = &mappingnotify;
41 	    handler[MapRequest] = &maprequest;
42 	    handler[MotionNotify] = &motionnotify;
43 	    handler[PropertyNotify] = &propertynotify;
44 	    handler[UnmapNotify] = &unmapnotify;
45 	}
46 
47 	void function(XEvent*)[LASTEvent] handler;
48 
49 	void listen(XEvent* ev)
50 	{
51         switch (ev.type) {
52             case KeyPress:
53                 this.keyboard.listen(ev);
54                 break;
55 
56             case ButtonPress:
57                 this.mouse.listen(ev);
58                 break;
59 
60             default: { }
61         }
62 
63 		if(handler[ev.type]) {
64             handler[ev.type](ev); /* call handler */
65         }
66 	}
67 }
68 
69 void maprequest(XEvent *e) 
70 {
71     static XWindowAttributes wa;
72     XMapRequestEvent *ev = &e.xmaprequest;
73 
74     if(!XGetWindowAttributes(AppDisplay.instance().dpy, ev.window, &wa))
75         return;
76     if(wa.override_redirect)
77         return;
78     if(!wintoclient(ev.window))
79         windowManager.manage(ev.window, &wa);
80 }
81 
82 void propertynotify(XEvent *e) 
83 {
84     
85     Client *c;
86     Window trans;
87     XPropertyEvent *ev = &e.xproperty;
88     if((ev.window == rootWin) && (ev.atom == XA_WM_NAME))
89         updatestatus();
90     else if(ev.state == PropertyDelete)
91         return; /* ignore */
92     else {
93         c = wintoclient(ev.window);
94         if(c) {
95             switch(ev.atom) {
96                 default:
97                     break;
98                 case XA_WM_TRANSIENT_FOR:
99                     if(!c.isfloating && (XGetTransientForHint(AppDisplay.instance().dpy, c.win, &trans))) {
100                         c.isfloating = (wintoclient(trans) !is null);
101                         if(c.isfloating) {
102                             arrange(c.mon);
103                         }
104                     }
105                     break;
106                 case XA_WM_NORMAL_HINTS:
107                     updatesizehints(c);
108                     break;
109                 case XA_WM_HINTS:
110                     updatewmhints(c);
111                     drawbars();
112                     break;
113             }
114 
115             if(ev.atom == XA_WM_NAME || ev.atom == netatom[NetWMName]) {
116                 windowManager.updatetitle(c);
117                 if(c == c.mon.sel)
118                     drawbar(c.mon);
119             }
120 
121             if(ev.atom == netatom[NetWMWindowType])
122                 windowManager.updatewindowtype(c);
123         }
124     }
125 }
126 
127 void focusin(XEvent *e) 
128 {  
129 	/* there are some broken focus acquiring clients */  
130     XFocusChangeEvent *ev = &e.xfocus;
131     if(selmon.sel && ev.window != selmon.sel.win) {
132         setfocus(selmon.sel);
133     }
134 }
135 
136 void unmapnotify(XEvent *e) 
137 {
138     
139     Client *c;
140     XUnmapEvent *ev = &e.xunmap;
141 
142     c=  wintoclient(ev.window);
143     if(c) {
144         if(ev.send_event)
145             setclientstate(c, WithdrawnState);
146         else
147             unmanage(c, false);
148     }
149 }
150 
151 void destroynotify(XEvent *e) 
152 {
153     Client *c;
154     XDestroyWindowEvent *ev = &e.xdestroywindow;
155 
156     c = wintoclient(ev.window);
157     if(c !is null) {
158         unmanage(c, true);
159     }
160 }
161 
162 void enternotify(XEvent *e) 
163 {
164     Client *c;
165     Monitor *m;
166     XCrossingEvent *ev = &e.xcrossing;
167 
168     if((ev.mode != NotifyNormal || ev.detail == NotifyInferior) && ev.window != rootWin)
169         return;
170     c = wintoclient(ev.window);
171     m = c ? c.mon : wintomon(ev.window);
172     if(m != selmon) {
173         unfocus(selmon.sel, true);
174         selmon = m;
175     } else if(!c || c == selmon.sel) {
176         return;
177     }
178     focus(c);
179 }
180 
181 void mappingnotify(XEvent *e) 
182 {
183     XMappingEvent *ev = &e.xmapping;
184 
185     XRefreshKeyboardMapping(ev);
186     if(ev.request == MappingKeyboard)
187         keyboardEventHandler.grabkeys();
188 }
189 
190 
191 void expose(XEvent *e) 
192 {
193     Monitor *m;
194     XExposeEvent *ev = &e.xexpose;
195 
196     if(ev.count == 0) {
197         m = wintomon(ev.window);
198         if(m !is null) {
199             drawbar(m);
200         }
201     }
202 }
203 
204 void configurerequest(XEvent *e) 
205 {
206     Client *c;
207     Monitor *m;
208     XConfigureRequestEvent *ev = &e.xconfigurerequest;
209     XWindowChanges wc;
210     c = wintoclient(ev.window);
211     if(c) {
212         if(ev.value_mask & CWBorderWidth) {
213             c.bw = ev.border_width;
214         } else if(c.isfloating || !selmon.lt[selmon.sellt].arrange) {
215             m = c.mon;
216             if(ev.value_mask & CWX) {
217                 c.oldx = c.x;
218                 c.x = m.mx + ev.x;
219             }
220             if(ev.value_mask & CWY) {
221                 c.oldy = c.y;
222                 c.y = m.my + ev.y;
223             }
224             if(ev.value_mask & CWWidth) {
225                 c.oldw = c.w;
226                 c.w = ev.width;
227             }
228             if(ev.value_mask & CWHeight) {
229                 c.oldh = c.h;
230                 c.h = ev.height;
231             }
232             if((c.x + c.w) > m.mx + m.mw && c.isfloating)
233                 c.x = m.mx + (m.mw / 2 - WIDTH(c) / 2); /* center in x direction */
234             if((c.y + c.h) > m.my + m.mh && c.isfloating)
235                 c.y = m.my + (m.mh / 2 - HEIGHT(c) / 2); /* center in y direction */
236             if((ev.value_mask & (CWX|CWY)) && !(ev.value_mask & (CWWidth|CWHeight)))
237                 configure(c);
238             if(ISVISIBLE(c))
239                 XMoveResizeWindow(AppDisplay.instance().dpy, c.win, c.x, c.y, c.w, c.h);
240         } else {
241             configure(c);
242         }
243     } else {
244         wc.x = ev.x;
245         wc.y = ev.y;
246         wc.width = ev.width;
247         wc.height = ev.height;
248         wc.border_width = ev.border_width;
249         wc.sibling = ev.above;
250         wc.stack_mode = ev.detail;
251 
252         // HACK to fix the slowdown XError issue. value_mask recieved is 36 but needs to be 12
253         // 36 ==> b2:width, b5:sibling
254         // 12 ==> b2:width, b3:height
255         ev.value_mask = 12;
256         XConfigureWindow(AppDisplay.instance().dpy, ev.window, ev.value_mask, &wc);
257     }
258     XSync(AppDisplay.instance().dpy, false);
259 }
260 
261 void configurenotify(XEvent *e) 
262 {
263     XConfigureEvent *ev = &e.xconfigure;
264     bool dirty;
265 
266     // TODO: updategeom handling sucks, needs to be simplified
267     if(ev.window == rootWin) {
268         dirty = (sw != ev.width || sh != ev.height);
269         sw = ev.width;
270         sh = ev.height;
271         if(updategeom() || dirty) {
272             drw.resize(sw, bh);
273             updatebars();
274             foreach(m; mons.range) {
275                 XMoveResizeWindow(AppDisplay.instance().dpy, m.barwin, m.wx, m.by, m.ww, bh);
276             }
277             focus(null);
278             arrange(null);
279         }
280     }
281 }
282 
283 void motionnotify(XEvent *e) 
284 {
285     static Monitor *mon = null;
286     Monitor *m;
287     XMotionEvent *ev = &e.xmotion;
288 
289     if(ev.window != rootWin)
290         return;
291     if((m = recttomon(ev.x_root, ev.y_root, 1, 1)) != mon && mon) {
292         unfocus(selmon.sel, true);
293         selmon = m;
294         focus(null);
295     }
296     mon = m;
297 }