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