aewl

annotate event.c @ 384:126e78129f1d

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