Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 549 lines (450 sloc) 11.416 kB
3d12c94 Initial revision
bernd authored
1 /*
2 * calmwm - the calm window manager
3 *
4 * Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
e5cabb0 - Remove the "all rights reserved" tag at the top of most of the source
oga authored
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3d12c94 Initial revision
bernd authored
17 *
18 * $Id$
19 */
20
21 /*
22 * NOTE:
23 * It is the responsibility of the caller to deal with memory
24 * management of the xevent's.
25 */
26
27 #include "headers.h"
28 #include "calmwm.h"
29
30 /*
31 * NOTE: in reality, many of these should move to client.c now that
32 * we've got this nice event layer.
33 */
34
35 void
36 xev_handle_maprequest(struct xevent *xev, XEvent *ee)
37 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
38 XMapRequestEvent *e = &ee->xmaprequest;
39 XWindowAttributes xattr;
40 struct client_ctx *cc = NULL, *old_cc;
41
3d12c94 Initial revision
bernd authored
42 #ifdef notyet
43 int state;
44 #endif
45
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
46 if ((old_cc = client_current()) != NULL)
3d12c94 Initial revision
bernd authored
47 client_ptrsave(old_cc);
48
75182c6 hit it with the knf stick.
oga authored
49 if ((cc = client_find(e->window)) == NULL) {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
50 XGetWindowAttributes(X_Dpy, e->window, &xattr);
3d12c94 Initial revision
bernd authored
51 cc = client_new(e->window, screen_fromroot(xattr.root), 1);
25af744 Kill obviously dead variable.
oga authored
52 }
3d12c94 Initial revision
bernd authored
53
54 #ifdef notyet /* XXX - possibly, we shouldn't map if
55 * the window is withdrawn. */
56 if (xu_getstate(cc, &state) == 0 && state == WithdrawnState)
57 warnx("WITHDRAWNSTATE for %s", cc->name);
58 #endif
59
60 client_ptrwarp(cc);
61 xev_register(xev);
62 }
63
64 void
65 xev_handle_unmapnotify(struct xevent *xev, XEvent *ee)
66 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
67 XUnmapEvent *e = &ee->xunmap;
68 struct client_ctx *cc;
3d12c94 Initial revision
bernd authored
69
01eecac Don't client_delete() on an Unmap event, only do that on a client del…
oga authored
70 if ((cc = client_find(e->window)) != NULL)
ec8e605 remove pwin, bringing us to one client, one window. we no longer have
okan authored
71 client_hide(cc);
3d12c94 Initial revision
bernd authored
72
73 xev_register(xev);
74 }
75
76 void
77 xev_handle_destroynotify(struct xevent *xev, XEvent *ee)
78 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
79 XDestroyWindowEvent *e = &ee->xdestroywindow;
80 struct client_ctx *cc;
3d12c94 Initial revision
bernd authored
81
82 if ((cc = client_find(e->window)) != NULL)
83 client_delete(cc, 1, 1);
84
85 xev_register(xev);
86 }
87
88 void
89 xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
90 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
91 XConfigureRequestEvent *e = &ee->xconfigurerequest;
92 struct client_ctx *cc;
93 struct screen_ctx *sc;
94 XWindowChanges wc;
3d12c94 Initial revision
bernd authored
95
96 if ((cc = client_find(e->window)) != NULL) {
97 sc = CCTOSC(cc);
98
99 if (e->value_mask & CWWidth)
100 cc->geom.width = e->width;
101 if (e->value_mask & CWHeight)
102 cc->geom.height = e->height;
103 if (e->value_mask & CWX)
104 cc->geom.x = e->x;
105 if (e->value_mask & CWY)
106 cc->geom.y = e->y;
107
75182c6 hit it with the knf stick.
oga authored
108 if (cc->geom.x == 0 &&
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
109 cc->geom.width >= DisplayWidth(X_Dpy, sc->which))
3d12c94 Initial revision
bernd authored
110 cc->geom.x -= cc->bwidth;
111
75182c6 hit it with the knf stick.
oga authored
112 if (cc->geom.y == 0 &&
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
113 cc->geom.height >= DisplayHeight(X_Dpy, sc->which))
75182c6 hit it with the knf stick.
oga authored
114 cc->geom.y -= cc->bwidth;
3d12c94 Initial revision
bernd authored
115
116 wc.x = cc->geom.x - cc->bwidth;
117 wc.y = cc->geom.y - cc->bwidth;
118 wc.width = cc->geom.width + cc->bwidth*2;
119 wc.height = cc->geom.height + cc->bwidth*2;
ec8e605 remove pwin, bringing us to one client, one window. we no longer have
okan authored
120 wc.border_width = cc->bwidth;
3d12c94 Initial revision
bernd authored
121
ec8e605 remove pwin, bringing us to one client, one window. we no longer have
okan authored
122 XConfigureWindow(X_Dpy, cc->win, e->value_mask, &wc);
3d12c94 Initial revision
bernd authored
123 xev_reconfig(cc);
ec8e605 remove pwin, bringing us to one client, one window. we no longer have
okan authored
124 } else {
125 /* let it do what it wants, it'll be ours when we map it. */
126 wc.x = e->x;
127 wc.y = e->y;
128 wc.width = e->width;
129 wc.height = e->height;
130 wc.stack_mode = Above;
131 e->value_mask &= ~CWStackMode;
132
133 XConfigureWindow(X_Dpy, e->window, e->value_mask, &wc);
3d12c94 Initial revision
bernd authored
134 }
135
136 xev_register(xev);
137 }
138
139 void
140 xev_handle_propertynotify(struct xevent *xev, XEvent *ee)
141 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
142 XPropertyEvent *e = &ee->xproperty;
143 struct client_ctx *cc;
144 long tmp;
3d12c94 Initial revision
bernd authored
145
146 if ((cc = client_find(e->window)) != NULL) {
75182c6 hit it with the knf stick.
oga authored
147 switch (e->atom) {
3d12c94 Initial revision
bernd authored
148 case XA_WM_NORMAL_HINTS:
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
149 XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp);
3d12c94 Initial revision
bernd authored
150 break;
151 case XA_WM_NAME:
152 client_setname(cc);
153 break;
154 default:
155 /* do nothing */
156 break;
157 }
158 }
159
160 xev_register(xev);
161 }
162
163 void
164 xev_reconfig(struct client_ctx *cc)
165 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
166 XConfigureEvent ce;
3d12c94 Initial revision
bernd authored
167
168 ce.type = ConfigureNotify;
169 ce.event = cc->win;
170 ce.window = cc->win;
171 ce.x = cc->geom.x;
172 ce.y = cc->geom.y;
173 ce.width = cc->geom.width;
174 ce.height = cc->geom.height;
ec8e605 remove pwin, bringing us to one client, one window. we no longer have
okan authored
175 ce.border_width = cc->bwidth;
3d12c94 Initial revision
bernd authored
176 ce.above = None;
177 ce.override_redirect = 0;
178
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
179 XSendEvent(X_Dpy, cc->win, False, StructureNotifyMask, (XEvent *)&ce);
3d12c94 Initial revision
bernd authored
180 }
181
182 void
183 xev_handle_enternotify(struct xevent *xev, XEvent *ee)
184 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
185 XCrossingEvent *e = &ee->xcrossing;
186 struct client_ctx *cc;
3d12c94 Initial revision
bernd authored
187
188 if ((cc = client_find(e->window)) == NULL) {
189 /*
190 * XXX - later. messes up unclutter. but may be
191 * needed when we introduce menu windows and such into
192 * the main event loop.
193 */
194 #ifdef notyet
195 if (e->window != e->root)
196 client_nocurrent();
197 #endif
198 } else
199 client_setactive(cc, 1);
200
201 xev_register(xev);
202 }
203
204 void
205 xev_handle_leavenotify(struct xevent *xev, XEvent *ee)
206 {
207 client_leave(NULL);
208
209 xev_register(xev);
210 }
211
212 /* We can split this into two event handlers. */
213 void
214 xev_handle_buttonpress(struct xevent *xev, XEvent *ee)
215 {
9657664 The mousebinding code missing a break once it had found the correct
oga authored
216 XButtonEvent *e = &ee->xbutton;
217 struct client_ctx *cc;
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
218 struct screen_ctx *sc;
9657664 The mousebinding code missing a break once it had found the correct
oga authored
219 struct mousebinding *mb;
3d12c94 Initial revision
bernd authored
220
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
221 sc = screen_fromroot(e->root);
3d12c94 Initial revision
bernd authored
222 cc = client_find(e->window);
223
4f2d472 Ignore caps lock and numlock for keyboard bindings. The way Xlib makes
oga authored
224 /* Ignore caps lock and numlock */
225 e->state &= ~(Mod2Mask | LockMask);
226
19ba704 Just rework the mouse binding calculation on event to look like the
oga authored
227 TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) {
228 if (e->button == mb->button && e->state == mb->modmask)
229 break;
9657664 The mousebinding code missing a break once it had found the correct
oga authored
230 }
3d12c94 Initial revision
bernd authored
231
19ba704 Just rework the mouse binding calculation on event to look like the
oga authored
232 if (mb == NULL)
3d12c94 Initial revision
bernd authored
233 goto out;
234
19ba704 Just rework the mouse binding calculation on event to look like the
oga authored
235 if (mb->context == MOUSEBIND_CTX_ROOT) {
236 if (e->window != sc->rootwin)
237 goto out;
238 } else if (mb->context == MOUSEBIND_CTX_WIN) {
239 cc = client_find(e->window);
240 if (cc == NULL)
241 goto out;
3d12c94 Initial revision
bernd authored
242 }
19ba704 Just rework the mouse binding calculation on event to look like the
oga authored
243
244 (*mb->callback)(cc, e);
5034a77 KNF, no binary change.
oga authored
245 out:
3d12c94 Initial revision
bernd authored
246 xev_register(xev);
247 }
248
249 void
250 xev_handle_buttonrelease(struct xevent *xev, XEvent *ee)
251 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
252 struct client_ctx *cc;
3d12c94 Initial revision
bernd authored
253
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
254 if ((cc = client_current()) != NULL)
3d12c94 Initial revision
bernd authored
255 group_sticky_toggle_exit(cc);
256
257 xev_register(xev);
258 }
259
260 void
261 xev_handle_keypress(struct xevent *xev, XEvent *ee)
262 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
263 XKeyEvent *e = &ee->xkey;
264 struct client_ctx *cc = NULL;
265 struct keybinding *kb;
266 KeySym keysym, skeysym;
267 int modshift;
3d12c94 Initial revision
bernd authored
268
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
269 keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
270 skeysym = XKeycodeToKeysym(X_Dpy, e->keycode, 1);
75182c6 hit it with the knf stick.
oga authored
271
4f2d472 Ignore caps lock and numlock for keyboard bindings. The way Xlib makes
oga authored
272 /* we don't care about caps lock and numlock here */
273 e->state &= ~(LockMask | Mod2Mask);
274
75182c6 hit it with the knf stick.
oga authored
275 TAILQ_FOREACH(kb, &Conf.keybindingq, entry) {
3d12c94 Initial revision
bernd authored
276 if (keysym != kb->keysym && skeysym == kb->keysym)
277 modshift = ShiftMask;
278 else
279 modshift = 0;
280
281 if ((kb->modmask | modshift) != e->state)
282 continue;
283
284 if ((kb->keycode != 0 && kb->keysym == NoSymbol &&
75182c6 hit it with the knf stick.
oga authored
285 kb->keycode == e->keycode) || kb->keysym ==
286 (modshift == 0 ? keysym : skeysym))
3d12c94 Initial revision
bernd authored
287 break;
75182c6 hit it with the knf stick.
oga authored
288 }
3d12c94 Initial revision
bernd authored
289
290 if (kb == NULL)
291 goto out;
292
75182c6 hit it with the knf stick.
oga authored
293 if ((kb->flags & (KBFLAG_NEEDCLIENT)) &&
3d12c94 Initial revision
bernd authored
294 (cc = client_find(e->window)) == NULL &&
295 (cc = client_current()) == NULL)
296 if (kb->flags & KBFLAG_NEEDCLIENT)
297 goto out;
298
299 (*kb->callback)(cc, kb->argument);
300
301 out:
302 xev_register(xev);
303 }
304
305 /*
7ef6f63 Typo: s/supression/suppression
oga authored
306 * This is only used for the alt suppression detection.
3d12c94 Initial revision
bernd authored
307 */
308 void
309 xev_handle_keyrelease(struct xevent *xev, XEvent *ee)
310 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
311 XKeyEvent *e = &ee->xkey;
312 struct screen_ctx *sc;
313 struct client_ctx *cc;
314 int keysym;
315
316 sc = screen_fromroot(e->root);
317 cc = client_current();
3d12c94 Initial revision
bernd authored
318
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
319 keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
3d12c94 Initial revision
bernd authored
320 if (keysym != XK_Alt_L && keysym != XK_Alt_R)
321 goto out;
322
323 sc->altpersist = 0;
75182c6 hit it with the knf stick.
oga authored
324
3d12c94 Initial revision
bernd authored
325 /*
326 * XXX - better interface... xevents should not know about
327 * how/when to mtf.
328 */
329 client_mtf(NULL);
330
7957a47 finally implement keyboard binding for group toggling
okan authored
331 if (cc != NULL) {
332 group_sticky_toggle_exit(cc);
333 XUngrabKeyboard(X_Dpy, CurrentTime);
334 }
335
5034a77 KNF, no binary change.
oga authored
336 out:
3d12c94 Initial revision
bernd authored
337 xev_register(xev);
338 }
339
340 void
341 xev_handle_clientmessage(struct xevent *xev, XEvent *ee)
342 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
343 XClientMessageEvent *e = &ee->xclient;
344 Atom xa_wm_change_state;
345 struct client_ctx *cc;
3d12c94 Initial revision
bernd authored
346
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
347 xa_wm_change_state = XInternAtom(X_Dpy, "WM_CHANGE_STATE", False);
348
349 if ((cc = client_find(e->window)) == NULL)
3d12c94 Initial revision
bernd authored
350 goto out;
351
352 if (e->message_type == xa_wm_change_state && e->format == 32 &&
353 e->data.l[0] == IconicState)
354 client_hide(cc);
355 out:
356 xev_register(xev);
357 }
358
96d7310 (mostly) proper xshape event support
okan authored
359 void
a0739c6 Xinerama and XRandR dual head support for cwm(1). Now we detect the x…
oga authored
360 xev_handle_randr(struct xevent *xev, XEvent *ee)
361 {
362 XRRScreenChangeNotifyEvent *rev = (XRRScreenChangeNotifyEvent *)ee;
363 struct client_ctx *cc;
364 struct screen_ctx *sc;
365
366 if ((cc = client_find(rev->window)) != NULL) {
367 XRRUpdateConfiguration(ee);
368 sc = CCTOSC(cc);
369 sc->xmax = rev->width;
370 sc->ymax = rev->height;
371 screen_init_xinerama(sc);
372 }
373 }
374
0444148 fix the froggy problem.
oga authored
375 /*
376 * Called when the keymap has changed.
377 * Ungrab all keys, reload keymap and then regrab
378 */
379 void
380 xev_handle_mapping(struct xevent *xev, XEvent *ee)
381 {
382 XMappingEvent *e = &ee->xmapping;
383 struct keybinding *kb;
384
385 TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
386 conf_ungrab(&Conf, kb);
387
388 XRefreshKeyboardMapping(e);
389
390 TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
391 conf_grab(&Conf, kb);
392
393 xev_register(xev);
394 }
395
3d12c94 Initial revision
bernd authored
396 /*
397 * X Event handling
398 */
399
75182c6 hit it with the knf stick.
oga authored
400 static struct xevent_q _xevq, _xevq_putaway;
401 static short _xev_q_lock = 0;
402 volatile sig_atomic_t _xev_quit = 0;
3d12c94 Initial revision
bernd authored
403
404 void
405 xev_init(void)
406 {
407 TAILQ_INIT(&_xevq);
408 TAILQ_INIT(&_xevq_putaway);
409 }
410
411 struct xevent *
412 xev_new(Window *win, Window *root,
413 int type, void (*cb)(struct xevent *, XEvent *), void *arg)
414 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
415 struct xevent *xev;
3d12c94 Initial revision
bernd authored
416
417 XMALLOC(xev, struct xevent);
418 xev->xev_win = win;
419 xev->xev_root = root;
420 xev->xev_type = type;
421 xev->xev_cb = cb;
422 xev->xev_arg = arg;
423
424 return (xev);
425 }
426
427 void
428 xev_register(struct xevent *xev)
429 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
430 struct xevent_q *xq;
3d12c94 Initial revision
bernd authored
431
432 xq = _xev_q_lock ? &_xevq_putaway : &_xevq;
433 TAILQ_INSERT_TAIL(xq, xev, entry);
434 }
435
436 void
437 _xev_reincorporate(void)
438 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
439 struct xevent *xev;
3d12c94 Initial revision
bernd authored
440
441 while ((xev = TAILQ_FIRST(&_xevq_putaway)) != NULL) {
442 TAILQ_REMOVE(&_xevq_putaway, xev, entry);
443 TAILQ_INSERT_TAIL(&_xevq, xev, entry);
444 }
445 }
446
447 void
448 xev_handle_expose(struct xevent *xev, XEvent *ee)
449 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
450 XExposeEvent *e = &ee->xexpose;
451 struct client_ctx *cc;
3d12c94 Initial revision
bernd authored
452
ec8e605 remove pwin, bringing us to one client, one window. we no longer have
okan authored
453 if ((cc = client_find(e->window)) != NULL && e->count == 0)
3d12c94 Initial revision
bernd authored
454 client_draw_border(cc);
455
456 xev_register(xev);
457 }
458
459 #define ASSIGN(xtype) do { \
460 root = e. xtype .root; \
461 win = e. xtype .window; \
462 } while (0)
463
464 #define ASSIGN1(xtype) do { \
465 win = e. xtype .window; \
466 } while (0)
467
468 void
469 xev_loop(void)
470 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
471 Window win, root;
472 XEvent e;
473 struct xevent *xev = NULL, *nextxev;
3d12c94 Initial revision
bernd authored
474 int type;
475
0f18223 Add quit function, bind it per default to CM-q and change exec_wm
simon authored
476 while (_xev_quit == 0) {
3d12c94 Initial revision
bernd authored
477 #ifdef DIAGNOSTIC
478 if (TAILQ_EMPTY(&_xevq))
479 errx(1, "X event queue empty");
75182c6 hit it with the knf stick.
oga authored
480 #endif
3d12c94 Initial revision
bernd authored
481
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
482 XNextEvent(X_Dpy, &e);
3d12c94 Initial revision
bernd authored
483 type = e.type;
484
485 win = root = 0;
486
487 switch (type) {
488 case MapRequest:
489 ASSIGN1(xmaprequest);
490 break;
491 case UnmapNotify:
492 ASSIGN1(xunmap);
493 break;
494 case ConfigureRequest:
495 ASSIGN1(xconfigurerequest);
496 break;
497 case PropertyNotify:
498 ASSIGN1(xproperty);
499 break;
500 case EnterNotify:
501 case LeaveNotify:
502 ASSIGN(xcrossing);
503 break;
504 case ButtonPress:
505 ASSIGN(xbutton);
506 break;
507 case ButtonRelease:
508 ASSIGN(xbutton);
509 break;
510 case KeyPress:
511 case KeyRelease:
512 ASSIGN(xkey);
513 break;
514 case DestroyNotify:
515 ASSIGN1(xdestroywindow);
516 break;
517 case ClientMessage:
518 ASSIGN1(xclient);
519 break;
96d7310 (mostly) proper xshape event support
okan authored
520 default:
ec8e605 remove pwin, bringing us to one client, one window. we no longer have
okan authored
521 if (e.type == Randr_ev)
a0739c6 Xinerama and XRandR dual head support for cwm(1). Now we detect the x…
oga authored
522 xev_handle_randr(xev, &e);
3d12c94 Initial revision
bernd authored
523 break;
524 }
525
526 /*
527 * Now, search for matches, and call each of them.
528 */
529 _xev_q_lock = 1;
530 for (xev = TAILQ_FIRST(&_xevq); xev != NULL; xev = nextxev) {
531 nextxev = TAILQ_NEXT(xev, entry);
532
533 if ((type != xev->xev_type && xev->xev_type != 0) ||
534 (xev->xev_win != NULL && win != *xev->xev_win) ||
535 (xev->xev_root != NULL && root != *xev->xev_root))
536 continue;
537
538 TAILQ_REMOVE(&_xevq, xev, entry);
539
540 (*xev->xev_cb)(xev, &e);
541 }
542 _xev_q_lock = 0;
543 _xev_reincorporate();
544 }
545 }
546
547 #undef ASSIGN
548 #undef ASSIGN1
Something went wrong with that request. Please try again.