13 #include "framerender.h"
15 #include "moveresize.h"
17 #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_dock(ObDock
*s
, XEvent
*e
);
45 static void event_handle_dockapp(ObDockApp
*app
, XEvent
*e
);
46 static void event_handle_client(ObClient
*c
, XEvent
*e
);
47 static void event_handle_menu(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
);
301 /* compress events */
304 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
306 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
307 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
314 static gboolean
event_ignore(XEvent
*e
, ObClient
*client
)
318 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
319 because of RevertToPointerRoot. If the focus ends up reverting to
320 pointer root on a workspace change, then the FocusIn event that we
321 want will be of type NotifyAncestor. This situation does not occur
322 for FocusOut, so it is safely ignored there.
324 if (INVALID_FOCUSIN(e
) ||
327 ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
328 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
330 /* says a client was not found for the event (or a valid FocusIn
333 e
->xfocus
.window
= None
;
338 ob_debug("FocusIn on %lx mode %d detail %d\n", e
->xfocus
.window
,
339 e
->xfocus
.mode
, e
->xfocus
.detail
);
343 if (INVALID_FOCUSOUT(e
)) {
345 ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n",
346 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
352 ob_debug("FocusOut on %lx mode %d detail %d\n",
353 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
358 gboolean fallback
= TRUE
;
361 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
362 e
->xfocus
.window
,&fe
))
363 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
365 if (fe
.type
== FocusOut
) {
367 ob_debug("found pending FocusOut");
369 if (!INVALID_FOCUSOUT(&fe
)) {
370 /* if there is a VALID FocusOut still coming, don't
371 fallback focus yet, we'll deal with it then */
372 XPutBackEvent(ob_display
, &fe
);
378 ob_debug("found pending FocusIn");
380 /* is the focused window getting a FocusOut/In back to
383 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
384 !event_ignore(&fe
, client
)) {
386 if focus_client is not set, then we can't do
387 this. we need the FocusIn. This happens in the
388 case when the set_focus_client(NULL) in the
389 focus_fallback function fires and then
390 focus_fallback picks the currently focused
391 window (such as on a SendToDesktop-esque action.
395 ob_debug("focused window got an Out/In back to "
396 "itself IGNORED both");
402 ob_debug("focused window got an Out/In back to "
403 "itself but focus_client was null "
404 "IGNORED just the Out");
410 /* once all the FocusOut's have been dealt with, if there
411 is a FocusIn still left and it is valid, then use it */
413 /* secret magic way of event_process telling us that no
414 client was found for the FocusIn event. ^_^ */
415 if (fe
.xfocus
.window
!= None
) {
423 ob_debug("no valid FocusIn and no FocusOut events found, "
426 focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS
);
432 /* NotifyUngrab occurs when a mouse button is released and the event is
433 caused, like when lowering a window */
434 /* NotifyVirtual occurs when ungrabbing the pointer */
435 if (e
->xcrossing
.mode
== NotifyGrab
||
436 e
->xcrossing
.detail
== NotifyInferior
||
437 (e
->xcrossing
.mode
== NotifyUngrab
&&
438 e
->xcrossing
.detail
== NotifyVirtual
)) {
440 ob_debug("%sNotify mode %d detail %d on %lx IGNORED",
441 (e
->type
== EnterNotify
? "Enter" : "Leave"),
443 e
->xcrossing
.detail
, client
?client
->window
:0);
448 ob_debug("%sNotify mode %d detail %d on %lx",
449 (e
->type
== EnterNotify
? "Enter" : "Leave"),
451 e
->xcrossing
.detail
, client
?client
->window
:0);
458 static void event_process(XEvent
*e
)
461 ObClient
*client
= NULL
;
463 ObDockApp
*dockapp
= NULL
;
465 ObWindow
*obwin
= NULL
;
467 window
= event_get_window(e
);
468 if ((obwin
= g_hash_table_lookup(window_map
, &window
))) {
469 switch (obwin
->type
) {
471 dock
= WINDOW_AS_DOCK(obwin
);
474 dockapp
= WINDOW_AS_DOCKAPP(obwin
);
477 menu
= WINDOW_AS_MENU(obwin
);
480 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
);
527 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
528 e
->type
== ButtonPress
||
529 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
530 event_handle_menu(client
, 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! */
545 /* user input (action-bound) events */
546 if (e
->type
== ButtonPress
|| e
->type
== ButtonRelease
||
547 e
->type
== MotionNotify
|| e
->type
== KeyPress
||
548 e
->type
== KeyRelease
)
550 ObFrameContext context
;
552 context
= frame_context(client
, e
->xany
.window
);
554 if (!keyboard_process_interactive_grab(e
, &client
, &context
)) {
556 if (e
->type
== ButtonPress
|| e
->type
== ButtonRelease
||
557 e
->type
== MotionNotify
)
558 mouse_event(client
, context
, e
);
559 else if (e
->type
== KeyPress
)
560 keyboard_event(client
, e
);
564 /* dispatch the event to registered handlers */
565 dispatch_x(e
, client
);
568 static void event_handle_root(XEvent
*e
)
574 ob_debug("Another WM has requested to replace us. Exiting.\n");
579 if (e
->xclient
.format
!= 32) break;
581 msgtype
= e
->xclient
.message_type
;
582 if (msgtype
== prop_atoms
.net_current_desktop
) {
583 unsigned int d
= e
->xclient
.data
.l
[0];
584 if (d
< screen_num_desktops
)
585 screen_set_desktop(d
);
586 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
587 unsigned int d
= e
->xclient
.data
.l
[0];
589 screen_set_num_desktops(d
);
590 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
591 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
595 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
596 screen_update_desktop_names();
597 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
598 screen_update_layout();
600 case ConfigureNotify
:
602 XRRUpdateConfiguration(e
);
609 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
610 ob_debug("VIDMODE EVENT\n");
616 static void event_handle_client(ObClient
*client
, XEvent
*e
)
624 case VisibilityNotify
:
625 client
->frame
->obscured
= e
->xvisibility
.state
!= VisibilityUnobscured
;
629 /* Wheel buttons don't draw because they are an instant click, so it
630 is a waste of resources to go drawing it. */
631 if (!(e
->xbutton
.button
== 4 || e
->xbutton
.button
== 5)) {
632 switch (frame_context(client
, e
->xbutton
.window
)) {
633 case OB_FRAME_CONTEXT_MAXIMIZE
:
634 client
->frame
->max_press
= (e
->type
== ButtonPress
);
635 framerender_frame(client
->frame
);
637 case OB_FRAME_CONTEXT_CLOSE
:
638 client
->frame
->close_press
= (e
->type
== ButtonPress
);
639 framerender_frame(client
->frame
);
641 case OB_FRAME_CONTEXT_ICONIFY
:
642 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
643 framerender_frame(client
->frame
);
645 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
646 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
647 framerender_frame(client
->frame
);
649 case OB_FRAME_CONTEXT_SHADE
:
650 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
651 framerender_frame(client
->frame
);
654 /* nothing changes with clicks for any other contexts */
661 ob_debug("FocusIn on client for %lx\n", client
->window
);
663 if (client
!= focus_client
) {
664 focus_set_client(client
);
665 frame_adjust_focus(client
->frame
, TRUE
);
670 ob_debug("FocusOut on client for %lx\n", client
->window
);
672 /* are we a fullscreen window or a transient of one? (checks layer)
673 if we are then we need to be iconified since we are losing focus
675 if (client
->layer
== OB_STACKING_LAYER_FULLSCREEN
&& !client
->iconic
&&
676 !client_search_focus_tree_full(client
))
677 /* iconify fullscreen windows when they and their transients
679 client_iconify(client
, TRUE
, TRUE
);
680 frame_adjust_focus(client
->frame
, FALSE
);
683 con
= frame_context(client
, e
->xcrossing
.window
);
685 case OB_FRAME_CONTEXT_MAXIMIZE
:
686 client
->frame
->max_hover
= FALSE
;
687 frame_adjust_state(client
->frame
);
689 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
690 client
->frame
->desk_hover
= FALSE
;
691 frame_adjust_state(client
->frame
);
693 case OB_FRAME_CONTEXT_SHADE
:
694 client
->frame
->shade_hover
= FALSE
;
695 frame_adjust_state(client
->frame
);
697 case OB_FRAME_CONTEXT_ICONIFY
:
698 client
->frame
->iconify_hover
= FALSE
;
699 frame_adjust_state(client
->frame
);
701 case OB_FRAME_CONTEXT_CLOSE
:
702 client
->frame
->close_hover
= FALSE
;
703 frame_adjust_state(client
->frame
);
710 con
= frame_context(client
, e
->xcrossing
.window
);
712 case OB_FRAME_CONTEXT_MAXIMIZE
:
713 client
->frame
->max_hover
= TRUE
;
714 frame_adjust_state(client
->frame
);
716 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
717 client
->frame
->desk_hover
= TRUE
;
718 frame_adjust_state(client
->frame
);
720 case OB_FRAME_CONTEXT_SHADE
:
721 client
->frame
->shade_hover
= TRUE
;
722 frame_adjust_state(client
->frame
);
724 case OB_FRAME_CONTEXT_ICONIFY
:
725 client
->frame
->iconify_hover
= TRUE
;
726 frame_adjust_state(client
->frame
);
728 case OB_FRAME_CONTEXT_CLOSE
:
729 client
->frame
->close_hover
= TRUE
;
730 frame_adjust_state(client
->frame
);
732 case OB_FRAME_CONTEXT_FRAME
:
733 if (client_normal(client
)) {
734 if (ob_state() == OB_STATE_STARTING
) {
735 /* move it to the top of the focus order */
736 guint desktop
= client
->desktop
;
737 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
738 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
740 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
742 } else if (config_focus_follow
) {
744 ob_debug("EnterNotify on %lx, focusing window\n",
747 client_focus(client
);
755 case ConfigureRequest
:
757 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
758 ConfigureRequest
, &ce
)) {
760 /* XXX if this causes bad things.. we can compress config req's
761 with the same mask. */
762 e
->xconfigurerequest
.value_mask
|=
763 ce
.xconfigurerequest
.value_mask
;
764 if (ce
.xconfigurerequest
.value_mask
& CWX
)
765 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
766 if (ce
.xconfigurerequest
.value_mask
& CWY
)
767 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
768 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
769 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
770 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
771 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
772 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
773 e
->xconfigurerequest
.border_width
=
774 ce
.xconfigurerequest
.border_width
;
775 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
776 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
779 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
780 if (client
->iconic
|| client
->shaded
) return;
782 /* resize, then move, as specified in the EWMH section 7.7 */
783 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
789 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
790 client
->border_width
= e
->xconfigurerequest
.border_width
;
792 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
793 e
->xconfigurerequest
.x
: client
->area
.x
;
794 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
795 e
->xconfigurerequest
.y
: client
->area
.y
;
796 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
797 e
->xconfigurerequest
.width
: client
->area
.width
;
798 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
799 e
->xconfigurerequest
.height
: client
->area
.height
;
805 client
->frame
->size
.left
+ client
->frame
->size
.right
;
807 client
->frame
->size
.top
+ client
->frame
->size
.bottom
;
808 client_find_onscreen(client
, &newx
, &newy
, fw
, fh
, TRUE
);
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
, TRUE
);
1012 if (e
->xclient
.data
.l
[0] & 1 << 8)
1014 if (e
->xclient
.data
.l
[0] & 1 << 9)
1018 client_configure(client
, OB_CORNER_TOPLEFT
,
1019 x
, y
, w
, h
, FALSE
, TRUE
);
1021 client
->gravity
= oldg
;
1024 case PropertyNotify
:
1025 /* validate cuz we query stuff off the client here */
1026 if (!client_validate(client
)) break;
1028 /* compress changes to a single property into a single change */
1029 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
1030 client
->window
, &ce
)) {
1031 /* XXX: it would be nice to compress ALL changes to a property,
1032 not just changes in a row without other props between. */
1033 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
1034 XPutBackEvent(ob_display
, &ce
);
1039 msgtype
= e
->xproperty
.atom
;
1040 if (msgtype
== XA_WM_NORMAL_HINTS
) {
1041 client_update_normal_hints(client
);
1042 /* normal hints can make a window non-resizable */
1043 client_setup_decor_and_functions(client
);
1045 else if (msgtype
== XA_WM_HINTS
)
1046 client_update_wmhints(client
);
1047 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
1048 client_update_transient_for(client
);
1049 client_get_type(client
);
1050 /* type may have changed, so update the layer */
1051 client_calc_layer(client
);
1052 client_setup_decor_and_functions(client
);
1054 else if (msgtype
== prop_atoms
.net_wm_name
||
1055 msgtype
== prop_atoms
.wm_name
||
1056 msgtype
== prop_atoms
.net_wm_icon_name
||
1057 msgtype
== prop_atoms
.wm_icon_name
)
1058 client_update_title(client
);
1059 else if (msgtype
== prop_atoms
.wm_class
)
1060 client_update_class(client
);
1061 else if (msgtype
== prop_atoms
.wm_protocols
) {
1062 client_update_protocols(client
);
1063 client_setup_decor_and_functions(client
);
1065 else if (msgtype
== prop_atoms
.net_wm_strut
) {
1066 client_update_strut(client
);
1068 else if (msgtype
== prop_atoms
.net_wm_icon
||
1069 msgtype
== prop_atoms
.kwm_win_icon
)
1070 client_update_icons(client
);
1074 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
1075 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
1076 frame_adjust_shape(client
->frame
);
1082 static void event_handle_menu(ObClient
*client
, XEvent
*e
)
1088 top
= g_list_nth_data(menu_visible
, 0);
1090 ob_debug("EVENT %d\n", e
->type
);
1093 menu_control_keyboard_nav(e
->xkey
.keycode
);
1096 ob_debug("BUTTON PRESS\n");
1100 ob_debug("BUTTON RELEASED\n");
1102 for (it
= menu_visible
; it
; it
= g_list_next(it
)) {
1103 ObMenu
*m
= it
->data
;
1104 if (e
->xbutton
.x_root
>= m
->location
.x
- ob_rr_theme
->bwidth
&&
1105 e
->xbutton
.y_root
>= m
->location
.y
- ob_rr_theme
->bwidth
&&
1106 e
->xbutton
.x_root
< m
->location
.x
+ m
->size
.width
+
1107 ob_rr_theme
->bwidth
&&
1108 e
->xbutton
.y_root
< m
->location
.y
+ m
->size
.height
+
1109 ob_rr_theme
->bwidth
) {
1110 if ((entry
= menu_find_entry_by_pos(it
->data
,
1115 m
->selected(entry
, e
->xbutton
.button
,
1124 /* will call the menu_hide() for each submenu as well */
1126 menu_control_keyboard_nav(ob_keycode(OB_KEY_ESCAPE
));
1130 ob_debug("motion\n");
1131 for (it
= menu_visible
; it
; it
= g_list_next(it
)) {
1132 ObMenu
*m
= it
->data
;
1133 if ((entry
= menu_find_entry_by_pos(it
->data
,
1138 if (m
->over
&& m
->over
->data
!= entry
)
1139 m
->mouseover(m
->over
->data
, FALSE
);
1141 m
->mouseover(entry
, TRUE
);
1150 void event_add_fd_handler(event_fd_handler
*h
) {
1151 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
1152 FD_SET(h
->fd
, &allset
);
1153 max_fd
= MAX(max_fd
, h
->fd
);
1156 static void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
1158 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
1161 static void find_max_fd()
1164 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
,
1166 max_fd
= MAX(x_fd
, tmpmax
);
1168 max_fd
= MAX(ice_fd
, max_fd
);
1172 void event_remove_fd(int n
)
1175 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
1179 static void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
1181 if (FD_ISSET( (int)n
, &selset
)) {
1182 event_fd_handler
*h
= (event_fd_handler
*)data
;
1183 g_assert(h
->fd
== (int)n
);
1184 h
->handler(h
->fd
, h
->data
);
1188 static void fd_event_handle()
1190 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
1193 static void event_handle_dock(ObDock
*s
, XEvent
*e
)
1197 stacking_raise(DOCK_AS_WINDOW(s
));
1208 static void event_handle_dockapp(ObDockApp
*app
, XEvent
*e
)
1212 dock_app_drag(app
, &e
->xmotion
);
1215 if (app
->ignore_unmaps
) {
1216 app
->ignore_unmaps
--;
1219 dock_remove(app
, TRUE
);
1222 dock_remove(app
, FALSE
);
1224 case ReparentNotify
:
1225 dock_remove(app
, FALSE
);
1227 case ConfigureNotify
:
1228 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);