10 #include "framerender.h"
12 #include "moveresize.h"
14 #include "extensions.h"
20 #include <X11/keysym.h>
21 #include <X11/Xatom.h>
25 # include <libsn/sn.h>
28 #ifdef HAVE_SYS_SELECT_H
29 # include <sys/select.h>
32 static void event_process(XEvent *e);
33 static void event_handle_root(XEvent *e);
34 static void event_handle_dock(Dock *s, XEvent *e);
35 static void event_handle_dockapp(DockApp *app, XEvent *e);
36 static void event_handle_client(Client *c, XEvent *e);
37 static void event_handle_menu(Menu *menu, Client *c, XEvent *e);
39 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
40 (e)->xfocus.detail == NotifyAncestor || \
41 (e)->xfocus.detail > NotifyNonlinearVirtual)
42 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
43 (e)->xfocus.detail == NotifyInferior || \
44 (e)->xfocus.detail == NotifyAncestor || \
45 (e)->xfocus.detail > NotifyNonlinearVirtual)
47 Time event_lasttime = 0;
49 /*! The value of the mask for the NumLock modifier */
50 unsigned int NumLockMask;
51 /*! The value of the mask for the ScrollLock modifier */
52 unsigned int ScrollLockMask;
53 /*! The key codes for the modifier keys */
54 static XModifierKeymap *modmap;
55 /*! Table of the constant modifier masks */
56 static const int mask_table[] = {
57 ShiftMask, LockMask, ControlMask, Mod1Mask,
58 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
60 static int mask_table_size;
62 static fd_set selset, allset;
63 static int max_fd, x_fd;
64 static GData *fd_handler_list;
66 void fd_event_handle();
70 mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]);
72 /* get lock masks that are defined by the display (not constant) */
73 modmap = XGetModifierMapping(ob_display);
75 if (modmap && modmap->max_keypermod > 0) {
77 const size_t size = mask_table_size * modmap->max_keypermod;
78 /* get the values of the keyboard lock modifiers
79 Note: Caps lock is not retrieved the same way as Scroll and Num
80 lock since it doesn't need to be. */
81 const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock);
82 const KeyCode scroll_lock = XKeysymToKeycode(ob_display,
85 for (cnt = 0; cnt < size; ++cnt) {
86 if (! modmap->modifiermap[cnt]) continue;
88 if (num_lock == modmap->modifiermap[cnt])
89 NumLockMask = mask_table[cnt / modmap->max_keypermod];
90 if (scroll_lock == modmap->modifiermap[cnt])
91 ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
96 max_fd = x_fd = ConnectionNumber(ob_display);
97 FD_SET(x_fd, &allset);
98 g_datalist_init(&fd_handler_list);
101 void event_shutdown()
103 XFreeModifiermap(modmap);
104 g_datalist_clear(&fd_handler_list);
110 struct timeval *wait;
111 gboolean had_event = FALSE;
115 There are slightly different event retrieval semantics here for
116 local (or high bandwidth) versus remote (or low bandwidth)
117 connections to the display/Xserver.
120 if (!XPending(ob_display))
124 This XSync allows for far more compression of events, which
125 makes things like Motion events perform far far better. Since
126 it also means network traffic for every event instead of every
127 X events (where X is the number retrieved at a time), it
128 probably should not be used for setups where Openbox is
129 running on a remote/low bandwidth display/Xserver.
131 XSync(ob_display, FALSE);
132 if (!XEventsQueued(ob_display, QueuedAlready))
135 XNextEvent(ob_display, &e);
138 sn_display_process_event(ob_sn_display, &e);
146 timer_dispatch((GTimeVal**)&wait);
148 select(max_fd + 1, &selset, NULL, NULL, wait);
150 /* handle the X events as soon as possible? */
151 if (FD_ISSET(x_fd, &selset))
158 static Window event_get_window(XEvent *e)
165 window = e->xmap.window;
168 window = e->xunmap.window;
171 window = e->xdestroywindow.window;
173 case ConfigureRequest:
174 window = e->xconfigurerequest.window;
176 case ConfigureNotify:
177 window = e->xconfigure.window;
181 if (extensions_xkb && e->type == extensions_xkb_event_basep) {
182 switch (((XkbAnyEvent*)&e)->xkb_type) {
184 window = ((XkbBellNotifyEvent*)&e)->window;
190 window = e->xany.window;
195 static void event_set_lasttime(XEvent *e)
197 /* grab the lasttime and hack up the state */
201 event_lasttime = e->xbutton.time;
204 event_lasttime = e->xkey.time;
207 event_lasttime = e->xkey.time;
210 event_lasttime = e->xmotion.time;
213 event_lasttime = e->xproperty.time;
217 event_lasttime = e->xcrossing.time;
220 event_lasttime = CurrentTime;
225 #define STRIP_MODS(s) \
226 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
227 /* kill off the Button1Mask etc, only want the modifiers */ \
228 s &= (ControlMask | ShiftMask | Mod1Mask | \
229 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
231 static void event_hack_mods(XEvent *e)
239 STRIP_MODS(e->xbutton.state);
242 STRIP_MODS(e->xkey.state);
245 STRIP_MODS(e->xkey.state);
246 /* remove from the state the mask of the modifier being released, if
247 it is a modifier key being released (this is a little ugly..) */
248 kp = modmap->modifiermap;
249 for (i = 0; i < mask_table_size; ++i) {
250 for (k = 0; k < modmap->max_keypermod; ++k) {
251 if (*kp == e->xkey.keycode) { /* found the keycode */
252 /* remove the mask for it */
253 e->xkey.state &= ~mask_table[i];
254 /* cause the first loop to break; */
256 break; /* get outta here! */
263 STRIP_MODS(e->xmotion.state);
264 /* compress events */
267 while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
269 e->xmotion.x_root = ce.xmotion.x_root;
270 e->xmotion.y_root = ce.xmotion.y_root;
277 static gboolean event_ignore(XEvent *e, Client *client)
281 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
282 because of RevertToPointerRoot. If the focus ends up reverting to
283 pointer root on a workspace change, then the FocusIn event that we
284 want will be of type NotifyAncestor. This situation does not occur
285 for FocusOut, so it is safely ignored there.
287 if (INVALID_FOCUSIN(e) ||
290 g_message("FocusIn on %lx mode %d detail %d IGNORED", e->xfocus.window,
291 e->xfocus.mode, e->xfocus.detail);
293 /* says a client was not found for the event (or a valid FocusIn
296 e->xfocus.window = None;
301 g_message("FocusIn on %lx mode %d detail %d", e->xfocus.window,
302 e->xfocus.mode, e->xfocus.detail);
306 if (INVALID_FOCUSOUT(e)) {
308 g_message("FocusOut on %lx mode %d detail %d IGNORED",
309 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
315 g_message("FocusOut on %lx mode %d detail %d",
316 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
321 gboolean fallback = TRUE;
324 if (!XCheckTypedWindowEvent(ob_display, FocusOut,
325 e->xfocus.window,&fe))
326 if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
328 if (fe.type == FocusOut) {
330 g_message("found pending FocusOut");
332 if (!INVALID_FOCUSOUT(&fe)) {
333 /* if there is a VALID FocusOut still coming, don't
334 fallback focus yet, we'll deal with it then */
335 XPutBackEvent(ob_display, &fe);
341 g_message("found pending FocusIn");
343 /* is the focused window getting a FocusOut/In back to
346 if (fe.xfocus.window == e->xfocus.window &&
347 !event_ignore(&fe, client)) {
349 if focus_client is not set, then we can't do
350 this. we need the FocusIn. This happens in the
351 case when the set_focus_client(NULL) in the
352 focus_fallback function fires and then
353 focus_fallback picks the currently focused
354 window (such as on a SendToDesktop-esque action.
358 g_message("focused window got an Out/In back to "
359 "itself IGNORED both");
365 g_message("focused window got an Out/In back to "
366 "itself but focus_client was null "
367 "IGNORED just the Out");
373 /* once all the FocusOut's have been dealt with, if there
374 is a FocusIn still left and it is valid, then use it */
376 /* secret magic way of event_process telling us that no
377 client was found for the FocusIn event. ^_^ */
378 if (fe.xfocus.window != None) {
386 g_message("no valid FocusIn and no FocusOut events found, "
389 focus_fallback(Fallback_NoFocus);
395 /* NotifyUngrab occurs when a mouse button is released and the event is
396 caused, like when lowering a window */
397 /* NotifyVirtual occurs when ungrabbing the pointer */
398 if (e->xcrossing.mode == NotifyGrab ||
399 e->xcrossing.detail == NotifyInferior ||
400 (e->xcrossing.mode == NotifyUngrab &&
401 e->xcrossing.detail == NotifyVirtual)) {
403 g_message("%sNotify mode %d detail %d on %lx IGNORED",
404 (e->type == EnterNotify ? "Enter" : "Leave"),
406 e->xcrossing.detail, client?client->window:0);
411 g_message("%sNotify mode %d detail %d on %lx",
412 (e->type == EnterNotify ? "Enter" : "Leave"),
414 e->xcrossing.detail, client?client->window:0);
421 static void event_process(XEvent *e)
424 Client *client = NULL;
426 DockApp *dockapp = NULL;
428 ObWindow *obwin = NULL;
430 window = event_get_window(e);
431 if ((obwin = g_hash_table_lookup(window_map, &window))) {
432 switch (obwin->type) {
434 dock = WINDOW_AS_DOCK(obwin);
437 dockapp = WINDOW_AS_DOCKAPP(obwin);
440 menu = WINDOW_AS_MENU(obwin);
443 client = WINDOW_AS_CLIENT(obwin);
445 case Window_Decoration:
446 client = WINDOW_AS_DECORATION(obwin)->frame->client;
448 case Window_Internal:
449 /* not to be used for events */
450 g_assert_not_reached();
455 event_set_lasttime(e);
457 if (event_ignore(e, client))
460 /* deal with it in the kernel */
462 event_handle_menu(menu, client, e);
465 event_handle_client(client, e);
467 event_handle_dockapp(dockapp, e);
469 event_handle_dock(dock, e);
470 else if (window == ob_root)
471 event_handle_root(e);
472 else if (e->type == MapRequest)
473 client_manage(window);
474 else if (e->type == ConfigureRequest) {
475 /* unhandled configure requests must be used to configure the
479 xwc.x = e->xconfigurerequest.x;
480 xwc.y = e->xconfigurerequest.y;
481 xwc.width = e->xconfigurerequest.width;
482 xwc.height = e->xconfigurerequest.height;
483 xwc.border_width = e->xconfigurerequest.border_width;
484 xwc.sibling = e->xconfigurerequest.above;
485 xwc.stack_mode = e->xconfigurerequest.detail;
487 /* we are not to be held responsible if someone sends us an
489 xerror_set_ignore(TRUE);
490 XConfigureWindow(ob_display, window,
491 e->xconfigurerequest.value_mask, &xwc);
492 xerror_set_ignore(FALSE);
495 if (moveresize_in_progress)
496 if (e->type == MotionNotify || e->type == ButtonRelease ||
497 e->type == ButtonPress ||
498 e->type == KeyPress || e->type == KeyRelease) {
501 return; /* no dispatch! */
505 /* user input (action-bound) events */
507 if (e->type == ButtonPress || e->type == ButtonRelease ||
508 e->type == MotionNotify)
509 mouse_event(e, client);
510 else if (e->type == KeyPress || e->type == KeyRelease)
514 /* dispatch the event to registered handlers */
515 dispatch_x(e, client);
518 static void event_handle_root(XEvent *e)
524 if (e->xclient.format != 32) break;
526 msgtype = e->xclient.message_type;
527 if (msgtype == prop_atoms.net_current_desktop) {
528 unsigned int d = e->xclient.data.l[0];
529 if (d < screen_num_desktops)
530 screen_set_desktop(d);
531 } else if (msgtype == prop_atoms.net_number_of_desktops) {
532 unsigned int d = e->xclient.data.l[0];
534 screen_set_num_desktops(d);
535 } else if (msgtype == prop_atoms.net_showing_desktop) {
536 screen_show_desktop(e->xclient.data.l[0] != 0);
540 if (e->xproperty.atom == prop_atoms.net_desktop_names)
541 screen_update_desktop_names();
542 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
543 screen_update_layout();
545 case ConfigureNotify:
547 XRRUpdateConfiguration(e);
549 if (e->xconfigure.width != screen_physical_size.width ||
550 e->xconfigure.height != screen_physical_size.height)
551 screen_resize(e->xconfigure.width, e->xconfigure.height);
556 if (extensions_vidmode && e->type == extensions_vidmode_event_basep) {
557 g_message("VIDMODE EVENT");
563 static void event_handle_client(Client *client, XEvent *e)
572 /* Wheel buttons don't draw because they are an instant click, so it
573 is a waste of resources to go drawing it. */
574 if (!(e->xbutton.button == 4 || e->xbutton.button == 5)) {
575 switch (frame_context(client, e->xbutton.window)) {
576 case Context_Maximize:
577 client->frame->max_press = (e->type == ButtonPress);
578 framerender_frame(client->frame);
581 client->frame->close_press = (e->type == ButtonPress);
582 framerender_frame(client->frame);
584 case Context_Iconify:
585 client->frame->iconify_press = (e->type == ButtonPress);
586 framerender_frame(client->frame);
588 case Context_AllDesktops:
589 client->frame->desk_press = (e->type == ButtonPress);
590 framerender_frame(client->frame);
593 client->frame->shade_press = (e->type == ButtonPress);
594 framerender_frame(client->frame);
597 /* nothing changes with clicks for any other contexts */
604 g_message("FocusIn on client for %lx", client->window);
606 if (client != focus_client) {
607 focus_set_client(client);
608 frame_adjust_focus(client->frame, TRUE);
613 g_message("FocusOut on client for %lx", client->window);
615 /* are we a fullscreen window or a transient of one? (checks layer)
616 if we are then we need to be iconified since we are losing focus
618 if (client->layer == Layer_Fullscreen && !client->iconic &&
619 !client_search_focus_tree_full(client))
620 /* iconify fullscreen windows when they and their transients
622 client_iconify(client, TRUE, TRUE);
623 frame_adjust_focus(client->frame, FALSE);
626 if (client_normal(client)) {
627 if (ob_state == State_Starting) {
628 /* move it to the top of the focus order */
629 guint desktop = client->desktop;
630 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
631 focus_order[desktop] = g_list_remove(focus_order[desktop],
633 focus_order[desktop] = g_list_prepend(focus_order[desktop],
635 } else if (config_focus_follow) {
637 g_message("EnterNotify on %lx, focusing window",
640 client_focus(client);
644 case ConfigureRequest:
646 while (XCheckTypedWindowEvent(ob_display, client->window,
647 ConfigureRequest, &ce)) {
649 /* XXX if this causes bad things.. we can compress config req's
650 with the same mask. */
651 e->xconfigurerequest.value_mask |=
652 ce.xconfigurerequest.value_mask;
653 if (ce.xconfigurerequest.value_mask & CWX)
654 e->xconfigurerequest.x = ce.xconfigurerequest.x;
655 if (ce.xconfigurerequest.value_mask & CWY)
656 e->xconfigurerequest.y = ce.xconfigurerequest.y;
657 if (ce.xconfigurerequest.value_mask & CWWidth)
658 e->xconfigurerequest.width = ce.xconfigurerequest.width;
659 if (ce.xconfigurerequest.value_mask & CWHeight)
660 e->xconfigurerequest.height = ce.xconfigurerequest.height;
661 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
662 e->xconfigurerequest.border_width =
663 ce.xconfigurerequest.border_width;
664 if (ce.xconfigurerequest.value_mask & CWStackMode)
665 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
668 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
669 if (client->iconic || client->shaded) return;
671 if (e->xconfigurerequest.value_mask & CWBorderWidth)
672 client->border_width = e->xconfigurerequest.border_width;
674 /* resize, then move, as specified in the EWMH section 7.7 */
675 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
680 x = (e->xconfigurerequest.value_mask & CWX) ?
681 e->xconfigurerequest.x : client->area.x;
682 y = (e->xconfigurerequest.value_mask & CWY) ?
683 e->xconfigurerequest.y : client->area.y;
684 w = (e->xconfigurerequest.value_mask & CWWidth) ?
685 e->xconfigurerequest.width : client->area.width;
686 h = (e->xconfigurerequest.value_mask & CWHeight) ?
687 e->xconfigurerequest.height : client->area.height;
689 switch (client->gravity) {
690 case NorthEastGravity:
692 corner = Corner_TopRight;
694 case SouthWestGravity:
696 corner = Corner_BottomLeft;
698 case SouthEastGravity:
699 corner = Corner_BottomRight;
701 default: /* NorthWest, Static, etc */
702 corner = Corner_TopLeft;
705 client_configure(client, corner, x, y, w, h, FALSE, FALSE);
708 if (e->xconfigurerequest.value_mask & CWStackMode) {
709 switch (e->xconfigurerequest.detail) {
712 stacking_lower(CLIENT_AS_WINDOW(client));
718 stacking_raise(CLIENT_AS_WINDOW(client));
724 if (client->ignore_unmaps) {
725 client->ignore_unmaps--;
728 client_unmanage(client);
731 client_unmanage(client);
734 /* this is when the client is first taken captive in the frame */
735 if (e->xreparent.parent == client->frame->plate) break;
738 This event is quite rare and is usually handled in unmapHandler.
739 However, if the window is unmapped when the reparent event occurs,
740 the window manager never sees it because an unmap event is not sent
741 to an already unmapped window.
744 /* we don't want the reparent event, put it back on the stack for the
745 X server to deal with after we unmanage the window */
746 XPutBackEvent(ob_display, e);
748 client_unmanage(client);
751 g_message("MapRequest for 0x%lx", client->window);
752 if (!client->iconic) break; /* this normally doesn't happen, but if it
753 does, we don't want it! */
754 if (screen_showing_desktop)
755 screen_show_desktop(FALSE);
756 client_iconify(client, FALSE, TRUE);
757 if (!client->frame->visible)
758 /* if its not visible still, then don't mess with it */
761 client_shade(client, FALSE);
762 client_focus(client);
763 stacking_raise(CLIENT_AS_WINDOW(client));
766 /* validate cuz we query stuff off the client here */
767 if (!client_validate(client)) break;
769 if (e->xclient.format != 32) return;
771 msgtype = e->xclient.message_type;
772 if (msgtype == prop_atoms.wm_change_state) {
773 /* compress changes into a single change */
774 while (XCheckTypedWindowEvent(ob_display, e->type,
775 client->window, &ce)) {
776 /* XXX: it would be nice to compress ALL messages of a
777 type, not just messages in a row without other
778 message types between. */
779 if (ce.xclient.message_type != msgtype) {
780 XPutBackEvent(ob_display, &ce);
783 e->xclient = ce.xclient;
785 client_set_wm_state(client, e->xclient.data.l[0]);
786 } else if (msgtype == prop_atoms.net_wm_desktop) {
787 /* compress changes into a single change */
788 while (XCheckTypedWindowEvent(ob_display, e->type,
789 client->window, &ce)) {
790 /* XXX: it would be nice to compress ALL messages of a
791 type, not just messages in a row without other
792 message types between. */
793 if (ce.xclient.message_type != msgtype) {
794 XPutBackEvent(ob_display, &ce);
797 e->xclient = ce.xclient;
799 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
800 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
801 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
803 } else if (msgtype == prop_atoms.net_wm_state) {
804 /* can't compress these */
805 g_message("net_wm_state %s %ld %ld for 0x%lx",
806 (e->xclient.data.l[0] == 0 ? "Remove" :
807 e->xclient.data.l[0] == 1 ? "Add" :
808 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
809 e->xclient.data.l[1], e->xclient.data.l[2],
811 client_set_state(client, e->xclient.data.l[0],
812 e->xclient.data.l[1], e->xclient.data.l[2]);
813 } else if (msgtype == prop_atoms.net_close_window) {
814 g_message("net_close_window for 0x%lx", client->window);
815 client_close(client);
816 } else if (msgtype == prop_atoms.net_active_window) {
817 g_message("net_active_window for 0x%lx", client->window);
818 client_activate(client);
819 } else if (msgtype == prop_atoms.net_wm_moveresize) {
820 g_message("net_wm_moveresize for 0x%lx", client->window);
821 if ((Atom)e->xclient.data.l[2] ==
822 prop_atoms.net_wm_moveresize_size_topleft ||
823 (Atom)e->xclient.data.l[2] ==
824 prop_atoms.net_wm_moveresize_size_top ||
825 (Atom)e->xclient.data.l[2] ==
826 prop_atoms.net_wm_moveresize_size_topright ||
827 (Atom)e->xclient.data.l[2] ==
828 prop_atoms.net_wm_moveresize_size_right ||
829 (Atom)e->xclient.data.l[2] ==
830 prop_atoms.net_wm_moveresize_size_right ||
831 (Atom)e->xclient.data.l[2] ==
832 prop_atoms.net_wm_moveresize_size_bottomright ||
833 (Atom)e->xclient.data.l[2] ==
834 prop_atoms.net_wm_moveresize_size_bottom ||
835 (Atom)e->xclient.data.l[2] ==
836 prop_atoms.net_wm_moveresize_size_bottomleft ||
837 (Atom)e->xclient.data.l[2] ==
838 prop_atoms.net_wm_moveresize_size_left ||
839 (Atom)e->xclient.data.l[2] ==
840 prop_atoms.net_wm_moveresize_move ||
841 (Atom)e->xclient.data.l[2] ==
842 prop_atoms.net_wm_moveresize_size_keyboard ||
843 (Atom)e->xclient.data.l[2] ==
844 prop_atoms.net_wm_moveresize_move_keyboard) {
846 moveresize_start(client, e->xclient.data.l[0],
847 e->xclient.data.l[1], e->xclient.data.l[3],
848 e->xclient.data.l[2]);
850 } else if (msgtype == prop_atoms.net_moveresize_window) {
851 int oldg = client->gravity;
852 int tmpg, x, y, w, h;
854 if (e->xclient.data.l[0] & 0xff)
855 tmpg = e->xclient.data.l[0] & 0xff;
859 if (e->xclient.data.l[0] & 1 << 8)
860 x = e->xclient.data.l[1];
863 if (e->xclient.data.l[0] & 1 << 9)
864 y = e->xclient.data.l[2];
867 if (e->xclient.data.l[0] & 1 << 10)
868 w = e->xclient.data.l[3];
871 if (e->xclient.data.l[0] & 1 << 11)
872 h = e->xclient.data.l[4];
875 client->gravity = tmpg;
876 client_configure(client, Corner_TopLeft, x, y, w, h, TRUE, TRUE);
877 client->gravity = oldg;
881 /* validate cuz we query stuff off the client here */
882 if (!client_validate(client)) break;
884 /* compress changes to a single property into a single change */
885 while (XCheckTypedWindowEvent(ob_display, e->type,
886 client->window, &ce)) {
887 /* XXX: it would be nice to compress ALL changes to a property,
888 not just changes in a row without other props between. */
889 if (ce.xproperty.atom != e->xproperty.atom) {
890 XPutBackEvent(ob_display, &ce);
895 msgtype = e->xproperty.atom;
896 if (msgtype == XA_WM_NORMAL_HINTS) {
897 client_update_normal_hints(client);
898 /* normal hints can make a window non-resizable */
899 client_setup_decor_and_functions(client);
901 else if (msgtype == XA_WM_HINTS)
902 client_update_wmhints(client);
903 else if (msgtype == XA_WM_TRANSIENT_FOR) {
904 client_update_transient_for(client);
905 client_get_type(client);
906 /* type may have changed, so update the layer */
907 client_calc_layer(client);
908 client_setup_decor_and_functions(client);
910 else if (msgtype == prop_atoms.net_wm_name ||
911 msgtype == prop_atoms.wm_name ||
912 msgtype == prop_atoms.net_wm_icon_name ||
913 msgtype == prop_atoms.wm_icon_name)
914 client_update_title(client);
915 else if (msgtype == prop_atoms.wm_class)
916 client_update_class(client);
917 else if (msgtype == prop_atoms.wm_protocols) {
918 client_update_protocols(client);
919 client_setup_decor_and_functions(client);
921 else if (msgtype == prop_atoms.net_wm_strut)
922 client_update_strut(client);
923 else if (msgtype == prop_atoms.net_wm_icon ||
924 msgtype == prop_atoms.kwm_win_icon)
925 client_update_icons(client);
929 if (extensions_shape && e->type == extensions_shape_event_basep) {
930 client->shaped = ((XShapeEvent*)e)->shaped;
931 frame_adjust_shape(client->frame);
937 static void event_handle_menu(Menu *menu, Client *client, XEvent *e)
941 g_message("EVENT %d", e->type);
944 g_message("BUTTON PRESS");
945 if (e->xbutton.button == 3)
947 else if (e->xbutton.button == 1) {
948 entry = menu_find_entry(menu, e->xbutton.window);
950 stacking_raise(MENU_AS_WINDOW(menu));
954 g_message("BUTTON RELEASED");
955 if (!menu->shown) break;
957 /* grab_pointer_window(FALSE, None, menu->frame);*/
959 if (e->xbutton.button == 1) {
960 entry = menu_find_entry(menu, e->xbutton.window);
964 guint ujunk, b, w, h;
965 XGetGeometry(ob_display, e->xbutton.window,
966 &wjunk, &junk, &junk, &w, &h, &b, &ujunk);
967 if (e->xbutton.x >= (signed)-b &&
968 e->xbutton.y >= (signed)-b &&
969 e->xbutton.x < (signed)(w+b) &&
970 e->xbutton.y < (signed)(h+b)) {
971 menu_entry_fire(entry);
979 g_message("enter/leave");
980 entry = menu_find_entry(menu, e->xcrossing.window);
983 menu->mouseover(entry, e->type == EnterNotify);
985 menu_control_mouseover(entry, e->type == EnterNotify);
987 menu_entry_render(entry);
993 void event_add_fd_handler(event_fd_handler *h) {
994 g_datalist_id_set_data(&fd_handler_list, h->fd, h);
995 FD_SET(h->fd, &allset);
996 max_fd = MAX(max_fd, h->fd);
999 void find_max_fd_foreach(GQuark n, gpointer data, gpointer max)
1001 *((unsigned int *)max) = MAX(*((unsigned int *)max), n);
1004 void event_remove_fd(int n)
1008 g_datalist_id_remove_data(&fd_handler_list, (GQuark)n);
1009 g_datalist_foreach(&fd_handler_list, find_max_fd_foreach, (gpointer)&tmpmax);
1010 max_fd = MAX(x_fd, tmpmax);
1013 void fd_event_handle_foreach(GQuark n, gpointer data, gpointer user_data)
1015 if (FD_ISSET( (int)n, &selset)) {
1016 event_fd_handler *h = (event_fd_handler *)data;
1017 g_assert(h->fd == (int)n);
1018 h->handler(h->fd, h->data);
1022 void fd_event_handle()
1024 g_datalist_foreach(&fd_handler_list, fd_event_handle_foreach, NULL);
1027 static void event_handle_dock(Dock *s, XEvent *e)
1031 stacking_raise(DOCK_AS_WINDOW(s));
1042 static void event_handle_dockapp(DockApp *app, XEvent *e)
1046 dock_app_drag(app, &e->xmotion);
1049 if (app->ignore_unmaps) {
1050 app->ignore_unmaps--;
1053 dock_remove(app, TRUE);
1056 dock_remove(app, FALSE);
1058 case ReparentNotify:
1059 dock_remove(app, FALSE);
1061 case ConfigureNotify:
1062 dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);