annotate event.c @ 16:cb5813c117e2

merge heads
author paulo
date Mon, 09 Apr 2018 20:13:53 -0600
parents 0968b3739b8d
children
rev   line source
paulo@0 1 /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
paulo@0 2 * See LICENSE file for license details.
paulo@0 3 */
paulo@0 4 #include "dwm.h"
paulo@0 5 #include <X11/keysym.h>
paulo@0 6 #include <X11/Xatom.h>
paulo@0 7
paulo@0 8 /* static */
paulo@0 9
paulo@6 10 static unsigned int cmdmod[4];
paulo@6 11 static unsigned int keymode = COMMANDMODE;
paulo@6 12 static KeySym cmdkeysym[4];
paulo@6 13
paulo@0 14 typedef struct {
paulo@0 15 unsigned long mod;
paulo@0 16 KeySym keysym;
paulo@0 17 void (*func)(Arg *arg);
paulo@0 18 Arg arg;
paulo@0 19 } Key;
paulo@0 20
paulo@0 21 KEYS
paulo@0 22
paulo@0 23 #define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
paulo@0 24 #define MOUSEMASK (BUTTONMASK | PointerMotionMask)
paulo@0 25
paulo@0 26 static Client *
paulo@0 27 getclient(Window w) {
paulo@0 28 Client *c;
paulo@0 29
paulo@0 30 for(c = clients; c && c->win != w; c = c->next);
paulo@0 31 return c;
paulo@0 32 }
paulo@0 33
paulo@0 34 static void
paulo@0 35 movemouse(Client *c) {
paulo@0 36 int x1, y1, ocx, ocy, di, nx, ny;
paulo@0 37 unsigned int dui;
paulo@0 38 Window dummy;
paulo@0 39 XEvent ev;
paulo@0 40
paulo@0 41 ocx = nx = c->x;
paulo@0 42 ocy = ny = c->y;
paulo@0 43 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
paulo@0 44 None, cursor[CurMove], CurrentTime) != GrabSuccess)
paulo@0 45 return;
paulo@0 46 c->ismax = False;
paulo@0 47 XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
paulo@0 48 for(;;) {
paulo@0 49 XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
paulo@0 50 switch (ev.type) {
paulo@0 51 case ButtonRelease:
paulo@0 52 XUngrabPointer(dpy, CurrentTime);
paulo@0 53 return;
paulo@0 54 case ConfigureRequest:
paulo@0 55 case Expose:
paulo@0 56 case MapRequest:
paulo@0 57 handler[ev.type](&ev);
paulo@0 58 break;
paulo@0 59 case MotionNotify:
paulo@0 60 XSync(dpy, False);
paulo@0 61 nx = ocx + (ev.xmotion.x - x1);
paulo@0 62 ny = ocy + (ev.xmotion.y - y1);
paulo@0 63 if(abs(wax + nx) < SNAP)
paulo@0 64 nx = wax;
paulo@0 65 else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP)
paulo@0 66 nx = wax + waw - c->w - 2 * c->border;
paulo@0 67 if(abs(way - ny) < SNAP)
paulo@0 68 ny = way;
paulo@0 69 else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP)
paulo@0 70 ny = way + wah - c->h - 2 * c->border;
paulo@0 71 resize(c, nx, ny, c->w, c->h, False);
paulo@0 72 break;
paulo@0 73 }
paulo@0 74 }
paulo@0 75 }
paulo@0 76
paulo@0 77 static void
paulo@0 78 resizemouse(Client *c) {
paulo@0 79 int ocx, ocy;
paulo@0 80 int nw, nh;
paulo@0 81 XEvent ev;
paulo@0 82
paulo@0 83 ocx = c->x;
paulo@0 84 ocy = c->y;
paulo@0 85 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
paulo@0 86 None, cursor[CurResize], CurrentTime) != GrabSuccess)
paulo@0 87 return;
paulo@0 88 c->ismax = False;
paulo@0 89 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
paulo@0 90 for(;;) {
paulo@0 91 XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
paulo@0 92 switch(ev.type) {
paulo@0 93 case ButtonRelease:
paulo@0 94 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
paulo@0 95 c->w + c->border - 1, c->h + c->border - 1);
paulo@0 96 XUngrabPointer(dpy, CurrentTime);
paulo@0 97 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
paulo@0 98 return;
paulo@0 99 case ConfigureRequest:
paulo@0 100 case Expose:
paulo@0 101 case MapRequest:
paulo@0 102 handler[ev.type](&ev);
paulo@0 103 break;
paulo@0 104 case MotionNotify:
paulo@0 105 XSync(dpy, False);
paulo@0 106 if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
paulo@0 107 nw = 1;
paulo@0 108 if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
paulo@0 109 nh = 1;
paulo@0 110 resize(c, c->x, c->y, nw, nh, True);
paulo@0 111 break;
paulo@0 112 }
paulo@0 113 }
paulo@0 114 }
paulo@0 115
paulo@0 116 static void
paulo@0 117 buttonpress(XEvent *e) {
paulo@0 118 int x;
paulo@0 119 Arg a;
paulo@0 120 Client *c;
paulo@0 121 XButtonPressedEvent *ev = &e->xbutton;
paulo@0 122
paulo@0 123 if(barwin == ev->window) {
paulo@0 124 x = 0;
paulo@0 125 for(a.i = 0; a.i < ntags; a.i++) {
paulo@0 126 x += textw(tags[a.i]);
paulo@0 127 if(ev->x < x) {
paulo@0 128 if(ev->button == Button1) {
paulo@0 129 if(ev->state & MODKEY)
paulo@0 130 tag(&a);
paulo@0 131 else
paulo@0 132 view(&a);
paulo@0 133 }
paulo@0 134 else if(ev->button == Button3) {
paulo@0 135 if(ev->state & MODKEY)
paulo@0 136 toggletag(&a);
paulo@0 137 else
paulo@0 138 toggleview(&a);
paulo@0 139 }
paulo@0 140 return;
paulo@0 141 }
paulo@0 142 }
paulo@0 143 if(ev->x < x + blw)
paulo@0 144 switch(ev->button) {
paulo@0 145 case Button1:
paulo@0 146 a.i = -1;
paulo@0 147 setlayout(&a);
paulo@0 148 break;
pang@2 149 case Button3:
pang@2 150 a.i = -2;
pang@2 151 setlayout(&a);
pang@2 152 break;
paulo@0 153 case Button4:
paulo@0 154 a.i = 1;
paulo@0 155 incnmaster(&a);
paulo@0 156 break;
paulo@0 157 case Button5:
paulo@0 158 a.i = -1;
paulo@0 159 incnmaster(&a);
paulo@0 160 break;
paulo@0 161 }
paulo@0 162 if(ev->x > x + blw)
paulo@0 163 switch(ev->button) {
paulo@3 164 case Button1: zoom(NULL); break;
paulo@3 165 case Button2: toggleversatile(NULL); break;
paulo@3 166 case Button3: killclient(NULL); break;
paulo@3 167 case Button4: pushup(NULL); break;
paulo@3 168 case Button5: pushdown(NULL); break;
paulo@3 169 }
paulo@3 170 }
paulo@3 171 else if(tbarwin == ev->window) {
paulo@3 172 int i, w;
paulo@4 173 for(i=0, c = clients; c; c = c->next) {
paulo@4 174 if(isvisible(c))
paulo@4 175 i++;
paulo@4 176 }
paulo@4 177 if(!i || i >= MAX_TASKS)
paulo@4 178 return;
paulo@4 179 else
paulo@4 180 w = sw/i;
paulo@3 181 switch(ev->button) {
paulo@3 182 case Button4: focusprev(NULL); return; break;
paulo@3 183 case Button5: focusnext(NULL); return; break;
paulo@0 184 }
paulo@3 185 for(i=1, c = clients; c && i*w<=sw; c = c->next, i++) {
paulo@3 186 for(; c && !isvisible(c); c = c->next);
paulo@3 187 if(i*w > ev->x) {
paulo@3 188 switch(ev->button) {
paulo@3 189 case Button1: focus(c); restack(); break;
paulo@3 190 case Button3: focus(c); zoom(NULL); break;
paulo@3 191 }
paulo@3 192 break;
paulo@3 193 }
paulo@3 194 }
paulo@3 195 }
paulo@0 196 else if((c = getclient(ev->window))) {
paulo@0 197 focus(c);
paulo@0 198 if(CLEANMASK(ev->state) != MODKEY)
paulo@0 199 return;
paulo@0 200 if(ev->button == Button1 && (lt->arrange == versatile || c->isversatile)) {
paulo@0 201 restack();
paulo@0 202 movemouse(c);
paulo@0 203 }
paulo@0 204 else if(ev->button == Button2)
paulo@0 205 zoom(NULL);
paulo@0 206 else if(ev->button == Button3
paulo@0 207 && (lt->arrange == versatile || c->isversatile) && !c->isfixed)
paulo@0 208 {
paulo@0 209 restack();
paulo@0 210 resizemouse(c);
paulo@0 211 }
paulo@0 212 }
paulo@0 213 }
paulo@0 214
paulo@0 215 static void
paulo@0 216 configurerequest(XEvent *e) {
paulo@0 217 Client *c;
paulo@0 218 XConfigureRequestEvent *ev = &e->xconfigurerequest;
paulo@0 219 XWindowChanges wc;
paulo@0 220
paulo@0 221 if((c = getclient(ev->window))) {
paulo@0 222 c->ismax = False;
paulo@0 223 if(ev->value_mask & CWBorderWidth)
paulo@0 224 c->border = ev->border_width;
paulo@0 225 if(c->isfixed || c->isversatile || (lt->arrange == versatile)) {
paulo@0 226 if(ev->value_mask & CWX)
paulo@0 227 c->x = ev->x;
paulo@0 228 if(ev->value_mask & CWY)
paulo@0 229 c->y = ev->y;
paulo@0 230 if(ev->value_mask & CWWidth)
paulo@0 231 c->w = ev->width;
paulo@0 232 if(ev->value_mask & CWHeight)
paulo@0 233 c->h = ev->height;
paulo@0 234 if((ev->value_mask & (CWX | CWY))
paulo@0 235 && !(ev->value_mask & (CWWidth | CWHeight)))
paulo@0 236 configure(c);
paulo@0 237 if(isvisible(c))
paulo@0 238 /* XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); */
paulo@0 239 resize(c, c->x, c->y, c->w, c->h, False);
paulo@0 240 }
paulo@0 241 else
paulo@0 242 configure(c);
paulo@0 243 }
paulo@0 244 else {
paulo@0 245 wc.x = ev->x;
paulo@0 246 wc.y = ev->y;
paulo@0 247 wc.width = ev->width;
paulo@0 248 wc.height = ev->height;
paulo@0 249 wc.border_width = ev->border_width;
paulo@0 250 wc.sibling = ev->above;
paulo@0 251 wc.stack_mode = ev->detail;
paulo@0 252 XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
paulo@0 253 }
paulo@0 254 XSync(dpy, False);
paulo@0 255 }
paulo@0 256
paulo@0 257 static void
paulo@0 258 destroynotify(XEvent *e) {
paulo@0 259 Client *c;
paulo@0 260 XDestroyWindowEvent *ev = &e->xdestroywindow;
paulo@0 261
paulo@0 262 if((c = getclient(ev->window)))
paulo@0 263 unmanage(c);
paulo@0 264 }
paulo@0 265
paulo@0 266 static void
paulo@0 267 enternotify(XEvent *e) {
paulo@0 268 Client *c;
paulo@0 269 XCrossingEvent *ev = &e->xcrossing;
paulo@0 270
paulo@0 271 if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
paulo@0 272 return;
paulo@3 273 if(!CLICK_TO_FOCUS && (c = getclient(ev->window)) && isvisible(c))
paulo@0 274 focus(c);
paulo@0 275 else if(ev->window == root) {
paulo@0 276 selscreen = True;
paulo@0 277 for(c = stack; c && !isvisible(c); c = c->snext);
paulo@0 278 focus(c);
paulo@0 279 }
paulo@0 280 }
paulo@0 281
paulo@0 282 static void
paulo@0 283 expose(XEvent *e) {
paulo@0 284 XExposeEvent *ev = &e->xexpose;
paulo@0 285
paulo@0 286 if(ev->count == 0) {
paulo@3 287 if(barwin == ev->window || tbarwin == ev->window)
paulo@0 288 drawstatus();
paulo@0 289 }
paulo@0 290 }
paulo@0 291
paulo@0 292 static void
paulo@6 293 defkeypress(XEvent *e) {
paulo@0 294 static unsigned int len = sizeof key / sizeof key[0];
paulo@0 295 unsigned int i;
paulo@0 296 KeySym keysym;
paulo@0 297 XKeyEvent *ev = &e->xkey;
paulo@0 298
paulo@0 299 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
paulo@0 300 for(i = 0; i < len; i++)
paulo@0 301 if(keysym == key[i].keysym
paulo@0 302 && CLEANMASK(key[i].mod) == CLEANMASK(ev->state))
paulo@0 303 {
paulo@0 304 if(key[i].func)
paulo@0 305 key[i].func(&key[i].arg);
paulo@0 306 }
paulo@0 307 }
paulo@0 308
paulo@0 309 static void
paulo@0 310 leavenotify(XEvent *e) {
paulo@0 311 XCrossingEvent *ev = &e->xcrossing;
paulo@0 312
paulo@0 313 if((ev->window == root) && !ev->same_screen) {
paulo@0 314 selscreen = False;
paulo@0 315 focus(NULL);
paulo@0 316 }
paulo@0 317 }
paulo@0 318
paulo@0 319 static void
paulo@0 320 mappingnotify(XEvent *e) {
paulo@0 321 XMappingEvent *ev = &e->xmapping;
paulo@0 322
paulo@0 323 XRefreshKeyboardMapping(ev);
paulo@0 324 if(ev->request == MappingKeyboard)
paulo@0 325 grabkeys();
paulo@0 326 }
paulo@0 327
paulo@0 328 static void
paulo@0 329 maprequest(XEvent *e) {
paulo@0 330 static XWindowAttributes wa;
paulo@0 331 XMapRequestEvent *ev = &e->xmaprequest;
paulo@0 332
paulo@0 333 if(!XGetWindowAttributes(dpy, ev->window, &wa))
paulo@0 334 return;
paulo@0 335 if(wa.override_redirect)
paulo@0 336 return;
paulo@0 337 if(!getclient(ev->window))
paulo@0 338 manage(ev->window, &wa);
paulo@0 339 }
paulo@0 340
paulo@0 341 static void
paulo@0 342 propertynotify(XEvent *e) {
paulo@0 343 Client *c;
paulo@0 344 Window trans;
paulo@0 345 XPropertyEvent *ev = &e->xproperty;
paulo@0 346
paulo@0 347 if(ev->state == PropertyDelete)
paulo@0 348 return; /* ignore */
paulo@0 349 if((c = getclient(ev->window))) {
paulo@0 350 switch (ev->atom) {
paulo@0 351 default: break;
paulo@0 352 case XA_WM_TRANSIENT_FOR:
paulo@0 353 XGetTransientForHint(dpy, c->win, &trans);
paulo@0 354 if(!c->isversatile && (c->isversatile = (getclient(trans) != NULL)))
paulo@0 355 lt->arrange();
paulo@0 356 break;
paulo@0 357 case XA_WM_NORMAL_HINTS:
paulo@0 358 updatesizehints(c);
paulo@0 359 break;
paulo@0 360 }
paulo@0 361 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
paulo@0 362 updatetitle(c);
paulo@0 363 if(c == sel)
paulo@0 364 drawstatus();
paulo@0 365 }
paulo@0 366 }
paulo@0 367 }
paulo@0 368
paulo@0 369 static void
paulo@0 370 unmapnotify(XEvent *e) {
paulo@0 371 Client *c;
paulo@0 372 XUnmapEvent *ev = &e->xunmap;
paulo@0 373
paulo@0 374 if((c = getclient(ev->window)))
paulo@0 375 unmanage(c);
paulo@0 376 }
paulo@0 377
paulo@6 378 typedef struct {
paulo@6 379 unsigned int mod[4];
paulo@6 380 KeySym keysym[4];
paulo@6 381 void (*func)(Arg *arg);
paulo@6 382 Arg arg;
paulo@6 383 } Command;
paulo@6 384
paulo@6 385 CMDKEYS
paulo@6 386 COMMANDS
paulo@6 387
paulo@6 388 void
paulo@6 389 keypress(XEvent *e) {
paulo@6 390 unsigned int i, j;
paulo@6 391 Arg a = {0};
paulo@6 392 Bool ismatch = False, maybematch = False;
paulo@6 393 KeySym keysym;
paulo@6 394 XKeyEvent *ev;
paulo@6 395
paulo@6 396 if(keymode == INSERTMODE)
paulo@6 397 defkeypress(e);
paulo@6 398 else if(keymode == COMMANDMODE) {
paulo@6 399 ev = &e->xkey;
paulo@6 400 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
paulo@6 401 if(keysym < XK_Shift_L || keysym > XK_Hyper_R) {
paulo@6 402 for(j = 0; j < LENGTH(cmdkeysym); j++)
paulo@6 403 if(cmdkeysym[j] == 0) {
paulo@6 404 cmdkeysym[j] = keysym;
paulo@6 405 cmdmod[j] = ev->state;
paulo@6 406 break;
paulo@6 407 }
paulo@6 408 for(i = 0; i < LENGTH(commands); i++) {
paulo@6 409 for(j = 0; j < LENGTH(cmdkeysym); j++) {
paulo@6 410 if(cmdkeysym[j] == commands[i].keysym[j]
paulo@6 411 && CLEANMASK(cmdmod[j]) == CLEANMASK(commands[i].mod[j]))
paulo@6 412 ismatch = True;
paulo@6 413 else if(cmdkeysym[j] == 0
paulo@6 414 && cmdmod[j] == 0) {
paulo@6 415 ismatch = False;
paulo@6 416 maybematch = True;
paulo@6 417 break;
paulo@6 418 } else {
paulo@6 419 ismatch = False;
paulo@6 420 break;
paulo@6 421 }
paulo@6 422 }
paulo@6 423 if(ismatch) {
paulo@6 424 if(commands[i].func)
paulo@6 425 commands[i].func(&(commands[i].arg));
paulo@6 426 clearcmd(&a);
paulo@6 427 break;
paulo@6 428 }
paulo@6 429
paulo@6 430 }
paulo@6 431 if(!maybematch)
paulo@6 432 clearcmd(&a);
paulo@6 433 if(!ismatch) {
paulo@6 434 for(i = 0; i < LENGTH(cmdkeys); i++)
paulo@6 435 if(keysym == cmdkeys[i].keysym
paulo@6 436 && CLEANMASK(cmdkeys[i].mod) == CLEANMASK(ev->state)
paulo@6 437 && cmdkeys[i].func) {
paulo@6 438 cmdkeys[i].func(&(cmdkeys[i].arg));
paulo@6 439 ismatch = True;
paulo@6 440 break;
paulo@6 441 }
paulo@6 442 }
paulo@6 443 }
paulo@6 444 }
paulo@6 445 }
paulo@6 446
paulo@0 447 /* extern */
paulo@0 448
paulo@0 449 void (*handler[LASTEvent]) (XEvent *) = {
paulo@0 450 [ButtonPress] = buttonpress,
paulo@0 451 [ConfigureRequest] = configurerequest,
paulo@0 452 [DestroyNotify] = destroynotify,
paulo@0 453 [EnterNotify] = enternotify,
paulo@0 454 [LeaveNotify] = leavenotify,
paulo@0 455 [Expose] = expose,
paulo@0 456 [KeyPress] = keypress,
paulo@0 457 [MappingNotify] = mappingnotify,
paulo@0 458 [MapRequest] = maprequest,
paulo@0 459 [PropertyNotify] = propertynotify,
paulo@0 460 [UnmapNotify] = unmapnotify
paulo@0 461 };
paulo@0 462
paulo@0 463 void
paulo@6 464 grabdefkeys(void) {
paulo@0 465 static unsigned int len = sizeof key / sizeof key[0];
paulo@0 466 unsigned int i;
paulo@0 467 KeyCode code;
paulo@0 468
paulo@0 469 XUngrabKey(dpy, AnyKey, AnyModifier, root);
paulo@0 470 for(i = 0; i < len; i++) {
paulo@0 471 code = XKeysymToKeycode(dpy, key[i].keysym);
paulo@0 472 XGrabKey(dpy, code, key[i].mod, root, True,
paulo@0 473 GrabModeAsync, GrabModeAsync);
paulo@0 474 XGrabKey(dpy, code, key[i].mod | LockMask, root, True,
paulo@0 475 GrabModeAsync, GrabModeAsync);
paulo@0 476 XGrabKey(dpy, code, key[i].mod | numlockmask, root, True,
paulo@0 477 GrabModeAsync, GrabModeAsync);
paulo@0 478 XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True,
paulo@0 479 GrabModeAsync, GrabModeAsync);
paulo@0 480 }
paulo@0 481 }
paulo@6 482
paulo@6 483 void
paulo@6 484 clearcmd(Arg *arg) {
paulo@6 485 unsigned int i;
paulo@6 486
paulo@6 487 for(i = 0; i < LENGTH(cmdkeysym); i++) {
paulo@6 488 cmdkeysym[i] = 0;
paulo@6 489 cmdmod[i] = 0;
paulo@6 490 }
paulo@6 491 }
paulo@6 492
paulo@6 493 void
paulo@6 494 grabkeys(void) {
paulo@6 495 if(keymode == INSERTMODE) {
paulo@6 496 XUngrabKeyboard(dpy, CurrentTime);
paulo@6 497 grabdefkeys();
paulo@6 498 } else if(keymode == COMMANDMODE) {
paulo@6 499 XUngrabKey(dpy, AnyKey, AnyModifier, root);
paulo@6 500 //XGrabKey(dpy, AnyKey, AnyModifier, root,
paulo@6 501 // True, GrabModeAsync, GrabModeAsync);
paulo@6 502 XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
paulo@6 503 }
paulo@6 504 }
paulo@6 505
paulo@6 506 void
paulo@6 507 setkeymode(Arg *arg) {
paulo@6 508 Arg a = {0};
paulo@6 509
paulo@6 510 if(!arg)
paulo@6 511 return;
paulo@6 512 keymode = arg->i;
paulo@6 513 clearcmd(&a);
paulo@6 514 grabkeys();
paulo@13 515 if(sel)
paulo@13 516 focus(sel);
paulo@13 517 else
paulo@13 518 drawstatus();
paulo@6 519 }
paulo@6 520
paulo@6 521 unsigned int
paulo@6 522 getkeymode(void) {
paulo@6 523 return keymode;
paulo@6 524 }
paulo@6 525
paulo@6 526 void
paulo@6 527 func_insert(void (*argfunc)(Arg *), Arg *arg) {
paulo@6 528 Arg a = { .i = INSERTMODE };
paulo@6 529 argfunc(arg);
paulo@6 530 setkeymode(&a);
paulo@6 531 }