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
)
226 /* grab the lasttime and hack up the state */
230 event_lasttime
= e
->xbutton
.time
;
233 event_lasttime
= e
->xkey
.time
;
236 event_lasttime
= e
->xkey
.time
;
239 event_lasttime
= e
->xmotion
.time
;
242 event_lasttime
= e
->xproperty
.time
;
246 event_lasttime
= e
->xcrossing
.time
;
249 event_lasttime
= CurrentTime
;
254 #define STRIP_MODS(s) \
255 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
256 /* kill off the Button1Mask etc, only want the modifiers */ \
257 s &= (ControlMask | ShiftMask | Mod1Mask | \
258 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
260 static void event_hack_mods(XEvent *e)
268 STRIP_MODS(e
->xbutton
.state
);
271 STRIP_MODS(e
->xkey
.state
);
274 STRIP_MODS(e
->xkey
.state
);
275 /* remove from the state the mask of the modifier being released, if
276 it is a modifier key being released (this is a little ugly..) */
277 kp
= modmap
->modifiermap
;
278 for (i
= 0; i
< mask_table_size
; ++i
) {
279 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
280 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
281 /* remove the mask for it */
282 e
->xkey
.state
&= ~mask_table
[i
];
283 /* cause the first loop to break; */
285 break; /* get outta here! */
292 STRIP_MODS(e
->xmotion
.state
);
293 /* compress events */
296 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
298 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
299 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
306 static gboolean
event_ignore(XEvent
*e
, ObClient
*client
)
310 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
311 because of RevertToPointerRoot. If the focus ends up reverting to
312 pointer root on a workspace change, then the FocusIn event that we
313 want will be of type NotifyAncestor. This situation does not occur
314 for FocusOut, so it is safely ignored there.
316 if (INVALID_FOCUSIN(e
) ||
319 ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
320 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
322 /* says a client was not found for the event (or a valid FocusIn
325 e
->xfocus
.window
= None
;
330 ob_debug("FocusIn on %lx mode %d detail %d\n", e
->xfocus
.window
,
331 e
->xfocus
.mode
, e
->xfocus
.detail
);
335 if (INVALID_FOCUSOUT(e
)) {
337 ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n",
338 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
344 ob_debug("FocusOut on %lx mode %d detail %d\n",
345 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
350 gboolean fallback
= TRUE
;
353 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
354 e
->xfocus
.window
,&fe
))
355 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
357 if (fe
.type
== FocusOut
) {
359 ob_debug("found pending FocusOut");
361 if (!INVALID_FOCUSOUT(&fe
)) {
362 /* if there is a VALID FocusOut still coming, don't
363 fallback focus yet, we'll deal with it then */
364 XPutBackEvent(ob_display
, &fe
);
370 ob_debug("found pending FocusIn");
372 /* is the focused window getting a FocusOut/In back to
375 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
376 !event_ignore(&fe
, client
)) {
378 if focus_client is not set, then we can't do
379 this. we need the FocusIn. This happens in the
380 case when the set_focus_client(NULL) in the
381 focus_fallback function fires and then
382 focus_fallback picks the currently focused
383 window (such as on a SendToDesktop-esque action.
387 ob_debug("focused window got an Out/In back to "
388 "itself IGNORED both");
394 ob_debug("focused window got an Out/In back to "
395 "itself but focus_client was null "
396 "IGNORED just the Out");
402 /* once all the FocusOut's have been dealt with, if there
403 is a FocusIn still left and it is valid, then use it */
405 /* secret magic way of event_process telling us that no
406 client was found for the FocusIn event. ^_^ */
407 if (fe
.xfocus
.window
!= None
) {
415 ob_debug("no valid FocusIn and no FocusOut events found, "
418 focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS
);
424 /* NotifyUngrab occurs when a mouse button is released and the event is
425 caused, like when lowering a window */
426 /* NotifyVirtual occurs when ungrabbing the pointer */
427 if (e
->xcrossing
.mode
== NotifyGrab
||
428 e
->xcrossing
.detail
== NotifyInferior
||
429 (e
->xcrossing
.mode
== NotifyUngrab
&&
430 e
->xcrossing
.detail
== NotifyVirtual
)) {
432 ob_debug("%sNotify mode %d detail %d on %lx IGNORED",
433 (e
->type
== EnterNotify
? "Enter" : "Leave"),
435 e
->xcrossing
.detail
, client
?client
->window
:0);
440 ob_debug("%sNotify mode %d detail %d on %lx",
441 (e
->type
== EnterNotify
? "Enter" : "Leave"),
443 e
->xcrossing
.detail
, client
?client
->window
:0);
450 static void event_process(XEvent
*e
)
453 ObClient
*client
= NULL
;
455 ObDockApp
*dockapp
= NULL
;
457 ObWindow
*obwin
= NULL
;
459 window
= event_get_window(e
);
460 if ((obwin
= g_hash_table_lookup(window_map
, &window
))) {
461 switch (obwin
->type
) {
463 dock
= WINDOW_AS_DOCK(obwin
);
466 dockapp
= WINDOW_AS_DOCKAPP(obwin
);
469 menu
= WINDOW_AS_MENU(obwin
);
472 client
= WINDOW_AS_CLIENT(obwin
);
474 case Window_Internal
:
475 /* not to be used for events */
476 g_assert_not_reached();
481 event_set_lasttime(e
);
483 if (event_ignore(e
, client
))
486 /* deal with it in the kernel */
488 event_handle_client(client
, e
);
490 event_handle_dockapp(dockapp
, e
);
492 event_handle_dock(dock
, e
);
493 else if (window
== RootWindow(ob_display
, ob_screen
))
494 event_handle_root(e
);
495 else if (e
->type
== MapRequest
)
496 client_manage(window
);
497 else if (e
->type
== ConfigureRequest
) {
498 /* unhandled configure requests must be used to configure the
502 xwc
.x
= e
->xconfigurerequest
.x
;
503 xwc
.y
= e
->xconfigurerequest
.y
;
504 xwc
.width
= e
->xconfigurerequest
.width
;
505 xwc
.height
= e
->xconfigurerequest
.height
;
506 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
507 xwc
.sibling
= e
->xconfigurerequest
.above
;
508 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
510 /* we are not to be held responsible if someone sends us an
512 xerror_set_ignore(TRUE
);
513 XConfigureWindow(ob_display
, window
,
514 e
->xconfigurerequest
.value_mask
, &xwc
);
515 xerror_set_ignore(FALSE
);
519 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
520 e
->type
== ButtonPress
||
521 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
522 event_handle_menu(client
, e
);
524 return; /* no dispatch! */
527 if (moveresize_in_progress
)
528 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
529 e
->type
== ButtonPress
||
530 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
533 return; /* no dispatch! */
537 /* user input (action-bound) events */
539 if (e->type == ButtonPress || e->type == ButtonRelease ||
540 e->type == MotionNotify)
541 mouse_event(e, client);
542 else if (e->type == KeyPress || e->type == KeyRelease)
546 /* dispatch the event to registered handlers */
547 dispatch_x(e
, client
);
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
)
608 /* Wheel buttons don't draw because they are an instant click, so it
609 is a waste of resources to go drawing it. */
610 if (!(e
->xbutton
.button
== 4 || e
->xbutton
.button
== 5)) {
611 switch (frame_context(client
, e
->xbutton
.window
)) {
612 case OB_FRAME_CONTEXT_MAXIMIZE
:
613 client
->frame
->max_press
= (e
->type
== ButtonPress
);
614 framerender_frame(client
->frame
);
616 case OB_FRAME_CONTEXT_CLOSE
:
617 client
->frame
->close_press
= (e
->type
== ButtonPress
);
618 framerender_frame(client
->frame
);
620 case OB_FRAME_CONTEXT_ICONIFY
:
621 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
622 framerender_frame(client
->frame
);
624 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
625 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
626 framerender_frame(client
->frame
);
628 case OB_FRAME_CONTEXT_SHADE
:
629 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
630 framerender_frame(client
->frame
);
633 /* nothing changes with clicks for any other contexts */
640 ob_debug("FocusIn on client for %lx\n", client
->window
);
642 if (client
!= focus_client
) {
643 focus_set_client(client
);
644 frame_adjust_focus(client
->frame
, TRUE
);
649 ob_debug("FocusOut on client for %lx\n", client
->window
);
651 /* are we a fullscreen window or a transient of one? (checks layer)
652 if we are then we need to be iconified since we are losing focus
654 if (client
->layer
== OB_STACKING_LAYER_FULLSCREEN
&& !client
->iconic
&&
655 !client_search_focus_tree_full(client
))
656 /* iconify fullscreen windows when they and their transients
658 client_iconify(client
, TRUE
, TRUE
);
659 frame_adjust_focus(client
->frame
, FALSE
);
662 con
= frame_context(client
, e
->xcrossing
.window
);
664 case OB_FRAME_CONTEXT_MAXIMIZE
:
665 client
->frame
->max_hover
= FALSE
;
666 frame_adjust_state(client
->frame
);
668 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
669 client
->frame
->desk_hover
= FALSE
;
670 frame_adjust_state(client
->frame
);
672 case OB_FRAME_CONTEXT_SHADE
:
673 client
->frame
->shade_hover
= FALSE
;
674 frame_adjust_state(client
->frame
);
676 case OB_FRAME_CONTEXT_ICONIFY
:
677 client
->frame
->iconify_hover
= FALSE
;
678 frame_adjust_state(client
->frame
);
680 case OB_FRAME_CONTEXT_CLOSE
:
681 client
->frame
->close_hover
= FALSE
;
682 frame_adjust_state(client
->frame
);
689 con
= frame_context(client
, e
->xcrossing
.window
);
691 case OB_FRAME_CONTEXT_MAXIMIZE
:
692 client
->frame
->max_hover
= TRUE
;
693 frame_adjust_state(client
->frame
);
695 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
696 client
->frame
->desk_hover
= TRUE
;
697 frame_adjust_state(client
->frame
);
699 case OB_FRAME_CONTEXT_SHADE
:
700 client
->frame
->shade_hover
= TRUE
;
701 frame_adjust_state(client
->frame
);
703 case OB_FRAME_CONTEXT_ICONIFY
:
704 client
->frame
->iconify_hover
= TRUE
;
705 frame_adjust_state(client
->frame
);
707 case OB_FRAME_CONTEXT_CLOSE
:
708 client
->frame
->close_hover
= TRUE
;
709 frame_adjust_state(client
->frame
);
711 case OB_FRAME_CONTEXT_FRAME
:
712 if (client_normal(client
)) {
713 if (ob_state() == OB_STATE_STARTING
) {
714 /* move it to the top of the focus order */
715 guint desktop
= client
->desktop
;
716 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
717 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
719 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
721 } else if (config_focus_follow
) {
723 ob_debug("EnterNotify on %lx, focusing window\n",
726 client_focus(client
);
734 case ConfigureRequest
:
736 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
737 ConfigureRequest
, &ce
)) {
739 /* XXX if this causes bad things.. we can compress config req's
740 with the same mask. */
741 e
->xconfigurerequest
.value_mask
|=
742 ce
.xconfigurerequest
.value_mask
;
743 if (ce
.xconfigurerequest
.value_mask
& CWX
)
744 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
745 if (ce
.xconfigurerequest
.value_mask
& CWY
)
746 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
747 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
748 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
749 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
750 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
751 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
752 e
->xconfigurerequest
.border_width
=
753 ce
.xconfigurerequest
.border_width
;
754 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
755 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
758 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
759 if (client
->iconic
|| client
->shaded
) return;
761 /* resize, then move, as specified in the EWMH section 7.7 */
762 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
768 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
769 client
->border_width
= e
->xconfigurerequest
.border_width
;
771 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
772 e
->xconfigurerequest
.x
: client
->area
.x
;
773 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
774 e
->xconfigurerequest
.y
: client
->area
.y
;
775 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
776 e
->xconfigurerequest
.width
: client
->area
.width
;
777 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
778 e
->xconfigurerequest
.height
: client
->area
.height
;
783 client_find_onscreen(client
, &newx
, &newy
, w
, h
, TRUE
);
784 if (e
->xconfigurerequest
.value_mask
& CWX
)
786 if (e
->xconfigurerequest
.value_mask
& CWY
)
790 switch (client
->gravity
) {
791 case NorthEastGravity
:
793 corner
= OB_CORNER_TOPRIGHT
;
795 case SouthWestGravity
:
797 corner
= OB_CORNER_BOTTOMLEFT
;
799 case SouthEastGravity
:
800 corner
= OB_CORNER_BOTTOMRIGHT
;
802 default: /* NorthWest, Static, etc */
803 corner
= OB_CORNER_TOPLEFT
;
806 client_configure_full(client
, corner
, x
, y
, w
, h
, FALSE
, TRUE
,
810 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
811 switch (e
->xconfigurerequest
.detail
) {
814 stacking_lower(CLIENT_AS_WINDOW(client
));
820 stacking_raise(CLIENT_AS_WINDOW(client
));
826 if (client
->ignore_unmaps
) {
827 client
->ignore_unmaps
--;
830 client_unmanage(client
);
833 client_unmanage(client
);
836 /* this is when the client is first taken captive in the frame */
837 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
840 This event is quite rare and is usually handled in unmapHandler.
841 However, if the window is unmapped when the reparent event occurs,
842 the window manager never sees it because an unmap event is not sent
843 to an already unmapped window.
846 /* we don't want the reparent event, put it back on the stack for the
847 X server to deal with after we unmanage the window */
848 XPutBackEvent(ob_display
, e
);
850 client_unmanage(client
);
853 ob_debug("MapRequest for 0x%lx\n", client
->window
);
854 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
855 does, we don't want it! */
856 if (screen_showing_desktop
)
857 screen_show_desktop(FALSE
);
858 client_iconify(client
, FALSE
, TRUE
);
859 if (!client
->frame
->visible
)
860 /* if its not visible still, then don't mess with it */
863 client_shade(client
, FALSE
);
864 client_focus(client
);
865 stacking_raise(CLIENT_AS_WINDOW(client
));
868 /* validate cuz we query stuff off the client here */
869 if (!client_validate(client
)) break;
871 if (e
->xclient
.format
!= 32) return;
873 msgtype
= e
->xclient
.message_type
;
874 if (msgtype
== prop_atoms
.wm_change_state
) {
875 /* compress changes into a single change */
876 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
877 client
->window
, &ce
)) {
878 /* XXX: it would be nice to compress ALL messages of a
879 type, not just messages in a row without other
880 message types between. */
881 if (ce
.xclient
.message_type
!= msgtype
) {
882 XPutBackEvent(ob_display
, &ce
);
885 e
->xclient
= ce
.xclient
;
887 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
888 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
889 /* compress changes into a single change */
890 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
891 client
->window
, &ce
)) {
892 /* XXX: it would be nice to compress ALL messages of a
893 type, not just messages in a row without other
894 message types between. */
895 if (ce
.xclient
.message_type
!= msgtype
) {
896 XPutBackEvent(ob_display
, &ce
);
899 e
->xclient
= ce
.xclient
;
901 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
902 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
903 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
905 } else if (msgtype
== prop_atoms
.net_wm_state
) {
906 /* can't compress these */
907 ob_debug("net_wm_state %s %ld %ld for 0x%lx\n",
908 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
909 e
->xclient
.data
.l
[0] == 1 ? "Add" :
910 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
911 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
913 client_set_state(client
, e
->xclient
.data
.l
[0],
914 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
915 } else if (msgtype
== prop_atoms
.net_close_window
) {
916 ob_debug("net_close_window for 0x%lx\n", client
->window
);
917 client_close(client
);
918 } else if (msgtype
== prop_atoms
.net_active_window
) {
919 ob_debug("net_active_window for 0x%lx\n", client
->window
);
920 client_activate(client
);
921 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
922 ob_debug("net_wm_moveresize for 0x%lx\n", client
->window
);
923 if ((Atom
)e
->xclient
.data
.l
[2] ==
924 prop_atoms
.net_wm_moveresize_size_topleft
||
925 (Atom
)e
->xclient
.data
.l
[2] ==
926 prop_atoms
.net_wm_moveresize_size_top
||
927 (Atom
)e
->xclient
.data
.l
[2] ==
928 prop_atoms
.net_wm_moveresize_size_topright
||
929 (Atom
)e
->xclient
.data
.l
[2] ==
930 prop_atoms
.net_wm_moveresize_size_right
||
931 (Atom
)e
->xclient
.data
.l
[2] ==
932 prop_atoms
.net_wm_moveresize_size_right
||
933 (Atom
)e
->xclient
.data
.l
[2] ==
934 prop_atoms
.net_wm_moveresize_size_bottomright
||
935 (Atom
)e
->xclient
.data
.l
[2] ==
936 prop_atoms
.net_wm_moveresize_size_bottom
||
937 (Atom
)e
->xclient
.data
.l
[2] ==
938 prop_atoms
.net_wm_moveresize_size_bottomleft
||
939 (Atom
)e
->xclient
.data
.l
[2] ==
940 prop_atoms
.net_wm_moveresize_size_left
||
941 (Atom
)e
->xclient
.data
.l
[2] ==
942 prop_atoms
.net_wm_moveresize_move
||
943 (Atom
)e
->xclient
.data
.l
[2] ==
944 prop_atoms
.net_wm_moveresize_size_keyboard
||
945 (Atom
)e
->xclient
.data
.l
[2] ==
946 prop_atoms
.net_wm_moveresize_move_keyboard
) {
948 moveresize_start(client
, e
->xclient
.data
.l
[0],
949 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
950 e
->xclient
.data
.l
[2]);
952 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
953 int oldg
= client
->gravity
;
954 int tmpg
, x
, y
, w
, h
;
956 if (e
->xclient
.data
.l
[0] & 0xff)
957 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
961 if (e
->xclient
.data
.l
[0] & 1 << 8)
962 x
= e
->xclient
.data
.l
[1];
965 if (e
->xclient
.data
.l
[0] & 1 << 9)
966 y
= e
->xclient
.data
.l
[2];
969 if (e
->xclient
.data
.l
[0] & 1 << 10)
970 w
= e
->xclient
.data
.l
[3];
972 w
= client
->area
.width
;
973 if (e
->xclient
.data
.l
[0] & 1 << 11)
974 h
= e
->xclient
.data
.l
[4];
976 h
= client
->area
.height
;
977 client
->gravity
= tmpg
;
982 client_find_onscreen(client
, &newx
, &newy
, w
, h
, TRUE
);
983 if (e
->xclient
.data
.l
[0] & 1 << 8)
985 if (e
->xclient
.data
.l
[0] & 1 << 9)
989 client_configure(client
, OB_CORNER_TOPLEFT
,
990 x
, y
, w
, h
, FALSE
, TRUE
);
992 client
->gravity
= oldg
;
996 /* validate cuz we query stuff off the client here */
997 if (!client_validate(client
)) break;
999 /* compress changes to a single property into a single change */
1000 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
1001 client
->window
, &ce
)) {
1002 /* XXX: it would be nice to compress ALL changes to a property,
1003 not just changes in a row without other props between. */
1004 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
1005 XPutBackEvent(ob_display
, &ce
);
1010 msgtype
= e
->xproperty
.atom
;
1011 if (msgtype
== XA_WM_NORMAL_HINTS
) {
1012 client_update_normal_hints(client
);
1013 /* normal hints can make a window non-resizable */
1014 client_setup_decor_and_functions(client
);
1016 else if (msgtype
== XA_WM_HINTS
)
1017 client_update_wmhints(client
);
1018 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
1019 client_update_transient_for(client
);
1020 client_get_type(client
);
1021 /* type may have changed, so update the layer */
1022 client_calc_layer(client
);
1023 client_setup_decor_and_functions(client
);
1025 else if (msgtype
== prop_atoms
.net_wm_name
||
1026 msgtype
== prop_atoms
.wm_name
||
1027 msgtype
== prop_atoms
.net_wm_icon_name
||
1028 msgtype
== prop_atoms
.wm_icon_name
)
1029 client_update_title(client
);
1030 else if (msgtype
== prop_atoms
.wm_class
)
1031 client_update_class(client
);
1032 else if (msgtype
== prop_atoms
.wm_protocols
) {
1033 client_update_protocols(client
);
1034 client_setup_decor_and_functions(client
);
1036 else if (msgtype
== prop_atoms
.net_wm_strut
) {
1037 client_update_strut(client
);
1039 else if (msgtype
== prop_atoms
.net_wm_icon
||
1040 msgtype
== prop_atoms
.kwm_win_icon
)
1041 client_update_icons(client
);
1045 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
1046 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
1047 frame_adjust_shape(client
->frame
);
1053 static void event_handle_menu(ObClient
*client
, XEvent
*e
)
1059 top
= g_list_nth_data(menu_visible
, 0);
1061 ob_debug("EVENT %d\n", e
->type
);
1064 menu_control_keyboard_nav(e
->xkey
.keycode
);
1067 ob_debug("BUTTON PRESS\n");
1071 ob_debug("BUTTON RELEASED\n");
1073 for (it
= menu_visible
; it
; it
= g_list_next(it
)) {
1074 ObMenu
*m
= it
->data
;
1075 if (e
->xbutton
.x_root
>= m
->location
.x
- ob_rr_theme
->bwidth
&&
1076 e
->xbutton
.y_root
>= m
->location
.y
- ob_rr_theme
->bwidth
&&
1077 e
->xbutton
.x_root
< m
->location
.x
+ m
->size
.width
+
1078 ob_rr_theme
->bwidth
&&
1079 e
->xbutton
.y_root
< m
->location
.y
+ m
->size
.height
+
1080 ob_rr_theme
->bwidth
) {
1081 if ((entry
= menu_find_entry_by_pos(it
->data
,
1086 m
->selected(entry
, e
->xbutton
.button
,
1095 /* will call the menu_hide() for each submenu as well */
1097 menu_control_keyboard_nav(ob_keycode(OB_KEY_ESCAPE
));
1101 ob_debug("motion\n");
1102 for (it
= menu_visible
; it
; it
= g_list_next(it
)) {
1103 ObMenu
*m
= it
->data
;
1104 if ((entry
= menu_find_entry_by_pos(it
->data
,
1109 if (m
->over
&& m
->over
->data
!= entry
)
1110 m
->mouseover(m
->over
->data
, FALSE
);
1112 m
->mouseover(entry
, TRUE
);
1121 void event_add_fd_handler(event_fd_handler
*h
) {
1122 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
1123 FD_SET(h
->fd
, &allset
);
1124 max_fd
= MAX(max_fd
, h
->fd
);
1127 static void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
1129 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
1132 static void find_max_fd()
1135 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
,
1137 max_fd
= MAX(x_fd
, tmpmax
);
1139 max_fd
= MAX(ice_fd
, tmpmax
);
1143 void event_remove_fd(int n
)
1146 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
1150 static void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
1152 if (FD_ISSET( (int)n
, &selset
)) {
1153 event_fd_handler
*h
= (event_fd_handler
*)data
;
1154 g_assert(h
->fd
== (int)n
);
1155 h
->handler(h
->fd
, h
->data
);
1159 static void fd_event_handle()
1161 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
1164 static void event_handle_dock(ObDock
*s
, XEvent
*e
)
1168 stacking_raise(DOCK_AS_WINDOW(s
));
1179 static void event_handle_dockapp(ObDockApp
*app
, XEvent
*e
)
1183 dock_app_drag(app
, &e
->xmotion
);
1186 if (app
->ignore_unmaps
) {
1187 app
->ignore_unmaps
--;
1190 dock_remove(app
, TRUE
);
1193 dock_remove(app
, FALSE
);
1195 case ReparentNotify
:
1196 dock_remove(app
, FALSE
);
1198 case ConfigureNotify
:
1199 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);