11 #include "menuframe.h"
14 #include "framerender.h"
16 #include "moveresize.h"
18 #include "extensions.h"
24 #include <X11/keysym.h>
25 #include <X11/Xatom.h>
29 # include <libsn/sn.h>
32 #ifdef HAVE_SYS_SELECT_H
33 # include <sys/select.h>
40 #include <X11/ICE/ICElib.h>
43 static void event_process(XEvent
*e
);
44 static void event_handle_root(XEvent
*e
);
45 static void event_handle_menu(XEvent
*e
);
46 static void event_handle_dock(ObDock
*s
, XEvent
*e
);
47 static void event_handle_dockapp(ObDockApp
*app
, XEvent
*e
);
48 static void event_handle_client(ObClient
*c
, XEvent
*e
);
49 static void fd_event_handle();
51 static void ice_watch(IceConn conn
, IcePointer data
, Bool opening
,
52 IcePointer
*watch_data
);
54 static void find_max_fd();
56 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
57 (e)->xfocus.detail == NotifyAncestor || \
58 (e)->xfocus.detail > NotifyNonlinearVirtual)
59 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
60 (e)->xfocus.detail == NotifyInferior || \
61 (e)->xfocus.detail == NotifyAncestor || \
62 (e)->xfocus.detail > NotifyNonlinearVirtual)
64 Time event_lasttime
= 0;
66 /*! The value of the mask for the NumLock modifier */
67 unsigned int NumLockMask
;
68 /*! The value of the mask for the ScrollLock modifier */
69 unsigned int ScrollLockMask
;
70 /*! The key codes for the modifier keys */
71 static XModifierKeymap
*modmap
;
72 /*! Table of the constant modifier masks */
73 static const int mask_table
[] = {
74 ShiftMask
, LockMask
, ControlMask
, Mod1Mask
,
75 Mod2Mask
, Mod3Mask
, Mod4Mask
, Mod5Mask
77 static int mask_table_size
;
79 static fd_set selset
, allset
;
81 static IceConn ice_conn
;
84 static int max_fd
, x_fd
;
85 static GData
*fd_handler_list
;
89 static void ice_watch(IceConn conn
, IcePointer data
, Bool opening
,
90 IcePointer
*watch_data
)
93 g_assert (ice_fd
< 0);
95 ice_fd
= IceConnectionNumber(conn
);
96 FD_SET(ice_fd
, &allset
);
98 FD_CLR(ice_fd
, &allset
);
107 mask_table_size
= sizeof(mask_table
) / sizeof(mask_table
[0]);
109 /* get lock masks that are defined by the display (not constant) */
110 modmap
= XGetModifierMapping(ob_display
);
112 if (modmap
&& modmap
->max_keypermod
> 0) {
114 const size_t size
= mask_table_size
* modmap
->max_keypermod
;
115 /* get the values of the keyboard lock modifiers
116 Note: Caps lock is not retrieved the same way as Scroll and Num
117 lock since it doesn't need to be. */
118 const KeyCode num_lock
= XKeysymToKeycode(ob_display
, XK_Num_Lock
);
119 const KeyCode scroll_lock
= XKeysymToKeycode(ob_display
,
122 for (cnt
= 0; cnt
< size
; ++cnt
) {
123 if (! modmap
->modifiermap
[cnt
]) continue;
125 if (num_lock
== modmap
->modifiermap
[cnt
])
126 NumLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
127 if (scroll_lock
== modmap
->modifiermap
[cnt
])
128 ScrollLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
133 max_fd
= x_fd
= ConnectionNumber(ob_display
);
134 FD_SET(x_fd
, &allset
);
138 IceAddConnectionWatch(ice_watch
, NULL
);
141 g_datalist_init(&fd_handler_list
);
144 void event_shutdown()
146 XFreeModifiermap(modmap
);
147 g_datalist_clear(&fd_handler_list
);
153 struct timeval
*wait
;
154 gboolean had_event
= FALSE
;
156 while (XPending(ob_display
)) {
157 XNextEvent(ob_display
, &e
);
160 sn_display_process_event(ob_sn_display
, &e
);
168 timer_dispatch((GTimeVal
**)&wait
);
170 select(max_fd
+ 1, &selset
, NULL
, NULL
, wait
);
172 /* handle the X events as soon as possible? */
173 if (FD_ISSET(x_fd
, &selset
))
177 if (ice_fd
>= 0 && FD_ISSET(ice_fd
, &selset
)) {
179 IceProcessMessages(ice_conn
, NULL
, &b
);
187 static Window
event_get_window(XEvent
*e
)
194 window
= RootWindow(ob_display
, ob_screen
);
197 window
= e
->xmap
.window
;
200 window
= e
->xunmap
.window
;
203 window
= e
->xdestroywindow
.window
;
205 case ConfigureRequest
:
206 window
= e
->xconfigurerequest
.window
;
208 case ConfigureNotify
:
209 window
= e
->xconfigure
.window
;
213 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
214 switch (((XkbAnyEvent
*)e
)->xkb_type
) {
216 window
= ((XkbBellNotifyEvent
*)e
)->window
;
222 window
= e
->xany
.window
;
227 static void event_set_lasttime(XEvent
*e
)
231 /* grab the lasttime and hack up the state */
247 t
= e
->xproperty
.time
;
251 t
= e
->xcrossing
.time
;
254 /* if more event types are anticipated, get their timestamp
259 if (t
> event_lasttime
)
263 #define STRIP_MODS(s) \
264 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
265 /* kill off the Button1Mask etc, only want the modifiers */ \
266 s &= (ControlMask | ShiftMask | Mod1Mask | \
267 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
269 static void event_hack_mods(XEvent *e)
277 STRIP_MODS(e
->xbutton
.state
);
280 STRIP_MODS(e
->xkey
.state
);
283 STRIP_MODS(e
->xkey
.state
);
284 /* remove from the state the mask of the modifier being released, if
285 it is a modifier key being released (this is a little ugly..) */
286 kp
= modmap
->modifiermap
;
287 for (i
= 0; i
< mask_table_size
; ++i
) {
288 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
289 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
290 /* remove the mask for it */
291 e
->xkey
.state
&= ~mask_table
[i
];
292 /* cause the first loop to break; */
294 break; /* get outta here! */
301 STRIP_MODS(e
->xmotion
.state
);
303 /* compress events */
306 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
308 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
309 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
317 static gboolean
event_ignore(XEvent
*e
, ObClient
*client
)
321 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
322 because of RevertToPointerRoot. If the focus ends up reverting to
323 pointer root on a workspace change, then the FocusIn event that we
324 want will be of type NotifyAncestor. This situation does not occur
325 for FocusOut, so it is safely ignored there.
327 if (INVALID_FOCUSIN(e
) ||
330 ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
331 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
333 /* says a client was not found for the event (or a valid FocusIn
336 e
->xfocus
.window
= None
;
341 ob_debug("FocusIn on %lx mode %d detail %d\n", e
->xfocus
.window
,
342 e
->xfocus
.mode
, e
->xfocus
.detail
);
346 if (INVALID_FOCUSOUT(e
)) {
348 ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n",
349 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
355 ob_debug("FocusOut on %lx mode %d detail %d\n",
356 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
361 gboolean fallback
= TRUE
;
364 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
365 e
->xfocus
.window
,&fe
))
366 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
368 if (fe
.type
== FocusOut
) {
370 ob_debug("found pending FocusOut");
372 if (!INVALID_FOCUSOUT(&fe
)) {
373 /* if there is a VALID FocusOut still coming, don't
374 fallback focus yet, we'll deal with it then */
375 XPutBackEvent(ob_display
, &fe
);
381 ob_debug("found pending FocusIn");
383 /* is the focused window getting a FocusOut/In back to
386 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
387 !event_ignore(&fe
, client
)) {
389 if focus_client is not set, then we can't do
390 this. we need the FocusIn. This happens in the
391 case when the set_focus_client(NULL) in the
392 focus_fallback function fires and then
393 focus_fallback picks the currently focused
394 window (such as on a SendToDesktop-esque action.
398 ob_debug("focused window got an Out/In back to "
399 "itself IGNORED both");
405 ob_debug("focused window got an Out/In back to "
406 "itself but focus_client was null "
407 "IGNORED just the Out");
413 /* once all the FocusOut's have been dealt with, if there
414 is a FocusIn still left and it is valid, then use it */
416 /* secret magic way of event_process telling us that no
417 client was found for the FocusIn event. ^_^ */
418 if (fe
.xfocus
.window
!= None
) {
426 ob_debug("no valid FocusIn and no FocusOut events found, "
429 focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS
);
435 /* NotifyUngrab occurs when a mouse button is released and the event is
436 caused, like when lowering a window */
437 /* NotifyVirtual occurs when ungrabbing the pointer */
438 if (e
->xcrossing
.mode
== NotifyGrab
||
439 e
->xcrossing
.detail
== NotifyInferior
||
440 (e
->xcrossing
.mode
== NotifyUngrab
&&
441 e
->xcrossing
.detail
== NotifyVirtual
)) {
443 ob_debug("%sNotify mode %d detail %d on %lx IGNORED",
444 (e
->type
== EnterNotify
? "Enter" : "Leave"),
446 e
->xcrossing
.detail
, client
?client
->window
:0);
451 ob_debug("%sNotify mode %d detail %d on %lx",
452 (e
->type
== EnterNotify
? "Enter" : "Leave"),
454 e
->xcrossing
.detail
, client
?client
->window
:0);
461 static void event_process(XEvent
*e
)
464 ObClient
*client
= NULL
;
466 ObDockApp
*dockapp
= NULL
;
467 ObWindow
*obwin
= NULL
;
469 window
= event_get_window(e
);
470 if ((obwin
= g_hash_table_lookup(window_map
, &window
))) {
471 switch (obwin
->type
) {
473 dock
= WINDOW_AS_DOCK(obwin
);
476 dockapp
= WINDOW_AS_DOCKAPP(obwin
);
479 client
= WINDOW_AS_CLIENT(obwin
);
482 case Window_Internal
:
483 /* not to be used for events */
484 g_assert_not_reached();
489 event_set_lasttime(e
);
491 if (event_ignore(e
, client
))
494 /* deal with it in the kernel */
496 event_handle_client(client
, e
);
498 event_handle_dockapp(dockapp
, e
);
500 event_handle_dock(dock
, e
);
501 else if (window
== RootWindow(ob_display
, ob_screen
))
502 event_handle_root(e
);
503 else if (e
->type
== MapRequest
)
504 client_manage(window
);
505 else if (e
->type
== ConfigureRequest
) {
506 /* unhandled configure requests must be used to configure the
510 xwc
.x
= e
->xconfigurerequest
.x
;
511 xwc
.y
= e
->xconfigurerequest
.y
;
512 xwc
.width
= e
->xconfigurerequest
.width
;
513 xwc
.height
= e
->xconfigurerequest
.height
;
514 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
515 xwc
.sibling
= e
->xconfigurerequest
.above
;
516 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
518 /* we are not to be held responsible if someone sends us an
520 xerror_set_ignore(TRUE
);
521 XConfigureWindow(ob_display
, window
,
522 e
->xconfigurerequest
.value_mask
, &xwc
);
523 xerror_set_ignore(FALSE
);
526 if (menu_frame_visible
)
527 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
528 e
->type
== ButtonPress
||
529 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
530 event_handle_menu(e
);
532 return; /* no dispatch! */
535 if (moveresize_in_progress
)
536 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
537 e
->type
== ButtonPress
||
538 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
541 return; /* no dispatch! */
544 /* user input (action-bound) events */
545 if (e
->type
== ButtonPress
|| e
->type
== ButtonRelease
||
546 e
->type
== MotionNotify
|| e
->type
== KeyPress
||
547 e
->type
== KeyRelease
)
549 ObFrameContext context
;
551 context
= frame_context(client
, e
->xany
.window
);
553 if (!keyboard_process_interactive_grab(e
, &client
, &context
)) {
555 if (e
->type
== ButtonPress
|| e
->type
== ButtonRelease
||
556 e
->type
== MotionNotify
)
557 mouse_event(client
, context
, e
);
558 else if (e
->type
== KeyPress
)
559 keyboard_event(client
, e
);
563 /* dispatch the event to registered handlers */
564 dispatch_x(e
, client
);
567 static void event_handle_root(XEvent
*e
)
573 ob_debug("Another WM has requested to replace us. Exiting.\n");
578 if (e
->xclient
.format
!= 32) break;
580 msgtype
= e
->xclient
.message_type
;
581 if (msgtype
== prop_atoms
.net_current_desktop
) {
582 unsigned int d
= e
->xclient
.data
.l
[0];
583 if (d
< screen_num_desktops
)
584 screen_set_desktop(d
);
585 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
586 unsigned int d
= e
->xclient
.data
.l
[0];
588 screen_set_num_desktops(d
);
589 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
590 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
594 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
595 screen_update_desktop_names();
596 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
597 screen_update_layout();
599 case ConfigureNotify
:
601 XRRUpdateConfiguration(e
);
608 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
609 ob_debug("VIDMODE EVENT\n");
615 static void event_handle_client(ObClient
*client
, XEvent
*e
)
623 case VisibilityNotify
:
624 client
->frame
->obscured
= e
->xvisibility
.state
!= VisibilityUnobscured
;
628 /* Wheel buttons don't draw because they are an instant click, so it
629 is a waste of resources to go drawing it. */
630 if (!(e
->xbutton
.button
== 4 || e
->xbutton
.button
== 5)) {
631 switch (frame_context(client
, e
->xbutton
.window
)) {
632 case OB_FRAME_CONTEXT_MAXIMIZE
:
633 client
->frame
->max_press
= (e
->type
== ButtonPress
);
634 framerender_frame(client
->frame
);
636 case OB_FRAME_CONTEXT_CLOSE
:
637 client
->frame
->close_press
= (e
->type
== ButtonPress
);
638 framerender_frame(client
->frame
);
640 case OB_FRAME_CONTEXT_ICONIFY
:
641 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
642 framerender_frame(client
->frame
);
644 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
645 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
646 framerender_frame(client
->frame
);
648 case OB_FRAME_CONTEXT_SHADE
:
649 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
650 framerender_frame(client
->frame
);
653 /* nothing changes with clicks for any other contexts */
660 ob_debug("FocusIn on client for %lx\n", client
->window
);
662 if (client
!= focus_client
) {
663 focus_set_client(client
);
664 frame_adjust_focus(client
->frame
, TRUE
);
669 ob_debug("FocusOut on client for %lx\n", client
->window
);
671 /* are we a fullscreen window or a transient of one? (checks layer)
672 if we are then we need to be iconified since we are losing focus
674 if (client
->layer
== OB_STACKING_LAYER_FULLSCREEN
&& !client
->iconic
&&
675 !client_search_focus_tree_full(client
))
676 /* iconify fullscreen windows when they and their transients
678 client_iconify(client
, TRUE
, TRUE
);
679 frame_adjust_focus(client
->frame
, FALSE
);
682 con
= frame_context(client
, e
->xcrossing
.window
);
684 case OB_FRAME_CONTEXT_MAXIMIZE
:
685 client
->frame
->max_hover
= FALSE
;
686 frame_adjust_state(client
->frame
);
688 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
689 client
->frame
->desk_hover
= FALSE
;
690 frame_adjust_state(client
->frame
);
692 case OB_FRAME_CONTEXT_SHADE
:
693 client
->frame
->shade_hover
= FALSE
;
694 frame_adjust_state(client
->frame
);
696 case OB_FRAME_CONTEXT_ICONIFY
:
697 client
->frame
->iconify_hover
= FALSE
;
698 frame_adjust_state(client
->frame
);
700 case OB_FRAME_CONTEXT_CLOSE
:
701 client
->frame
->close_hover
= FALSE
;
702 frame_adjust_state(client
->frame
);
709 con
= frame_context(client
, e
->xcrossing
.window
);
711 case OB_FRAME_CONTEXT_MAXIMIZE
:
712 client
->frame
->max_hover
= TRUE
;
713 frame_adjust_state(client
->frame
);
715 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
716 client
->frame
->desk_hover
= TRUE
;
717 frame_adjust_state(client
->frame
);
719 case OB_FRAME_CONTEXT_SHADE
:
720 client
->frame
->shade_hover
= TRUE
;
721 frame_adjust_state(client
->frame
);
723 case OB_FRAME_CONTEXT_ICONIFY
:
724 client
->frame
->iconify_hover
= TRUE
;
725 frame_adjust_state(client
->frame
);
727 case OB_FRAME_CONTEXT_CLOSE
:
728 client
->frame
->close_hover
= TRUE
;
729 frame_adjust_state(client
->frame
);
731 case OB_FRAME_CONTEXT_FRAME
:
732 if (client_normal(client
)) {
733 if (ob_state() == OB_STATE_STARTING
) {
734 /* move it to the top of the focus order */
735 guint desktop
= client
->desktop
;
736 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
737 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
739 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
741 } else if (config_focus_follow
) {
743 ob_debug("EnterNotify on %lx, focusing window\n",
746 client_focus(client
);
754 case ConfigureRequest
:
756 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
757 ConfigureRequest
, &ce
)) {
759 /* XXX if this causes bad things.. we can compress config req's
760 with the same mask. */
761 e
->xconfigurerequest
.value_mask
|=
762 ce
.xconfigurerequest
.value_mask
;
763 if (ce
.xconfigurerequest
.value_mask
& CWX
)
764 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
765 if (ce
.xconfigurerequest
.value_mask
& CWY
)
766 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
767 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
768 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
769 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
770 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
771 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
772 e
->xconfigurerequest
.border_width
=
773 ce
.xconfigurerequest
.border_width
;
774 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
775 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
778 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
779 if (client
->iconic
|| client
->shaded
) return;
781 /* resize, then move, as specified in the EWMH section 7.7 */
782 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
788 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
789 client
->border_width
= e
->xconfigurerequest
.border_width
;
791 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
792 e
->xconfigurerequest
.x
: client
->area
.x
;
793 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
794 e
->xconfigurerequest
.y
: client
->area
.y
;
795 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
796 e
->xconfigurerequest
.width
: client
->area
.width
;
797 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
798 e
->xconfigurerequest
.height
: client
->area
.height
;
804 client
->frame
->size
.left
+ client
->frame
->size
.right
;
806 client
->frame
->size
.top
+ client
->frame
->size
.bottom
;
807 client_find_onscreen(client
, &newx
, &newy
, fw
, fh
,
808 client_normal(client
));
809 if (e
->xconfigurerequest
.value_mask
& CWX
)
811 if (e
->xconfigurerequest
.value_mask
& CWY
)
815 switch (client
->gravity
) {
816 case NorthEastGravity
:
818 corner
= OB_CORNER_TOPRIGHT
;
820 case SouthWestGravity
:
822 corner
= OB_CORNER_BOTTOMLEFT
;
824 case SouthEastGravity
:
825 corner
= OB_CORNER_BOTTOMRIGHT
;
827 default: /* NorthWest, Static, etc */
828 corner
= OB_CORNER_TOPLEFT
;
831 client_configure_full(client
, corner
, x
, y
, w
, h
, FALSE
, TRUE
,
835 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
836 switch (e
->xconfigurerequest
.detail
) {
839 stacking_lower(CLIENT_AS_WINDOW(client
));
845 stacking_raise(CLIENT_AS_WINDOW(client
));
851 if (client
->ignore_unmaps
) {
852 client
->ignore_unmaps
--;
855 client_unmanage(client
);
858 client_unmanage(client
);
861 /* this is when the client is first taken captive in the frame */
862 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
865 This event is quite rare and is usually handled in unmapHandler.
866 However, if the window is unmapped when the reparent event occurs,
867 the window manager never sees it because an unmap event is not sent
868 to an already unmapped window.
871 /* we don't want the reparent event, put it back on the stack for the
872 X server to deal with after we unmanage the window */
873 XPutBackEvent(ob_display
, e
);
875 client_unmanage(client
);
878 ob_debug("MapRequest for 0x%lx\n", client
->window
);
879 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
880 does, we don't want it! */
881 if (screen_showing_desktop
)
882 screen_show_desktop(FALSE
);
883 client_iconify(client
, FALSE
, TRUE
);
884 if (!client
->frame
->visible
)
885 /* if its not visible still, then don't mess with it */
888 client_shade(client
, FALSE
);
889 client_focus(client
);
890 stacking_raise(CLIENT_AS_WINDOW(client
));
893 /* validate cuz we query stuff off the client here */
894 if (!client_validate(client
)) break;
896 if (e
->xclient
.format
!= 32) return;
898 msgtype
= e
->xclient
.message_type
;
899 if (msgtype
== prop_atoms
.wm_change_state
) {
900 /* compress changes into a single change */
901 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
902 client
->window
, &ce
)) {
903 /* XXX: it would be nice to compress ALL messages of a
904 type, not just messages in a row without other
905 message types between. */
906 if (ce
.xclient
.message_type
!= msgtype
) {
907 XPutBackEvent(ob_display
, &ce
);
910 e
->xclient
= ce
.xclient
;
912 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
913 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
914 /* compress changes into a single change */
915 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
916 client
->window
, &ce
)) {
917 /* XXX: it would be nice to compress ALL messages of a
918 type, not just messages in a row without other
919 message types between. */
920 if (ce
.xclient
.message_type
!= msgtype
) {
921 XPutBackEvent(ob_display
, &ce
);
924 e
->xclient
= ce
.xclient
;
926 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
927 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
928 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
930 } else if (msgtype
== prop_atoms
.net_wm_state
) {
931 /* can't compress these */
932 ob_debug("net_wm_state %s %ld %ld for 0x%lx\n",
933 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
934 e
->xclient
.data
.l
[0] == 1 ? "Add" :
935 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
936 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
938 client_set_state(client
, e
->xclient
.data
.l
[0],
939 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
940 } else if (msgtype
== prop_atoms
.net_close_window
) {
941 ob_debug("net_close_window for 0x%lx\n", client
->window
);
942 client_close(client
);
943 } else if (msgtype
== prop_atoms
.net_active_window
) {
944 ob_debug("net_active_window for 0x%lx\n", client
->window
);
945 client_activate(client
, FALSE
);
946 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
947 ob_debug("net_wm_moveresize for 0x%lx\n", client
->window
);
948 if ((Atom
)e
->xclient
.data
.l
[2] ==
949 prop_atoms
.net_wm_moveresize_size_topleft
||
950 (Atom
)e
->xclient
.data
.l
[2] ==
951 prop_atoms
.net_wm_moveresize_size_top
||
952 (Atom
)e
->xclient
.data
.l
[2] ==
953 prop_atoms
.net_wm_moveresize_size_topright
||
954 (Atom
)e
->xclient
.data
.l
[2] ==
955 prop_atoms
.net_wm_moveresize_size_right
||
956 (Atom
)e
->xclient
.data
.l
[2] ==
957 prop_atoms
.net_wm_moveresize_size_right
||
958 (Atom
)e
->xclient
.data
.l
[2] ==
959 prop_atoms
.net_wm_moveresize_size_bottomright
||
960 (Atom
)e
->xclient
.data
.l
[2] ==
961 prop_atoms
.net_wm_moveresize_size_bottom
||
962 (Atom
)e
->xclient
.data
.l
[2] ==
963 prop_atoms
.net_wm_moveresize_size_bottomleft
||
964 (Atom
)e
->xclient
.data
.l
[2] ==
965 prop_atoms
.net_wm_moveresize_size_left
||
966 (Atom
)e
->xclient
.data
.l
[2] ==
967 prop_atoms
.net_wm_moveresize_move
||
968 (Atom
)e
->xclient
.data
.l
[2] ==
969 prop_atoms
.net_wm_moveresize_size_keyboard
||
970 (Atom
)e
->xclient
.data
.l
[2] ==
971 prop_atoms
.net_wm_moveresize_move_keyboard
) {
973 moveresize_start(client
, e
->xclient
.data
.l
[0],
974 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
975 e
->xclient
.data
.l
[2]);
977 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
978 int oldg
= client
->gravity
;
979 int tmpg
, x
, y
, w
, h
;
981 if (e
->xclient
.data
.l
[0] & 0xff)
982 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
986 if (e
->xclient
.data
.l
[0] & 1 << 8)
987 x
= e
->xclient
.data
.l
[1];
990 if (e
->xclient
.data
.l
[0] & 1 << 9)
991 y
= e
->xclient
.data
.l
[2];
994 if (e
->xclient
.data
.l
[0] & 1 << 10)
995 w
= e
->xclient
.data
.l
[3];
997 w
= client
->area
.width
;
998 if (e
->xclient
.data
.l
[0] & 1 << 11)
999 h
= e
->xclient
.data
.l
[4];
1001 h
= client
->area
.height
;
1002 client
->gravity
= tmpg
;
1008 client
->frame
->size
.left
+ client
->frame
->size
.right
;
1010 client
->frame
->size
.top
+ client
->frame
->size
.bottom
;
1011 client_find_onscreen(client
, &newx
, &newy
, fw
, fh
,
1012 client_normal(client
));
1013 if (e
->xclient
.data
.l
[0] & 1 << 8)
1015 if (e
->xclient
.data
.l
[0] & 1 << 9)
1019 client_configure(client
, OB_CORNER_TOPLEFT
,
1020 x
, y
, w
, h
, FALSE
, TRUE
);
1022 client
->gravity
= oldg
;
1025 case PropertyNotify
:
1026 /* validate cuz we query stuff off the client here */
1027 if (!client_validate(client
)) break;
1029 /* compress changes to a single property into a single change */
1030 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
1031 client
->window
, &ce
)) {
1032 /* XXX: it would be nice to compress ALL changes to a property,
1033 not just changes in a row without other props between. */
1034 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
1035 XPutBackEvent(ob_display
, &ce
);
1040 msgtype
= e
->xproperty
.atom
;
1041 if (msgtype
== XA_WM_NORMAL_HINTS
) {
1042 client_update_normal_hints(client
);
1043 /* normal hints can make a window non-resizable */
1044 client_setup_decor_and_functions(client
);
1046 else if (msgtype
== XA_WM_HINTS
)
1047 client_update_wmhints(client
);
1048 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
1049 client_update_transient_for(client
);
1050 client_get_type(client
);
1051 /* type may have changed, so update the layer */
1052 client_calc_layer(client
);
1053 client_setup_decor_and_functions(client
);
1055 else if (msgtype
== prop_atoms
.net_wm_name
||
1056 msgtype
== prop_atoms
.wm_name
||
1057 msgtype
== prop_atoms
.net_wm_icon_name
||
1058 msgtype
== prop_atoms
.wm_icon_name
)
1059 client_update_title(client
);
1060 else if (msgtype
== prop_atoms
.wm_class
)
1061 client_update_class(client
);
1062 else if (msgtype
== prop_atoms
.wm_protocols
) {
1063 client_update_protocols(client
);
1064 client_setup_decor_and_functions(client
);
1066 else if (msgtype
== prop_atoms
.net_wm_strut
) {
1067 client_update_strut(client
);
1069 else if (msgtype
== prop_atoms
.net_wm_icon
||
1070 msgtype
== prop_atoms
.kwm_win_icon
)
1071 client_update_icons(client
);
1075 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
1076 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
1077 frame_adjust_shape(client
->frame
);
1083 void event_add_fd_handler(event_fd_handler
*h
) {
1084 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
1085 FD_SET(h
->fd
, &allset
);
1086 max_fd
= MAX(max_fd
, h
->fd
);
1089 static void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
1091 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
1094 static void find_max_fd()
1097 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
,
1099 max_fd
= MAX(x_fd
, tmpmax
);
1101 max_fd
= MAX(ice_fd
, max_fd
);
1105 void event_remove_fd(int n
)
1108 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
1112 static void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
1114 if (FD_ISSET( (int)n
, &selset
)) {
1115 event_fd_handler
*h
= (event_fd_handler
*)data
;
1116 g_assert(h
->fd
== (int)n
);
1117 h
->handler(h
->fd
, h
->data
);
1121 static void fd_event_handle()
1123 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
1126 static void event_handle_dock(ObDock
*s
, XEvent
*e
)
1130 stacking_raise(DOCK_AS_WINDOW(s
));
1141 static void event_handle_dockapp(ObDockApp
*app
, XEvent
*e
)
1145 dock_app_drag(app
, &e
->xmotion
);
1148 if (app
->ignore_unmaps
) {
1149 app
->ignore_unmaps
--;
1152 dock_remove(app
, TRUE
);
1155 dock_remove(app
, FALSE
);
1157 case ReparentNotify
:
1158 dock_remove(app
, FALSE
);
1160 case ConfigureNotify
:
1161 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);
1166 static void event_handle_menu(XEvent
*ev
)
1169 ObMenuEntryFrame
*e
;
1173 if (!(f
= menu_frame_under(ev
->xmotion
.x_root
,
1174 ev
->xmotion
.y_root
)))
1175 menu_frame_hide_all();
1177 if ((e
= menu_entry_frame_under(ev
->xmotion
.x_root
,
1178 ev
->xmotion
.y_root
)))
1179 menu_entry_frame_execute(e
);
1183 if ((f
= menu_frame_under(ev
->xmotion
.x_root
,
1184 ev
->xmotion
.y_root
))) {
1185 menu_frame_move_on_screen(f
);
1186 if ((e
= menu_entry_frame_under(ev
->xmotion
.x_root
,
1187 ev
->xmotion
.y_root
)))
1188 menu_frame_select(f
, e
);