11 #include "framerender.h"
13 #include "moveresize.h"
15 #include "extensions.h"
21 #include <X11/keysym.h>
22 #include <X11/Xatom.h>
26 # include <libsn/sn.h>
29 #ifdef HAVE_SYS_SELECT_H
30 # include <sys/select.h>
37 #include <X11/ICE/ICElib.h>
40 static void event_process(XEvent *e);
41 static void event_handle_root(XEvent *e);
42 static void event_handle_dock(ObDock *s, XEvent *e);
43 static void event_handle_dockapp(ObDockApp *app, XEvent *e);
44 static void event_handle_client(ObClient *c, XEvent *e);
45 static void event_handle_menu(ObClient *c, XEvent *e);
46 static void fd_event_handle();
48 static void ice_watch(IceConn conn, IcePointer data, Bool opening,
49 IcePointer *watch_data);
51 static void find_max_fd();
53 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
54 (e)->xfocus.detail == NotifyAncestor || \
55 (e)->xfocus.detail > NotifyNonlinearVirtual)
56 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
57 (e)->xfocus.detail == NotifyInferior || \
58 (e)->xfocus.detail == NotifyAncestor || \
59 (e)->xfocus.detail > NotifyNonlinearVirtual)
61 Time event_lasttime = 0;
63 /*! The value of the mask for the NumLock modifier */
64 unsigned int NumLockMask;
65 /*! The value of the mask for the ScrollLock modifier */
66 unsigned int ScrollLockMask;
67 /*! The key codes for the modifier keys */
68 static XModifierKeymap *modmap;
69 /*! Table of the constant modifier masks */
70 static const int mask_table[] = {
71 ShiftMask, LockMask, ControlMask, Mod1Mask,
72 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
74 static int mask_table_size;
76 static fd_set selset, allset;
78 static IceConn ice_conn;
81 static int max_fd, x_fd;
82 static GData *fd_handler_list;
86 static void ice_watch(IceConn conn, IcePointer data, Bool opening,
87 IcePointer *watch_data)
90 g_assert (ice_fd < 0);
92 ice_fd = IceConnectionNumber(conn);
93 FD_SET(ice_fd, &allset);
95 FD_CLR(ice_fd, &allset);
104 mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]);
106 /* get lock masks that are defined by the display (not constant) */
107 modmap = XGetModifierMapping(ob_display);
109 if (modmap && modmap->max_keypermod > 0) {
111 const size_t size = mask_table_size * modmap->max_keypermod;
112 /* get the values of the keyboard lock modifiers
113 Note: Caps lock is not retrieved the same way as Scroll and Num
114 lock since it doesn't need to be. */
115 const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock);
116 const KeyCode scroll_lock = XKeysymToKeycode(ob_display,
119 for (cnt = 0; cnt < size; ++cnt) {
120 if (! modmap->modifiermap[cnt]) continue;
122 if (num_lock == modmap->modifiermap[cnt])
123 NumLockMask = mask_table[cnt / modmap->max_keypermod];
124 if (scroll_lock == modmap->modifiermap[cnt])
125 ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
130 max_fd = x_fd = ConnectionNumber(ob_display);
131 FD_SET(x_fd, &allset);
135 IceAddConnectionWatch(ice_watch, NULL);
138 g_datalist_init(&fd_handler_list);
141 void event_shutdown()
143 XFreeModifiermap(modmap);
144 g_datalist_clear(&fd_handler_list);
150 struct timeval *wait;
151 gboolean had_event = FALSE;
153 while (XPending(ob_display)) {
154 XNextEvent(ob_display, &e);
157 sn_display_process_event(ob_sn_display, &e);
165 timer_dispatch((GTimeVal**)&wait);
167 select(max_fd + 1, &selset, NULL, NULL, wait);
169 /* handle the X events as soon as possible? */
170 if (FD_ISSET(x_fd, &selset))
174 if (ice_fd >= 0 && FD_ISSET(ice_fd, &selset)) {
176 IceProcessMessages(ice_conn, NULL, &b);
184 static Window event_get_window(XEvent *e)
191 window = RootWindow(ob_display, ob_screen);
194 window = e->xmap.window;
197 window = e->xunmap.window;
200 window = e->xdestroywindow.window;
202 case ConfigureRequest:
203 window = e->xconfigurerequest.window;
205 case ConfigureNotify:
206 window = e->xconfigure.window;
210 if (extensions_xkb && e->type == extensions_xkb_event_basep) {
211 switch (((XkbAnyEvent*)&e)->xkb_type) {
213 window = ((XkbBellNotifyEvent*)&e)->window;
219 window = e->xany.window;
224 static void event_set_lasttime(XEvent *e)
228 /* grab the lasttime and hack up the state */
244 t = e->xproperty.time;
248 t = e->xcrossing.time;
251 /* if more event types are anticipated, get their timestamp
256 if (t > event_lasttime)
260 #define STRIP_MODS(s) \
261 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
262 /* kill off the Button1Mask etc, only want the modifiers */ \
263 s &= (ControlMask | ShiftMask | Mod1Mask | \
264 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
266 static void event_hack_mods(XEvent *e)
274 STRIP_MODS(e->xbutton.state);
277 STRIP_MODS(e->xkey.state);
280 STRIP_MODS(e->xkey.state);
281 /* remove from the state the mask of the modifier being released, if
282 it is a modifier key being released (this is a little ugly..) */
283 kp = modmap->modifiermap;
284 for (i = 0; i < mask_table_size; ++i) {
285 for (k = 0; k < modmap->max_keypermod; ++k) {
286 if (*kp == e->xkey.keycode) { /* found the keycode */
287 /* remove the mask for it */
288 e->xkey.state &= ~mask_table[i];
289 /* cause the first loop to break; */
291 break; /* get outta here! */
298 STRIP_MODS(e->xmotion.state);
299 /* compress events */
302 while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
304 e->xmotion.x_root = ce.xmotion.x_root;
305 e->xmotion.y_root = ce.xmotion.y_root;
312 static gboolean event_ignore(XEvent *e, ObClient *client)
316 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
317 because of RevertToPointerRoot. If the focus ends up reverting to
318 pointer root on a workspace change, then the FocusIn event that we
319 want will be of type NotifyAncestor. This situation does not occur
320 for FocusOut, so it is safely ignored there.
322 if (INVALID_FOCUSIN(e) ||
325 ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
326 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
328 /* says a client was not found for the event (or a valid FocusIn
331 e->xfocus.window = None;
336 ob_debug("FocusIn on %lx mode %d detail %d\n", e->xfocus.window,
337 e->xfocus.mode, e->xfocus.detail);
341 if (INVALID_FOCUSOUT(e)) {
343 ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n",
344 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
350 ob_debug("FocusOut on %lx mode %d detail %d\n",
351 e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
356 gboolean fallback = TRUE;
359 if (!XCheckTypedWindowEvent(ob_display, FocusOut,
360 e->xfocus.window,&fe))
361 if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
363 if (fe.type == FocusOut) {
365 ob_debug("found pending FocusOut");
367 if (!INVALID_FOCUSOUT(&fe)) {
368 /* if there is a VALID FocusOut still coming, don't
369 fallback focus yet, we'll deal with it then */
370 XPutBackEvent(ob_display, &fe);
376 ob_debug("found pending FocusIn");
378 /* is the focused window getting a FocusOut/In back to
381 if (fe.xfocus.window == e->xfocus.window &&
382 !event_ignore(&fe, client)) {
384 if focus_client is not set, then we can't do
385 this. we need the FocusIn. This happens in the
386 case when the set_focus_client(NULL) in the
387 focus_fallback function fires and then
388 focus_fallback picks the currently focused
389 window (such as on a SendToDesktop-esque action.
393 ob_debug("focused window got an Out/In back to "
394 "itself IGNORED both");
400 ob_debug("focused window got an Out/In back to "
401 "itself but focus_client was null "
402 "IGNORED just the Out");
408 /* once all the FocusOut's have been dealt with, if there
409 is a FocusIn still left and it is valid, then use it */
411 /* secret magic way of event_process telling us that no
412 client was found for the FocusIn event. ^_^ */
413 if (fe.xfocus.window != None) {
421 ob_debug("no valid FocusIn and no FocusOut events found, "
424 focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS);
430 /* NotifyUngrab occurs when a mouse button is released and the event is
431 caused, like when lowering a window */
432 /* NotifyVirtual occurs when ungrabbing the pointer */
433 if (e->xcrossing.mode == NotifyGrab ||
434 e->xcrossing.detail == NotifyInferior ||
435 (e->xcrossing.mode == NotifyUngrab &&
436 e->xcrossing.detail == NotifyVirtual)) {
438 ob_debug("%sNotify mode %d detail %d on %lx IGNORED",
439 (e->type == EnterNotify ? "Enter" : "Leave"),
441 e->xcrossing.detail, client?client->window:0);
446 ob_debug("%sNotify mode %d detail %d on %lx",
447 (e->type == EnterNotify ? "Enter" : "Leave"),
449 e->xcrossing.detail, client?client->window:0);
456 static void event_process(XEvent *e)
459 ObClient *client = NULL;
461 ObDockApp *dockapp = NULL;
463 ObWindow *obwin = NULL;
465 window = event_get_window(e);
466 if ((obwin = g_hash_table_lookup(window_map, &window))) {
467 switch (obwin->type) {
469 dock = WINDOW_AS_DOCK(obwin);
472 dockapp = WINDOW_AS_DOCKAPP(obwin);
475 menu = WINDOW_AS_MENU(obwin);
478 client = WINDOW_AS_CLIENT(obwin);
480 case Window_Internal:
481 /* not to be used for events */
482 g_assert_not_reached();
487 event_set_lasttime(e);
489 if (event_ignore(e, client))
492 /* deal with it in the kernel */
494 event_handle_client(client, e);
496 event_handle_dockapp(dockapp, e);
498 event_handle_dock(dock, e);
499 else if (window == RootWindow(ob_display, ob_screen))
500 event_handle_root(e);
501 else if (e->type == MapRequest)
502 client_manage(window);
503 else if (e->type == ConfigureRequest) {
504 /* unhandled configure requests must be used to configure the
508 xwc.x = e->xconfigurerequest.x;
509 xwc.y = e->xconfigurerequest.y;
510 xwc.width = e->xconfigurerequest.width;
511 xwc.height = e->xconfigurerequest.height;
512 xwc.border_width = e->xconfigurerequest.border_width;
513 xwc.sibling = e->xconfigurerequest.above;
514 xwc.stack_mode = e->xconfigurerequest.detail;
516 /* we are not to be held responsible if someone sends us an
518 xerror_set_ignore(TRUE);
519 XConfigureWindow(ob_display, window,
520 e->xconfigurerequest.value_mask, &xwc);
521 xerror_set_ignore(FALSE);
525 if (e->type == MotionNotify || e->type == ButtonRelease ||
526 e->type == ButtonPress ||
527 e->type == KeyPress || e->type == KeyRelease) {
528 event_handle_menu(client, e);
530 return; /* no dispatch! */
533 if (moveresize_in_progress)
534 if (e->type == MotionNotify || e->type == ButtonRelease ||
535 e->type == ButtonPress ||
536 e->type == KeyPress || e->type == KeyRelease) {
539 return; /* no dispatch! */
543 /* user input (action-bound) events */
545 if (e->type == ButtonPress || e->type == ButtonRelease ||
546 e->type == MotionNotify)
547 mouse_event(e, client);
548 else if (e->type == KeyPress || e->type == KeyRelease)
552 /* dispatch the event to registered handlers */
553 dispatch_x(e, client);
556 static void event_handle_root(XEvent *e)
562 ob_debug("Another WM has requested to replace us. Exiting.\n");
567 if (e->xclient.format != 32) break;
569 msgtype = e->xclient.message_type;
570 if (msgtype == prop_atoms.net_current_desktop) {
571 unsigned int d = e->xclient.data.l[0];
572 if (d < screen_num_desktops)
573 screen_set_desktop(d);
574 } else if (msgtype == prop_atoms.net_number_of_desktops) {
575 unsigned int d = e->xclient.data.l[0];
577 screen_set_num_desktops(d);
578 } else if (msgtype == prop_atoms.net_showing_desktop) {
579 screen_show_desktop(e->xclient.data.l[0] != 0);
583 if (e->xproperty.atom == prop_atoms.net_desktop_names)
584 screen_update_desktop_names();
585 else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
586 screen_update_layout();
588 case ConfigureNotify:
590 XRRUpdateConfiguration(e);
597 if (extensions_vidmode && e->type == extensions_vidmode_event_basep) {
598 ob_debug("VIDMODE EVENT\n");
604 static void event_handle_client(ObClient *client, XEvent *e)
614 /* Wheel buttons don't draw because they are an instant click, so it
615 is a waste of resources to go drawing it. */
616 if (!(e->xbutton.button == 4 || e->xbutton.button == 5)) {
617 switch (frame_context(client, e->xbutton.window)) {
618 case OB_FRAME_CONTEXT_MAXIMIZE:
619 client->frame->max_press = (e->type == ButtonPress);
620 framerender_frame(client->frame);
622 case OB_FRAME_CONTEXT_CLOSE:
623 client->frame->close_press = (e->type == ButtonPress);
624 framerender_frame(client->frame);
626 case OB_FRAME_CONTEXT_ICONIFY:
627 client->frame->iconify_press = (e->type == ButtonPress);
628 framerender_frame(client->frame);
630 case OB_FRAME_CONTEXT_ALLDESKTOPS:
631 client->frame->desk_press = (e->type == ButtonPress);
632 framerender_frame(client->frame);
634 case OB_FRAME_CONTEXT_SHADE:
635 client->frame->shade_press = (e->type == ButtonPress);
636 framerender_frame(client->frame);
639 /* nothing changes with clicks for any other contexts */
646 ob_debug("FocusIn on client for %lx\n", client->window);
648 if (client != focus_client) {
649 focus_set_client(client);
650 frame_adjust_focus(client->frame, TRUE);
655 ob_debug("FocusOut on client for %lx\n", client->window);
657 /* are we a fullscreen window or a transient of one? (checks layer)
658 if we are then we need to be iconified since we are losing focus
660 if (client->layer == OB_STACKING_LAYER_FULLSCREEN && !client->iconic &&
661 !client_search_focus_tree_full(client))
662 /* iconify fullscreen windows when they and their transients
664 client_iconify(client, TRUE, TRUE);
665 frame_adjust_focus(client->frame, FALSE);
668 con = frame_context(client, e->xcrossing.window);
670 case OB_FRAME_CONTEXT_MAXIMIZE:
671 client->frame->max_hover = FALSE;
672 frame_adjust_state(client->frame);
674 case OB_FRAME_CONTEXT_ALLDESKTOPS:
675 client->frame->desk_hover = FALSE;
676 frame_adjust_state(client->frame);
678 case OB_FRAME_CONTEXT_SHADE:
679 client->frame->shade_hover = FALSE;
680 frame_adjust_state(client->frame);
682 case OB_FRAME_CONTEXT_ICONIFY:
683 client->frame->iconify_hover = FALSE;
684 frame_adjust_state(client->frame);
686 case OB_FRAME_CONTEXT_CLOSE:
687 client->frame->close_hover = FALSE;
688 frame_adjust_state(client->frame);
695 con = frame_context(client, e->xcrossing.window);
697 case OB_FRAME_CONTEXT_MAXIMIZE:
698 client->frame->max_hover = TRUE;
699 frame_adjust_state(client->frame);
701 case OB_FRAME_CONTEXT_ALLDESKTOPS:
702 client->frame->desk_hover = TRUE;
703 frame_adjust_state(client->frame);
705 case OB_FRAME_CONTEXT_SHADE:
706 client->frame->shade_hover = TRUE;
707 frame_adjust_state(client->frame);
709 case OB_FRAME_CONTEXT_ICONIFY:
710 client->frame->iconify_hover = TRUE;
711 frame_adjust_state(client->frame);
713 case OB_FRAME_CONTEXT_CLOSE:
714 client->frame->close_hover = TRUE;
715 frame_adjust_state(client->frame);
717 case OB_FRAME_CONTEXT_FRAME:
718 if (client_normal(client)) {
719 if (ob_state() == OB_STATE_STARTING) {
720 /* move it to the top of the focus order */
721 guint desktop = client->desktop;
722 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
723 focus_order[desktop] = g_list_remove(focus_order[desktop],
725 focus_order[desktop] = g_list_prepend(focus_order[desktop],
727 } else if (config_focus_follow) {
729 ob_debug("EnterNotify on %lx, focusing window\n",
732 client_focus(client);
740 case ConfigureRequest:
742 while (XCheckTypedWindowEvent(ob_display, client->window,
743 ConfigureRequest, &ce)) {
745 /* XXX if this causes bad things.. we can compress config req's
746 with the same mask. */
747 e->xconfigurerequest.value_mask |=
748 ce.xconfigurerequest.value_mask;
749 if (ce.xconfigurerequest.value_mask & CWX)
750 e->xconfigurerequest.x = ce.xconfigurerequest.x;
751 if (ce.xconfigurerequest.value_mask & CWY)
752 e->xconfigurerequest.y = ce.xconfigurerequest.y;
753 if (ce.xconfigurerequest.value_mask & CWWidth)
754 e->xconfigurerequest.width = ce.xconfigurerequest.width;
755 if (ce.xconfigurerequest.value_mask & CWHeight)
756 e->xconfigurerequest.height = ce.xconfigurerequest.height;
757 if (ce.xconfigurerequest.value_mask & CWBorderWidth)
758 e->xconfigurerequest.border_width =
759 ce.xconfigurerequest.border_width;
760 if (ce.xconfigurerequest.value_mask & CWStackMode)
761 e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
764 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
765 if (client->iconic || client->shaded) return;
767 /* resize, then move, as specified in the EWMH section 7.7 */
768 if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
774 if (e->xconfigurerequest.value_mask & CWBorderWidth)
775 client->border_width = e->xconfigurerequest.border_width;
777 x = (e->xconfigurerequest.value_mask & CWX) ?
778 e->xconfigurerequest.x : client->area.x;
779 y = (e->xconfigurerequest.value_mask & CWY) ?
780 e->xconfigurerequest.y : client->area.y;
781 w = (e->xconfigurerequest.value_mask & CWWidth) ?
782 e->xconfigurerequest.width : client->area.width;
783 h = (e->xconfigurerequest.value_mask & CWHeight) ?
784 e->xconfigurerequest.height : client->area.height;
790 client->frame->size.left + client->frame->size.right;
792 client->frame->size.top + client->frame->size.bottom;
793 client_find_onscreen(client, &newx, &newy, fw, fh, TRUE);
794 if (e->xconfigurerequest.value_mask & CWX)
796 if (e->xconfigurerequest.value_mask & CWY)
800 switch (client->gravity) {
801 case NorthEastGravity:
803 corner = OB_CORNER_TOPRIGHT;
805 case SouthWestGravity:
807 corner = OB_CORNER_BOTTOMLEFT;
809 case SouthEastGravity:
810 corner = OB_CORNER_BOTTOMRIGHT;
812 default: /* NorthWest, Static, etc */
813 corner = OB_CORNER_TOPLEFT;
816 client_configure_full(client, corner, x, y, w, h, FALSE, TRUE,
820 if (e->xconfigurerequest.value_mask & CWStackMode) {
821 switch (e->xconfigurerequest.detail) {
824 stacking_lower(CLIENT_AS_WINDOW(client));
830 stacking_raise(CLIENT_AS_WINDOW(client));
836 if (client->ignore_unmaps) {
837 client->ignore_unmaps--;
840 client_unmanage(client);
843 client_unmanage(client);
846 /* this is when the client is first taken captive in the frame */
847 if (e->xreparent.parent == client->frame->plate) break;
850 This event is quite rare and is usually handled in unmapHandler.
851 However, if the window is unmapped when the reparent event occurs,
852 the window manager never sees it because an unmap event is not sent
853 to an already unmapped window.
856 /* we don't want the reparent event, put it back on the stack for the
857 X server to deal with after we unmanage the window */
858 XPutBackEvent(ob_display, e);
860 client_unmanage(client);
863 ob_debug("MapRequest for 0x%lx\n", client->window);
864 if (!client->iconic) break; /* this normally doesn't happen, but if it
865 does, we don't want it! */
866 if (screen_showing_desktop)
867 screen_show_desktop(FALSE);
868 client_iconify(client, FALSE, TRUE);
869 if (!client->frame->visible)
870 /* if its not visible still, then don't mess with it */
873 client_shade(client, FALSE);
874 client_focus(client);
875 stacking_raise(CLIENT_AS_WINDOW(client));
878 /* validate cuz we query stuff off the client here */
879 if (!client_validate(client)) break;
881 if (e->xclient.format != 32) return;
883 msgtype = e->xclient.message_type;
884 if (msgtype == prop_atoms.wm_change_state) {
885 /* compress changes into a single change */
886 while (XCheckTypedWindowEvent(ob_display, e->type,
887 client->window, &ce)) {
888 /* XXX: it would be nice to compress ALL messages of a
889 type, not just messages in a row without other
890 message types between. */
891 if (ce.xclient.message_type != msgtype) {
892 XPutBackEvent(ob_display, &ce);
895 e->xclient = ce.xclient;
897 client_set_wm_state(client, e->xclient.data.l[0]);
898 } else if (msgtype == prop_atoms.net_wm_desktop) {
899 /* compress changes into a single change */
900 while (XCheckTypedWindowEvent(ob_display, e->type,
901 client->window, &ce)) {
902 /* XXX: it would be nice to compress ALL messages of a
903 type, not just messages in a row without other
904 message types between. */
905 if (ce.xclient.message_type != msgtype) {
906 XPutBackEvent(ob_display, &ce);
909 e->xclient = ce.xclient;
911 if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
912 (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
913 client_set_desktop(client, (unsigned)e->xclient.data.l[0],
915 } else if (msgtype == prop_atoms.net_wm_state) {
916 /* can't compress these */
917 ob_debug("net_wm_state %s %ld %ld for 0x%lx\n",
918 (e->xclient.data.l[0] == 0 ? "Remove" :
919 e->xclient.data.l[0] == 1 ? "Add" :
920 e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
921 e->xclient.data.l[1], e->xclient.data.l[2],
923 client_set_state(client, e->xclient.data.l[0],
924 e->xclient.data.l[1], e->xclient.data.l[2]);
925 } else if (msgtype == prop_atoms.net_close_window) {
926 ob_debug("net_close_window for 0x%lx\n", client->window);
927 client_close(client);
928 } else if (msgtype == prop_atoms.net_active_window) {
929 ob_debug("net_active_window for 0x%lx\n", client->window);
930 client_activate(client);
931 } else if (msgtype == prop_atoms.net_wm_moveresize) {
932 ob_debug("net_wm_moveresize for 0x%lx\n", client->window);
933 if ((Atom)e->xclient.data.l[2] ==
934 prop_atoms.net_wm_moveresize_size_topleft ||
935 (Atom)e->xclient.data.l[2] ==
936 prop_atoms.net_wm_moveresize_size_top ||
937 (Atom)e->xclient.data.l[2] ==
938 prop_atoms.net_wm_moveresize_size_topright ||
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_right ||
943 (Atom)e->xclient.data.l[2] ==
944 prop_atoms.net_wm_moveresize_size_bottomright ||
945 (Atom)e->xclient.data.l[2] ==
946 prop_atoms.net_wm_moveresize_size_bottom ||
947 (Atom)e->xclient.data.l[2] ==
948 prop_atoms.net_wm_moveresize_size_bottomleft ||
949 (Atom)e->xclient.data.l[2] ==
950 prop_atoms.net_wm_moveresize_size_left ||
951 (Atom)e->xclient.data.l[2] ==
952 prop_atoms.net_wm_moveresize_move ||
953 (Atom)e->xclient.data.l[2] ==
954 prop_atoms.net_wm_moveresize_size_keyboard ||
955 (Atom)e->xclient.data.l[2] ==
956 prop_atoms.net_wm_moveresize_move_keyboard) {
958 moveresize_start(client, e->xclient.data.l[0],
959 e->xclient.data.l[1], e->xclient.data.l[3],
960 e->xclient.data.l[2]);
962 } else if (msgtype == prop_atoms.net_moveresize_window) {
963 int oldg = client->gravity;
964 int tmpg, x, y, w, h;
966 if (e->xclient.data.l[0] & 0xff)
967 tmpg = e->xclient.data.l[0] & 0xff;
971 if (e->xclient.data.l[0] & 1 << 8)
972 x = e->xclient.data.l[1];
975 if (e->xclient.data.l[0] & 1 << 9)
976 y = e->xclient.data.l[2];
979 if (e->xclient.data.l[0] & 1 << 10)
980 w = e->xclient.data.l[3];
982 w = client->area.width;
983 if (e->xclient.data.l[0] & 1 << 11)
984 h = e->xclient.data.l[4];
986 h = client->area.height;
987 client->gravity = tmpg;
993 client->frame->size.left + client->frame->size.right;
995 client->frame->size.top + client->frame->size.bottom;
996 client_find_onscreen(client, &newx, &newy, fw, fh, TRUE);
997 if (e->xclient.data.l[0] & 1 << 8)
999 if (e->xclient.data.l[0] & 1 << 9)
1003 client_configure(client, OB_CORNER_TOPLEFT,
1004 x, y, w, h, FALSE, TRUE);
1006 client->gravity = oldg;
1009 case PropertyNotify:
1010 /* validate cuz we query stuff off the client here */
1011 if (!client_validate(client)) break;
1013 /* compress changes to a single property into a single change */
1014 while (XCheckTypedWindowEvent(ob_display, e->type,
1015 client->window, &ce)) {
1016 /* XXX: it would be nice to compress ALL changes to a property,
1017 not just changes in a row without other props between. */
1018 if (ce.xproperty.atom != e->xproperty.atom) {
1019 XPutBackEvent(ob_display, &ce);
1024 msgtype = e->xproperty.atom;
1025 if (msgtype == XA_WM_NORMAL_HINTS) {
1026 client_update_normal_hints(client);
1027 /* normal hints can make a window non-resizable */
1028 client_setup_decor_and_functions(client);
1030 else if (msgtype == XA_WM_HINTS)
1031 client_update_wmhints(client);
1032 else if (msgtype == XA_WM_TRANSIENT_FOR) {
1033 client_update_transient_for(client);
1034 client_get_type(client);
1035 /* type may have changed, so update the layer */
1036 client_calc_layer(client);
1037 client_setup_decor_and_functions(client);
1039 else if (msgtype == prop_atoms.net_wm_name ||
1040 msgtype == prop_atoms.wm_name ||
1041 msgtype == prop_atoms.net_wm_icon_name ||
1042 msgtype == prop_atoms.wm_icon_name)
1043 client_update_title(client);
1044 else if (msgtype == prop_atoms.wm_class)
1045 client_update_class(client);
1046 else if (msgtype == prop_atoms.wm_protocols) {
1047 client_update_protocols(client);
1048 client_setup_decor_and_functions(client);
1050 else if (msgtype == prop_atoms.net_wm_strut) {
1051 client_update_strut(client);
1053 else if (msgtype == prop_atoms.net_wm_icon ||
1054 msgtype == prop_atoms.kwm_win_icon)
1055 client_update_icons(client);
1059 if (extensions_shape && e->type == extensions_shape_event_basep) {
1060 client->shaped = ((XShapeEvent*)e)->shaped;
1061 frame_adjust_shape(client->frame);
1067 static void event_handle_menu(ObClient *client, XEvent *e)
1073 top = g_list_nth_data(menu_visible, 0);
1075 ob_debug("EVENT %d\n", e->type);
1078 menu_control_keyboard_nav(e->xkey.keycode);
1081 ob_debug("BUTTON PRESS\n");
1085 ob_debug("BUTTON RELEASED\n");
1087 for (it = menu_visible; it; it = g_list_next(it)) {
1088 ObMenu *m = it->data;
1089 if (e->xbutton.x_root >= m->location.x - ob_rr_theme->bwidth &&
1090 e->xbutton.y_root >= m->location.y - ob_rr_theme->bwidth &&
1091 e->xbutton.x_root < m->location.x + m->size.width +
1092 ob_rr_theme->bwidth &&
1093 e->xbutton.y_root < m->location.y + m->size.height +
1094 ob_rr_theme->bwidth) {
1095 if ((entry = menu_find_entry_by_pos(it->data,
1100 m->selected(entry, e->xbutton.button,
1109 /* will call the menu_hide() for each submenu as well */
1111 menu_control_keyboard_nav(ob_keycode(OB_KEY_ESCAPE));
1115 ob_debug("motion\n");
1116 for (it = menu_visible; it; it = g_list_next(it)) {
1117 ObMenu *m = it->data;
1118 if ((entry = menu_find_entry_by_pos(it->data,
1123 if (m->over && m->over->data != entry)
1124 m->mouseover(m->over->data, FALSE);
1126 m->mouseover(entry, TRUE);
1135 void event_add_fd_handler(event_fd_handler *h) {
1136 g_datalist_id_set_data(&fd_handler_list, h->fd, h);
1137 FD_SET(h->fd, &allset);
1138 max_fd = MAX(max_fd, h->fd);
1141 static void find_max_fd_foreach(GQuark n, gpointer data, gpointer max)
1143 *((unsigned int *)max) = MAX(*((unsigned int *)max), n);
1146 static void find_max_fd()
1149 g_datalist_foreach(&fd_handler_list, find_max_fd_foreach,
1151 max_fd = MAX(x_fd, tmpmax);
1153 max_fd = MAX(ice_fd, max_fd);
1157 void event_remove_fd(int n)
1160 g_datalist_id_remove_data(&fd_handler_list, (GQuark)n);
1164 static void fd_event_handle_foreach(GQuark n, gpointer data, gpointer user_data)
1166 if (FD_ISSET( (int)n, &selset)) {
1167 event_fd_handler *h = (event_fd_handler *)data;
1168 g_assert(h->fd == (int)n);
1169 h->handler(h->fd, h->data);
1173 static void fd_event_handle()
1175 g_datalist_foreach(&fd_handler_list, fd_event_handle_foreach, NULL);
1178 static void event_handle_dock(ObDock *s, XEvent *e)
1182 stacking_raise(DOCK_AS_WINDOW(s));
1193 static void event_handle_dockapp(ObDockApp *app, XEvent *e)
1197 dock_app_drag(app, &e->xmotion);
1200 if (app->ignore_unmaps) {
1201 app->ignore_unmaps--;
1204 dock_remove(app, TRUE);
1207 dock_remove(app, FALSE);
1209 case ReparentNotify:
1210 dock_remove(app, FALSE);
1212 case ConfigureNotify:
1213 dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);