9 #include "framerender.h"
11 #include "moveresize.h"
13 #include "extensions.h"
18 #include <X11/keysym.h>
19 #include <X11/Xatom.h>
20 #ifdef HAVE_SYS_SELECT_H
21 # include <sys/select.h>
24 static void event_process(XEvent
*e
);
25 static void event_handle_root(XEvent
*e
);
26 static void event_handle_client(Client
*c
, XEvent
*e
);
27 static void event_handle_menu(Menu
*menu
, XEvent
*e
);
29 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
30 (e)->xfocus.detail > NotifyNonlinearVirtual)
31 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
32 (e)->xfocus.detail == NotifyInferior || \
33 (e)->xfocus.detail == NotifyAncestor || \
34 (e)->xfocus.detail > NotifyNonlinearVirtual)
36 Time event_lasttime
= 0;
38 /*! The value of the mask for the NumLock modifier */
39 unsigned int NumLockMask
;
40 /*! The value of the mask for the ScrollLock modifier */
41 unsigned int ScrollLockMask
;
42 /*! The key codes for the modifier keys */
43 static XModifierKeymap
*modmap
;
44 /*! Table of the constant modifier masks */
45 static const int mask_table
[] = {
46 ShiftMask
, LockMask
, ControlMask
, Mod1Mask
,
47 Mod2Mask
, Mod3Mask
, Mod4Mask
, Mod5Mask
49 static int mask_table_size
;
53 mask_table_size
= sizeof(mask_table
) / sizeof(mask_table
[0]);
55 /* get lock masks that are defined by the display (not constant) */
56 modmap
= XGetModifierMapping(ob_display
);
58 if (modmap
&& modmap
->max_keypermod
> 0) {
60 const size_t size
= mask_table_size
* modmap
->max_keypermod
;
61 /* get the values of the keyboard lock modifiers
62 Note: Caps lock is not retrieved the same way as Scroll and Num
63 lock since it doesn't need to be. */
64 const KeyCode num_lock
= XKeysymToKeycode(ob_display
, XK_Num_Lock
);
65 const KeyCode scroll_lock
= XKeysymToKeycode(ob_display
,
68 for (cnt
= 0; cnt
< size
; ++cnt
) {
69 if (! modmap
->modifiermap
[cnt
]) continue;
71 if (num_lock
== modmap
->modifiermap
[cnt
])
72 NumLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
73 if (scroll_lock
== modmap
->modifiermap
[cnt
])
74 ScrollLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
81 XFreeModifiermap(modmap
);
90 gboolean had_event
= FALSE
;
94 There are slightly different event retrieval semantics here for
95 local (or high bandwidth) versus remote (or low bandwidth)
96 connections to the display/Xserver.
99 if (!XPending(ob_display
))
103 This XSync allows for far more compression of events, which
104 makes things like Motion events perform far far better. Since
105 it also means network traffic for every event instead of every
106 X events (where X is the number retrieved at a time), it
107 probably should not be used for setups where Openbox is
108 running on a remote/low bandwidth display/Xserver.
110 XSync(ob_display
, FALSE
);
111 if (!XEventsQueued(ob_display
, QueuedAlready
))
114 XNextEvent(ob_display
, &e
);
121 timer_dispatch((GTimeVal
**)&wait
);
122 x_fd
= ConnectionNumber(ob_display
);
124 FD_SET(x_fd
, &selset
);
125 select(x_fd
+ 1, &selset
, NULL
, NULL
, wait
);
129 static Window
event_get_window(XEvent
*e
)
136 window
= e
->xmap
.window
;
139 window
= e
->xunmap
.window
;
142 window
= e
->xdestroywindow
.window
;
144 case ConfigureRequest
:
145 window
= e
->xconfigurerequest
.window
;
147 case ConfigureNotify
:
148 window
= e
->xconfigure
.window
;
152 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
153 switch (((XkbAnyEvent
*)&e
)->xkb_type
) {
155 window
= ((XkbBellNotifyEvent
*)&e
)->window
;
161 window
= e
->xany
.window
;
166 static void event_set_lasttime(XEvent
*e
)
168 /* grab the lasttime and hack up the state */
172 event_lasttime
= e
->xbutton
.time
;
175 event_lasttime
= e
->xkey
.time
;
178 event_lasttime
= e
->xkey
.time
;
181 event_lasttime
= e
->xmotion
.time
;
184 event_lasttime
= e
->xproperty
.time
;
188 event_lasttime
= e
->xcrossing
.time
;
191 event_lasttime
= CurrentTime
;
196 #define STRIP_MODS(s) \
197 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
198 /* kill off the Button1Mask etc, only want the modifiers */ \
199 s &= (ControlMask | ShiftMask | Mod1Mask | \
200 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
202 static void event_hack_mods(XEvent *e)
210 STRIP_MODS(e
->xbutton
.state
);
213 STRIP_MODS(e
->xkey
.state
);
216 STRIP_MODS(e
->xkey
.state
);
217 /* remove from the state the mask of the modifier being released, if
218 it is a modifier key being released (this is a little ugly..) */
219 kp
= modmap
->modifiermap
;
220 for (i
= 0; i
< mask_table_size
; ++i
) {
221 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
222 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
223 /* remove the mask for it */
224 e
->xkey
.state
&= ~mask_table
[i
];
225 /* cause the first loop to break; */
227 break; /* get outta here! */
234 STRIP_MODS(e
->xmotion
.state
);
235 /* compress events */
238 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
240 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
241 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
248 static gboolean
event_ignore(XEvent
*e
, Client
*client
)
252 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
253 because of RevertToPointerRoot. If the focus ends up reverting to
254 pointer root on a workspace change, then the FocusIn event that we
255 want will be of type NotifyAncestor. This situation does not occur
256 for FocusOut, so it is safely ignored there.
258 if (INVALID_FOCUSIN(e
) ||
261 g_message("FocusIn on %lx mode %d detail %d IGNORED", e
->xfocus
.window
,
262 e
->xfocus
.mode
, e
->xfocus
.detail
);
264 /* says a client was not found for the event (or a valid FocusIn
267 e
->xfocus
.window
= None
;
272 g_message("FocusIn on %lx mode %d detail %d", e
->xfocus
.window
,
273 e
->xfocus
.mode
, e
->xfocus
.detail
);
277 if (INVALID_FOCUSOUT(e
)) {
279 g_message("FocusOut on %lx mode %d detail %d IGNORED",
280 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
286 g_message("FocusOut on %lx mode %d detail %d",
287 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
292 gboolean fallback
= TRUE
;
295 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
296 e
->xfocus
.window
,&fe
))
297 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
299 if (fe
.type
== FocusOut
) {
301 g_message("found pending FocusOut");
303 if (!INVALID_FOCUSOUT(&fe
)) {
304 /* if there is a VALID FocusOut still coming, don't
305 fallback focus yet, we'll deal with it then */
306 XPutBackEvent(ob_display
, &fe
);
312 g_message("found pending FocusIn");
314 /* is the focused window getting a FocusOut/In back to
316 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
317 !event_ignore(&fe
, client
)) {
319 g_message("focused window got an Out/In back to "
320 "itself IGNORED both");
325 /* once all the FocusOut's have been dealt with, if there
326 is a FocusIn still left and it is valid, then use it */
328 /* secret magic way of event_process telling us that no
329 client was found for the FocusIn event. ^_^ */
330 if (fe
.xfocus
.window
!= None
) {
338 g_message("no valid FocusIn and no FocusOut events found, "
341 focus_fallback(Fallback_NoFocus
);
347 /* NotifyUngrab occurs when a mouse button is released and the event is
348 caused, like when lowering a window */
349 /* NotifyVirtual occurs when ungrabbing the pointer */
350 if (e
->xcrossing
.mode
== NotifyGrab
||
351 e
->xcrossing
.detail
== NotifyInferior
||
352 (e
->xcrossing
.mode
== NotifyUngrab
&&
353 e
->xcrossing
.detail
== NotifyVirtual
)) {
355 g_message("%sNotify mode %d detail %d on %lx IGNORED",
356 (e
->type
== EnterNotify
? "Enter" : "Leave"),
358 e
->xcrossing
.detail
, client
?client
->window
:0);
363 g_message("%sNotify mode %d detail %d on %lx",
364 (e
->type
== EnterNotify
? "Enter" : "Leave"),
366 e
->xcrossing
.detail
, client
?client
->window
:0);
373 static void event_process(XEvent
*e
)
379 window
= event_get_window(e
);
380 if (!(client
= g_hash_table_lookup(client_map
, &window
)))
381 menu
= g_hash_table_lookup(menu_map
, &window
);
383 event_set_lasttime(e
);
385 if (event_ignore(e
, client
))
388 /* deal with it in the kernel */
390 event_handle_menu(menu
, e
);
393 event_handle_client(client
, e
);
394 else if (window
== ob_root
)
395 event_handle_root(e
);
396 else if (e
->type
== MapRequest
)
397 client_manage(window
);
398 else if (e
->type
== ConfigureRequest
) {
399 /* unhandled configure requests must be used to configure the
403 xwc
.x
= e
->xconfigurerequest
.x
;
404 xwc
.y
= e
->xconfigurerequest
.y
;
405 xwc
.width
= e
->xconfigurerequest
.width
;
406 xwc
.height
= e
->xconfigurerequest
.height
;
407 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
408 xwc
.sibling
= e
->xconfigurerequest
.above
;
409 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
411 /* we are not to be held responsible if someone sends us an
413 xerror_set_ignore(TRUE
);
414 XConfigureWindow(ob_display
, window
,
415 e
->xconfigurerequest
.value_mask
, &xwc
);
416 xerror_set_ignore(FALSE
);
419 if (moveresize_in_progress
)
420 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
421 e
->type
== ButtonPress
||
422 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
425 return; /* no dispatch! */
429 /* user input (action-bound) events */
431 if (e->type == ButtonPress || e->type == ButtonRelease ||
432 e->type == MotionNotify)
433 mouse_event(e, client);
434 else if (e->type == KeyPress || e->type == KeyRelease)
438 /* dispatch the event to registered handlers */
439 dispatch_x(e
, client
);
442 static void event_handle_root(XEvent
*e
)
448 if (e
->xclient
.format
!= 32) break;
450 msgtype
= e
->xclient
.message_type
;
451 if (msgtype
== prop_atoms
.net_current_desktop
) {
452 unsigned int d
= e
->xclient
.data
.l
[0];
453 if (d
< screen_num_desktops
)
454 screen_set_desktop(d
);
455 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
456 unsigned int d
= e
->xclient
.data
.l
[0];
458 screen_set_num_desktops(d
);
459 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
460 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
464 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
465 screen_update_desktop_names();
466 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
467 screen_update_layout();
469 case ConfigureNotify
:
471 XRRUpdateConfiguration(e
);
473 if (e
->xconfigure
.width
!= screen_physical_size
.width
||
474 e
->xconfigure
.height
!= screen_physical_size
.height
)
475 screen_resize(e
->xconfigure
.width
, e
->xconfigure
.height
);
480 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
481 g_message("VIDMODE EVENT");
487 static void event_handle_client(Client
*client
, XEvent
*e
)
496 switch (frame_context(client
, e
->xbutton
.window
)) {
497 case Context_Maximize
:
498 client
->frame
->max_press
= (e
->type
== ButtonPress
);
499 framerender_frame(client
->frame
);
502 client
->frame
->close_press
= (e
->type
== ButtonPress
);
503 framerender_frame(client
->frame
);
505 case Context_Iconify
:
506 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
507 framerender_frame(client
->frame
);
509 case Context_AllDesktops
:
510 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
511 framerender_frame(client
->frame
);
514 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
515 framerender_frame(client
->frame
);
518 /* nothing changes with clicks for any other contexts */
524 g_message("FocusIn on client for %lx", client
->window
);
526 focus_set_client(client
);
527 frame_adjust_focus(client
->frame
, TRUE
);
531 g_message("FocusOut on client for %lx", client
->window
);
533 /* are we a fullscreen window or a transient of one? (checks layer)
534 if we are then we need to be iconified since we are losing focus
536 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
537 !client_search_focus_tree_full(client
))
538 /* iconify fullscreen windows when they and their transients
540 client_iconify(client
, TRUE
, TRUE
);
541 frame_adjust_focus(client
->frame
, FALSE
);
544 if (client_normal(client
)) {
545 if (ob_state
== State_Starting
) {
546 /* move it to the top of the focus order */
547 guint desktop
= client
->desktop
;
548 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
549 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
551 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
553 } else if (config_focus_follow
) {
555 g_message("EnterNotify on %lx, focusing window",
558 client_focus(client
);
562 case ConfigureRequest
:
564 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
565 ConfigureRequest
, &ce
)) {
567 /* XXX if this causes bad things.. we can compress config req's
568 with the same mask. */
569 e
->xconfigurerequest
.value_mask
|=
570 ce
.xconfigurerequest
.value_mask
;
571 if (ce
.xconfigurerequest
.value_mask
& CWX
)
572 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
573 if (ce
.xconfigurerequest
.value_mask
& CWY
)
574 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
575 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
576 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
577 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
578 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
579 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
580 e
->xconfigurerequest
.border_width
=
581 ce
.xconfigurerequest
.border_width
;
582 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
583 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
586 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
587 if (client
->iconic
|| client
->shaded
) return;
589 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
590 client
->border_width
= e
->xconfigurerequest
.border_width
;
592 /* resize, then move, as specified in the EWMH section 7.7 */
593 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
598 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
599 e
->xconfigurerequest
.x
: client
->area
.x
;
600 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
601 e
->xconfigurerequest
.y
: client
->area
.y
;
602 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
603 e
->xconfigurerequest
.width
: client
->area
.width
;
604 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
605 e
->xconfigurerequest
.height
: client
->area
.height
;
607 switch (client
->gravity
) {
608 case NorthEastGravity
:
610 corner
= Corner_TopRight
;
612 case SouthWestGravity
:
614 corner
= Corner_BottomLeft
;
616 case SouthEastGravity
:
617 corner
= Corner_BottomRight
;
619 default: /* NorthWest, Static, etc */
620 corner
= Corner_TopLeft
;
623 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
626 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
627 switch (e
->xconfigurerequest
.detail
) {
630 stacking_lower(client
);
636 stacking_raise(client
);
642 if (client
->ignore_unmaps
) {
643 client
->ignore_unmaps
--;
646 client_unmanage(client
);
649 client_unmanage(client
);
652 /* this is when the client is first taken captive in the frame */
653 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
656 This event is quite rare and is usually handled in unmapHandler.
657 However, if the window is unmapped when the reparent event occurs,
658 the window manager never sees it because an unmap event is not sent
659 to an already unmapped window.
662 /* we don't want the reparent event, put it back on the stack for the
663 X server to deal with after we unmanage the window */
664 XPutBackEvent(ob_display
, e
);
666 client_unmanage(client
);
669 g_message("MapRequest for 0x%lx", client
->window
);
670 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
671 does, we don't want it! */
672 if (screen_showing_desktop
)
673 screen_show_desktop(FALSE
);
674 client_iconify(client
, FALSE
, TRUE
);
675 if (!client
->frame
->visible
)
676 /* if its not visible still, then don't mess with it */
679 client_shade(client
, FALSE
);
680 client_focus(client
);
681 stacking_raise(client
);
684 /* validate cuz we query stuff off the client here */
685 if (!client_validate(client
)) break;
687 if (e
->xclient
.format
!= 32) return;
689 msgtype
= e
->xclient
.message_type
;
690 if (msgtype
== prop_atoms
.wm_change_state
) {
691 /* compress changes into a single change */
692 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
693 client
->window
, &ce
)) {
694 /* XXX: it would be nice to compress ALL messages of a
695 type, not just messages in a row without other
696 message types between. */
697 if (ce
.xclient
.message_type
!= msgtype
) {
698 XPutBackEvent(ob_display
, &ce
);
701 e
->xclient
= ce
.xclient
;
703 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
704 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
705 /* compress changes into a single change */
706 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
707 client
->window
, &ce
)) {
708 /* XXX: it would be nice to compress ALL messages of a
709 type, not just messages in a row without other
710 message types between. */
711 if (ce
.xclient
.message_type
!= msgtype
) {
712 XPutBackEvent(ob_display
, &ce
);
715 e
->xclient
= ce
.xclient
;
717 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
718 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
719 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
721 } else if (msgtype
== prop_atoms
.net_wm_state
) {
722 /* can't compress these */
723 g_message("net_wm_state %s %ld %ld for 0x%lx",
724 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
725 e
->xclient
.data
.l
[0] == 1 ? "Add" :
726 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
727 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
729 client_set_state(client
, e
->xclient
.data
.l
[0],
730 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
731 } else if (msgtype
== prop_atoms
.net_close_window
) {
732 g_message("net_close_window for 0x%lx", client
->window
);
733 client_close(client
);
734 } else if (msgtype
== prop_atoms
.net_active_window
) {
735 g_message("net_active_window for 0x%lx", client
->window
);
736 client_activate(client
);
737 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
738 g_message("net_wm_moveresize for 0x%lx", client
->window
);
739 if ((Atom
)e
->xclient
.data
.l
[2] ==
740 prop_atoms
.net_wm_moveresize_size_topleft
||
741 (Atom
)e
->xclient
.data
.l
[2] ==
742 prop_atoms
.net_wm_moveresize_size_top
||
743 (Atom
)e
->xclient
.data
.l
[2] ==
744 prop_atoms
.net_wm_moveresize_size_topright
||
745 (Atom
)e
->xclient
.data
.l
[2] ==
746 prop_atoms
.net_wm_moveresize_size_right
||
747 (Atom
)e
->xclient
.data
.l
[2] ==
748 prop_atoms
.net_wm_moveresize_size_right
||
749 (Atom
)e
->xclient
.data
.l
[2] ==
750 prop_atoms
.net_wm_moveresize_size_bottomright
||
751 (Atom
)e
->xclient
.data
.l
[2] ==
752 prop_atoms
.net_wm_moveresize_size_bottom
||
753 (Atom
)e
->xclient
.data
.l
[2] ==
754 prop_atoms
.net_wm_moveresize_size_bottomleft
||
755 (Atom
)e
->xclient
.data
.l
[2] ==
756 prop_atoms
.net_wm_moveresize_size_left
||
757 (Atom
)e
->xclient
.data
.l
[2] ==
758 prop_atoms
.net_wm_moveresize_move
||
759 (Atom
)e
->xclient
.data
.l
[2] ==
760 prop_atoms
.net_wm_moveresize_size_keyboard
||
761 (Atom
)e
->xclient
.data
.l
[2] ==
762 prop_atoms
.net_wm_moveresize_move_keyboard
) {
764 moveresize_start(client
, e
->xclient
.data
.l
[0],
765 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
766 e
->xclient
.data
.l
[2]);
768 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
769 int oldg
= client
->gravity
;
770 int tmpg
, x
, y
, w
, h
;
772 if (e
->xclient
.data
.l
[0] & 0xff)
773 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
777 if (e
->xclient
.data
.l
[0] & 1 << 8)
778 x
= e
->xclient
.data
.l
[1];
781 if (e
->xclient
.data
.l
[0] & 1 << 9)
782 y
= e
->xclient
.data
.l
[2];
785 if (e
->xclient
.data
.l
[0] & 1 << 10)
786 w
= e
->xclient
.data
.l
[3];
789 if (e
->xclient
.data
.l
[0] & 1 << 11)
790 h
= e
->xclient
.data
.l
[4];
793 client
->gravity
= tmpg
;
794 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
795 client
->gravity
= oldg
;
799 /* validate cuz we query stuff off the client here */
800 if (!client_validate(client
)) break;
802 /* compress changes to a single property into a single change */
803 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
804 client
->window
, &ce
)) {
805 /* XXX: it would be nice to compress ALL changes to a property,
806 not just changes in a row without other props between. */
807 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
808 XPutBackEvent(ob_display
, &ce
);
813 msgtype
= e
->xproperty
.atom
;
814 if (msgtype
== XA_WM_NORMAL_HINTS
) {
815 client_update_normal_hints(client
);
816 /* normal hints can make a window non-resizable */
817 client_setup_decor_and_functions(client
);
819 else if (msgtype
== XA_WM_HINTS
)
820 client_update_wmhints(client
);
821 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
822 client_update_transient_for(client
);
823 client_get_type(client
);
824 /* type may have changed, so update the layer */
825 client_calc_layer(client
);
826 client_setup_decor_and_functions(client
);
828 else if (msgtype
== prop_atoms
.net_wm_name
||
829 msgtype
== prop_atoms
.wm_name
||
830 msgtype
== prop_atoms
.net_wm_icon_name
||
831 msgtype
== prop_atoms
.wm_icon_name
)
832 client_update_title(client
);
833 else if (msgtype
== prop_atoms
.wm_class
)
834 client_update_class(client
);
835 else if (msgtype
== prop_atoms
.wm_protocols
) {
836 client_update_protocols(client
);
837 client_setup_decor_and_functions(client
);
839 else if (msgtype
== prop_atoms
.net_wm_strut
)
840 client_update_strut(client
);
841 else if (msgtype
== prop_atoms
.net_wm_icon
)
842 client_update_icons(client
);
843 else if (msgtype
== prop_atoms
.kwm_win_icon
)
844 client_update_kwm_icon(client
);
848 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
849 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
850 frame_adjust_shape(client
->frame
);
856 static void event_handle_menu(Menu
*menu
, XEvent
*e
)
860 g_message("EVENT %d", e
->type
);
863 g_message("BUTTON PRESS");
864 if (e
->xbutton
.button
== 3)
868 g_message("BUTTON RELEASED");
869 if (!menu
->shown
) break;
871 /* grab_pointer_window(FALSE, None, menu->frame);*/
873 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
877 guint ujunk
, b
, w
, h
;
878 XGetGeometry(ob_display
, e
->xbutton
.window
,
879 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
880 if (e
->xbutton
.x
>= (signed)-b
&&
881 e
->xbutton
.y
>= (signed)-b
&&
882 e
->xbutton
.x
< (signed)(w
+b
) &&
883 e
->xbutton
.y
< (signed)(h
+b
)) {
884 menu_entry_fire(entry
);
890 g_message("enter/leave");
891 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
894 menu
->mouseover(entry
, e
->type
== EnterNotify
);
896 menu_control_mouseover(entry
, e
->type
== EnterNotify
);
898 menu_entry_render(entry
);