event.c (7116B)
1 /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com> 2 * See LICENSE file for license details. 3 */ 4 #include "2wm.h" 5 #include <stdlib.h> 6 #include <X11/keysym.h> 7 #include <X11/Xatom.h> 8 9 /* static */ 10 11 typedef struct { 12 unsigned long mod; 13 KeySym keysym; 14 void (*func)(Arg *arg); 15 Arg arg; 16 } Key; 17 18 KEYS 19 20 #define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) 21 #define MOUSEMASK (BUTTONMASK | PointerMotionMask) 22 23 static void 24 movemouse(Client *c) { 25 int x1, y1, ocx, ocy, di; 26 unsigned int dui; 27 Window dummy; 28 XEvent ev; 29 30 ocx = c->x; 31 ocy = c->y; 32 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 33 None, cursor[CurMove], CurrentTime) != GrabSuccess) 34 return; 35 c->ismax = False; 36 XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui); 37 for(;;) { 38 XMaskEvent(dpy, MOUSEMASK | SubstructureRedirectMask, &ev); 39 switch (ev.type) { 40 case ButtonRelease: 41 resize(c, True); 42 XUngrabPointer(dpy, CurrentTime); 43 return; 44 case ConfigureRequest: 45 case MapRequest: 46 handler[ev.type](&ev); 47 break; 48 case MotionNotify: 49 XSync(dpy, False); 50 c->x = ocx + (ev.xmotion.x - x1); 51 c->y = ocy + (ev.xmotion.y - y1); 52 if(abs(sx + c->x) < SNAP) 53 c->x = sx; 54 else if(abs((sx + sw) - (c->x + c->w + 2 * c->border)) < SNAP) 55 c->x = sx + sw - c->w - 2 * c->border; 56 if(abs(sy - c->y) < SNAP) 57 c->y = sy; 58 else if(abs((sy + sh) - (c->y + c->h + 2 * c->border)) < SNAP) 59 c->y = sy + sh - c->h - 2 * c->border; 60 resize(c, False); 61 break; 62 } 63 } 64 } 65 66 static void 67 resizemouse(Client *c) { 68 int ocx, ocy; 69 int nw, nh; 70 XEvent ev; 71 72 ocx = c->x; 73 ocy = c->y; 74 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 75 None, cursor[CurResize], CurrentTime) != GrabSuccess) 76 return; 77 c->ismax = False; 78 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1); 79 for(;;) { 80 XMaskEvent(dpy, MOUSEMASK | SubstructureRedirectMask , &ev); 81 switch(ev.type) { 82 case ButtonRelease: 83 resize(c, True); 84 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, 85 c->w + c->border - 1, c->h + c->border - 1); 86 XUngrabPointer(dpy, CurrentTime); 87 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); 88 return; 89 case ConfigureRequest: 90 case MapRequest: 91 handler[ev.type](&ev); 92 break; 93 case MotionNotify: 94 XSync(dpy, False); 95 nw = ev.xmotion.x - ocx - 2 * c->border + 1; 96 c->w = nw > 0 ? nw : 1; 97 nh = ev.xmotion.y - ocy - 2 * c->border + 1; 98 c->h = nh > 0 ? nh : 1; 99 resize(c, True); 100 break; 101 } 102 } 103 } 104 105 static void 106 buttonpress(XEvent *e) { 107 Client *c; 108 XButtonPressedEvent *ev = &e->xbutton; 109 110 if((c = getclient(ev->window))) { 111 focus(c); 112 if(CLEANMASK(ev->state) != MODKEY) 113 return; 114 if(ev->button == Button1 && c->isfloat) { 115 restack(); 116 movemouse(c); 117 } 118 else if(ev->button == Button2) 119 zoom(NULL); 120 else if(ev->button == Button3 && c->isfloat && !c->isfixed) { 121 restack(); 122 resizemouse(c); 123 } 124 } 125 } 126 127 static void 128 configurerequest(XEvent *e) { 129 unsigned long newmask; 130 Client *c; 131 XConfigureRequestEvent *ev = &e->xconfigurerequest; 132 XWindowChanges wc; 133 134 if((c = getclient(ev->window))) { 135 c->ismax = False; 136 if(ev->value_mask & CWX) 137 c->x = ev->x; 138 if(ev->value_mask & CWY) 139 c->y = ev->y; 140 if(ev->value_mask & CWWidth) 141 c->w = ev->width; 142 if(ev->value_mask & CWHeight) 143 c->h = ev->height; 144 if(ev->value_mask & CWBorderWidth) 145 c->border = ev->border_width; 146 wc.x = c->x; 147 wc.y = c->y; 148 wc.width = c->w; 149 wc.height = c->h; 150 newmask = ev->value_mask & (~(CWSibling | CWStackMode | CWBorderWidth)); 151 if(newmask) 152 XConfigureWindow(dpy, c->win, newmask, &wc); 153 else 154 configure(c); 155 XSync(dpy, False); 156 if(c->isfloat) { 157 resize(c, False); 158 if(c->view != view) 159 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); 160 } 161 else 162 arrange(); 163 } 164 else { 165 wc.x = ev->x; 166 wc.y = ev->y; 167 wc.width = ev->width; 168 wc.height = ev->height; 169 wc.border_width = ev->border_width; 170 wc.sibling = ev->above; 171 wc.stack_mode = ev->detail; 172 XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); 173 XSync(dpy, False); 174 } 175 } 176 177 static void 178 destroynotify(XEvent *e) { 179 Client *c; 180 XDestroyWindowEvent *ev = &e->xdestroywindow; 181 182 if((c = getclient(ev->window))) 183 unmanage(c); 184 } 185 186 static void 187 enternotify(XEvent *e) { 188 Client *c; 189 XCrossingEvent *ev = &e->xcrossing; 190 191 if(ev->mode != NotifyNormal || ev->detail == NotifyInferior) 192 return; 193 if((c = getclient(ev->window)) && c->view == view) 194 focus(c); 195 else if(ev->window == root) { 196 selscreen = True; 197 for(c = stack; c && c->view != view; c = c->snext); 198 focus(c); 199 } 200 } 201 202 static void 203 keypress(XEvent *e) { 204 static unsigned int len = sizeof key / sizeof key[0]; 205 unsigned int i; 206 KeySym keysym; 207 XKeyEvent *ev = &e->xkey; 208 209 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); 210 for(i = 0; i < len; i++) { 211 if(keysym == key[i].keysym 212 && CLEANMASK(key[i].mod) == CLEANMASK(ev->state)) 213 { 214 if(key[i].func) 215 key[i].func(&key[i].arg); 216 } 217 } 218 } 219 220 static void 221 leavenotify(XEvent *e) { 222 XCrossingEvent *ev = &e->xcrossing; 223 224 if((ev->window == root) && !ev->same_screen) { 225 selscreen = False; 226 focus(NULL); 227 } 228 } 229 230 static void 231 mappingnotify(XEvent *e) { 232 XMappingEvent *ev = &e->xmapping; 233 234 XRefreshKeyboardMapping(ev); 235 if(ev->request == MappingKeyboard) 236 grabkeys(); 237 } 238 239 static void 240 maprequest(XEvent *e) { 241 static XWindowAttributes wa; 242 XMapRequestEvent *ev = &e->xmaprequest; 243 244 if(!XGetWindowAttributes(dpy, ev->window, &wa)) 245 return; 246 if(wa.override_redirect) 247 return; 248 if(!getclient(ev->window)) 249 manage(ev->window, &wa); 250 } 251 252 static void 253 propertynotify(XEvent *e) { 254 Client *c; 255 Window trans; 256 XPropertyEvent *ev = &e->xproperty; 257 258 if(ev->state == PropertyDelete) 259 return; /* ignore */ 260 if((c = getclient(ev->window))) { 261 switch (ev->atom) { 262 default: break; 263 case XA_WM_TRANSIENT_FOR: 264 XGetTransientForHint(dpy, c->win, &trans); 265 if(!c->isfloat && (c->isfloat = (trans != 0))) 266 arrange(); 267 break; 268 case XA_WM_NORMAL_HINTS: 269 updatesizehints(c); 270 break; 271 } 272 } 273 } 274 275 static void 276 unmapnotify(XEvent *e) { 277 Client *c; 278 XUnmapEvent *ev = &e->xunmap; 279 280 if((c = getclient(ev->window))) 281 unmanage(c); 282 } 283 284 /* extern */ 285 286 void (*handler[LASTEvent]) (XEvent *) = { 287 [ButtonPress] = buttonpress, 288 [ConfigureRequest] = configurerequest, 289 [DestroyNotify] = destroynotify, 290 [EnterNotify] = enternotify, 291 [LeaveNotify] = leavenotify, 292 [KeyPress] = keypress, 293 [MappingNotify] = mappingnotify, 294 [MapRequest] = maprequest, 295 [PropertyNotify] = propertynotify, 296 [UnmapNotify] = unmapnotify 297 }; 298 299 void 300 grabkeys(void) { 301 static unsigned int len = sizeof key / sizeof key[0]; 302 unsigned int i; 303 KeyCode code; 304 305 XUngrabKey(dpy, AnyKey, AnyModifier, root); 306 for(i = 0; i < len; i++) { 307 code = XKeysymToKeycode(dpy, key[i].keysym); 308 XGrabKey(dpy, code, key[i].mod, root, True, 309 GrabModeAsync, GrabModeAsync); 310 XGrabKey(dpy, code, key[i].mod | LockMask, root, True, 311 GrabModeAsync, GrabModeAsync); 312 XGrabKey(dpy, code, key[i].mod | numlockmask, root, True, 313 GrabModeAsync, GrabModeAsync); 314 XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True, 315 GrabModeAsync, GrabModeAsync); 316 } 317 }