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
345 if (fe.xfocus.window == e->xfocus.window &&
346 !event_ignore(&fe, client)) {
348 g_message("focused window got an Out/In back to "
349 "itself IGNORED both");
354 /* once all the FocusOut's have been dealt with, if there
355 is a FocusIn still left and it is valid, then use it */
357 /* secret magic way of event_process telling us that no
358 client was found for the FocusIn event. ^_^ */
359 if (fe.xfocus.window != None) {
367 g_message("no valid FocusIn and no FocusOut events found, "
370 focus_fallback(Fallback_NoFocus);
376 /* NotifyUngrab occurs when a mouse button is released and the event is
377 caused, like when lowering a window */
378 /* NotifyVirtual occurs when ungrabbing the pointer */
379 if (e->xcrossing.mode == NotifyGrab ||
380 e->xcrossing.detail == NotifyInferior ||
381 (e->xcrossing.mode == NotifyUngrab &&
382 e->xcrossing.detail == NotifyVirtual)) {
384 g_message("%sNotify mode %d detail %d on %lx IGNORED",
385 (e->type == EnterNotify ? "Enter" : "Leave"),
387 e->xcrossing.detail, client?client->window:0);
392 g_message("%sNotify mode %d detail %d on %lx",
393 (e->type == EnterNotify ? "Enter" : "Leave"),
395 e->xcrossing.detail, client?client->window:0);
402 static void event_process(XEvent *e)
405 Client *client = NULL;
407 DockApp *dockapp = NULL;
409 ObWindow *obwin = NULL;
411 window = event_get_window(e);
412 if ((obwin = g_hash_table_lookup(window_map, &window))) {
413 switch (obwin->type) {
415 dock = WINDOW_AS_DOCK(obwin);
418 dockapp = WINDOW_AS_DOCKAPP(obwin);
421 menu = WINDOW_AS_MENU(obwin);
424 client = WINDOW_AS_CLIENT(obwin);
426 case Window_Internal:
427 /* not to be used for events */
428 g_assert_not_reached();
433 event_set_lasttime(e);
435 if (event_ignore(e, client))
438 /* deal with it in the kernel */
440 event_handle_menu(menu, client, e);
443 event_handle_client(client, e);
445 event_handle_dockapp(dockapp, e);
447 event_handle_dock(dock, e);
448 else if (window == ob_root)
449 event_handle_root(e);
450 else if (e->type == MapRequest)
451 client_manage(window);
452 else if (e->type == ConfigureRequest) {
453 /* unhandled configure requests must be used to configure the
457 xwc.x = e->xconfigurerequest.x;
458 xwc.y = e->xconfigurerequest.y;
459 xwc.width = e->xconfigurerequest.width;
460 xwc.height = e->xconfigurerequest.height;
461 xwc.border_width = e->xconfigurerequest.border_width;
462 xwc.sibling = e->xconfigurerequest.above;
463 xwc.stack_mode = e->xconfigurerequest.detail;
465 /* we are not to be held responsible if someone sends us an
467 xerror_set_ignore(TRUE);
468 XConfigureWindow(ob_display, window,
469 e->xconfigurerequest.value_mask, &xwc);
470 xerror_set_ignore(FALSE);
473 if (moveresize_in_progress)
474 if (e->type == MotionNotify || e->type == ButtonRelease ||
475 e->type == ButtonPress ||
476 e->type == KeyPress || e->type == KeyRelease) {
479 return; /* no dispatch! */
483 /* user input (action-bound) events */
485 if (e->type == ButtonPress || e->type == ButtonRelease ||
486 e->type == MotionNotify)
487 mouse_event(e, client);
488 else if (e->type == KeyPress || e->type == KeyRelease)
492 /* dispatch the event to registered handlers */
493 dispatch_x(e, client);
496 static void event_handle_root(XEvent *e)
502 if (e->xclient.format != 32) break;
504 msgtype = e->xclient.message_type;
505 if (msgtype == prop_atoms.net_current_desktop) {
506 unsigned int d = e->xclient.data.l[0];
507 if (d < screen_num_desktops)
508 screen_set_desktop(d);
509 } else if (msgtype == prop_atoms.net_number_of_desktops) {
510 unsigned int d = e->xclient.data.l[0];
512 screen_set_num_desktops(d);
513 } else if (msgtype == prop_atoms.net_showing_desktop) {
514 screen_show_desktop(e->xclient.data.l[0] != 0);
518 if (e->xproperty.atom == prop_atoms.net_desktop_names)
519 screen_update_desktop_names();
520 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
521 screen_update_layout();
523 case ConfigureNotify:
525 XRRUpdateConfiguration(e);
527 if (e->xconfigure.width != screen_physical_size.width ||
528 e->xconfigure.height != screen_physical_size.height)
529 screen_resize(e->xconfigure.width, e->xconfigure.height);
534 if (extensions_vidmode && e->type == extensions_vidmode_event_basep) {
535 g_message("VIDMODE EVENT");
541 static void event_handle_client(Client *client, XEvent *e)
550 /* Wheel buttons don't draw because they are an instant click, so it
551 is a waste of resources to go drawing it. */
552 if (!(e->xbutton.button == 4 || e->xbutton.button == 5)) {
553 switch (frame_context(client, e->xbutton.window)) {
554 case Context_Maximize:
555 client->frame->max_press = (e->type == ButtonPress);
556 framerender_frame(client->frame);
559 client->frame->close_press = (e->type == ButtonPress);
560 framerender_frame(client->frame);
562 case Context_Iconify:
563 client->frame->iconify_press = (e->type == ButtonPress);
564 framerender_frame(client->frame);
566 case Context_AllDesktops:
567 client->frame->desk_press = (e->type == ButtonPress);
568 framerender_frame(client->frame);
571 client->frame->shade_press = (e->type == ButtonPress);
572 framerender_frame(client->frame);
575 /* nothing changes with clicks for any other contexts */
582 g_message("FocusIn on client for %lx", client->window);
584 focus_set_client(client);
585 frame_adjust_focus(client->frame, TRUE);
589 g_message("FocusOut on client for %lx", client->window);
591 /* are we a fullscreen window or a transient of one? (checks layer)
592 if we are then we need to be iconified since we are losing focus
594 if (client->layer == Layer_Fullscreen && !client->iconic &&
595 !client_search_focus_tree_full(client))
596 /* iconify fullscreen windows when they and their transients
598 client_iconify(client, TRUE, TRUE);
599 frame_adjust_focus(client->frame, FALSE);
602 if (client_normal(client)) {
603 if (ob_state == State_Starting) {
604 /* move it to the top of the focus order */
605 guint desktop = client->desktop;
606 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
607 focus_order[desktop] = g_list_remove(focus_order[desktop],
609 focus_order[desktop] = g_list_prepend(focus_order[desktop],
611 } else if (config_focus_follow) {
613 g_message("EnterNotify on %lx, focusing window",
616 client_focus(client);
620 case ConfigureRequest:
622 while (XCheckTypedWindowEvent(ob_display, client->window,
623 ConfigureRequest, &ce)) {
625 /* XXX if this causes bad things.. we can compress config req's
626 with the same mask. */
627 e->xconfigurerequest.value_mask |=
628 ce.xconfigurerequest.value_mask;
629 if (ce.xconfigurerequest.value_mask & CWX)
630 e->xconfigurerequest.x = ce.xconfigurerequest.x;
631 if (ce.xconfigurerequest.value_mask & CWY)
632 e->xconfigurerequest.y = ce.xconfigurerequest.y;
633 if (ce.xconfigurerequest.value_mask & CWWidth)
634 e->xconfigurerequest.width = ce.xconfigurerequest.width;
635 if (ce.xconfigurerequest.value_mask & CWHeight)
636 e->xconfigurerequest.height = ce.xconfigurerequest.height;
637 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
638 e->xconfigurerequest.border_width =
639 ce.xconfigurerequest.border_width;
640 if (ce.xconfigurerequest.value_mask & CWStackMode)
641 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
644 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
645 if (client->iconic || client->shaded) return;
647 if (e->xconfigurerequest.value_mask & CWBorderWidth)
648 client->border_width = e->xconfigurerequest.border_width;
650 /* resize, then move, as specified in the EWMH section 7.7 */
651 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
656 x = (e->xconfigurerequest.value_mask & CWX) ?
657 e->xconfigurerequest.x : client->area.x;
658 y = (e->xconfigurerequest.value_mask & CWY) ?
659 e->xconfigurerequest.y : client->area.y;
660 w = (e->xconfigurerequest.value_mask & CWWidth) ?
661 e->xconfigurerequest.width : client->area.width;
662 h = (e->xconfigurerequest.value_mask & CWHeight) ?
663 e->xconfigurerequest.height : client->area.height;
665 switch (client->gravity) {
666 case NorthEastGravity:
668 corner = Corner_TopRight;
670 case SouthWestGravity:
672 corner = Corner_BottomLeft;
674 case SouthEastGravity:
675 corner = Corner_BottomRight;
677 default: /* NorthWest, Static, etc */
678 corner = Corner_TopLeft;
681 client_configure(client, corner, x, y, w, h, FALSE, FALSE);
684 if (e->xconfigurerequest.value_mask & CWStackMode) {
685 switch (e->xconfigurerequest.detail) {
688 stacking_lower(CLIENT_AS_WINDOW(client));
694 stacking_raise(CLIENT_AS_WINDOW(client));
700 if (client->ignore_unmaps) {
701 client->ignore_unmaps--;
704 client_unmanage(client);
707 client_unmanage(client);
710 /* this is when the client is first taken captive in the frame */
711 if (e->xreparent.parent == client->frame->plate) break;
714 This event is quite rare and is usually handled in unmapHandler.
715 However, if the window is unmapped when the reparent event occurs,
716 the window manager never sees it because an unmap event is not sent
717 to an already unmapped window.
720 /* we don't want the reparent event, put it back on the stack for the
721 X server to deal with after we unmanage the window */
722 XPutBackEvent(ob_display, e);
724 client_unmanage(client);
727 g_message("MapRequest for 0x%lx", client->window);
728 if (!client->iconic) break; /* this normally doesn't happen, but if it
729 does, we don't want it! */
730 if (screen_showing_desktop)
731 screen_show_desktop(FALSE);
732 client_iconify(client, FALSE, TRUE);
733 if (!client->frame->visible)
734 /* if its not visible still, then don't mess with it */
737 client_shade(client, FALSE);
738 client_focus(client);
739 stacking_raise(CLIENT_AS_WINDOW(client));
742 /* validate cuz we query stuff off the client here */
743 if (!client_validate(client)) break;
745 if (e->xclient.format != 32) return;
747 msgtype = e->xclient.message_type;
748 if (msgtype == prop_atoms.wm_change_state) {
749 /* compress changes into a single change */
750 while (XCheckTypedWindowEvent(ob_display, e->type,
751 client->window, &ce)) {
752 /* XXX: it would be nice to compress ALL messages of a
753 type, not just messages in a row without other
754 message types between. */
755 if (ce.xclient.message_type != msgtype) {
756 XPutBackEvent(ob_display, &ce);
759 e->xclient = ce.xclient;
761 client_set_wm_state(client, e->xclient.data.l[0]);
762 } else if (msgtype == prop_atoms.net_wm_desktop) {
763 /* compress changes into a single change */
764 while (XCheckTypedWindowEvent(ob_display, e->type,
765 client->window, &ce)) {
766 /* XXX: it would be nice to compress ALL messages of a
767 type, not just messages in a row without other
768 message types between. */
769 if (ce.xclient.message_type != msgtype) {
770 XPutBackEvent(ob_display, &ce);
773 e->xclient = ce.xclient;
775 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
776 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
777 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
779 } else if (msgtype == prop_atoms.net_wm_state) {
780 /* can't compress these */
781 g_message("net_wm_state %s %ld %ld for 0x%lx",
782 (e->xclient.data.l[0] == 0 ? "Remove" :
783 e->xclient.data.l[0] == 1 ? "Add" :
784 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
785 e->xclient.data.l[1], e->xclient.data.l[2],
787 client_set_state(client, e->xclient.data.l[0],
788 e->xclient.data.l[1], e->xclient.data.l[2]);
789 } else if (msgtype == prop_atoms.net_close_window) {
790 g_message("net_close_window for 0x%lx", client->window);
791 client_close(client);
792 } else if (msgtype == prop_atoms.net_active_window) {
793 g_message("net_active_window for 0x%lx", client->window);
794 client_activate(client);
795 } else if (msgtype == prop_atoms.net_wm_moveresize) {
796 g_message("net_wm_moveresize for 0x%lx", client->window);
797 if ((Atom)e->xclient.data.l[2] ==
798 prop_atoms.net_wm_moveresize_size_topleft ||
799 (Atom)e->xclient.data.l[2] ==
800 prop_atoms.net_wm_moveresize_size_top ||
801 (Atom)e->xclient.data.l[2] ==
802 prop_atoms.net_wm_moveresize_size_topright ||
803 (Atom)e->xclient.data.l[2] ==
804 prop_atoms.net_wm_moveresize_size_right ||
805 (Atom)e->xclient.data.l[2] ==
806 prop_atoms.net_wm_moveresize_size_right ||
807 (Atom)e->xclient.data.l[2] ==
808 prop_atoms.net_wm_moveresize_size_bottomright ||
809 (Atom)e->xclient.data.l[2] ==
810 prop_atoms.net_wm_moveresize_size_bottom ||
811 (Atom)e->xclient.data.l[2] ==
812 prop_atoms.net_wm_moveresize_size_bottomleft ||
813 (Atom)e->xclient.data.l[2] ==
814 prop_atoms.net_wm_moveresize_size_left ||
815 (Atom)e->xclient.data.l[2] ==
816 prop_atoms.net_wm_moveresize_move ||
817 (Atom)e->xclient.data.l[2] ==
818 prop_atoms.net_wm_moveresize_size_keyboard ||
819 (Atom)e->xclient.data.l[2] ==
820 prop_atoms.net_wm_moveresize_move_keyboard) {
822 moveresize_start(client, e->xclient.data.l[0],
823 e->xclient.data.l[1], e->xclient.data.l[3],
824 e->xclient.data.l[2]);
826 } else if (msgtype == prop_atoms.net_moveresize_window) {
827 int oldg = client->gravity;
828 int tmpg, x, y, w, h;
830 if (e->xclient.data.l[0] & 0xff)
831 tmpg = e->xclient.data.l[0] & 0xff;
835 if (e->xclient.data.l[0] & 1 << 8)
836 x = e->xclient.data.l[1];
839 if (e->xclient.data.l[0] & 1 << 9)
840 y = e->xclient.data.l[2];
843 if (e->xclient.data.l[0] & 1 << 10)
844 w = e->xclient.data.l[3];
847 if (e->xclient.data.l[0] & 1 << 11)
848 h = e->xclient.data.l[4];
851 client->gravity = tmpg;
852 client_configure(client, Corner_TopLeft, x, y, w, h, TRUE, TRUE);
853 client->gravity = oldg;
857 /* validate cuz we query stuff off the client here */
858 if (!client_validate(client)) break;
860 /* compress changes to a single property into a single change */
861 while (XCheckTypedWindowEvent(ob_display, e->type,
862 client->window, &ce)) {
863 /* XXX: it would be nice to compress ALL changes to a property,
864 not just changes in a row without other props between. */
865 if (ce.xproperty.atom != e->xproperty.atom) {
866 XPutBackEvent(ob_display, &ce);
871 msgtype = e->xproperty.atom;
872 if (msgtype == XA_WM_NORMAL_HINTS) {
873 client_update_normal_hints(client);
874 /* normal hints can make a window non-resizable */
875 client_setup_decor_and_functions(client);
877 else if (msgtype == XA_WM_HINTS)
878 client_update_wmhints(client);
879 else if (msgtype == XA_WM_TRANSIENT_FOR) {
880 client_update_transient_for(client);
881 client_get_type(client);
882 /* type may have changed, so update the layer */
883 client_calc_layer(client);
884 client_setup_decor_and_functions(client);
886 else if (msgtype == prop_atoms.net_wm_name ||
887 msgtype == prop_atoms.wm_name ||
888 msgtype == prop_atoms.net_wm_icon_name ||
889 msgtype == prop_atoms.wm_icon_name)
890 client_update_title(client);
891 else if (msgtype == prop_atoms.wm_class)
892 client_update_class(client);
893 else if (msgtype == prop_atoms.wm_protocols) {
894 client_update_protocols(client);
895 client_setup_decor_and_functions(client);
897 else if (msgtype == prop_atoms.net_wm_strut)
898 client_update_strut(client);
899 else if (msgtype == prop_atoms.net_wm_icon ||
900 msgtype == prop_atoms.kwm_win_icon)
901 client_update_icons(client);
905 if (extensions_shape && e->type == extensions_shape_event_basep) {
906 client->shaped = ((XShapeEvent*)e)->shaped;
907 frame_adjust_shape(client->frame);
913 static void event_handle_menu(Menu *menu, Client *client, XEvent *e)
917 g_message("EVENT %d", e->type);
920 g_message("BUTTON PRESS");
921 if (e->xbutton.button == 3)
923 else if (e->xbutton.button == 1) {
924 entry = menu_find_entry(menu, e->xbutton.window);
926 stacking_raise(MENU_AS_WINDOW(menu));
930 g_message("BUTTON RELEASED");
931 if (!menu->shown) break;
933 /* grab_pointer_window(FALSE, None, menu->frame);*/
935 if (e->xbutton.button == 1) {
936 entry = menu_find_entry(menu, e->xbutton.window);
940 guint ujunk, b, w, h;
941 XGetGeometry(ob_display, e->xbutton.window,
942 &wjunk, &junk, &junk, &w, &h, &b, &ujunk);
943 if (e->xbutton.x >= (signed)-b &&
944 e->xbutton.y >= (signed)-b &&
945 e->xbutton.x < (signed)(w+b) &&
946 e->xbutton.y < (signed)(h+b)) {
947 menu_entry_fire(entry);
955 g_message("enter/leave");
956 entry = menu_find_entry(menu, e->xcrossing.window);
959 menu->mouseover(entry, e->type == EnterNotify);
961 menu_control_mouseover(entry, e->type == EnterNotify);
963 menu_entry_render(entry);
969 void event_add_fd_handler(event_fd_handler *h) {
970 g_datalist_id_set_data(&fd_handler_list, h->fd, h);
971 FD_SET(h->fd, &allset);
972 max_fd = MAX(max_fd, h->fd);
975 void find_max_fd_foreach(GQuark n, gpointer data, gpointer max)
977 *((unsigned int *)max) = MAX(*((unsigned int *)max), n);
980 void event_remove_fd(int n)
984 g_datalist_id_remove_data(&fd_handler_list, (GQuark)n);
985 g_datalist_foreach(&fd_handler_list, find_max_fd_foreach, (gpointer)&tmpmax);
986 max_fd = MAX(x_fd, tmpmax);
989 void fd_event_handle_foreach(GQuark n, gpointer data, gpointer user_data)
991 if (FD_ISSET( (int)n, &selset)) {
992 event_fd_handler *h = (event_fd_handler *)data;
993 g_assert(h->fd == (int)n);
994 h->handler(h->fd, h->data);
998 void fd_event_handle()
1000 g_datalist_foreach(&fd_handler_list, fd_event_handle_foreach, NULL);
1003 static void event_handle_dock(Dock *s, XEvent *e)
1007 stacking_raise(DOCK_AS_WINDOW(s));
1018 static void event_handle_dockapp(DockApp *app, XEvent *e)
1022 dock_app_drag(app, &e->xmotion);
1025 if (app->ignore_unmaps) {
1026 app->ignore_unmaps--;
1029 dock_remove(app, TRUE);
1032 dock_remove(app, FALSE);
1034 case ReparentNotify:
1035 dock_remove(app, FALSE);
1037 case ConfigureNotify:
1038 dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);