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 }