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 }