]> Dogcows Code - chaz/openbox/blob - openbox/event.c
1db1829c402a7478620dfea9e67ff8f5b1aa617f
[chaz/openbox] / openbox / event.c
1 #include "openbox.h"
2 #include "client.h"
3 #include "xerror.h"
4 #include "prop.h"
5 #include "config.h"
6 #include "screen.h"
7 #include "frame.h"
8 #include "menu.h"
9 #include "framerender.h"
10 #include "focus.h"
11 #include "moveresize.h"
12 #include "stacking.h"
13 #include "extensions.h"
14 #include "timer.h"
15 #include "dispatch.h"
16
17 #include <X11/Xlib.h>
18 #include <X11/keysym.h>
19 #include <X11/Xatom.h>
20 #ifdef HAVE_SYS_SELECT_H
21 # include <sys/select.h>
22 #endif
23
24 static void event_process(XEvent *e);
25 static void event_handle_root(XEvent *e);
26 static void event_handle_client(Client *c, XEvent *e);
27 static void event_handle_menu(Menu *menu, XEvent *e);
28
29 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
30 (e)->xfocus.detail > NotifyNonlinearVirtual)
31 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
32 (e)->xfocus.detail == NotifyInferior || \
33 (e)->xfocus.detail == NotifyAncestor || \
34 (e)->xfocus.detail > NotifyNonlinearVirtual)
35
36 Time event_lasttime = 0;
37
38 /*! The value of the mask for the NumLock modifier */
39 unsigned int NumLockMask;
40 /*! The value of the mask for the ScrollLock modifier */
41 unsigned int ScrollLockMask;
42 /*! The key codes for the modifier keys */
43 static XModifierKeymap *modmap;
44 /*! Table of the constant modifier masks */
45 static const int mask_table[] = {
46 ShiftMask, LockMask, ControlMask, Mod1Mask,
47 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
48 };
49 static int mask_table_size;
50
51 void event_startup()
52 {
53 mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]);
54
55 /* get lock masks that are defined by the display (not constant) */
56 modmap = XGetModifierMapping(ob_display);
57 g_assert(modmap);
58 if (modmap && modmap->max_keypermod > 0) {
59 size_t cnt;
60 const size_t size = mask_table_size * modmap->max_keypermod;
61 /* get the values of the keyboard lock modifiers
62 Note: Caps lock is not retrieved the same way as Scroll and Num
63 lock since it doesn't need to be. */
64 const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock);
65 const KeyCode scroll_lock = XKeysymToKeycode(ob_display,
66 XK_Scroll_Lock);
67
68 for (cnt = 0; cnt < size; ++cnt) {
69 if (! modmap->modifiermap[cnt]) continue;
70
71 if (num_lock == modmap->modifiermap[cnt])
72 NumLockMask = mask_table[cnt / modmap->max_keypermod];
73 if (scroll_lock == modmap->modifiermap[cnt])
74 ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
75 }
76 }
77 }
78
79 void event_shutdown()
80 {
81 XFreeModifiermap(modmap);
82 }
83
84 void event_loop()
85 {
86 fd_set selset;
87 XEvent e;
88 int x_fd;
89 struct timeval *wait;
90 gboolean had_event = FALSE;
91
92 while (TRUE) {
93 /*
94 There are slightly different event retrieval semantics here for
95 local (or high bandwidth) versus remote (or low bandwidth)
96 connections to the display/Xserver.
97 */
98 if (ob_remote) {
99 if (!XPending(ob_display))
100 break;
101 } else {
102 /*
103 This XSync allows for far more compression of events, which
104 makes things like Motion events perform far far better. Since
105 it also means network traffic for every event instead of every
106 X events (where X is the number retrieved at a time), it
107 probably should not be used for setups where Openbox is
108 running on a remote/low bandwidth display/Xserver.
109 */
110 XSync(ob_display, FALSE);
111 if (!XEventsQueued(ob_display, QueuedAlready))
112 break;
113 }
114 XNextEvent(ob_display, &e);
115
116 event_process(&e);
117 had_event = TRUE;
118 }
119
120 if (!had_event) {
121 timer_dispatch((GTimeVal**)&wait);
122 x_fd = ConnectionNumber(ob_display);
123 FD_ZERO(&selset);
124 FD_SET(x_fd, &selset);
125 select(x_fd + 1, &selset, NULL, NULL, wait);
126 }
127 }
128
129 static Window event_get_window(XEvent *e)
130 {
131 Window window;
132
133 /* pick a window */
134 switch (e->type) {
135 case MapRequest:
136 window = e->xmap.window;
137 break;
138 case UnmapNotify:
139 window = e->xunmap.window;
140 break;
141 case DestroyNotify:
142 window = e->xdestroywindow.window;
143 break;
144 case ConfigureRequest:
145 window = e->xconfigurerequest.window;
146 break;
147 default:
148 #ifdef XKB
149 if (extensions_xkb && e->type == extensions_xkb_event_basep) {
150 switch (((XkbAnyEvent*)&e)->xkb_type) {
151 case XkbBellNotify:
152 window = ((XkbBellNotifyEvent*)&e)->window;
153 default:
154 window = None;
155 }
156 } else
157 #endif
158 window = e->xany.window;
159 }
160 return window;
161 }
162
163 static void event_set_lasttime(XEvent *e)
164 {
165 /* grab the lasttime and hack up the state */
166 switch (e->type) {
167 case ButtonPress:
168 case ButtonRelease:
169 event_lasttime = e->xbutton.time;
170 break;
171 case KeyPress:
172 event_lasttime = e->xkey.time;
173 break;
174 case KeyRelease:
175 event_lasttime = e->xkey.time;
176 break;
177 case MotionNotify:
178 event_lasttime = e->xmotion.time;
179 break;
180 case PropertyNotify:
181 event_lasttime = e->xproperty.time;
182 break;
183 case EnterNotify:
184 case LeaveNotify:
185 event_lasttime = e->xcrossing.time;
186 break;
187 default:
188 event_lasttime = CurrentTime;
189 break;
190 }
191 }
192
193 #define STRIP_MODS(s) \
194 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
195 /* kill off the Button1Mask etc, only want the modifiers */ \
196 s &= (ControlMask | ShiftMask | Mod1Mask | \
197 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
198
199 static void event_hack_mods(XEvent *e)
200 {
201 KeyCode *kp;
202 int i, k;
203
204 switch (e->type) {
205 case ButtonPress:
206 case ButtonRelease:
207 STRIP_MODS(e->xbutton.state);
208 break;
209 case KeyPress:
210 STRIP_MODS(e->xkey.state);
211 break;
212 case KeyRelease:
213 STRIP_MODS(e->xkey.state);
214 /* remove from the state the mask of the modifier being released, if
215 it is a modifier key being released (this is a little ugly..) */
216 kp = modmap->modifiermap;
217 for (i = 0; i < mask_table_size; ++i) {
218 for (k = 0; k < modmap->max_keypermod; ++k) {
219 if (*kp == e->xkey.keycode) { /* found the keycode */
220 /* remove the mask for it */
221 e->xkey.state &= ~mask_table[i];
222 /* cause the first loop to break; */
223 i = mask_table_size;
224 break; /* get outta here! */
225 }
226 ++kp;
227 }
228 }
229 break;
230 case MotionNotify:
231 STRIP_MODS(e->xmotion.state);
232 /* compress events */
233 {
234 XEvent ce;
235 while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
236 e->type, &ce)) {
237 e->xmotion.x_root = ce.xmotion.x_root;
238 e->xmotion.y_root = ce.xmotion.y_root;
239 }
240 }
241 break;
242 }
243 }
244
245 static gboolean event_ignore(XEvent *e, Client *client)
246 {
247 switch(e->type) {
248 case FocusIn:
249 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
250 because of RevertToPointerRoot. If the focus ends up reverting to
251 pointer root on a workspace change, then the FocusIn event that we
252 want will be of type NotifyAncestor. This situation does not occur
253 for FocusOut, so it is safely ignored there.
254 */
255 if (INVALID_FOCUSIN(e) ||
256 client == NULL) {
257 #ifdef DEBUG_FOCUS
258 g_message("FocusIn on %lx mode %d detail %d IGNORED", e->xfocus.window,
259 e->xfocus.mode, e->xfocus.detail);
260 #endif
261 /* says a client was not found for the event (or a valid FocusIn
262 event was not found.
263 */
264 e->xfocus.window = None;
265 return TRUE;
266 }
267
268 #ifdef DEBUG_FOCUS
269 g_message("FocusIn on %lx mode %d detail %d", e->xfocus.window,
270 e->xfocus.mode, e->xfocus.detail);
271 #endif
272 break;
273 case FocusOut:
274 if (INVALID_FOCUSOUT(e)) {
275 #ifdef DEBUG_FOCUS
276 g_message("FocusOut on %lx mode %d detail %d IGNORED",
277 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
278 #endif
279 return TRUE;
280 }
281
282 #ifdef DEBUG_FOCUS
283 g_message("FocusOut on %lx mode %d detail %d",
284 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
285 #endif
286
287 /* Try process a FocusIn first, and if a legit one isn't found, then
288 do the fallback shiznit. */
289 {
290 XEvent fe;
291 gboolean fallback = TRUE;
292
293 while (TRUE) {
294 if (!XCheckTypedEvent(ob_display, FocusOut, &fe))
295 if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
296 break;
297 if (fe.type == FocusOut) {
298 #ifdef DEBUG_FOCUS
299 g_message("found pending FocusOut");
300 #endif
301 if (!INVALID_FOCUSOUT(&fe)) {
302 /* if there is a VALID FocusOut still coming, don't
303 fallback focus yet, we'll deal with it then */
304 XPutBackEvent(ob_display, &fe);
305 fallback = FALSE;
306 break;
307 }
308 } else {
309 #ifdef DEBUG_FOCUS
310 g_message("found pending FocusIn");
311 #endif
312 /* once all the FocusOut's have been dealt with, if there
313 is a FocusIn still left and it is valid, then use it */
314 event_process(&fe);
315 /* secret magic way of event_process telling us that no
316 client was found for the FocusIn event. ^_^ */
317 if (fe.xfocus.window != None) {
318 fallback = FALSE;
319 break;
320 }
321 }
322 }
323 if (fallback) {
324 #ifdef DEBUG_FOCUS
325 g_message("no valid FocusIn and no FocusOut events found, "
326 "falling back");
327 #endif
328 focus_fallback(Fallback_NoFocus);
329 }
330 }
331 break;
332 case EnterNotify:
333 case LeaveNotify:
334 /* NotifyUngrab occurs when a mouse button is released and the event is
335 caused, like when lowering a window */
336 /* NotifyVirtual occurs when ungrabbing the pointer */
337 if (e->xcrossing.mode == NotifyGrab ||
338 e->xcrossing.detail == NotifyInferior ||
339 (e->xcrossing.mode == NotifyUngrab &&
340 e->xcrossing.detail == NotifyVirtual))
341 return TRUE;
342 break;
343 }
344 return FALSE;
345 }
346
347 static void event_process(XEvent *e)
348 {
349 Window window;
350 Client *client;
351 Menu *menu = NULL;
352
353 window = event_get_window(e);
354 if (!(client = g_hash_table_lookup(client_map, &window)))
355 menu = g_hash_table_lookup(menu_map, &window);
356 event_set_lasttime(e);
357 event_hack_mods(e);
358 if (event_ignore(e, client))
359 return;
360
361 /* deal with it in the kernel */
362 if (menu) {
363 event_handle_menu(menu, e);
364 return;
365 } else if (client)
366 event_handle_client(client, e);
367 else if (window == ob_root)
368 event_handle_root(e);
369 else if (e->type == MapRequest)
370 client_manage(window);
371 else if (e->type == ConfigureRequest) {
372 /* unhandled configure requests must be used to configure the
373 window directly */
374 XWindowChanges xwc;
375
376 xwc.x = e->xconfigurerequest.x;
377 xwc.y = e->xconfigurerequest.y;
378 xwc.width = e->xconfigurerequest.width;
379 xwc.height = e->xconfigurerequest.height;
380 xwc.border_width = e->xconfigurerequest.border_width;
381 xwc.sibling = e->xconfigurerequest.above;
382 xwc.stack_mode = e->xconfigurerequest.detail;
383
384 /* we are not to be held responsible if someone sends us an
385 invalid request! */
386 xerror_set_ignore(TRUE);
387 XConfigureWindow(ob_display, window,
388 e->xconfigurerequest.value_mask, &xwc);
389 xerror_set_ignore(FALSE);
390 }
391
392 if (moveresize_in_progress)
393 if (e->type == MotionNotify || e->type == ButtonRelease ||
394 e->type == ButtonPress ||
395 e->type == KeyPress || e->type == KeyRelease) {
396 moveresize_event(e);
397 return; /* no dispatch! */
398 }
399
400 /* user input (action-bound) events */
401 /*
402 if (e->type == ButtonPress || e->type == ButtonRelease ||
403 e->type == MotionNotify)
404 mouse_event(e, client);
405 else if (e->type == KeyPress || e->type == KeyRelease)
406 ;
407 */
408
409 /* dispatch the event to registered handlers */
410 dispatch_x(e, client);
411 }
412
413 static void event_handle_root(XEvent *e)
414 {
415 Atom msgtype;
416
417 switch(e->type) {
418 case ClientMessage:
419 if (e->xclient.format != 32) break;
420
421 msgtype = e->xclient.message_type;
422 if (msgtype == prop_atoms.net_current_desktop) {
423 unsigned int d = e->xclient.data.l[0];
424 if (d < screen_num_desktops)
425 screen_set_desktop(d);
426 } else if (msgtype == prop_atoms.net_number_of_desktops) {
427 unsigned int d = e->xclient.data.l[0];
428 if (d > 0)
429 screen_set_num_desktops(d);
430 } else if (msgtype == prop_atoms.net_showing_desktop) {
431 screen_show_desktop(e->xclient.data.l[0] != 0);
432 }
433 break;
434 case PropertyNotify:
435 if (e->xproperty.atom == prop_atoms.net_desktop_names)
436 screen_update_desktop_names();
437 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
438 screen_update_layout();
439 break;
440 }
441 }
442
443 static void event_handle_client(Client *client, XEvent *e)
444 {
445 XEvent ce;
446 Atom msgtype;
447 int i=0;
448
449 switch (e->type) {
450 case ButtonPress:
451 case ButtonRelease:
452 switch (frame_context(client, e->xbutton.window)) {
453 case Context_Maximize:
454 client->frame->max_press = (e->type == ButtonPress);
455 framerender_frame(client->frame);
456 break;
457 case Context_Close:
458 client->frame->close_press = (e->type == ButtonPress);
459 framerender_frame(client->frame);
460 break;
461 case Context_Iconify:
462 client->frame->iconify_press = (e->type == ButtonPress);
463 framerender_frame(client->frame);
464 break;
465 case Context_AllDesktops:
466 client->frame->desk_press = (e->type == ButtonPress);
467 framerender_frame(client->frame);
468 break;
469 case Context_Shade:
470 client->frame->shade_press = (e->type == ButtonPress);
471 framerender_frame(client->frame);
472 break;
473 default:
474 /* nothing changes with clicks for any other contexts */
475 break;
476 }
477 break;
478 case FocusIn:
479 focus_set_client(client);
480 case FocusOut:
481 #ifdef DEBUG_FOCUS
482 g_message("Focus%s on client for %lx", (e->type==FocusIn?"In":"Out"),
483 client->window);
484 #endif
485 /* focus state can affect the stacking layer */
486 client_calc_layer(client);
487 frame_adjust_focus(client->frame);
488 break;
489 case EnterNotify:
490 if (client_normal(client)) {
491 if (ob_state == State_Starting) {
492 /* move it to the top of the focus order */
493 guint desktop = client->desktop;
494 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
495 focus_order[desktop] = g_list_remove(focus_order[desktop],
496 client);
497 focus_order[desktop] = g_list_prepend(focus_order[desktop],
498 client);
499 } else if (config_focus_follow) {
500 #ifdef DEBUG_FOCUS
501 g_message("EnterNotify on %lx, focusing window",
502 client->window);
503 #endif
504 client_focus(client);
505 }
506 }
507 break;
508 case ConfigureRequest:
509 /* compress these */
510 while (XCheckTypedWindowEvent(ob_display, client->window,
511 ConfigureRequest, &ce)) {
512 ++i;
513 /* XXX if this causes bad things.. we can compress config req's
514 with the same mask. */
515 e->xconfigurerequest.value_mask |=
516 ce.xconfigurerequest.value_mask;
517 if (ce.xconfigurerequest.value_mask & CWX)
518 e->xconfigurerequest.x = ce.xconfigurerequest.x;
519 if (ce.xconfigurerequest.value_mask & CWY)
520 e->xconfigurerequest.y = ce.xconfigurerequest.y;
521 if (ce.xconfigurerequest.value_mask & CWWidth)
522 e->xconfigurerequest.width = ce.xconfigurerequest.width;
523 if (ce.xconfigurerequest.value_mask & CWHeight)
524 e->xconfigurerequest.height = ce.xconfigurerequest.height;
525 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
526 e->xconfigurerequest.border_width =
527 ce.xconfigurerequest.border_width;
528 if (ce.xconfigurerequest.value_mask & CWStackMode)
529 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
530 }
531
532 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
533 if (client->iconic || client->shaded) return;
534
535 if (e->xconfigurerequest.value_mask & CWBorderWidth)
536 client->border_width = e->xconfigurerequest.border_width;
537
538 /* resize, then move, as specified in the EWMH section 7.7 */
539 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
540 CWX | CWY)) {
541 int x, y, w, h;
542 Corner corner;
543
544 x = (e->xconfigurerequest.value_mask & CWX) ?
545 e->xconfigurerequest.x : client->area.x;
546 y = (e->xconfigurerequest.value_mask & CWY) ?
547 e->xconfigurerequest.y : client->area.y;
548 w = (e->xconfigurerequest.value_mask & CWWidth) ?
549 e->xconfigurerequest.width : client->area.width;
550 h = (e->xconfigurerequest.value_mask & CWHeight) ?
551 e->xconfigurerequest.height : client->area.height;
552
553 switch (client->gravity) {
554 case NorthEastGravity:
555 case EastGravity:
556 corner = Corner_TopRight;
557 break;
558 case SouthWestGravity:
559 case SouthGravity:
560 corner = Corner_BottomLeft;
561 break;
562 case SouthEastGravity:
563 corner = Corner_BottomRight;
564 break;
565 default: /* NorthWest, Static, etc */
566 corner = Corner_TopLeft;
567 }
568
569 client_configure(client, corner, x, y, w, h, FALSE, FALSE);
570 }
571
572 if (e->xconfigurerequest.value_mask & CWStackMode) {
573 switch (e->xconfigurerequest.detail) {
574 case Below:
575 case BottomIf:
576 stacking_lower(client);
577 break;
578
579 case Above:
580 case TopIf:
581 default:
582 stacking_raise(client);
583 break;
584 }
585 }
586 break;
587 case UnmapNotify:
588 if (client->ignore_unmaps) {
589 client->ignore_unmaps--;
590 break;
591 }
592 client_unmanage(client);
593 break;
594 case DestroyNotify:
595 client_unmanage(client);
596 break;
597 case ReparentNotify:
598 /* this is when the client is first taken captive in the frame */
599 if (e->xreparent.parent == client->frame->plate) break;
600
601 /*
602 This event is quite rare and is usually handled in unmapHandler.
603 However, if the window is unmapped when the reparent event occurs,
604 the window manager never sees it because an unmap event is not sent
605 to an already unmapped window.
606 */
607
608 /* we don't want the reparent event, put it back on the stack for the
609 X server to deal with after we unmanage the window */
610 XPutBackEvent(ob_display, e);
611
612 client_unmanage(client);
613 break;
614 case MapRequest:
615 g_message("MapRequest for 0x%lx", client->window);
616 if (!client->iconic) break; /* this normally doesn't happen, but if it
617 does, we don't want it! */
618 if (screen_showing_desktop)
619 screen_show_desktop(FALSE);
620 client_iconify(client, FALSE, TRUE);
621 if (!client->frame->visible)
622 /* if its not visible still, then don't mess with it */
623 break;
624 if (client->shaded)
625 client_shade(client, FALSE);
626 client_focus(client);
627 stacking_raise(client);
628 break;
629 case ClientMessage:
630 /* validate cuz we query stuff off the client here */
631 if (!client_validate(client)) break;
632
633 if (e->xclient.format != 32) return;
634
635 msgtype = e->xclient.message_type;
636 if (msgtype == prop_atoms.wm_change_state) {
637 /* compress changes into a single change */
638 while (XCheckTypedWindowEvent(ob_display, e->type,
639 client->window, &ce)) {
640 /* XXX: it would be nice to compress ALL messages of a
641 type, not just messages in a row without other
642 message types between. */
643 if (ce.xclient.message_type != msgtype) {
644 XPutBackEvent(ob_display, &ce);
645 break;
646 }
647 e->xclient = ce.xclient;
648 }
649 client_set_wm_state(client, e->xclient.data.l[0]);
650 } else if (msgtype == prop_atoms.net_wm_desktop) {
651 /* compress changes into a single change */
652 while (XCheckTypedWindowEvent(ob_display, e->type,
653 client->window, &ce)) {
654 /* XXX: it would be nice to compress ALL messages of a
655 type, not just messages in a row without other
656 message types between. */
657 if (ce.xclient.message_type != msgtype) {
658 XPutBackEvent(ob_display, &ce);
659 break;
660 }
661 e->xclient = ce.xclient;
662 }
663 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
664 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
665 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
666 FALSE);
667 } else if (msgtype == prop_atoms.net_wm_state) {
668 /* can't compress these */
669 g_message("net_wm_state %s %ld %ld for 0x%lx",
670 (e->xclient.data.l[0] == 0 ? "Remove" :
671 e->xclient.data.l[0] == 1 ? "Add" :
672 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
673 e->xclient.data.l[1], e->xclient.data.l[2],
674 client->window);
675 client_set_state(client, e->xclient.data.l[0],
676 e->xclient.data.l[1], e->xclient.data.l[2]);
677 } else if (msgtype == prop_atoms.net_close_window) {
678 g_message("net_close_window for 0x%lx", client->window);
679 client_close(client);
680 } else if (msgtype == prop_atoms.net_active_window) {
681 g_message("net_active_window for 0x%lx", client->window);
682 if (screen_showing_desktop)
683 screen_show_desktop(FALSE);
684 if (client->iconic)
685 client_iconify(client, FALSE, TRUE);
686 else if (!client->frame->visible)
687 /* if its not visible for other reasons, then don't mess
688 with it */
689 break;
690 if (client->shaded)
691 client_shade(client, FALSE);
692 client_focus(client);
693 stacking_raise(client);
694 } else if (msgtype == prop_atoms.net_wm_moveresize) {
695 g_message("net_wm_moveresize for 0x%lx", client->window);
696 if ((Atom)e->xclient.data.l[2] ==
697 prop_atoms.net_wm_moveresize_size_topleft ||
698 (Atom)e->xclient.data.l[2] ==
699 prop_atoms.net_wm_moveresize_size_top ||
700 (Atom)e->xclient.data.l[2] ==
701 prop_atoms.net_wm_moveresize_size_topright ||
702 (Atom)e->xclient.data.l[2] ==
703 prop_atoms.net_wm_moveresize_size_right ||
704 (Atom)e->xclient.data.l[2] ==
705 prop_atoms.net_wm_moveresize_size_right ||
706 (Atom)e->xclient.data.l[2] ==
707 prop_atoms.net_wm_moveresize_size_bottomright ||
708 (Atom)e->xclient.data.l[2] ==
709 prop_atoms.net_wm_moveresize_size_bottom ||
710 (Atom)e->xclient.data.l[2] ==
711 prop_atoms.net_wm_moveresize_size_bottomleft ||
712 (Atom)e->xclient.data.l[2] ==
713 prop_atoms.net_wm_moveresize_size_left ||
714 (Atom)e->xclient.data.l[2] ==
715 prop_atoms.net_wm_moveresize_move ||
716 (Atom)e->xclient.data.l[2] ==
717 prop_atoms.net_wm_moveresize_size_keyboard ||
718 (Atom)e->xclient.data.l[2] ==
719 prop_atoms.net_wm_moveresize_move_keyboard) {
720
721 moveresize_start(client, e->xclient.data.l[0],
722 e->xclient.data.l[1], e->xclient.data.l[3],
723 e->xclient.data.l[2]);
724 }
725 } else if (msgtype == prop_atoms.net_moveresize_window) {
726 int oldg = client->gravity;
727 int tmpg, x, y, w, h;
728
729 if (e->xclient.data.l[0] & 0xff)
730 tmpg = e->xclient.data.l[0] & 0xff;
731 else
732 tmpg = oldg;
733
734 if (e->xclient.data.l[0] & 1 << 8)
735 x = e->xclient.data.l[1];
736 else
737 x = client->area.x;
738 if (e->xclient.data.l[0] & 1 << 9)
739 y = e->xclient.data.l[2];
740 else
741 y = client->area.y;
742 if (e->xclient.data.l[0] & 1 << 10)
743 w = e->xclient.data.l[3];
744 else
745 w = client->area.y;
746 if (e->xclient.data.l[0] & 1 << 11)
747 h = e->xclient.data.l[4];
748 else
749 h = client->area.y;
750 client->gravity = tmpg;
751 client_configure(client, Corner_TopLeft, x, y, w, h, TRUE, TRUE);
752 client->gravity = oldg;
753 }
754 break;
755 case PropertyNotify:
756 /* validate cuz we query stuff off the client here */
757 if (!client_validate(client)) break;
758
759 /* compress changes to a single property into a single change */
760 while (XCheckTypedWindowEvent(ob_display, e->type,
761 client->window, &ce)) {
762 /* XXX: it would be nice to compress ALL changes to a property,
763 not just changes in a row without other props between. */
764 if (ce.xproperty.atom != e->xproperty.atom) {
765 XPutBackEvent(ob_display, &ce);
766 break;
767 }
768 }
769
770 msgtype = e->xproperty.atom;
771 if (msgtype == XA_WM_NORMAL_HINTS) {
772 client_update_normal_hints(client);
773 /* normal hints can make a window non-resizable */
774 client_setup_decor_and_functions(client);
775 }
776 else if (msgtype == XA_WM_HINTS)
777 client_update_wmhints(client);
778 else if (msgtype == XA_WM_TRANSIENT_FOR) {
779 client_update_transient_for(client);
780 client_get_type(client);
781 /* type may have changed, so update the layer */
782 client_calc_layer(client);
783 client_setup_decor_and_functions(client);
784 }
785 else if (msgtype == prop_atoms.net_wm_name ||
786 msgtype == prop_atoms.wm_name)
787 client_update_title(client);
788 else if (msgtype == prop_atoms.net_wm_icon_name ||
789 msgtype == prop_atoms.wm_icon_name)
790 client_update_icon_title(client);
791 else if (msgtype == prop_atoms.wm_class)
792 client_update_class(client);
793 else if (msgtype == prop_atoms.wm_protocols) {
794 client_update_protocols(client);
795 client_setup_decor_and_functions(client);
796 }
797 else if (msgtype == prop_atoms.net_wm_strut)
798 client_update_strut(client);
799 else if (msgtype == prop_atoms.net_wm_icon)
800 client_update_icons(client);
801 else if (msgtype == prop_atoms.kwm_win_icon)
802 client_update_kwm_icon(client);
803 default:
804 ;
805 #ifdef SHAPE
806 if (extensions_shape && e->type == extensions_shape_event_basep) {
807 client->shaped = ((XShapeEvent*)e)->shaped;
808 frame_adjust_shape(client->frame);
809 }
810 #endif
811 }
812 }
813
814 static void event_handle_menu(Menu *menu, XEvent *e)
815 {
816 MenuEntry *entry;
817
818 g_message("EVENT %d", e->type);
819 switch (e->type) {
820 case ButtonPress:
821 if (e->xbutton.button == 3)
822 menu_hide(menu);
823 break;
824 case ButtonRelease:
825 if (!menu->shown) break;
826
827 /* grab_pointer_window(FALSE, None, menu->frame);*/
828
829 entry = menu_find_entry(menu, e->xbutton.window);
830 if (entry) {
831 int junk;
832 Window wjunk;
833 guint ujunk, b, w, h;
834 XGetGeometry(ob_display, e->xbutton.window,
835 &wjunk, &junk, &junk, &w, &h, &b, &ujunk);
836 if (e->xbutton.x >= (signed)-b &&
837 e->xbutton.y >= (signed)-b &&
838 e->xbutton.x < (signed)(w+b) &&
839 e->xbutton.y < (signed)(h+b)) {
840 menu_entry_fire(entry);
841 }
842 }
843 break;
844 case EnterNotify:
845 case LeaveNotify:
846 g_message("enter/leave");
847 entry = menu_find_entry(menu, e->xcrossing.window);
848 if (entry) {
849 entry->hilite = e->type == EnterNotify;
850 menu_entry_render(entry);
851 }
852 break;
853 }
854 }
This page took 0.072903 seconds and 4 git commands to generate.