10 #include "framerender.h"
12 #include "moveresize.h"
14 #include "extensions.h"
20 #include <X11/keysym.h>
21 #include <X11/Xatom.h>
24 #ifdef HAVE_SYS_SELECT_H
25 # include <sys/select.h>
28 static void event_process(XEvent *e);
29 static void event_handle_root(XEvent *e);
30 static void event_handle_dock(Dock *s, XEvent *e);
31 static void event_handle_dockapp(DockApp *app, XEvent *e);
32 static void event_handle_client(Client *c, XEvent *e);
33 static void event_handle_menu(Menu *menu, XEvent *e);
35 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
36 (e)->xfocus.detail > NotifyNonlinearVirtual)
37 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
38 (e)->xfocus.detail == NotifyInferior || \
39 (e)->xfocus.detail == NotifyAncestor || \
40 (e)->xfocus.detail > NotifyNonlinearVirtual)
42 Time event_lasttime = 0;
44 /*! The value of the mask for the NumLock modifier */
45 unsigned int NumLockMask;
46 /*! The value of the mask for the ScrollLock modifier */
47 unsigned int ScrollLockMask;
48 /*! The key codes for the modifier keys */
49 static XModifierKeymap *modmap;
50 /*! Table of the constant modifier masks */
51 static const int mask_table[] = {
52 ShiftMask, LockMask, ControlMask, Mod1Mask,
53 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
55 static int mask_table_size;
57 static fd_set selset, allset;
58 static int max_fd, x_fd;
59 static GData *fd_handler_list;
61 void fd_event_handle();
65 mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]);
67 /* get lock masks that are defined by the display (not constant) */
68 modmap = XGetModifierMapping(ob_display);
70 if (modmap && modmap->max_keypermod > 0) {
72 const size_t size = mask_table_size * modmap->max_keypermod;
73 /* get the values of the keyboard lock modifiers
74 Note: Caps lock is not retrieved the same way as Scroll and Num
75 lock since it doesn't need to be. */
76 const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock);
77 const KeyCode scroll_lock = XKeysymToKeycode(ob_display,
80 for (cnt = 0; cnt < size; ++cnt) {
81 if (! modmap->modifiermap[cnt]) continue;
83 if (num_lock == modmap->modifiermap[cnt])
84 NumLockMask = mask_table[cnt / modmap->max_keypermod];
85 if (scroll_lock == modmap->modifiermap[cnt])
86 ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
91 max_fd = x_fd = ConnectionNumber(ob_display);
92 FD_SET(x_fd, &allset);
93 g_datalist_init(&fd_handler_list);
98 XFreeModifiermap(modmap);
99 g_datalist_clear(&fd_handler_list);
105 struct timeval *wait;
106 gboolean had_event = FALSE;
110 There are slightly different event retrieval semantics here for
111 local (or high bandwidth) versus remote (or low bandwidth)
112 connections to the display/Xserver.
115 if (!XPending(ob_display))
119 This XSync allows for far more compression of events, which
120 makes things like Motion events perform far far better. Since
121 it also means network traffic for every event instead of every
122 X events (where X is the number retrieved at a time), it
123 probably should not be used for setups where Openbox is
124 running on a remote/low bandwidth display/Xserver.
126 XSync(ob_display, FALSE);
127 if (!XEventsQueued(ob_display, QueuedAlready))
130 XNextEvent(ob_display, &e);
137 timer_dispatch((GTimeVal**)&wait);
139 select(max_fd + 1, &selset, NULL, NULL, wait);
141 /* handle the X events as soon as possible? */
142 if (FD_ISSET(x_fd, &selset))
149 static Window event_get_window(XEvent *e)
156 window = e->xmap.window;
159 window = e->xunmap.window;
162 window = e->xdestroywindow.window;
164 case ConfigureRequest:
165 window = e->xconfigurerequest.window;
167 case ConfigureNotify:
168 window = e->xconfigure.window;
172 if (extensions_xkb && e->type == extensions_xkb_event_basep) {
173 switch (((XkbAnyEvent*)&e)->xkb_type) {
175 window = ((XkbBellNotifyEvent*)&e)->window;
181 window = e->xany.window;
186 static void event_set_lasttime(XEvent *e)
188 /* grab the lasttime and hack up the state */
192 event_lasttime = e->xbutton.time;
195 event_lasttime = e->xkey.time;
198 event_lasttime = e->xkey.time;
201 event_lasttime = e->xmotion.time;
204 event_lasttime = e->xproperty.time;
208 event_lasttime = e->xcrossing.time;
211 event_lasttime = CurrentTime;
216 #define STRIP_MODS(s) \
217 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
218 /* kill off the Button1Mask etc, only want the modifiers */ \
219 s &= (ControlMask | ShiftMask | Mod1Mask | \
220 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
222 static void event_hack_mods(XEvent *e)
230 STRIP_MODS(e->xbutton.state);
233 STRIP_MODS(e->xkey.state);
236 STRIP_MODS(e->xkey.state);
237 /* remove from the state the mask of the modifier being released, if
238 it is a modifier key being released (this is a little ugly..) */
239 kp = modmap->modifiermap;
240 for (i = 0; i < mask_table_size; ++i) {
241 for (k = 0; k < modmap->max_keypermod; ++k) {
242 if (*kp == e->xkey.keycode) { /* found the keycode */
243 /* remove the mask for it */
244 e->xkey.state &= ~mask_table[i];
245 /* cause the first loop to break; */
247 break; /* get outta here! */
254 STRIP_MODS(e->xmotion.state);
255 /* compress events */
258 while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
260 e->xmotion.x_root = ce.xmotion.x_root;
261 e->xmotion.y_root = ce.xmotion.y_root;
268 static gboolean event_ignore(XEvent *e, Client *client)
272 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
273 because of RevertToPointerRoot. If the focus ends up reverting to
274 pointer root on a workspace change, then the FocusIn event that we
275 want will be of type NotifyAncestor. This situation does not occur
276 for FocusOut, so it is safely ignored there.
278 if (INVALID_FOCUSIN(e) ||
281 g_message("FocusIn on %lx mode %d detail %d IGNORED", e->xfocus.window,
282 e->xfocus.mode, e->xfocus.detail);
284 /* says a client was not found for the event (or a valid FocusIn
287 e->xfocus.window = None;
292 g_message("FocusIn on %lx mode %d detail %d", e->xfocus.window,
293 e->xfocus.mode, e->xfocus.detail);
297 if (INVALID_FOCUSOUT(e)) {
299 g_message("FocusOut on %lx mode %d detail %d IGNORED",
300 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
306 g_message("FocusOut on %lx mode %d detail %d",
307 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
312 gboolean fallback = TRUE;
315 if (!XCheckTypedWindowEvent(ob_display, FocusOut,
316 e->xfocus.window,&fe))
317 if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
319 if (fe.type == FocusOut) {
321 g_message("found pending FocusOut");
323 if (!INVALID_FOCUSOUT(&fe)) {
324 /* if there is a VALID FocusOut still coming, don't
325 fallback focus yet, we'll deal with it then */
326 XPutBackEvent(ob_display, &fe);
332 g_message("found pending FocusIn");
334 /* is the focused window getting a FocusOut/In back to
336 if (fe.xfocus.window == e->xfocus.window &&
337 !event_ignore(&fe, client)) {
339 g_message("focused window got an Out/In back to "
340 "itself IGNORED both");
345 /* once all the FocusOut's have been dealt with, if there
346 is a FocusIn still left and it is valid, then use it */
348 /* secret magic way of event_process telling us that no
349 client was found for the FocusIn event. ^_^ */
350 if (fe.xfocus.window != None) {
358 g_message("no valid FocusIn and no FocusOut events found, "
361 focus_fallback(Fallback_NoFocus);
367 /* NotifyUngrab occurs when a mouse button is released and the event is
368 caused, like when lowering a window */
369 /* NotifyVirtual occurs when ungrabbing the pointer */
370 if (e->xcrossing.mode == NotifyGrab ||
371 e->xcrossing.detail == NotifyInferior ||
372 (e->xcrossing.mode == NotifyUngrab &&
373 e->xcrossing.detail == NotifyVirtual)) {
375 g_message("%sNotify mode %d detail %d on %lx IGNORED",
376 (e->type == EnterNotify ? "Enter" : "Leave"),
378 e->xcrossing.detail, client?client->window:0);
383 g_message("%sNotify mode %d detail %d on %lx",
384 (e->type == EnterNotify ? "Enter" : "Leave"),
386 e->xcrossing.detail, client?client->window:0);
393 static void event_process(XEvent *e)
396 Client *client = NULL;
398 DockApp *dockapp = NULL;
400 ObWindow *obwin = NULL;
402 window = event_get_window(e);
403 if ((obwin = g_hash_table_lookup(window_map, &window))) {
404 switch (obwin->type) {
406 dock = WINDOW_AS_DOCK(obwin);
409 dockapp = WINDOW_AS_DOCKAPP(obwin);
412 menu = WINDOW_AS_MENU(obwin);
415 client = WINDOW_AS_CLIENT(obwin);
417 case Window_Internal:
418 /* not to be used for events */
419 g_assert_not_reached();
424 event_set_lasttime(e);
426 if (event_ignore(e, client))
429 /* deal with it in the kernel */
431 event_handle_menu(menu, e);
434 event_handle_client(client, e);
436 event_handle_dockapp(dockapp, e);
438 event_handle_dock(dock, e);
439 else if (window == ob_root)
440 event_handle_root(e);
441 else if (e->type == MapRequest)
442 client_manage(window);
443 else if (e->type == ConfigureRequest) {
444 /* unhandled configure requests must be used to configure the
448 xwc.x = e->xconfigurerequest.x;
449 xwc.y = e->xconfigurerequest.y;
450 xwc.width = e->xconfigurerequest.width;
451 xwc.height = e->xconfigurerequest.height;
452 xwc.border_width = e->xconfigurerequest.border_width;
453 xwc.sibling = e->xconfigurerequest.above;
454 xwc.stack_mode = e->xconfigurerequest.detail;
456 /* we are not to be held responsible if someone sends us an
458 xerror_set_ignore(TRUE);
459 XConfigureWindow(ob_display, window,
460 e->xconfigurerequest.value_mask, &xwc);
461 xerror_set_ignore(FALSE);
464 if (moveresize_in_progress)
465 if (e->type == MotionNotify || e->type == ButtonRelease ||
466 e->type == ButtonPress ||
467 e->type == KeyPress || e->type == KeyRelease) {
470 return; /* no dispatch! */
474 /* user input (action-bound) events */
476 if (e->type == ButtonPress || e->type == ButtonRelease ||
477 e->type == MotionNotify)
478 mouse_event(e, client);
479 else if (e->type == KeyPress || e->type == KeyRelease)
483 /* dispatch the event to registered handlers */
484 dispatch_x(e, client);
487 static void event_handle_root(XEvent *e)
493 if (e->xclient.format != 32) break;
495 msgtype = e->xclient.message_type;
496 if (msgtype == prop_atoms.net_current_desktop) {
497 unsigned int d = e->xclient.data.l[0];
498 if (d < screen_num_desktops)
499 screen_set_desktop(d);
500 } else if (msgtype == prop_atoms.net_number_of_desktops) {
501 unsigned int d = e->xclient.data.l[0];
503 screen_set_num_desktops(d);
504 } else if (msgtype == prop_atoms.net_showing_desktop) {
505 screen_show_desktop(e->xclient.data.l[0] != 0);
509 if (e->xproperty.atom == prop_atoms.net_desktop_names)
510 screen_update_desktop_names();
511 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
512 screen_update_layout();
514 case ConfigureNotify:
516 XRRUpdateConfiguration(e);
518 if (e->xconfigure.width != screen_physical_size.width ||
519 e->xconfigure.height != screen_physical_size.height)
520 screen_resize(e->xconfigure.width, e->xconfigure.height);
525 if (extensions_vidmode && e->type == extensions_vidmode_event_basep) {
526 g_message("VIDMODE EVENT");
532 static void event_handle_client(Client *client, XEvent *e)
541 /* Wheel buttons don't draw because they are an instant click, so it
542 is a waste of resources to go drawing it. */
543 if (!(e->xbutton.button == 4 || e->xbutton.button == 5)) {
544 switch (frame_context(client, e->xbutton.window)) {
545 case Context_Maximize:
546 client->frame->max_press = (e->type == ButtonPress);
547 framerender_frame(client->frame);
550 client->frame->close_press = (e->type == ButtonPress);
551 framerender_frame(client->frame);
553 case Context_Iconify:
554 client->frame->iconify_press = (e->type == ButtonPress);
555 framerender_frame(client->frame);
557 case Context_AllDesktops:
558 client->frame->desk_press = (e->type == ButtonPress);
559 framerender_frame(client->frame);
562 client->frame->shade_press = (e->type == ButtonPress);
563 framerender_frame(client->frame);
566 /* nothing changes with clicks for any other contexts */
573 g_message("FocusIn on client for %lx", client->window);
575 focus_set_client(client);
576 frame_adjust_focus(client->frame, TRUE);
580 g_message("FocusOut on client for %lx", client->window);
582 /* are we a fullscreen window or a transient of one? (checks layer)
583 if we are then we need to be iconified since we are losing focus
585 if (client->layer == Layer_Fullscreen && !client->iconic &&
586 !client_search_focus_tree_full(client))
587 /* iconify fullscreen windows when they and their transients
589 client_iconify(client, TRUE, TRUE);
590 frame_adjust_focus(client->frame, FALSE);
593 if (client_normal(client)) {
594 if (ob_state == State_Starting) {
595 /* move it to the top of the focus order */
596 guint desktop = client->desktop;
597 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
598 focus_order[desktop] = g_list_remove(focus_order[desktop],
600 focus_order[desktop] = g_list_prepend(focus_order[desktop],
602 } else if (config_focus_follow) {
604 g_message("EnterNotify on %lx, focusing window",
607 client_focus(client);
611 case ConfigureRequest:
613 while (XCheckTypedWindowEvent(ob_display, client->window,
614 ConfigureRequest, &ce)) {
616 /* XXX if this causes bad things.. we can compress config req's
617 with the same mask. */
618 e->xconfigurerequest.value_mask |=
619 ce.xconfigurerequest.value_mask;
620 if (ce.xconfigurerequest.value_mask & CWX)
621 e->xconfigurerequest.x = ce.xconfigurerequest.x;
622 if (ce.xconfigurerequest.value_mask & CWY)
623 e->xconfigurerequest.y = ce.xconfigurerequest.y;
624 if (ce.xconfigurerequest.value_mask & CWWidth)
625 e->xconfigurerequest.width = ce.xconfigurerequest.width;
626 if (ce.xconfigurerequest.value_mask & CWHeight)
627 e->xconfigurerequest.height = ce.xconfigurerequest.height;
628 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
629 e->xconfigurerequest.border_width =
630 ce.xconfigurerequest.border_width;
631 if (ce.xconfigurerequest.value_mask & CWStackMode)
632 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
635 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
636 if (client->iconic || client->shaded) return;
638 if (e->xconfigurerequest.value_mask & CWBorderWidth)
639 client->border_width = e->xconfigurerequest.border_width;
641 /* resize, then move, as specified in the EWMH section 7.7 */
642 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
647 x = (e->xconfigurerequest.value_mask & CWX) ?
648 e->xconfigurerequest.x : client->area.x;
649 y = (e->xconfigurerequest.value_mask & CWY) ?
650 e->xconfigurerequest.y : client->area.y;
651 w = (e->xconfigurerequest.value_mask & CWWidth) ?
652 e->xconfigurerequest.width : client->area.width;
653 h = (e->xconfigurerequest.value_mask & CWHeight) ?
654 e->xconfigurerequest.height : client->area.height;
656 switch (client->gravity) {
657 case NorthEastGravity:
659 corner = Corner_TopRight;
661 case SouthWestGravity:
663 corner = Corner_BottomLeft;
665 case SouthEastGravity:
666 corner = Corner_BottomRight;
668 default: /* NorthWest, Static, etc */
669 corner = Corner_TopLeft;
672 client_configure(client, corner, x, y, w, h, FALSE, FALSE);
675 if (e->xconfigurerequest.value_mask & CWStackMode) {
676 switch (e->xconfigurerequest.detail) {
679 stacking_lower(CLIENT_AS_WINDOW(client));
685 stacking_raise(CLIENT_AS_WINDOW(client));
691 if (client->ignore_unmaps) {
692 client->ignore_unmaps--;
695 client_unmanage(client);
698 client_unmanage(client);
701 /* this is when the client is first taken captive in the frame */
702 if (e->xreparent.parent == client->frame->plate) break;
705 This event is quite rare and is usually handled in unmapHandler.
706 However, if the window is unmapped when the reparent event occurs,
707 the window manager never sees it because an unmap event is not sent
708 to an already unmapped window.
711 /* we don't want the reparent event, put it back on the stack for the
712 X server to deal with after we unmanage the window */
713 XPutBackEvent(ob_display, e);
715 client_unmanage(client);
718 g_message("MapRequest for 0x%lx", client->window);
719 if (!client->iconic) break; /* this normally doesn't happen, but if it
720 does, we don't want it! */
721 if (screen_showing_desktop)
722 screen_show_desktop(FALSE);
723 client_iconify(client, FALSE, TRUE);
724 if (!client->frame->visible)
725 /* if its not visible still, then don't mess with it */
728 client_shade(client, FALSE);
729 client_focus(client);
730 stacking_raise(CLIENT_AS_WINDOW(client));
733 /* validate cuz we query stuff off the client here */
734 if (!client_validate(client)) break;
736 if (e->xclient.format != 32) return;
738 msgtype = e->xclient.message_type;
739 if (msgtype == prop_atoms.wm_change_state) {
740 /* compress changes into a single change */
741 while (XCheckTypedWindowEvent(ob_display, e->type,
742 client->window, &ce)) {
743 /* XXX: it would be nice to compress ALL messages of a
744 type, not just messages in a row without other
745 message types between. */
746 if (ce.xclient.message_type != msgtype) {
747 XPutBackEvent(ob_display, &ce);
750 e->xclient = ce.xclient;
752 client_set_wm_state(client, e->xclient.data.l[0]);
753 } else if (msgtype == prop_atoms.net_wm_desktop) {
754 /* compress changes into a single change */
755 while (XCheckTypedWindowEvent(ob_display, e->type,
756 client->window, &ce)) {
757 /* XXX: it would be nice to compress ALL messages of a
758 type, not just messages in a row without other
759 message types between. */
760 if (ce.xclient.message_type != msgtype) {
761 XPutBackEvent(ob_display, &ce);
764 e->xclient = ce.xclient;
766 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
767 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
768 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
770 } else if (msgtype == prop_atoms.net_wm_state) {
771 /* can't compress these */
772 g_message("net_wm_state %s %ld %ld for 0x%lx",
773 (e->xclient.data.l[0] == 0 ? "Remove" :
774 e->xclient.data.l[0] == 1 ? "Add" :
775 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
776 e->xclient.data.l[1], e->xclient.data.l[2],
778 client_set_state(client, e->xclient.data.l[0],
779 e->xclient.data.l[1], e->xclient.data.l[2]);
780 } else if (msgtype == prop_atoms.net_close_window) {
781 g_message("net_close_window for 0x%lx", client->window);
782 client_close(client);
783 } else if (msgtype == prop_atoms.net_active_window) {
784 g_message("net_active_window for 0x%lx", client->window);
785 client_activate(client);
786 } else if (msgtype == prop_atoms.net_wm_moveresize) {
787 g_message("net_wm_moveresize for 0x%lx", client->window);
788 if ((Atom)e->xclient.data.l[2] ==
789 prop_atoms.net_wm_moveresize_size_topleft ||
790 (Atom)e->xclient.data.l[2] ==
791 prop_atoms.net_wm_moveresize_size_top ||
792 (Atom)e->xclient.data.l[2] ==
793 prop_atoms.net_wm_moveresize_size_topright ||
794 (Atom)e->xclient.data.l[2] ==
795 prop_atoms.net_wm_moveresize_size_right ||
796 (Atom)e->xclient.data.l[2] ==
797 prop_atoms.net_wm_moveresize_size_right ||
798 (Atom)e->xclient.data.l[2] ==
799 prop_atoms.net_wm_moveresize_size_bottomright ||
800 (Atom)e->xclient.data.l[2] ==
801 prop_atoms.net_wm_moveresize_size_bottom ||
802 (Atom)e->xclient.data.l[2] ==
803 prop_atoms.net_wm_moveresize_size_bottomleft ||
804 (Atom)e->xclient.data.l[2] ==
805 prop_atoms.net_wm_moveresize_size_left ||
806 (Atom)e->xclient.data.l[2] ==
807 prop_atoms.net_wm_moveresize_move ||
808 (Atom)e->xclient.data.l[2] ==
809 prop_atoms.net_wm_moveresize_size_keyboard ||
810 (Atom)e->xclient.data.l[2] ==
811 prop_atoms.net_wm_moveresize_move_keyboard) {
813 moveresize_start(client, e->xclient.data.l[0],
814 e->xclient.data.l[1], e->xclient.data.l[3],
815 e->xclient.data.l[2]);
817 } else if (msgtype == prop_atoms.net_moveresize_window) {
818 int oldg = client->gravity;
819 int tmpg, x, y, w, h;
821 if (e->xclient.data.l[0] & 0xff)
822 tmpg = e->xclient.data.l[0] & 0xff;
826 if (e->xclient.data.l[0] & 1 << 8)
827 x = e->xclient.data.l[1];
830 if (e->xclient.data.l[0] & 1 << 9)
831 y = e->xclient.data.l[2];
834 if (e->xclient.data.l[0] & 1 << 10)
835 w = e->xclient.data.l[3];
838 if (e->xclient.data.l[0] & 1 << 11)
839 h = e->xclient.data.l[4];
842 client->gravity = tmpg;
843 client_configure(client, Corner_TopLeft, x, y, w, h, TRUE, TRUE);
844 client->gravity = oldg;
848 /* validate cuz we query stuff off the client here */
849 if (!client_validate(client)) break;
851 /* compress changes to a single property into a single change */
852 while (XCheckTypedWindowEvent(ob_display, e->type,
853 client->window, &ce)) {
854 /* XXX: it would be nice to compress ALL changes to a property,
855 not just changes in a row without other props between. */
856 if (ce.xproperty.atom != e->xproperty.atom) {
857 XPutBackEvent(ob_display, &ce);
862 msgtype = e->xproperty.atom;
863 if (msgtype == XA_WM_NORMAL_HINTS) {
864 client_update_normal_hints(client);
865 /* normal hints can make a window non-resizable */
866 client_setup_decor_and_functions(client);
868 else if (msgtype == XA_WM_HINTS)
869 client_update_wmhints(client);
870 else if (msgtype == XA_WM_TRANSIENT_FOR) {
871 client_update_transient_for(client);
872 client_get_type(client);
873 /* type may have changed, so update the layer */
874 client_calc_layer(client);
875 client_setup_decor_and_functions(client);
877 else if (msgtype == prop_atoms.net_wm_name ||
878 msgtype == prop_atoms.wm_name ||
879 msgtype == prop_atoms.net_wm_icon_name ||
880 msgtype == prop_atoms.wm_icon_name)
881 client_update_title(client);
882 else if (msgtype == prop_atoms.wm_class)
883 client_update_class(client);
884 else if (msgtype == prop_atoms.wm_protocols) {
885 client_update_protocols(client);
886 client_setup_decor_and_functions(client);
888 else if (msgtype == prop_atoms.net_wm_strut)
889 client_update_strut(client);
890 else if (msgtype == prop_atoms.net_wm_icon)
891 client_update_icons(client);
892 else if (msgtype == prop_atoms.kwm_win_icon)
893 client_update_kwm_icon(client);
897 if (extensions_shape && e->type == extensions_shape_event_basep) {
898 client->shaped = ((XShapeEvent*)e)->shaped;
899 frame_adjust_shape(client->frame);
905 static void event_handle_menu(Menu *menu, XEvent *e)
909 g_message("EVENT %d", e->type);
912 g_message("BUTTON PRESS");
913 if (e->xbutton.button == 3)
915 else if (e->xbutton.button == 1) {
916 entry = menu_find_entry(menu, e->xbutton.window);
918 stacking_raise(MENU_AS_WINDOW(menu));
922 g_message("BUTTON RELEASED");
923 if (!menu->shown) break;
925 /* grab_pointer_window(FALSE, None, menu->frame);*/
927 entry = menu_find_entry(menu, e->xbutton.window);
931 guint ujunk, b, w, h;
932 XGetGeometry(ob_display, e->xbutton.window,
933 &wjunk, &junk, &junk, &w, &h, &b, &ujunk);
934 if (e->xbutton.x >= (signed)-b &&
935 e->xbutton.y >= (signed)-b &&
936 e->xbutton.x < (signed)(w+b) &&
937 e->xbutton.y < (signed)(h+b)) {
938 menu_entry_fire(entry);
945 g_message("enter/leave");
946 entry = menu_find_entry(menu, e->xcrossing.window);
949 menu->mouseover(entry, e->type == EnterNotify);
951 menu_control_mouseover(entry, e->type == EnterNotify);
953 menu_entry_render(entry);
959 void event_add_fd_handler(event_fd_handler *h) {
960 g_datalist_id_set_data(&fd_handler_list, h->fd, h);
961 FD_SET(h->fd, &allset);
962 max_fd = MAX(max_fd, h->fd);
965 void find_max_fd_foreach(GQuark n, gpointer data, gpointer max)
967 *((unsigned int *)max) = MAX(*((unsigned int *)max), n);
970 void event_remove_fd(int n)
974 g_datalist_id_remove_data(&fd_handler_list, (GQuark)n);
975 g_datalist_foreach(&fd_handler_list, find_max_fd_foreach, (gpointer)&tmpmax);
976 max_fd = MAX(x_fd, tmpmax);
979 void fd_event_handle_foreach(GQuark n, gpointer data, gpointer user_data)
981 if (FD_ISSET( (int)n, &selset)) {
982 event_fd_handler *h = (event_fd_handler *)data;
983 g_assert(h->fd == (int)n);
984 h->handler(h->fd, h->data);
988 void fd_event_handle()
990 g_datalist_foreach(&fd_handler_list, fd_event_handle_foreach, NULL);
993 static void event_handle_dock(Dock *s, XEvent *e)
997 stacking_raise(DOCK_AS_WINDOW(s));
1007 static void event_handle_dockapp(DockApp *app, XEvent *e)
1011 dock_app_drag(app, &e->xmotion);
1014 if (app->ignore_unmaps) {
1015 app->ignore_unmaps--;
1018 dock_remove(app, TRUE);
1021 dock_remove(app, FALSE);
1023 case ReparentNotify:
1024 dock_remove(app, FALSE);
1026 case ConfigureNotify:
1027 dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);