aewl

annotate event.c @ 725:d99be681d502

handling WM_STATE seems to make DnD in gtk/qt apps working, well let's handle this in dwm as well
author Anselm R. Garbe <arg@suckless.org>
date Sun, 28 Jan 2007 20:29:41 +0100
parents 7034ee0f48d6
children 6283adb1fcf2
rev   line source
arg@644 1 /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
garbeam@5 2 * See LICENSE file for license details.
garbeam@5 3 */
garbeam@76 4 #include "dwm.h"
garbeam@5 5 #include <stdlib.h>
garbeam@5 6 #include <X11/keysym.h>
garbeam@13 7 #include <X11/Xatom.h>
garbeam@5 8
arg@146 9 /* static */
arg@114 10
arg@114 11 typedef struct {
arg@114 12 unsigned long mod;
arg@114 13 KeySym keysym;
arg@589 14 void (*func)(Arg *arg);
arg@114 15 Arg arg;
arg@114 16 } Key;
arg@114 17
arg@146 18 KEYS
garbeam@75 19
arg@291 20 #define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
arg@538 21 #define MOUSEMASK (BUTTONMASK | PointerMotionMask)
garbeam@5 22
garbeam@77 23 static void
arg@461 24 movemouse(Client *c) {
garbeam@77 25 int x1, y1, ocx, ocy, di;
garbeam@77 26 unsigned int dui;
garbeam@77 27 Window dummy;
arg@123 28 XEvent ev;
garbeam@77 29
arg@115 30 ocx = c->x;
arg@115 31 ocy = c->y;
arg@148 32 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
arg@123 33 None, cursor[CurMove], CurrentTime) != GrabSuccess)
garbeam@77 34 return;
arg@482 35 c->ismax = False;
garbeam@77 36 XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
garbeam@77 37 for(;;) {
arg@708 38 XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
garbeam@77 39 switch (ev.type) {
arg@490 40 case ButtonRelease:
arg@708 41 resize(c, True);
arg@490 42 XUngrabPointer(dpy, CurrentTime);
arg@490 43 return;
arg@708 44 case ConfigureRequest:
garbeam@77 45 case Expose:
arg@708 46 case MapRequest:
arg@708 47 handler[ev.type](&ev);
garbeam@77 48 break;
garbeam@77 49 case MotionNotify:
garbeam@79 50 XSync(dpy, False);
arg@115 51 c->x = ocx + (ev.xmotion.x - x1);
arg@115 52 c->y = ocy + (ev.xmotion.y - y1);
arg@565 53 if(abs(wax + c->x) < SNAP)
arg@565 54 c->x = wax;
arg@708 55 else if(abs((wax + waw) - (c->x + c->w + 2 * c->border)) < SNAP)
arg@708 56 c->x = wax + waw - c->w - 2 * c->border;
arg@565 57 if(abs(way - c->y) < SNAP)
arg@565 58 c->y = way;
arg@708 59 else if(abs((way + wah) - (c->y + c->h + 2 * c->border)) < SNAP)
arg@708 60 c->y = way + wah - c->h - 2 * c->border;
arg@708 61 resize(c, False);
garbeam@77 62 break;
garbeam@77 63 }
garbeam@77 64 }
garbeam@77 65 }
garbeam@77 66
garbeam@77 67 static void
arg@461 68 resizemouse(Client *c) {
garbeam@77 69 int ocx, ocy;
arg@268 70 int nw, nh;
arg@123 71 XEvent ev;
garbeam@77 72
arg@115 73 ocx = c->x;
arg@115 74 ocy = c->y;
arg@148 75 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
arg@532 76 None, cursor[CurResize], CurrentTime) != GrabSuccess)
garbeam@77 77 return;
arg@482 78 c->ismax = False;
arg@708 79 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
garbeam@77 80 for(;;) {
arg@708 81 XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
garbeam@77 82 switch(ev.type) {
arg@490 83 case ButtonRelease:
arg@708 84 resize(c, True);
arg@490 85 XUngrabPointer(dpy, CurrentTime);
arg@490 86 return;
arg@708 87 case ConfigureRequest:
garbeam@77 88 case Expose:
arg@708 89 case MapRequest:
arg@708 90 handler[ev.type](&ev);
garbeam@77 91 break;
garbeam@77 92 case MotionNotify:
garbeam@79 93 XSync(dpy, False);
arg@708 94 nw = ev.xmotion.x - ocx - 2 * c->border + 1;
arg@708 95 c->w = nw > 0 ? nw : 1;
arg@708 96 nh = ev.xmotion.y - ocy - 2 * c->border + 1;
arg@708 97 c->h = nh > 0 ? nh : 1;
arg@708 98 resize(c, True);
garbeam@77 99 break;
garbeam@77 100 }
garbeam@77 101 }
garbeam@77 102 }
garbeam@73 103
garbeam@73 104 static void
arg@461 105 buttonpress(XEvent *e) {
garbeam@73 106 int x;
garbeam@73 107 Arg a;
arg@123 108 Client *c;
garbeam@18 109 XButtonPressedEvent *ev = &e->xbutton;
garbeam@18 110
garbeam@73 111 if(barwin == ev->window) {
arg@362 112 x = 0;
arg@362 113 for(a.i = 0; a.i < ntags; a.i++) {
arg@362 114 x += textw(tags[a.i]);
arg@362 115 if(ev->x < x) {
arg@399 116 if(ev->button == Button1) {
arg@398 117 if(ev->state & MODKEY)
arg@398 118 tag(&a);
arg@398 119 else
arg@398 120 view(&a);
arg@399 121 }
arg@399 122 else if(ev->button == Button3) {
arg@398 123 if(ev->state & MODKEY)
arg@398 124 toggletag(&a);
arg@398 125 else
arg@398 126 toggleview(&a);
arg@394 127 }
arg@362 128 return;
garbeam@73 129 }
garbeam@73 130 }
arg@676 131 if(ev->x < x + bmw)
arg@676 132 switch(ev->button) {
arg@676 133 case Button1:
arg@676 134 togglemode(NULL);
arg@676 135 break;
arg@676 136 case Button4:
arg@676 137 a.i = 1;
arg@676 138 incnmaster(&a);
arg@676 139 break;
arg@676 140 case Button5:
arg@676 141 a.i = -1;
arg@676 142 incnmaster(&a);
arg@676 143 break;
arg@676 144 }
garbeam@73 145 }
garbeam@58 146 else if((c = getclient(ev->window))) {
arg@143 147 focus(c);
arg@473 148 if(CLEANMASK(ev->state) != MODKEY)
arg@318 149 return;
arg@400 150 if(ev->button == Button1 && (arrange == dofloat || c->isfloat)) {
arg@487 151 restack();
arg@399 152 movemouse(c);
arg@399 153 }
arg@399 154 else if(ev->button == Button2)
arg@248 155 zoom(NULL);
arg@550 156 else if(ev->button == Button3 && (arrange == dofloat || c->isfloat) &&
arg@550 157 !c->isfixed) {
arg@487 158 restack();
arg@399 159 resizemouse(c);
garbeam@18 160 }
garbeam@18 161 }
garbeam@18 162 }
garbeam@18 163
garbeam@18 164 static void
arg@461 165 configurerequest(XEvent *e) {
arg@286 166 unsigned long newmask;
arg@123 167 Client *c;
garbeam@5 168 XConfigureRequestEvent *ev = &e->xconfigurerequest;
garbeam@5 169 XWindowChanges wc;
garbeam@5 170
garbeam@18 171 if((c = getclient(ev->window))) {
arg@488 172 c->ismax = False;
arg@195 173 if(ev->value_mask & CWX)
arg@195 174 c->x = ev->x;
arg@195 175 if(ev->value_mask & CWY)
arg@195 176 c->y = ev->y;
arg@195 177 if(ev->value_mask & CWWidth)
arg@195 178 c->w = ev->width;
arg@195 179 if(ev->value_mask & CWHeight)
arg@195 180 c->h = ev->height;
garbeam@29 181 if(ev->value_mask & CWBorderWidth)
arg@164 182 c->border = ev->border_width;
arg@164 183 wc.x = c->x;
arg@164 184 wc.y = c->y;
arg@164 185 wc.width = c->w;
arg@164 186 wc.height = c->h;
arg@164 187 newmask = ev->value_mask & (~(CWSibling | CWStackMode | CWBorderWidth));
arg@164 188 if(newmask)
arg@164 189 XConfigureWindow(dpy, c->win, newmask, &wc);
arg@491 190 else
arg@491 191 configure(c);
arg@195 192 XSync(dpy, False);
arg@505 193 if(c->isfloat) {
arg@708 194 resize(c, False);
arg@508 195 if(!isvisible(c))
arg@687 196 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
arg@505 197 }
arg@196 198 else
arg@533 199 arrange();
garbeam@5 200 }
arg@164 201 else {
arg@164 202 wc.x = ev->x;
arg@164 203 wc.y = ev->y;
arg@164 204 wc.width = ev->width;
arg@164 205 wc.height = ev->height;
arg@164 206 wc.border_width = ev->border_width;
arg@164 207 wc.sibling = ev->above;
arg@164 208 wc.stack_mode = ev->detail;
arg@164 209 XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
arg@195 210 XSync(dpy, False);
arg@164 211 }
garbeam@5 212 }
garbeam@5 213
garbeam@5 214 static void
arg@461 215 destroynotify(XEvent *e) {
garbeam@5 216 Client *c;
garbeam@5 217 XDestroyWindowEvent *ev = &e->xdestroywindow;
garbeam@5 218
garbeam@11 219 if((c = getclient(ev->window)))
garbeam@11 220 unmanage(c);
garbeam@5 221 }
garbeam@5 222
garbeam@5 223 static void
arg@461 224 enternotify(XEvent *e) {
arg@123 225 Client *c;
garbeam@5 226 XCrossingEvent *ev = &e->xcrossing;
garbeam@5 227
arg@232 228 if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
garbeam@5 229 return;
arg@687 230 if((c = getclient(ev->window)) && isvisible(c))
garbeam@13 231 focus(c);
arg@239 232 else if(ev->window == root) {
arg@716 233 selscreen = True;
arg@708 234 for(c = stack; c && !isvisible(c); c = c->snext);
arg@708 235 focus(c);
arg@239 236 }
garbeam@5 237 }
garbeam@5 238
garbeam@5 239 static void
arg@461 240 expose(XEvent *e) {
garbeam@5 241 XExposeEvent *ev = &e->xexpose;
garbeam@5 242
garbeam@5 243 if(ev->count == 0) {
garbeam@70 244 if(barwin == ev->window)
garbeam@74 245 drawstatus();
garbeam@5 246 }
garbeam@5 247 }
garbeam@5 248
garbeam@5 249 static void
arg@461 250 keypress(XEvent *e) {
arg@581 251 static unsigned int len = sizeof key / sizeof key[0];
arg@589 252 unsigned int i;
garbeam@76 253 KeySym keysym;
arg@123 254 XKeyEvent *ev = &e->xkey;
garbeam@76 255
garbeam@76 256 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
arg@275 257 for(i = 0; i < len; i++) {
arg@461 258 if(keysym == key[i].keysym
arg@461 259 && CLEANMASK(key[i].mod) == CLEANMASK(ev->state))
arg@275 260 {
arg@589 261 if(key[i].func)
arg@589 262 key[i].func(&key[i].arg);
garbeam@76 263 }
arg@275 264 }
garbeam@76 265 }
garbeam@76 266
garbeam@76 267 static void
arg@461 268 leavenotify(XEvent *e) {
garbeam@76 269 XCrossingEvent *ev = &e->xcrossing;
garbeam@76 270
arg@701 271 if((ev->window == root) && !ev->same_screen) {
arg@716 272 selscreen = False;
arg@711 273 focus(NULL);
arg@701 274 }
garbeam@76 275 }
garbeam@76 276
garbeam@76 277 static void
arg@461 278 mappingnotify(XEvent *e) {
arg@279 279 XMappingEvent *ev = &e->xmapping;
arg@279 280
arg@279 281 XRefreshKeyboardMapping(ev);
arg@279 282 if(ev->request == MappingKeyboard)
arg@279 283 grabkeys();
arg@279 284 }
arg@279 285
arg@279 286 static void
arg@461 287 maprequest(XEvent *e) {
arg@123 288 static XWindowAttributes wa;
garbeam@5 289 XMapRequestEvent *ev = &e->xmaprequest;
garbeam@5 290
garbeam@5 291 if(!XGetWindowAttributes(dpy, ev->window, &wa))
garbeam@5 292 return;
garbeam@5 293 if(wa.override_redirect) {
garbeam@5 294 XSelectInput(dpy, ev->window,
garbeam@5 295 (StructureNotifyMask | PropertyChangeMask));
garbeam@5 296 return;
garbeam@5 297 }
garbeam@10 298 if(!getclient(ev->window))
garbeam@10 299 manage(ev->window, &wa);
garbeam@5 300 }
garbeam@5 301
garbeam@5 302 static void
arg@461 303 propertynotify(XEvent *e) {
arg@123 304 Client *c;
arg@123 305 Window trans;
garbeam@5 306 XPropertyEvent *ev = &e->xproperty;
garbeam@5 307
garbeam@5 308 if(ev->state == PropertyDelete)
garbeam@5 309 return; /* ignore */
garbeam@13 310 if((c = getclient(ev->window))) {
garbeam@77 311 if(ev->atom == wmatom[WMProtocols]) {
garbeam@75 312 c->proto = getproto(c->win);
garbeam@30 313 return;
garbeam@30 314 }
garbeam@13 315 switch (ev->atom) {
garbeam@13 316 default: break;
garbeam@13 317 case XA_WM_TRANSIENT_FOR:
garbeam@53 318 XGetTransientForHint(dpy, c->win, &trans);
garbeam@80 319 if(!c->isfloat && (c->isfloat = (trans != 0)))
arg@533 320 arrange();
garbeam@13 321 break;
garbeam@13 322 case XA_WM_NORMAL_HINTS:
arg@639 323 updatesizehints(c);
garbeam@13 324 break;
garbeam@13 325 }
garbeam@77 326 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
arg@454 327 updatetitle(c);
arg@690 328 if(c == sel)
arg@690 329 drawstatus();
garbeam@13 330 }
garbeam@13 331 }
garbeam@5 332 }
garbeam@5 333
garbeam@5 334 static void
arg@461 335 unmapnotify(XEvent *e) {
garbeam@5 336 Client *c;
garbeam@5 337 XUnmapEvent *ev = &e->xunmap;
garbeam@5 338
garbeam@10 339 if((c = getclient(ev->window)))
garbeam@10 340 unmanage(c);
garbeam@5 341 }
garbeam@76 342
garbeam@84 343 /* extern */
garbeam@76 344
garbeam@76 345 void (*handler[LASTEvent]) (XEvent *) = {
garbeam@76 346 [ButtonPress] = buttonpress,
garbeam@76 347 [ConfigureRequest] = configurerequest,
garbeam@76 348 [DestroyNotify] = destroynotify,
garbeam@76 349 [EnterNotify] = enternotify,
garbeam@76 350 [LeaveNotify] = leavenotify,
garbeam@76 351 [Expose] = expose,
garbeam@76 352 [KeyPress] = keypress,
arg@279 353 [MappingNotify] = mappingnotify,
garbeam@76 354 [MapRequest] = maprequest,
garbeam@76 355 [PropertyNotify] = propertynotify,
garbeam@76 356 [UnmapNotify] = unmapnotify
garbeam@76 357 };
garbeam@76 358
garbeam@76 359 void
arg@487 360 grabkeys(void) {
arg@581 361 static unsigned int len = sizeof key / sizeof key[0];
garbeam@76 362 unsigned int i;
garbeam@76 363 KeyCode code;
garbeam@76 364
arg@279 365 XUngrabKey(dpy, AnyKey, AnyModifier, root);
garbeam@76 366 for(i = 0; i < len; i++) {
garbeam@76 367 code = XKeysymToKeycode(dpy, key[i].keysym);
garbeam@76 368 XGrabKey(dpy, code, key[i].mod, root, True,
garbeam@76 369 GrabModeAsync, GrabModeAsync);
arg@160 370 XGrabKey(dpy, code, key[i].mod | LockMask, root, True,
arg@160 371 GrabModeAsync, GrabModeAsync);
arg@291 372 XGrabKey(dpy, code, key[i].mod | numlockmask, root, True,
arg@146 373 GrabModeAsync, GrabModeAsync);
arg@291 374 XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True,
arg@146 375 GrabModeAsync, GrabModeAsync);
garbeam@76 376 }
garbeam@76 377 }
arg@292 378
arg@292 379 void
arg@487 380 procevent(void) {
arg@292 381 XEvent ev;
arg@292 382
arg@292 383 while(XPending(dpy)) {
arg@292 384 XNextEvent(dpy, &ev);
arg@292 385 if(handler[ev.type])
arg@292 386 (handler[ev.type])(&ev); /* call handler */
arg@292 387 }
arg@292 388 }