11 #include "menuframe.h"
15 #include "framerender.h"
17 #include "moveresize.h"
19 #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(const XEvent
*e
, gpointer data
);
43 static void event_handle_root(XEvent
*e
);
44 static void event_handle_menu(XEvent
*e
);
45 static void event_handle_dock(ObDock
*s
, XEvent
*e
);
46 static void event_handle_dockapp(ObDockApp
*app
, XEvent
*e
);
47 static void event_handle_client(ObClient
*c
, XEvent
*e
);
49 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
50 (e)->xfocus.detail == NotifyAncestor || \
51 (e)->xfocus.detail > NotifyNonlinearVirtual)
52 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
53 (e)->xfocus.detail == NotifyInferior || \
54 (e)->xfocus.detail == NotifyAncestor || \
55 (e)->xfocus.detail > NotifyNonlinearVirtual)
57 Time event_lasttime
= 0;
59 /*! The value of the mask for the NumLock modifier */
60 unsigned int NumLockMask
;
61 /*! The value of the mask for the ScrollLock modifier */
62 unsigned int ScrollLockMask
;
63 /*! The key codes for the modifier keys */
64 static XModifierKeymap
*modmap
;
65 /*! Table of the constant modifier masks */
66 static const int mask_table
[] = {
67 ShiftMask
, LockMask
, ControlMask
, Mod1Mask
,
68 Mod2Mask
, Mod3Mask
, Mod4Mask
, Mod5Mask
70 static int mask_table_size
;
73 static void ice_handler(int fd
, gpointer conn
)
76 IceProcessMessages(conn
, NULL
, &b
);
79 static void ice_watch(IceConn conn
, IcePointer data
, Bool opening
,
80 IcePointer
*watch_data
)
85 fd
= IceConnectionNumber(conn
);
86 ob_main_loop_fd_add(ob_main_loop
, fd
, ice_handler
, conn
, NULL
);
88 ob_main_loop_fd_remove(ob_main_loop
, fd
);
95 static void sn_handler(const XEvent
*e
, gpointer display
)
99 sn_display_process_event(display
, &ec
);
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
];
131 ob_main_loop_x_add(ob_main_loop
, event_process
, NULL
, NULL
);
134 IceAddConnectionWatch(ice_watch
, NULL
);
138 ob_main_loop_x_add(ob_main_loop
, sn_handler
, ob_sn_display
, NULL
);
142 void event_shutdown()
144 XFreeModifiermap(modmap
);
147 static Window
event_get_window(XEvent
*e
)
154 window
= RootWindow(ob_display
, ob_screen
);
157 window
= e
->xmap
.window
;
160 window
= e
->xunmap
.window
;
163 window
= e
->xdestroywindow
.window
;
165 case ConfigureRequest
:
166 window
= e
->xconfigurerequest
.window
;
168 case ConfigureNotify
:
169 window
= e
->xconfigure
.window
;
173 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
174 switch (((XkbAnyEvent
*)e
)->xkb_type
) {
176 window
= ((XkbBellNotifyEvent
*)e
)->window
;
182 window
= e
->xany
.window
;
187 static void event_set_lasttime(XEvent
*e
)
191 /* grab the lasttime and hack up the state */
207 t
= e
->xproperty
.time
;
211 t
= e
->xcrossing
.time
;
214 /* if more event types are anticipated, get their timestamp
219 if (t
> event_lasttime
)
223 #define STRIP_MODS(s) \
224 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
225 /* kill off the Button1Mask etc, only want the modifiers */ \
226 s &= (ControlMask | ShiftMask | Mod1Mask | \
227 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
229 static void event_hack_mods(XEvent *e)
237 STRIP_MODS(e
->xbutton
.state
);
240 STRIP_MODS(e
->xkey
.state
);
243 STRIP_MODS(e
->xkey
.state
);
244 /* remove from the state the mask of the modifier being released, if
245 it is a modifier key being released (this is a little ugly..) */
246 kp
= modmap
->modifiermap
;
247 for (i
= 0; i
< mask_table_size
; ++i
) {
248 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
249 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
250 /* remove the mask for it */
251 e
->xkey
.state
&= ~mask_table
[i
];
252 /* cause the first loop to break; */
254 break; /* get outta here! */
261 STRIP_MODS(e
->xmotion
.state
);
262 /* compress events */
265 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
267 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
268 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
275 static gboolean
event_ignore(XEvent
*e
, ObClient
*client
)
279 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
280 because of RevertToPointerRoot. If the focus ends up reverting to
281 pointer root on a workspace change, then the FocusIn event that we
282 want will be of type NotifyAncestor. This situation does not occur
283 for FocusOut, so it is safely ignored there.
285 if (INVALID_FOCUSIN(e
) ||
288 ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
289 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
291 /* says a client was not found for the event (or a valid FocusIn
294 e
->xfocus
.window
= None
;
299 ob_debug("FocusIn on %lx mode %d detail %d\n", e
->xfocus
.window
,
300 e
->xfocus
.mode
, e
->xfocus
.detail
);
304 if (INVALID_FOCUSOUT(e
)) {
306 ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n",
307 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
313 ob_debug("FocusOut on %lx mode %d detail %d\n",
314 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
319 gboolean fallback
= TRUE
;
322 if (!XCheckTypedWindowEvent(ob_display
, e
->xfocus
.window
,
324 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
326 if (fe
.type
== FocusOut
) {
328 ob_debug("found pending FocusOut");
330 if (!INVALID_FOCUSOUT(&fe
)) {
331 /* if there is a VALID FocusOut still coming, don't
332 fallback focus yet, we'll deal with it then */
333 XPutBackEvent(ob_display
, &fe
);
339 ob_debug("found pending FocusIn");
341 /* is the focused window getting a FocusOut/In back to
344 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
345 !event_ignore(&fe
, client
)) {
347 if focus_client is not set, then we can't do
348 this. we need the FocusIn. This happens in the
349 case when the set_focus_client(NULL) in the
350 focus_fallback function fires and then
351 focus_fallback picks the currently focused
352 window (such as on a SendToDesktop-esque action.
356 ob_debug("focused window got an Out/In back to "
357 "itself IGNORED both");
361 event_process(&fe
, NULL
);
363 ob_debug("focused window got an Out/In back to "
364 "itself but focus_client was null "
365 "IGNORED just the Out");
371 /* once all the FocusOut's have been dealt with, if there
372 is a FocusIn still left and it is valid, then use it */
373 event_process(&fe
, NULL
);
374 /* secret magic way of event_process telling us that no
375 client was found for the FocusIn event. ^_^ */
376 if (fe
.xfocus
.window
!= None
) {
384 ob_debug("no valid FocusIn and no FocusOut events found, "
387 focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS
);
393 /* NotifyUngrab occurs when a mouse button is released and the event is
394 caused, like when lowering a window */
395 /* NotifyVirtual occurs when ungrabbing the pointer */
396 if (e
->xcrossing
.mode
== NotifyGrab
||
397 e
->xcrossing
.detail
== NotifyInferior
||
398 (e
->xcrossing
.mode
== NotifyUngrab
&&
399 e
->xcrossing
.detail
== NotifyVirtual
)) {
401 ob_debug("%sNotify mode %d detail %d on %lx IGNORED",
402 (e
->type
== EnterNotify
? "Enter" : "Leave"),
404 e
->xcrossing
.detail
, client
?client
->window
:0);
409 ob_debug("%sNotify mode %d detail %d on %lx",
410 (e
->type
== EnterNotify
? "Enter" : "Leave"),
412 e
->xcrossing
.detail
, client
?client
->window
:0);
419 static void event_process(const XEvent
*ec
, gpointer data
)
422 ObClient
*client
= NULL
;
424 ObDockApp
*dockapp
= NULL
;
425 ObWindow
*obwin
= NULL
;
428 /* make a copy we can mangle */
432 g_message("Event %d", e
->type
);
434 window
= event_get_window(e
);
435 if ((obwin
= g_hash_table_lookup(window_map
, &window
))) {
436 switch (obwin
->type
) {
438 dock
= WINDOW_AS_DOCK(obwin
);
441 dockapp
= WINDOW_AS_DOCKAPP(obwin
);
444 client
= WINDOW_AS_CLIENT(obwin
);
447 case Window_Internal
:
448 /* not to be used for events */
449 g_assert_not_reached();
454 event_set_lasttime(e
);
456 if (event_ignore(e
, client
))
459 /* deal with it in the kernel */
461 event_handle_client(client
, e
);
463 event_handle_dockapp(dockapp
, e
);
465 event_handle_dock(dock
, e
);
466 else if (window
== RootWindow(ob_display
, ob_screen
))
467 event_handle_root(e
);
468 else if (e
->type
== MapRequest
)
469 client_manage(window
);
470 else if (e
->type
== ConfigureRequest
) {
471 /* unhandled configure requests must be used to configure the
475 xwc
.x
= e
->xconfigurerequest
.x
;
476 xwc
.y
= e
->xconfigurerequest
.y
;
477 xwc
.width
= e
->xconfigurerequest
.width
;
478 xwc
.height
= e
->xconfigurerequest
.height
;
479 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
480 xwc
.sibling
= e
->xconfigurerequest
.above
;
481 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
483 /* we are not to be held responsible if someone sends us an
485 xerror_set_ignore(TRUE
);
486 XConfigureWindow(ob_display
, window
,
487 e
->xconfigurerequest
.value_mask
, &xwc
);
488 xerror_set_ignore(FALSE
);
491 /* user input (action-bound) events */
492 if (e
->type
== ButtonPress
|| e
->type
== ButtonRelease
||
493 e
->type
== MotionNotify
|| e
->type
== KeyPress
||
494 e
->type
== KeyRelease
)
496 if (menu_frame_visible
)
497 event_handle_menu(e
);
498 else if (moveresize_in_progress
)
501 ObFrameContext context
;
503 context
= frame_context(client
, e
->xany
.window
);
505 if (!keyboard_process_interactive_grab(e
, &client
, &context
)) {
506 if (e
->type
== ButtonPress
|| e
->type
== ButtonRelease
||
507 e
->type
== MotionNotify
)
508 mouse_event(client
, context
, e
);
509 else if (e
->type
== KeyPress
)
510 keyboard_event(client
, e
);
516 static void event_handle_root(XEvent
*e
)
522 ob_debug("Another WM has requested to replace us. Exiting.\n");
527 if (e
->xclient
.format
!= 32) break;
529 msgtype
= e
->xclient
.message_type
;
530 if (msgtype
== prop_atoms
.net_current_desktop
) {
531 unsigned int d
= e
->xclient
.data
.l
[0];
532 if (d
< screen_num_desktops
)
533 screen_set_desktop(d
);
534 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
535 unsigned int d
= e
->xclient
.data
.l
[0];
537 screen_set_num_desktops(d
);
538 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
539 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
543 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
544 screen_update_desktop_names();
545 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
546 screen_update_layout();
548 case ConfigureNotify
:
550 XRRUpdateConfiguration(e
);
557 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
558 ob_debug("VIDMODE EVENT\n");
564 static void event_handle_client(ObClient
*client
, XEvent
*e
)
572 case VisibilityNotify
:
573 client
->frame
->obscured
= e
->xvisibility
.state
!= VisibilityUnobscured
;
577 /* Wheel buttons don't draw because they are an instant click, so it
578 is a waste of resources to go drawing it. */
579 if (!(e
->xbutton
.button
== 4 || e
->xbutton
.button
== 5)) {
580 switch (frame_context(client
, e
->xbutton
.window
)) {
581 case OB_FRAME_CONTEXT_MAXIMIZE
:
582 client
->frame
->max_press
= (e
->type
== ButtonPress
);
583 framerender_frame(client
->frame
);
585 case OB_FRAME_CONTEXT_CLOSE
:
586 client
->frame
->close_press
= (e
->type
== ButtonPress
);
587 framerender_frame(client
->frame
);
589 case OB_FRAME_CONTEXT_ICONIFY
:
590 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
591 framerender_frame(client
->frame
);
593 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
594 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
595 framerender_frame(client
->frame
);
597 case OB_FRAME_CONTEXT_SHADE
:
598 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
599 framerender_frame(client
->frame
);
602 /* nothing changes with clicks for any other contexts */
609 ob_debug("FocusIn on client for %lx\n", client
->window
);
611 if (client
!= focus_client
) {
612 focus_set_client(client
);
613 frame_adjust_focus(client
->frame
, TRUE
);
618 ob_debug("FocusOut on client for %lx\n", client
->window
);
620 /* are we a fullscreen window or a transient of one? (checks layer)
621 if we are then we need to be iconified since we are losing focus
623 if (client
->layer
== OB_STACKING_LAYER_FULLSCREEN
&& !client
->iconic
&&
624 !client_search_focus_tree_full(client
))
625 /* iconify fullscreen windows when they and their transients
627 client_iconify(client
, TRUE
, TRUE
);
628 frame_adjust_focus(client
->frame
, FALSE
);
631 con
= frame_context(client
, e
->xcrossing
.window
);
633 case OB_FRAME_CONTEXT_MAXIMIZE
:
634 client
->frame
->max_hover
= FALSE
;
635 frame_adjust_state(client
->frame
);
637 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
638 client
->frame
->desk_hover
= FALSE
;
639 frame_adjust_state(client
->frame
);
641 case OB_FRAME_CONTEXT_SHADE
:
642 client
->frame
->shade_hover
= FALSE
;
643 frame_adjust_state(client
->frame
);
645 case OB_FRAME_CONTEXT_ICONIFY
:
646 client
->frame
->iconify_hover
= FALSE
;
647 frame_adjust_state(client
->frame
);
649 case OB_FRAME_CONTEXT_CLOSE
:
650 client
->frame
->close_hover
= FALSE
;
651 frame_adjust_state(client
->frame
);
658 con
= frame_context(client
, e
->xcrossing
.window
);
660 case OB_FRAME_CONTEXT_MAXIMIZE
:
661 client
->frame
->max_hover
= TRUE
;
662 frame_adjust_state(client
->frame
);
664 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
665 client
->frame
->desk_hover
= TRUE
;
666 frame_adjust_state(client
->frame
);
668 case OB_FRAME_CONTEXT_SHADE
:
669 client
->frame
->shade_hover
= TRUE
;
670 frame_adjust_state(client
->frame
);
672 case OB_FRAME_CONTEXT_ICONIFY
:
673 client
->frame
->iconify_hover
= TRUE
;
674 frame_adjust_state(client
->frame
);
676 case OB_FRAME_CONTEXT_CLOSE
:
677 client
->frame
->close_hover
= TRUE
;
678 frame_adjust_state(client
->frame
);
680 case OB_FRAME_CONTEXT_FRAME
:
681 if (client_normal(client
)) {
682 if (ob_state() == OB_STATE_STARTING
) {
683 /* move it to the top of the focus order */
684 guint desktop
= client
->desktop
;
685 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
686 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
688 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
690 } else if (config_focus_follow
) {
692 ob_debug("EnterNotify on %lx, focusing window\n",
695 client_focus(client
);
703 case ConfigureRequest
:
705 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
706 ConfigureRequest
, &ce
)) {
708 /* XXX if this causes bad things.. we can compress config req's
709 with the same mask. */
710 e
->xconfigurerequest
.value_mask
|=
711 ce
.xconfigurerequest
.value_mask
;
712 if (ce
.xconfigurerequest
.value_mask
& CWX
)
713 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
714 if (ce
.xconfigurerequest
.value_mask
& CWY
)
715 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
716 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
717 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
718 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
719 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
720 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
721 e
->xconfigurerequest
.border_width
=
722 ce
.xconfigurerequest
.border_width
;
723 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
724 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
727 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
728 if (client
->iconic
|| client
->shaded
) return;
730 /* resize, then move, as specified in the EWMH section 7.7 */
731 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
737 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
738 client
->border_width
= e
->xconfigurerequest
.border_width
;
740 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
741 e
->xconfigurerequest
.x
: client
->area
.x
;
742 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
743 e
->xconfigurerequest
.y
: client
->area
.y
;
744 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
745 e
->xconfigurerequest
.width
: client
->area
.width
;
746 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
747 e
->xconfigurerequest
.height
: client
->area
.height
;
753 client
->frame
->size
.left
+ client
->frame
->size
.right
;
755 client
->frame
->size
.top
+ client
->frame
->size
.bottom
;
756 client_find_onscreen(client
, &newx
, &newy
, fw
, fh
,
757 client_normal(client
));
758 if (e
->xconfigurerequest
.value_mask
& CWX
)
760 if (e
->xconfigurerequest
.value_mask
& CWY
)
764 switch (client
->gravity
) {
765 case NorthEastGravity
:
767 corner
= OB_CORNER_TOPRIGHT
;
769 case SouthWestGravity
:
771 corner
= OB_CORNER_BOTTOMLEFT
;
773 case SouthEastGravity
:
774 corner
= OB_CORNER_BOTTOMRIGHT
;
776 default: /* NorthWest, Static, etc */
777 corner
= OB_CORNER_TOPLEFT
;
780 client_configure_full(client
, corner
, x
, y
, w
, h
, FALSE
, TRUE
,
784 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
785 switch (e
->xconfigurerequest
.detail
) {
788 stacking_lower(CLIENT_AS_WINDOW(client
));
794 stacking_raise(CLIENT_AS_WINDOW(client
));
800 if (client
->ignore_unmaps
) {
801 client
->ignore_unmaps
--;
804 client_unmanage(client
);
807 client_unmanage(client
);
810 /* this is when the client is first taken captive in the frame */
811 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
814 This event is quite rare and is usually handled in unmapHandler.
815 However, if the window is unmapped when the reparent event occurs,
816 the window manager never sees it because an unmap event is not sent
817 to an already unmapped window.
820 /* we don't want the reparent event, put it back on the stack for the
821 X server to deal with after we unmanage the window */
822 XPutBackEvent(ob_display
, e
);
824 client_unmanage(client
);
827 ob_debug("MapRequest for 0x%lx\n", client
->window
);
828 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
829 does, we don't want it! */
830 if (screen_showing_desktop
)
831 screen_show_desktop(FALSE
);
832 client_iconify(client
, FALSE
, TRUE
);
833 if (!client
->frame
->visible
)
834 /* if its not visible still, then don't mess with it */
837 client_shade(client
, FALSE
);
838 client_focus(client
);
839 stacking_raise(CLIENT_AS_WINDOW(client
));
842 /* validate cuz we query stuff off the client here */
843 if (!client_validate(client
)) break;
845 if (e
->xclient
.format
!= 32) return;
847 msgtype
= e
->xclient
.message_type
;
848 if (msgtype
== prop_atoms
.wm_change_state
) {
849 /* compress changes into a single change */
850 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
852 /* XXX: it would be nice to compress ALL messages of a
853 type, not just messages in a row without other
854 message types between. */
855 if (ce
.xclient
.message_type
!= msgtype
) {
856 XPutBackEvent(ob_display
, &ce
);
859 e
->xclient
= ce
.xclient
;
861 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
862 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
863 /* compress changes into a single change */
864 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
866 /* XXX: it would be nice to compress ALL messages of a
867 type, not just messages in a row without other
868 message types between. */
869 if (ce
.xclient
.message_type
!= msgtype
) {
870 XPutBackEvent(ob_display
, &ce
);
873 e
->xclient
= ce
.xclient
;
875 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
876 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
877 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
879 } else if (msgtype
== prop_atoms
.net_wm_state
) {
880 /* can't compress these */
881 ob_debug("net_wm_state %s %ld %ld for 0x%lx\n",
882 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
883 e
->xclient
.data
.l
[0] == 1 ? "Add" :
884 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
885 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
887 client_set_state(client
, e
->xclient
.data
.l
[0],
888 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
889 } else if (msgtype
== prop_atoms
.net_close_window
) {
890 ob_debug("net_close_window for 0x%lx\n", client
->window
);
891 client_close(client
);
892 } else if (msgtype
== prop_atoms
.net_active_window
) {
893 ob_debug("net_active_window for 0x%lx\n", client
->window
);
894 client_activate(client
, FALSE
);
895 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
896 ob_debug("net_wm_moveresize for 0x%lx\n", client
->window
);
897 if ((Atom
)e
->xclient
.data
.l
[2] ==
898 prop_atoms
.net_wm_moveresize_size_topleft
||
899 (Atom
)e
->xclient
.data
.l
[2] ==
900 prop_atoms
.net_wm_moveresize_size_top
||
901 (Atom
)e
->xclient
.data
.l
[2] ==
902 prop_atoms
.net_wm_moveresize_size_topright
||
903 (Atom
)e
->xclient
.data
.l
[2] ==
904 prop_atoms
.net_wm_moveresize_size_right
||
905 (Atom
)e
->xclient
.data
.l
[2] ==
906 prop_atoms
.net_wm_moveresize_size_right
||
907 (Atom
)e
->xclient
.data
.l
[2] ==
908 prop_atoms
.net_wm_moveresize_size_bottomright
||
909 (Atom
)e
->xclient
.data
.l
[2] ==
910 prop_atoms
.net_wm_moveresize_size_bottom
||
911 (Atom
)e
->xclient
.data
.l
[2] ==
912 prop_atoms
.net_wm_moveresize_size_bottomleft
||
913 (Atom
)e
->xclient
.data
.l
[2] ==
914 prop_atoms
.net_wm_moveresize_size_left
||
915 (Atom
)e
->xclient
.data
.l
[2] ==
916 prop_atoms
.net_wm_moveresize_move
||
917 (Atom
)e
->xclient
.data
.l
[2] ==
918 prop_atoms
.net_wm_moveresize_size_keyboard
||
919 (Atom
)e
->xclient
.data
.l
[2] ==
920 prop_atoms
.net_wm_moveresize_move_keyboard
) {
922 moveresize_start(client
, e
->xclient
.data
.l
[0],
923 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
924 e
->xclient
.data
.l
[2]);
926 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
927 int oldg
= client
->gravity
;
928 int tmpg
, x
, y
, w
, h
;
930 if (e
->xclient
.data
.l
[0] & 0xff)
931 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
935 if (e
->xclient
.data
.l
[0] & 1 << 8)
936 x
= e
->xclient
.data
.l
[1];
939 if (e
->xclient
.data
.l
[0] & 1 << 9)
940 y
= e
->xclient
.data
.l
[2];
943 if (e
->xclient
.data
.l
[0] & 1 << 10)
944 w
= e
->xclient
.data
.l
[3];
946 w
= client
->area
.width
;
947 if (e
->xclient
.data
.l
[0] & 1 << 11)
948 h
= e
->xclient
.data
.l
[4];
950 h
= client
->area
.height
;
951 client
->gravity
= tmpg
;
957 client
->frame
->size
.left
+ client
->frame
->size
.right
;
959 client
->frame
->size
.top
+ client
->frame
->size
.bottom
;
960 client_find_onscreen(client
, &newx
, &newy
, fw
, fh
,
961 client_normal(client
));
962 if (e
->xclient
.data
.l
[0] & 1 << 8)
964 if (e
->xclient
.data
.l
[0] & 1 << 9)
968 client_configure(client
, OB_CORNER_TOPLEFT
,
969 x
, y
, w
, h
, FALSE
, TRUE
);
971 client
->gravity
= oldg
;
975 /* validate cuz we query stuff off the client here */
976 if (!client_validate(client
)) break;
978 /* compress changes to a single property into a single change */
979 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
983 /* XXX: it would be nice to compress ALL changes to a property,
984 not just changes in a row without other props between. */
986 a
= ce
.xproperty
.atom
;
987 b
= e
->xproperty
.atom
;
991 if ((a
== prop_atoms
.net_wm_name
||
992 a
== prop_atoms
.wm_name
||
993 a
== prop_atoms
.net_wm_icon_name
||
994 a
== prop_atoms
.wm_icon_name
)
996 (b
== prop_atoms
.net_wm_name
||
997 b
== prop_atoms
.wm_name
||
998 b
== prop_atoms
.net_wm_icon_name
||
999 b
== prop_atoms
.wm_icon_name
)) {
1002 if ((a
== prop_atoms
.net_wm_icon
||
1003 a
== prop_atoms
.kwm_win_icon
)
1005 (b
== prop_atoms
.net_wm_icon
||
1006 b
== prop_atoms
.kwm_win_icon
))
1009 XPutBackEvent(ob_display
, &ce
);
1013 msgtype
= e
->xproperty
.atom
;
1014 if (msgtype
== XA_WM_NORMAL_HINTS
) {
1015 client_update_normal_hints(client
);
1016 /* normal hints can make a window non-resizable */
1017 client_setup_decor_and_functions(client
);
1018 } else if (msgtype
== XA_WM_HINTS
) {
1019 client_update_wmhints(client
);
1020 } else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
1021 client_update_transient_for(client
);
1022 client_get_type(client
);
1023 /* type may have changed, so update the layer */
1024 client_calc_layer(client
);
1025 client_setup_decor_and_functions(client
);
1026 } else if (msgtype
== prop_atoms
.net_wm_name
||
1027 msgtype
== prop_atoms
.wm_name
||
1028 msgtype
== prop_atoms
.net_wm_icon_name
||
1029 msgtype
== prop_atoms
.wm_icon_name
) {
1030 client_update_title(client
);
1031 } else if (msgtype
== prop_atoms
.wm_class
) {
1032 client_update_class(client
);
1033 } else if (msgtype
== prop_atoms
.wm_protocols
) {
1034 client_update_protocols(client
);
1035 client_setup_decor_and_functions(client
);
1037 else if (msgtype
== prop_atoms
.net_wm_strut
) {
1038 client_update_strut(client
);
1040 else if (msgtype
== prop_atoms
.net_wm_icon
||
1041 msgtype
== prop_atoms
.kwm_win_icon
) {
1042 client_update_icons(client
);
1047 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
1048 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
1049 frame_adjust_shape(client
->frame
);
1055 static void event_handle_dock(ObDock
*s
, XEvent
*e
)
1059 stacking_raise(DOCK_AS_WINDOW(s
));
1070 static void event_handle_dockapp(ObDockApp
*app
, XEvent
*e
)
1074 dock_app_drag(app
, &e
->xmotion
);
1077 if (app
->ignore_unmaps
) {
1078 app
->ignore_unmaps
--;
1081 dock_remove(app
, TRUE
);
1084 dock_remove(app
, FALSE
);
1086 case ReparentNotify
:
1087 dock_remove(app
, FALSE
);
1089 case ConfigureNotify
:
1090 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);
1095 ObMenuFrame
* find_active_menu()
1100 for (it
= menu_frame_visible
; it
; it
= g_list_next(it
)) {
1105 return it
? it
->data
: NULL
;
1108 static void event_handle_menu(XEvent
*ev
)
1111 ObMenuEntryFrame
*e
;
1115 if (!(f
= menu_frame_under(ev
->xbutton
.x_root
,
1116 ev
->xbutton
.y_root
)))
1117 menu_frame_hide_all();
1119 if ((e
= menu_entry_frame_under(ev
->xbutton
.x_root
,
1120 ev
->xbutton
.y_root
)))
1121 menu_entry_frame_execute(e
,
1122 !(ev
->xbutton
.state
& ControlMask
));
1126 if ((f
= menu_frame_under(ev
->xmotion
.x_root
,
1127 ev
->xmotion
.y_root
))) {
1128 menu_frame_move_on_screen(f
);
1129 if ((e
= menu_entry_frame_under(ev
->xmotion
.x_root
,
1130 ev
->xmotion
.y_root
)))
1131 menu_frame_select(f
, e
);
1135 if (ev
->xkey
.keycode
== ob_keycode(OB_KEY_ESCAPE
))
1136 menu_frame_hide_all();
1137 else if (ev
->xkey
.keycode
== ob_keycode(OB_KEY_RETURN
)) {
1139 if ((f
= find_active_menu()))
1140 menu_entry_frame_execute(f
->selected
,
1141 !(ev
->xkey
.state
& ControlMask
));
1142 } else if (ev
->xkey
.keycode
== ob_keycode(OB_KEY_LEFT
)) {
1144 if ((f
= find_active_menu()) && f
->parent
)
1145 menu_frame_select(f
, NULL
);
1146 } else if (ev
->xkey
.keycode
== ob_keycode(OB_KEY_RIGHT
)) {
1148 if ((f
= find_active_menu()) && f
->child
)
1149 menu_frame_select_next(f
->child
);
1150 } else if (ev
->xkey
.keycode
== ob_keycode(OB_KEY_UP
)) {
1152 if ((f
= find_active_menu()))
1153 menu_frame_select_previous(f
);
1154 } else if (ev
->xkey
.keycode
== ob_keycode(OB_KEY_DOWN
)) {
1156 if ((f
= find_active_menu()))
1157 menu_frame_select_next(f
);