11 #include "menuframe.h"
14 #include "framerender.h"
16 #include "moveresize.h"
18 #include "extensions.h"
23 #include <X11/keysym.h>
24 #include <X11/Xatom.h>
28 # include <libsn/sn.h>
31 #ifdef HAVE_SYS_SELECT_H
32 # include <sys/select.h>
39 #include <X11/ICE/ICElib.h>
42 static void event_process(XEvent *e);
43 static void event_handle_root(XEvent *e);
44 static void event_handle_menu(XEvent *e);
45 static void event_handle_dock(ObDock *s, XEvent *e);
46 static void event_handle_dockapp(ObDockApp *app, XEvent *e);
47 static void event_handle_client(ObClient *c, XEvent *e);
48 static void fd_event_handle();
50 static void ice_watch(IceConn conn, IcePointer data, Bool opening,
51 IcePointer *watch_data);
53 static void find_max_fd();
55 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
56 (e)->xfocus.detail == NotifyAncestor || \
57 (e)->xfocus.detail > NotifyNonlinearVirtual)
58 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
59 (e)->xfocus.detail == NotifyInferior || \
60 (e)->xfocus.detail == NotifyAncestor || \
61 (e)->xfocus.detail > NotifyNonlinearVirtual)
63 Time event_lasttime = 0;
65 /*! The value of the mask for the NumLock modifier */
66 unsigned int NumLockMask;
67 /*! The value of the mask for the ScrollLock modifier */
68 unsigned int ScrollLockMask;
69 /*! The key codes for the modifier keys */
70 static XModifierKeymap *modmap;
71 /*! Table of the constant modifier masks */
72 static const int mask_table[] = {
73 ShiftMask, LockMask, ControlMask, Mod1Mask,
74 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
76 static int mask_table_size;
78 static fd_set selset, allset;
80 static IceConn ice_conn;
83 static int max_fd, x_fd;
84 static GData *fd_handler_list;
88 static void ice_watch(IceConn conn, IcePointer data, Bool opening,
89 IcePointer *watch_data)
92 g_assert (ice_fd < 0);
94 ice_fd = IceConnectionNumber(conn);
95 FD_SET(ice_fd, &allset);
97 FD_CLR(ice_fd, &allset);
106 mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]);
108 /* get lock masks that are defined by the display (not constant) */
109 modmap = XGetModifierMapping(ob_display);
111 if (modmap && modmap->max_keypermod > 0) {
113 const size_t size = mask_table_size * modmap->max_keypermod;
114 /* get the values of the keyboard lock modifiers
115 Note: Caps lock is not retrieved the same way as Scroll and Num
116 lock since it doesn't need to be. */
117 const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock);
118 const KeyCode scroll_lock = XKeysymToKeycode(ob_display,
121 for (cnt = 0; cnt < size; ++cnt) {
122 if (! modmap->modifiermap[cnt]) continue;
124 if (num_lock == modmap->modifiermap[cnt])
125 NumLockMask = mask_table[cnt / modmap->max_keypermod];
126 if (scroll_lock == modmap->modifiermap[cnt])
127 ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
132 max_fd = x_fd = ConnectionNumber(ob_display);
133 FD_SET(x_fd, &allset);
137 IceAddConnectionWatch(ice_watch, NULL);
140 g_datalist_init(&fd_handler_list);
143 void event_shutdown()
145 XFreeModifiermap(modmap);
146 g_datalist_clear(&fd_handler_list);
152 struct timeval *wait;
153 gboolean had_event = FALSE;
155 while (XPending(ob_display)) {
156 XNextEvent(ob_display, &e);
159 sn_display_process_event(ob_sn_display, &e);
167 timer_dispatch((GTimeVal**)&wait);
169 select(max_fd + 1, &selset, NULL, NULL, wait);
171 /* handle the X events as soon as possible? */
172 if (FD_ISSET(x_fd, &selset))
176 if (ice_fd >= 0 && FD_ISSET(ice_fd, &selset)) {
178 IceProcessMessages(ice_conn, NULL, &b);
186 static Window event_get_window(XEvent *e)
193 window = RootWindow(ob_display, ob_screen);
196 window = e->xmap.window;
199 window = e->xunmap.window;
202 window = e->xdestroywindow.window;
204 case ConfigureRequest:
205 window = e->xconfigurerequest.window;
207 case ConfigureNotify:
208 window = e->xconfigure.window;
212 if (extensions_xkb && e->type == extensions_xkb_event_basep) {
213 switch (((XkbAnyEvent*)e)->xkb_type) {
215 window = ((XkbBellNotifyEvent*)e)->window;
221 window = e->xany.window;
226 static void event_set_lasttime(XEvent *e)
230 /* grab the lasttime and hack up the state */
246 t = e->xproperty.time;
250 t = e->xcrossing.time;
253 /* if more event types are anticipated, get their timestamp
258 if (t > event_lasttime)
262 #define STRIP_MODS(s) \
263 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
264 /* kill off the Button1Mask etc, only want the modifiers */ \
265 s &= (ControlMask | ShiftMask | Mod1Mask | \
266 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
268 static void event_hack_mods(XEvent *e)
276 STRIP_MODS(e->xbutton.state);
279 STRIP_MODS(e->xkey.state);
282 STRIP_MODS(e->xkey.state);
283 /* remove from the state the mask of the modifier being released, if
284 it is a modifier key being released (this is a little ugly..) */
285 kp = modmap->modifiermap;
286 for (i = 0; i < mask_table_size; ++i) {
287 for (k = 0; k < modmap->max_keypermod; ++k) {
288 if (*kp == e->xkey.keycode) { /* found the keycode */
289 /* remove the mask for it */
290 e->xkey.state &= ~mask_table[i];
291 /* cause the first loop to break; */
293 break; /* get outta here! */
300 STRIP_MODS(e->xmotion.state);
302 /* compress events */
305 while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
307 e->xmotion.x_root = ce.xmotion.x_root;
308 e->xmotion.y_root = ce.xmotion.y_root;
316 static gboolean event_ignore(XEvent *e, ObClient *client)
320 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
321 because of RevertToPointerRoot. If the focus ends up reverting to
322 pointer root on a workspace change, then the FocusIn event that we
323 want will be of type NotifyAncestor. This situation does not occur
324 for FocusOut, so it is safely ignored there.
326 if (INVALID_FOCUSIN(e) ||
329 ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
330 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
332 /* says a client was not found for the event (or a valid FocusIn
335 e->xfocus.window = None;
340 ob_debug("FocusIn on %lx mode %d detail %d\n", e->xfocus.window,
341 e->xfocus.mode, e->xfocus.detail);
345 if (INVALID_FOCUSOUT(e)) {
347 ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n",
348 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
354 ob_debug("FocusOut on %lx mode %d detail %d\n",
355 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
360 gboolean fallback = TRUE;
363 if (!XCheckTypedWindowEvent(ob_display, FocusOut,
364 e->xfocus.window,&fe))
365 if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
367 if (fe.type == FocusOut) {
369 ob_debug("found pending FocusOut");
371 if (!INVALID_FOCUSOUT(&fe)) {
372 /* if there is a VALID FocusOut still coming, don't
373 fallback focus yet, we'll deal with it then */
374 XPutBackEvent(ob_display, &fe);
380 ob_debug("found pending FocusIn");
382 /* is the focused window getting a FocusOut/In back to
385 if (fe.xfocus.window == e->xfocus.window &&
386 !event_ignore(&fe, client)) {
388 if focus_client is not set, then we can't do
389 this. we need the FocusIn. This happens in the
390 case when the set_focus_client(NULL) in the
391 focus_fallback function fires and then
392 focus_fallback picks the currently focused
393 window (such as on a SendToDesktop-esque action.
397 ob_debug("focused window got an Out/In back to "
398 "itself IGNORED both");
404 ob_debug("focused window got an Out/In back to "
405 "itself but focus_client was null "
406 "IGNORED just the Out");
412 /* once all the FocusOut's have been dealt with, if there
413 is a FocusIn still left and it is valid, then use it */
415 /* secret magic way of event_process telling us that no
416 client was found for the FocusIn event. ^_^ */
417 if (fe.xfocus.window != None) {
425 ob_debug("no valid FocusIn and no FocusOut events found, "
428 focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS);
434 /* NotifyUngrab occurs when a mouse button is released and the event is
435 caused, like when lowering a window */
436 /* NotifyVirtual occurs when ungrabbing the pointer */
437 if (e->xcrossing.mode == NotifyGrab ||
438 e->xcrossing.detail == NotifyInferior ||
439 (e->xcrossing.mode == NotifyUngrab &&
440 e->xcrossing.detail == NotifyVirtual)) {
442 ob_debug("%sNotify mode %d detail %d on %lx IGNORED",
443 (e->type == EnterNotify ? "Enter" : "Leave"),
445 e->xcrossing.detail, client?client->window:0);
450 ob_debug("%sNotify mode %d detail %d on %lx",
451 (e->type == EnterNotify ? "Enter" : "Leave"),
453 e->xcrossing.detail, client?client->window:0);
460 static void event_process(XEvent *e)
463 ObClient *client = NULL;
465 ObDockApp *dockapp = NULL;
466 ObWindow *obwin = NULL;
468 window = event_get_window(e);
469 if ((obwin = g_hash_table_lookup(window_map, &window))) {
470 switch (obwin->type) {
472 dock = WINDOW_AS_DOCK(obwin);
475 dockapp = WINDOW_AS_DOCKAPP(obwin);
478 client = WINDOW_AS_CLIENT(obwin);
481 case Window_Internal:
482 /* not to be used for events */
483 g_assert_not_reached();
488 event_set_lasttime(e);
490 if (event_ignore(e, client))
493 /* deal with it in the kernel */
495 event_handle_client(client, e);
497 event_handle_dockapp(dockapp, e);
499 event_handle_dock(dock, e);
500 else if (window == RootWindow(ob_display, ob_screen))
501 event_handle_root(e);
502 else if (e->type == MapRequest)
503 client_manage(window);
504 else if (e->type == ConfigureRequest) {
505 /* unhandled configure requests must be used to configure the
509 xwc.x = e->xconfigurerequest.x;
510 xwc.y = e->xconfigurerequest.y;
511 xwc.width = e->xconfigurerequest.width;
512 xwc.height = e->xconfigurerequest.height;
513 xwc.border_width = e->xconfigurerequest.border_width;
514 xwc.sibling = e->xconfigurerequest.above;
515 xwc.stack_mode = e->xconfigurerequest.detail;
517 /* we are not to be held responsible if someone sends us an
519 xerror_set_ignore(TRUE);
520 XConfigureWindow(ob_display, window,
521 e->xconfigurerequest.value_mask, &xwc);
522 xerror_set_ignore(FALSE);
525 /* user input (action-bound) events */
526 if (e->type == ButtonPress || e->type == ButtonRelease ||
527 e->type == MotionNotify || e->type == KeyPress ||
528 e->type == KeyRelease)
530 if (menu_frame_visible)
531 event_handle_menu(e);
532 else if (moveresize_in_progress)
535 ObFrameContext context;
537 context = frame_context(client, e->xany.window);
539 if (!keyboard_process_interactive_grab(e, &client, &context)) {
540 if (e->type == ButtonPress || e->type == ButtonRelease ||
541 e->type == MotionNotify)
542 mouse_event(client, context, e);
543 else if (e->type == KeyPress)
544 keyboard_event(client, e);
550 static void event_handle_root(XEvent *e)
556 ob_debug("Another WM has requested to replace us. Exiting.\n");
561 if (e->xclient.format != 32) break;
563 msgtype = e->xclient.message_type;
564 if (msgtype == prop_atoms.net_current_desktop) {
565 unsigned int d = e->xclient.data.l[0];
566 if (d < screen_num_desktops)
567 screen_set_desktop(d);
568 } else if (msgtype == prop_atoms.net_number_of_desktops) {
569 unsigned int d = e->xclient.data.l[0];
571 screen_set_num_desktops(d);
572 } else if (msgtype == prop_atoms.net_showing_desktop) {
573 screen_show_desktop(e->xclient.data.l[0] != 0);
577 if (e->xproperty.atom == prop_atoms.net_desktop_names)
578 screen_update_desktop_names();
579 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
580 screen_update_layout();
582 case ConfigureNotify:
584 XRRUpdateConfiguration(e);
591 if (extensions_vidmode && e->type == extensions_vidmode_event_basep) {
592 ob_debug("VIDMODE EVENT\n");
598 static void event_handle_client(ObClient *client, XEvent *e)
606 case VisibilityNotify:
607 client->frame->obscured = e->xvisibility.state != VisibilityUnobscured;
611 /* Wheel buttons don't draw because they are an instant click, so it
612 is a waste of resources to go drawing it. */
613 if (!(e->xbutton.button == 4 || e->xbutton.button == 5)) {
614 switch (frame_context(client, e->xbutton.window)) {
615 case OB_FRAME_CONTEXT_MAXIMIZE:
616 client->frame->max_press = (e->type == ButtonPress);
617 framerender_frame(client->frame);
619 case OB_FRAME_CONTEXT_CLOSE:
620 client->frame->close_press = (e->type == ButtonPress);
621 framerender_frame(client->frame);
623 case OB_FRAME_CONTEXT_ICONIFY:
624 client->frame->iconify_press = (e->type == ButtonPress);
625 framerender_frame(client->frame);
627 case OB_FRAME_CONTEXT_ALLDESKTOPS:
628 client->frame->desk_press = (e->type == ButtonPress);
629 framerender_frame(client->frame);
631 case OB_FRAME_CONTEXT_SHADE:
632 client->frame->shade_press = (e->type == ButtonPress);
633 framerender_frame(client->frame);
636 /* nothing changes with clicks for any other contexts */
643 ob_debug("FocusIn on client for %lx\n", client->window);
645 if (client != focus_client) {
646 focus_set_client(client);
647 frame_adjust_focus(client->frame, TRUE);
652 ob_debug("FocusOut on client for %lx\n", client->window);
654 /* are we a fullscreen window or a transient of one? (checks layer)
655 if we are then we need to be iconified since we are losing focus
657 if (client->layer == OB_STACKING_LAYER_FULLSCREEN && !client->iconic &&
658 !client_search_focus_tree_full(client))
659 /* iconify fullscreen windows when they and their transients
661 client_iconify(client, TRUE, TRUE);
662 frame_adjust_focus(client->frame, FALSE);
665 con = frame_context(client, e->xcrossing.window);
667 case OB_FRAME_CONTEXT_MAXIMIZE:
668 client->frame->max_hover = FALSE;
669 frame_adjust_state(client->frame);
671 case OB_FRAME_CONTEXT_ALLDESKTOPS:
672 client->frame->desk_hover = FALSE;
673 frame_adjust_state(client->frame);
675 case OB_FRAME_CONTEXT_SHADE:
676 client->frame->shade_hover = FALSE;
677 frame_adjust_state(client->frame);
679 case OB_FRAME_CONTEXT_ICONIFY:
680 client->frame->iconify_hover = FALSE;
681 frame_adjust_state(client->frame);
683 case OB_FRAME_CONTEXT_CLOSE:
684 client->frame->close_hover = FALSE;
685 frame_adjust_state(client->frame);
692 con = frame_context(client, e->xcrossing.window);
694 case OB_FRAME_CONTEXT_MAXIMIZE:
695 client->frame->max_hover = TRUE;
696 frame_adjust_state(client->frame);
698 case OB_FRAME_CONTEXT_ALLDESKTOPS:
699 client->frame->desk_hover = TRUE;
700 frame_adjust_state(client->frame);
702 case OB_FRAME_CONTEXT_SHADE:
703 client->frame->shade_hover = TRUE;
704 frame_adjust_state(client->frame);
706 case OB_FRAME_CONTEXT_ICONIFY:
707 client->frame->iconify_hover = TRUE;
708 frame_adjust_state(client->frame);
710 case OB_FRAME_CONTEXT_CLOSE:
711 client->frame->close_hover = TRUE;
712 frame_adjust_state(client->frame);
714 case OB_FRAME_CONTEXT_FRAME:
715 if (client_normal(client)) {
716 if (ob_state() == OB_STATE_STARTING) {
717 /* move it to the top of the focus order */
718 guint desktop = client->desktop;
719 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
720 focus_order[desktop] = g_list_remove(focus_order[desktop],
722 focus_order[desktop] = g_list_prepend(focus_order[desktop],
724 } else if (config_focus_follow) {
726 ob_debug("EnterNotify on %lx, focusing window\n",
729 client_focus(client);
737 case ConfigureRequest:
739 while (XCheckTypedWindowEvent(ob_display, client->window,
740 ConfigureRequest, &ce)) {
742 /* XXX if this causes bad things.. we can compress config req's
743 with the same mask. */
744 e->xconfigurerequest.value_mask |=
745 ce.xconfigurerequest.value_mask;
746 if (ce.xconfigurerequest.value_mask & CWX)
747 e->xconfigurerequest.x = ce.xconfigurerequest.x;
748 if (ce.xconfigurerequest.value_mask & CWY)
749 e->xconfigurerequest.y = ce.xconfigurerequest.y;
750 if (ce.xconfigurerequest.value_mask & CWWidth)
751 e->xconfigurerequest.width = ce.xconfigurerequest.width;
752 if (ce.xconfigurerequest.value_mask & CWHeight)
753 e->xconfigurerequest.height = ce.xconfigurerequest.height;
754 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
755 e->xconfigurerequest.border_width =
756 ce.xconfigurerequest.border_width;
757 if (ce.xconfigurerequest.value_mask & CWStackMode)
758 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
761 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
762 if (client->iconic || client->shaded) return;
764 /* resize, then move, as specified in the EWMH section 7.7 */
765 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
771 if (e->xconfigurerequest.value_mask & CWBorderWidth)
772 client->border_width = e->xconfigurerequest.border_width;
774 x = (e->xconfigurerequest.value_mask & CWX) ?
775 e->xconfigurerequest.x : client->area.x;
776 y = (e->xconfigurerequest.value_mask & CWY) ?
777 e->xconfigurerequest.y : client->area.y;
778 w = (e->xconfigurerequest.value_mask & CWWidth) ?
779 e->xconfigurerequest.width : client->area.width;
780 h = (e->xconfigurerequest.value_mask & CWHeight) ?
781 e->xconfigurerequest.height : client->area.height;
787 client->frame->size.left + client->frame->size.right;
789 client->frame->size.top + client->frame->size.bottom;
790 client_find_onscreen(client, &newx, &newy, fw, fh,
791 client_normal(client));
792 if (e->xconfigurerequest.value_mask & CWX)
794 if (e->xconfigurerequest.value_mask & CWY)
798 switch (client->gravity) {
799 case NorthEastGravity:
801 corner = OB_CORNER_TOPRIGHT;
803 case SouthWestGravity:
805 corner = OB_CORNER_BOTTOMLEFT;
807 case SouthEastGravity:
808 corner = OB_CORNER_BOTTOMRIGHT;
810 default: /* NorthWest, Static, etc */
811 corner = OB_CORNER_TOPLEFT;
814 client_configure_full(client, corner, x, y, w, h, FALSE, TRUE,
818 if (e->xconfigurerequest.value_mask & CWStackMode) {
819 switch (e->xconfigurerequest.detail) {
822 stacking_lower(CLIENT_AS_WINDOW(client));
828 stacking_raise(CLIENT_AS_WINDOW(client));
834 if (client->ignore_unmaps) {
835 client->ignore_unmaps--;
838 client_unmanage(client);
841 client_unmanage(client);
844 /* this is when the client is first taken captive in the frame */
845 if (e->xreparent.parent == client->frame->plate) break;
848 This event is quite rare and is usually handled in unmapHandler.
849 However, if the window is unmapped when the reparent event occurs,
850 the window manager never sees it because an unmap event is not sent
851 to an already unmapped window.
854 /* we don't want the reparent event, put it back on the stack for the
855 X server to deal with after we unmanage the window */
856 XPutBackEvent(ob_display, e);
858 client_unmanage(client);
861 ob_debug("MapRequest for 0x%lx\n", client->window);
862 if (!client->iconic) break; /* this normally doesn't happen, but if it
863 does, we don't want it! */
864 if (screen_showing_desktop)
865 screen_show_desktop(FALSE);
866 client_iconify(client, FALSE, TRUE);
867 if (!client->frame->visible)
868 /* if its not visible still, then don't mess with it */
871 client_shade(client, FALSE);
872 client_focus(client);
873 stacking_raise(CLIENT_AS_WINDOW(client));
876 /* validate cuz we query stuff off the client here */
877 if (!client_validate(client)) break;
879 if (e->xclient.format != 32) return;
881 msgtype = e->xclient.message_type;
882 if (msgtype == prop_atoms.wm_change_state) {
883 /* compress changes into a single change */
884 while (XCheckTypedWindowEvent(ob_display, e->type,
885 client->window, &ce)) {
886 /* XXX: it would be nice to compress ALL messages of a
887 type, not just messages in a row without other
888 message types between. */
889 if (ce.xclient.message_type != msgtype) {
890 XPutBackEvent(ob_display, &ce);
893 e->xclient = ce.xclient;
895 client_set_wm_state(client, e->xclient.data.l[0]);
896 } else if (msgtype == prop_atoms.net_wm_desktop) {
897 /* compress changes into a single change */
898 while (XCheckTypedWindowEvent(ob_display, e->type,
899 client->window, &ce)) {
900 /* XXX: it would be nice to compress ALL messages of a
901 type, not just messages in a row without other
902 message types between. */
903 if (ce.xclient.message_type != msgtype) {
904 XPutBackEvent(ob_display, &ce);
907 e->xclient = ce.xclient;
909 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
910 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
911 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
913 } else if (msgtype == prop_atoms.net_wm_state) {
914 /* can't compress these */
915 ob_debug("net_wm_state %s %ld %ld for 0x%lx\n",
916 (e->xclient.data.l[0] == 0 ? "Remove" :
917 e->xclient.data.l[0] == 1 ? "Add" :
918 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
919 e->xclient.data.l[1], e->xclient.data.l[2],
921 client_set_state(client, e->xclient.data.l[0],
922 e->xclient.data.l[1], e->xclient.data.l[2]);
923 } else if (msgtype == prop_atoms.net_close_window) {
924 ob_debug("net_close_window for 0x%lx\n", client->window);
925 client_close(client);
926 } else if (msgtype == prop_atoms.net_active_window) {
927 ob_debug("net_active_window for 0x%lx\n", client->window);
928 client_activate(client, FALSE);
929 } else if (msgtype == prop_atoms.net_wm_moveresize) {
930 ob_debug("net_wm_moveresize for 0x%lx\n", client->window);
931 if ((Atom)e->xclient.data.l[2] ==
932 prop_atoms.net_wm_moveresize_size_topleft ||
933 (Atom)e->xclient.data.l[2] ==
934 prop_atoms.net_wm_moveresize_size_top ||
935 (Atom)e->xclient.data.l[2] ==
936 prop_atoms.net_wm_moveresize_size_topright ||
937 (Atom)e->xclient.data.l[2] ==
938 prop_atoms.net_wm_moveresize_size_right ||
939 (Atom)e->xclient.data.l[2] ==
940 prop_atoms.net_wm_moveresize_size_right ||
941 (Atom)e->xclient.data.l[2] ==
942 prop_atoms.net_wm_moveresize_size_bottomright ||
943 (Atom)e->xclient.data.l[2] ==
944 prop_atoms.net_wm_moveresize_size_bottom ||
945 (Atom)e->xclient.data.l[2] ==
946 prop_atoms.net_wm_moveresize_size_bottomleft ||
947 (Atom)e->xclient.data.l[2] ==
948 prop_atoms.net_wm_moveresize_size_left ||
949 (Atom)e->xclient.data.l[2] ==
950 prop_atoms.net_wm_moveresize_move ||
951 (Atom)e->xclient.data.l[2] ==
952 prop_atoms.net_wm_moveresize_size_keyboard ||
953 (Atom)e->xclient.data.l[2] ==
954 prop_atoms.net_wm_moveresize_move_keyboard) {
956 moveresize_start(client, e->xclient.data.l[0],
957 e->xclient.data.l[1], e->xclient.data.l[3],
958 e->xclient.data.l[2]);
960 } else if (msgtype == prop_atoms.net_moveresize_window) {
961 int oldg = client->gravity;
962 int tmpg, x, y, w, h;
964 if (e->xclient.data.l[0] & 0xff)
965 tmpg = e->xclient.data.l[0] & 0xff;
969 if (e->xclient.data.l[0] & 1 << 8)
970 x = e->xclient.data.l[1];
973 if (e->xclient.data.l[0] & 1 << 9)
974 y = e->xclient.data.l[2];
977 if (e->xclient.data.l[0] & 1 << 10)
978 w = e->xclient.data.l[3];
980 w = client->area.width;
981 if (e->xclient.data.l[0] & 1 << 11)
982 h = e->xclient.data.l[4];
984 h = client->area.height;
985 client->gravity = tmpg;
991 client->frame->size.left + client->frame->size.right;
993 client->frame->size.top + client->frame->size.bottom;
994 client_find_onscreen(client, &newx, &newy, fw, fh,
995 client_normal(client));
996 if (e->xclient.data.l[0] & 1 << 8)
998 if (e->xclient.data.l[0] & 1 << 9)
1002 client_configure(client, OB_CORNER_TOPLEFT,
1003 x, y, w, h, FALSE, TRUE);
1005 client->gravity = oldg;
1008 case PropertyNotify:
1009 /* validate cuz we query stuff off the client here */
1010 if (!client_validate(client)) break;
1012 /* compress changes to a single property into a single change */
1013 while (XCheckTypedWindowEvent(ob_display, e->type,
1014 client->window, &ce)) {
1015 /* XXX: it would be nice to compress ALL changes to a property,
1016 not just changes in a row without other props between. */
1017 if (ce.xproperty.atom != e->xproperty.atom) {
1018 XPutBackEvent(ob_display, &ce);
1023 msgtype = e->xproperty.atom;
1024 if (msgtype == XA_WM_NORMAL_HINTS) {
1025 client_update_normal_hints(client);
1026 /* normal hints can make a window non-resizable */
1027 client_setup_decor_and_functions(client);
1029 else if (msgtype == XA_WM_HINTS)
1030 client_update_wmhints(client);
1031 else if (msgtype == XA_WM_TRANSIENT_FOR) {
1032 client_update_transient_for(client);
1033 client_get_type(client);
1034 /* type may have changed, so update the layer */
1035 client_calc_layer(client);
1036 client_setup_decor_and_functions(client);
1038 else if (msgtype == prop_atoms.net_wm_name ||
1039 msgtype == prop_atoms.wm_name ||
1040 msgtype == prop_atoms.net_wm_icon_name ||
1041 msgtype == prop_atoms.wm_icon_name)
1042 client_update_title(client);
1043 else if (msgtype == prop_atoms.wm_class)
1044 client_update_class(client);
1045 else if (msgtype == prop_atoms.wm_protocols) {
1046 client_update_protocols(client);
1047 client_setup_decor_and_functions(client);
1049 else if (msgtype == prop_atoms.net_wm_strut) {
1050 client_update_strut(client);
1052 else if (msgtype == prop_atoms.net_wm_icon ||
1053 msgtype == prop_atoms.kwm_win_icon)
1054 client_update_icons(client);
1058 if (extensions_shape && e->type == extensions_shape_event_basep) {
1059 client->shaped = ((XShapeEvent*)e)->shaped;
1060 frame_adjust_shape(client->frame);
1066 void event_add_fd_handler(event_fd_handler *h) {
1067 g_datalist_id_set_data(&fd_handler_list, h->fd, h);
1068 FD_SET(h->fd, &allset);
1069 max_fd = MAX(max_fd, h->fd);
1072 static void find_max_fd_foreach(GQuark n, gpointer data, gpointer max)
1074 *((unsigned int *)max) = MAX(*((unsigned int *)max), n);
1077 static void find_max_fd()
1080 g_datalist_foreach(&fd_handler_list, find_max_fd_foreach,
1082 max_fd = MAX(x_fd, tmpmax);
1084 max_fd = MAX(ice_fd, max_fd);
1088 void event_remove_fd(gint n)
1091 g_datalist_id_remove_data(&fd_handler_list, (GQuark)n);
1095 static void fd_event_handle_foreach(GQuark n,
1096 gpointer data, gpointer user_data)
1098 if (FD_ISSET( (int)n, &selset)) {
1099 event_fd_handler *h = (event_fd_handler *)data;
1100 g_assert(h->fd == (int)n);
1101 h->handler(h->fd, h->data);
1105 static void fd_event_handle()
1107 g_datalist_foreach(&fd_handler_list, fd_event_handle_foreach, NULL);
1110 static void event_handle_dock(ObDock *s, XEvent *e)
1114 stacking_raise(DOCK_AS_WINDOW(s));
1125 static void event_handle_dockapp(ObDockApp *app, XEvent *e)
1129 dock_app_drag(app, &e->xmotion);
1132 if (app->ignore_unmaps) {
1133 app->ignore_unmaps--;
1136 dock_remove(app, TRUE);
1139 dock_remove(app, FALSE);
1141 case ReparentNotify:
1142 dock_remove(app, FALSE);
1144 case ConfigureNotify:
1145 dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);
1150 ObMenuFrame* find_active_menu()
1155 for (it = menu_frame_visible; it; it = g_list_next(it)) {
1160 return it ? it->data : NULL;
1163 static void event_handle_menu(XEvent *ev)
1166 ObMenuEntryFrame *e;
1170 if (!(f = menu_frame_under(ev->xbutton.x_root,
1171 ev->xbutton.y_root)))
1172 menu_frame_hide_all();
1174 if ((e = menu_entry_frame_under(ev->xbutton.x_root,
1175 ev->xbutton.y_root)))
1176 menu_entry_frame_execute(e,
1177 !(ev->xbutton.state & ControlMask));
1181 if ((f = menu_frame_under(ev->xmotion.x_root,
1182 ev->xmotion.y_root))) {
1183 menu_frame_move_on_screen(f);
1184 if ((e = menu_entry_frame_under(ev->xmotion.x_root,
1185 ev->xmotion.y_root)))
1186 menu_frame_select(f, e);
1190 if (ev->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
1191 menu_frame_hide_all();
1192 else if (ev->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
1194 if ((f = find_active_menu()))
1195 menu_entry_frame_execute(f->selected,
1196 !(ev->xkey.state & ControlMask));
1197 } else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) {
1199 if ((f = find_active_menu()) && f->parent)
1200 menu_frame_select(f, NULL);
1201 } else if (ev->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) {
1203 if ((f = find_active_menu()) && f->child && f->child->entries)
1204 menu_frame_select(f->child, f->child->entries->data);
1205 } else if (ev->xkey.keycode == ob_keycode(OB_KEY_UP)) {
1207 if ((f = find_active_menu()))
1208 menu_frame_select_previous(f);
1209 } else if (ev->xkey.keycode == ob_keycode(OB_KEY_DOWN)) {
1211 if ((f = find_active_menu()))
1212 menu_frame_select_next(f);