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 Time event_lasttime
= 0;
31 /*! The value of the mask for the NumLock modifier */
32 unsigned int NumLockMask
;
33 /*! The value of the mask for the ScrollLock modifier */
34 unsigned int ScrollLockMask
;
35 /*! The key codes for the modifier keys */
36 static XModifierKeymap
*modmap
;
37 /*! Table of the constant modifier masks */
38 static const int mask_table
[] = {
39 ShiftMask
, LockMask
, ControlMask
, Mod1Mask
,
40 Mod2Mask
, Mod3Mask
, Mod4Mask
, Mod5Mask
42 static int mask_table_size
;
46 mask_table_size
= sizeof(mask_table
) / sizeof(mask_table
[0]);
48 /* get lock masks that are defined by the display (not constant) */
49 modmap
= XGetModifierMapping(ob_display
);
51 if (modmap
&& modmap
->max_keypermod
> 0) {
53 const size_t size
= mask_table_size
* modmap
->max_keypermod
;
54 /* get the values of the keyboard lock modifiers
55 Note: Caps lock is not retrieved the same way as Scroll and Num
56 lock since it doesn't need to be. */
57 const KeyCode num_lock
= XKeysymToKeycode(ob_display
, XK_Num_Lock
);
58 const KeyCode scroll_lock
= XKeysymToKeycode(ob_display
,
61 for (cnt
= 0; cnt
< size
; ++cnt
) {
62 if (! modmap
->modifiermap
[cnt
]) continue;
64 if (num_lock
== modmap
->modifiermap
[cnt
])
65 NumLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
66 if (scroll_lock
== modmap
->modifiermap
[cnt
])
67 ScrollLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
74 XFreeModifiermap(modmap
);
83 gboolean had_event
= FALSE
;
87 There are slightly different event retrieval semantics here for
88 local (or high bandwidth) versus remote (or low bandwidth)
89 connections to the display/Xserver.
92 if (!XPending(ob_display
))
96 This XSync allows for far more compression of events, which
97 makes things like Motion events perform far far better. Since
98 it also means network traffic for every event instead of every
99 X events (where X is the number retrieved at a time), it
100 probably should not be used for setups where Openbox is
101 running on a remote/low bandwidth display/Xserver.
103 XSync(ob_display
, FALSE
);
104 if (!XEventsQueued(ob_display
, QueuedAlready
))
107 XNextEvent(ob_display
, &e
);
114 timer_dispatch((GTimeVal
**)&wait
);
115 x_fd
= ConnectionNumber(ob_display
);
117 FD_SET(x_fd
, &selset
);
118 select(x_fd
+ 1, &selset
, NULL
, NULL
, wait
);
122 static Window
event_get_window(XEvent
*e
)
129 window
= e
->xmap
.window
;
132 window
= e
->xunmap
.window
;
135 window
= e
->xdestroywindow
.window
;
137 case ConfigureRequest
:
138 window
= e
->xconfigurerequest
.window
;
142 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
143 switch (((XkbAnyEvent
*)&e
)->xkb_type
) {
145 window
= ((XkbBellNotifyEvent
*)&e
)->window
;
151 window
= e
->xany
.window
;
156 static void event_set_lasttime(XEvent
*e
)
158 /* grab the lasttime and hack up the state */
162 event_lasttime
= e
->xbutton
.time
;
165 event_lasttime
= e
->xkey
.time
;
168 event_lasttime
= e
->xkey
.time
;
171 event_lasttime
= e
->xmotion
.time
;
174 event_lasttime
= e
->xproperty
.time
;
178 event_lasttime
= e
->xcrossing
.time
;
181 event_lasttime
= CurrentTime
;
186 #define STRIP_MODS(s) \
187 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
188 /* kill off the Button1Mask etc, only want the modifiers */ \
189 s &= (ControlMask | ShiftMask | Mod1Mask | \
190 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
192 static void event_hack_mods(XEvent *e)
200 STRIP_MODS(e
->xbutton
.state
);
203 STRIP_MODS(e
->xkey
.state
);
206 STRIP_MODS(e
->xkey
.state
);
207 /* remove from the state the mask of the modifier being released, if
208 it is a modifier key being released (this is a little ugly..) */
209 kp
= modmap
->modifiermap
;
210 for (i
= 0; i
< mask_table_size
; ++i
) {
211 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
212 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
213 /* remove the mask for it */
214 e
->xkey
.state
&= ~mask_table
[i
];
215 /* cause the first loop to break; */
217 break; /* get outta here! */
224 STRIP_MODS(e
->xmotion
.state
);
225 /* compress events */
228 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
230 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
231 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
238 static gboolean
event_ignore(XEvent
*e
, Client
*client
)
243 g_message("FocusIn on %lx mode %d detail %d", window
,
244 e
->xfocus
.mode
, e
->xfocus
.detail
);
246 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
247 because of RevertToPointerRoot. If the focus ends up reverting to
248 pointer root on a workspace change, then the FocusIn event that we
249 want will be of type NotifyAncestor. This situation does not occur
250 for FocusOut, so it is safely ignored there.
252 if (e
->xfocus
.detail
== NotifyInferior
||
253 e
->xfocus
.detail
> NotifyNonlinearVirtual
||
255 /* says a client was not found for the event (or a valid FocusIn
258 e
->xfocus
.window
= None
;
263 g_message("FocusIn on %lx", window
);
268 g_message("FocusOut on %lx mode %d detail %d", window
,
269 e
->xfocus
.mode
, e
->xfocus
.detail
);
271 if (e
->xfocus
.mode
== NotifyGrab
||
272 e
->xfocus
.detail
== NotifyInferior
||
273 e
->xfocus
.detail
== NotifyAncestor
||
274 e
->xfocus
.detail
> NotifyNonlinearVirtual
) return TRUE
;
277 g_message("FocusOut on %lx", window
);
279 /* Try process a FocusIn first, and if a legit one isn't found, then
280 do the fallback shiznit. */
283 gboolean isfo
= FALSE
;
285 if (XCheckTypedEvent(ob_display
, FocusIn
, &fi
)) {
288 /* when we have gotten a fi/fo pair, then see if there are any
289 more fo's coming. if there are, then don't fallback just yet
291 if ((isfo
= XCheckTypedEvent(ob_display
, FocusOut
, &fo
)))
292 XPutBackEvent(ob_display
, &fo
);
294 /* secret magic way of event_process telling us that no client
295 was found for the FocusIn event. ^_^ */
296 if (!isfo
&& fi
.xfocus
.window
== None
)
297 focus_fallback(Fallback_NoFocus
);
298 if (fi
.xfocus
.window
== e
->xfocus
.window
)
301 focus_fallback(Fallback_NoFocus
);
306 /* NotifyUngrab occurs when a mouse button is released and the event is
307 caused, like when lowering a window */
308 /* NotifyVirtual occurs when ungrabbing the pointer */
309 if (e
->xcrossing
.mode
== NotifyGrab
||
310 e
->xcrossing
.detail
== NotifyInferior
||
311 (e
->xcrossing
.mode
== NotifyUngrab
&&
312 e
->xcrossing
.detail
== NotifyVirtual
))
319 static void event_process(XEvent
*e
)
325 window
= event_get_window(e
);
326 if (!(client
= g_hash_table_lookup(client_map
, &window
)))
327 menu
= g_hash_table_lookup(menu_map
, &window
);
328 event_set_lasttime(e
);
330 if (event_ignore(e
, client
))
333 /* deal with it in the kernel */
335 event_handle_menu(menu
, e
);
338 event_handle_client(client
, e
);
339 else if (window
== ob_root
)
340 event_handle_root(e
);
341 else if (e
->type
== MapRequest
)
342 client_manage(window
);
343 else if (e
->type
== ConfigureRequest
) {
344 /* unhandled configure requests must be used to configure the
348 xwc
.x
= e
->xconfigurerequest
.x
;
349 xwc
.y
= e
->xconfigurerequest
.y
;
350 xwc
.width
= e
->xconfigurerequest
.width
;
351 xwc
.height
= e
->xconfigurerequest
.height
;
352 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
353 xwc
.sibling
= e
->xconfigurerequest
.above
;
354 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
356 /* we are not to be held responsible if someone sends us an
358 xerror_set_ignore(TRUE
);
359 XConfigureWindow(ob_display
, window
,
360 e
->xconfigurerequest
.value_mask
, &xwc
);
361 xerror_set_ignore(FALSE
);
364 if (moveresize_in_progress
)
365 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
366 e
->type
== ButtonPress
||
367 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
369 return; /* no dispatch! */
372 /* user input (action-bound) events */
374 if (e->type == ButtonPress || e->type == ButtonRelease ||
375 e->type == MotionNotify)
376 mouse_event(e, client);
377 else if (e->type == KeyPress || e->type == KeyRelease)
381 /* dispatch the event to registered handlers */
382 dispatch_x(e
, client
);
385 static void event_handle_root(XEvent
*e
)
391 if (e
->xclient
.format
!= 32) break;
393 msgtype
= e
->xclient
.message_type
;
394 if (msgtype
== prop_atoms
.net_current_desktop
) {
395 unsigned int d
= e
->xclient
.data
.l
[0];
396 if (d
< screen_num_desktops
)
397 screen_set_desktop(d
);
398 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
399 unsigned int d
= e
->xclient
.data
.l
[0];
401 screen_set_num_desktops(d
);
402 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
403 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
407 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
408 screen_update_desktop_names();
409 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
410 screen_update_layout();
415 static void event_handle_client(Client
*client
, XEvent
*e
)
424 switch (frame_context(client
, e
->xbutton
.window
)) {
425 case Context_Maximize
:
426 client
->frame
->max_press
= (e
->type
== ButtonPress
);
427 framerender_frame(client
->frame
);
430 client
->frame
->close_press
= (e
->type
== ButtonPress
);
431 framerender_frame(client
->frame
);
433 case Context_Iconify
:
434 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
435 framerender_frame(client
->frame
);
437 case Context_AllDesktops
:
438 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
439 framerender_frame(client
->frame
);
442 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
443 framerender_frame(client
->frame
);
446 /* nothing changes with clicks for any other contexts */
451 focus_set_client(client
);
454 g_message("Focus%s on client for %lx", (e
->type
==FocusIn
?"In":"Out"),
457 /* focus state can affect the stacking layer */
458 client_calc_layer(client
);
459 frame_adjust_focus(client
->frame
);
462 if (client_normal(client
)) {
463 if (ob_state
== State_Starting
) {
464 /* move it to the top of the focus order */
465 guint desktop
= client
->desktop
;
466 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
467 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
469 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
471 } else if (config_focus_follow
) {
473 g_message("EnterNotify on %lx, focusing window",
476 client_focus(client
);
480 case ConfigureRequest
:
482 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
483 ConfigureRequest
, &ce
)) {
485 /* XXX if this causes bad things.. we can compress config req's
486 with the same mask. */
487 e
->xconfigurerequest
.value_mask
|=
488 ce
.xconfigurerequest
.value_mask
;
489 if (ce
.xconfigurerequest
.value_mask
& CWX
)
490 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
491 if (ce
.xconfigurerequest
.value_mask
& CWY
)
492 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
493 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
494 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
495 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
496 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
497 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
498 e
->xconfigurerequest
.border_width
=
499 ce
.xconfigurerequest
.border_width
;
500 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
501 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
504 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
505 if (client
->iconic
|| client
->shaded
) return;
507 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
508 client
->border_width
= e
->xconfigurerequest
.border_width
;
510 /* resize, then move, as specified in the EWMH section 7.7 */
511 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
516 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
517 e
->xconfigurerequest
.x
: client
->area
.x
;
518 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
519 e
->xconfigurerequest
.y
: client
->area
.y
;
520 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
521 e
->xconfigurerequest
.width
: client
->area
.width
;
522 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
523 e
->xconfigurerequest
.height
: client
->area
.height
;
525 switch (client
->gravity
) {
526 case NorthEastGravity
:
528 corner
= Corner_TopRight
;
530 case SouthWestGravity
:
532 corner
= Corner_BottomLeft
;
534 case SouthEastGravity
:
535 corner
= Corner_BottomRight
;
537 default: /* NorthWest, Static, etc */
538 corner
= Corner_TopLeft
;
541 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
544 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
545 switch (e
->xconfigurerequest
.detail
) {
548 stacking_lower(client
);
554 stacking_raise(client
);
560 if (client
->ignore_unmaps
) {
561 client
->ignore_unmaps
--;
564 client_unmanage(client
);
567 client_unmanage(client
);
570 /* this is when the client is first taken captive in the frame */
571 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
574 This event is quite rare and is usually handled in unmapHandler.
575 However, if the window is unmapped when the reparent event occurs,
576 the window manager never sees it because an unmap event is not sent
577 to an already unmapped window.
580 /* we don't want the reparent event, put it back on the stack for the
581 X server to deal with after we unmanage the window */
582 XPutBackEvent(ob_display
, e
);
584 client_unmanage(client
);
587 g_message("MapRequest for 0x%lx", client
->window
);
588 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
589 does, we don't want it! */
590 if (screen_showing_desktop
)
591 screen_show_desktop(FALSE
);
592 client_iconify(client
, FALSE
, TRUE
);
593 if (!client
->frame
->visible
)
594 /* if its not visible still, then don't mess with it */
597 client_shade(client
, FALSE
);
598 client_focus(client
);
599 stacking_raise(client
);
602 /* validate cuz we query stuff off the client here */
603 if (!client_validate(client
)) break;
605 if (e
->xclient
.format
!= 32) return;
607 msgtype
= e
->xclient
.message_type
;
608 if (msgtype
== prop_atoms
.wm_change_state
) {
609 /* compress changes into a single change */
610 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
611 client
->window
, &ce
)) {
612 /* XXX: it would be nice to compress ALL messages of a
613 type, not just messages in a row without other
614 message types between. */
615 if (ce
.xclient
.message_type
!= msgtype
) {
616 XPutBackEvent(ob_display
, &ce
);
619 e
->xclient
= ce
.xclient
;
621 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
622 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
623 /* compress changes into a single change */
624 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
625 client
->window
, &ce
)) {
626 /* XXX: it would be nice to compress ALL messages of a
627 type, not just messages in a row without other
628 message types between. */
629 if (ce
.xclient
.message_type
!= msgtype
) {
630 XPutBackEvent(ob_display
, &ce
);
633 e
->xclient
= ce
.xclient
;
635 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
636 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
637 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
639 } else if (msgtype
== prop_atoms
.net_wm_state
) {
640 /* can't compress these */
641 g_message("net_wm_state %s %ld %ld for 0x%lx",
642 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
643 e
->xclient
.data
.l
[0] == 1 ? "Add" :
644 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
645 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
647 client_set_state(client
, e
->xclient
.data
.l
[0],
648 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
649 } else if (msgtype
== prop_atoms
.net_close_window
) {
650 g_message("net_close_window for 0x%lx", client
->window
);
651 client_close(client
);
652 } else if (msgtype
== prop_atoms
.net_active_window
) {
653 g_message("net_active_window for 0x%lx", client
->window
);
654 if (screen_showing_desktop
)
655 screen_show_desktop(FALSE
);
657 client_iconify(client
, FALSE
, TRUE
);
658 else if (!client
->frame
->visible
)
659 /* if its not visible for other reasons, then don't mess
663 client_shade(client
, FALSE
);
664 client_focus(client
);
665 stacking_raise(client
);
666 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
667 g_message("net_wm_moveresize for 0x%lx", client
->window
);
668 if ((Atom
)e
->xclient
.data
.l
[2] ==
669 prop_atoms
.net_wm_moveresize_size_topleft
||
670 (Atom
)e
->xclient
.data
.l
[2] ==
671 prop_atoms
.net_wm_moveresize_size_top
||
672 (Atom
)e
->xclient
.data
.l
[2] ==
673 prop_atoms
.net_wm_moveresize_size_topright
||
674 (Atom
)e
->xclient
.data
.l
[2] ==
675 prop_atoms
.net_wm_moveresize_size_right
||
676 (Atom
)e
->xclient
.data
.l
[2] ==
677 prop_atoms
.net_wm_moveresize_size_right
||
678 (Atom
)e
->xclient
.data
.l
[2] ==
679 prop_atoms
.net_wm_moveresize_size_bottomright
||
680 (Atom
)e
->xclient
.data
.l
[2] ==
681 prop_atoms
.net_wm_moveresize_size_bottom
||
682 (Atom
)e
->xclient
.data
.l
[2] ==
683 prop_atoms
.net_wm_moveresize_size_bottomleft
||
684 (Atom
)e
->xclient
.data
.l
[2] ==
685 prop_atoms
.net_wm_moveresize_size_left
||
686 (Atom
)e
->xclient
.data
.l
[2] ==
687 prop_atoms
.net_wm_moveresize_move
||
688 (Atom
)e
->xclient
.data
.l
[2] ==
689 prop_atoms
.net_wm_moveresize_size_keyboard
||
690 (Atom
)e
->xclient
.data
.l
[2] ==
691 prop_atoms
.net_wm_moveresize_move_keyboard
) {
693 g_message("client %lx x %d y %d button %d corner %d",
694 client
, e
->xclient
.data
.l
[0],
695 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
696 e
->xclient
.data
.l
[2]);
697 moveresize_start(client
, e
->xclient
.data
.l
[0],
698 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
699 e
->xclient
.data
.l
[2]);
701 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
702 int oldg
= client
->gravity
;
703 int tmpg
, x
, y
, w
, h
;
705 if (e
->xclient
.data
.l
[0] & 0xff)
706 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
710 if (e
->xclient
.data
.l
[0] & 1 << 8)
711 x
= e
->xclient
.data
.l
[1];
714 if (e
->xclient
.data
.l
[0] & 1 << 9)
715 y
= e
->xclient
.data
.l
[2];
718 if (e
->xclient
.data
.l
[0] & 1 << 10)
719 w
= e
->xclient
.data
.l
[3];
722 if (e
->xclient
.data
.l
[0] & 1 << 11)
723 h
= e
->xclient
.data
.l
[4];
726 client
->gravity
= tmpg
;
727 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
728 client
->gravity
= oldg
;
732 /* validate cuz we query stuff off the client here */
733 if (!client_validate(client
)) break;
735 /* compress changes to a single property into a single change */
736 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
737 client
->window
, &ce
)) {
738 /* XXX: it would be nice to compress ALL changes to a property,
739 not just changes in a row without other props between. */
740 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
741 XPutBackEvent(ob_display
, &ce
);
746 msgtype
= e
->xproperty
.atom
;
747 if (msgtype
== XA_WM_NORMAL_HINTS
) {
748 client_update_normal_hints(client
);
749 /* normal hints can make a window non-resizable */
750 client_setup_decor_and_functions(client
);
752 else if (msgtype
== XA_WM_HINTS
)
753 client_update_wmhints(client
);
754 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
755 client_update_transient_for(client
);
756 client_get_type(client
);
757 /* type may have changed, so update the layer */
758 client_calc_layer(client
);
759 client_setup_decor_and_functions(client
);
761 else if (msgtype
== prop_atoms
.net_wm_name
||
762 msgtype
== prop_atoms
.wm_name
)
763 client_update_title(client
);
764 else if (msgtype
== prop_atoms
.net_wm_icon_name
||
765 msgtype
== prop_atoms
.wm_icon_name
)
766 client_update_icon_title(client
);
767 else if (msgtype
== prop_atoms
.wm_class
)
768 client_update_class(client
);
769 else if (msgtype
== prop_atoms
.wm_protocols
) {
770 client_update_protocols(client
);
771 client_setup_decor_and_functions(client
);
773 else if (msgtype
== prop_atoms
.net_wm_strut
)
774 client_update_strut(client
);
775 else if (msgtype
== prop_atoms
.net_wm_icon
)
776 client_update_icons(client
);
777 else if (msgtype
== prop_atoms
.kwm_win_icon
)
778 client_update_kwm_icon(client
);
782 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
783 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
784 frame_adjust_shape(client
->frame
);
790 static void event_handle_menu(Menu
*menu
, XEvent
*e
)
794 g_message("EVENT %d", e
->type
);
797 if (e
->xbutton
.button
== 3)
801 if (!menu
->shown
) break;
803 /* grab_pointer_window(FALSE, None, menu->frame);*/
805 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
809 guint ujunk
, b
, w
, h
;
810 XGetGeometry(ob_display
, e
->xbutton
.window
,
811 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
812 if (e
->xbutton
.x
>= (signed)-b
&&
813 e
->xbutton
.y
>= (signed)-b
&&
814 e
->xbutton
.x
< (signed)(w
+b
) &&
815 e
->xbutton
.y
< (signed)(h
+b
)) {
816 menu_entry_fire(entry
);
822 g_message("enter/leave");
823 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
825 entry
->hilite
= e
->type
== EnterNotify
;
826 menu_entry_render(entry
);