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
;
149 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
150 switch (((XkbAnyEvent
*)&e
)->xkb_type
) {
152 window
= ((XkbBellNotifyEvent
*)&e
)->window
;
158 window
= e
->xany
.window
;
163 static void event_set_lasttime(XEvent
*e
)
165 /* grab the lasttime and hack up the state */
169 event_lasttime
= e
->xbutton
.time
;
172 event_lasttime
= e
->xkey
.time
;
175 event_lasttime
= e
->xkey
.time
;
178 event_lasttime
= e
->xmotion
.time
;
181 event_lasttime
= e
->xproperty
.time
;
185 event_lasttime
= e
->xcrossing
.time
;
188 event_lasttime
= CurrentTime
;
193 #define STRIP_MODS(s) \
194 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
195 /* kill off the Button1Mask etc, only want the modifiers */ \
196 s &= (ControlMask | ShiftMask | Mod1Mask | \
197 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
199 static void event_hack_mods(XEvent *e)
207 STRIP_MODS(e
->xbutton
.state
);
210 STRIP_MODS(e
->xkey
.state
);
213 STRIP_MODS(e
->xkey
.state
);
214 /* remove from the state the mask of the modifier being released, if
215 it is a modifier key being released (this is a little ugly..) */
216 kp
= modmap
->modifiermap
;
217 for (i
= 0; i
< mask_table_size
; ++i
) {
218 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
219 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
220 /* remove the mask for it */
221 e
->xkey
.state
&= ~mask_table
[i
];
222 /* cause the first loop to break; */
224 break; /* get outta here! */
231 STRIP_MODS(e
->xmotion
.state
);
232 /* compress events */
235 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
237 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
238 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
245 static gboolean
event_ignore(XEvent
*e
, Client
*client
)
249 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
250 because of RevertToPointerRoot. If the focus ends up reverting to
251 pointer root on a workspace change, then the FocusIn event that we
252 want will be of type NotifyAncestor. This situation does not occur
253 for FocusOut, so it is safely ignored there.
255 if (INVALID_FOCUSIN(e
) ||
258 g_message("FocusIn on %lx mode %d detail %d IGNORED", e
->xfocus
.window
,
259 e
->xfocus
.mode
, e
->xfocus
.detail
);
261 /* says a client was not found for the event (or a valid FocusIn
264 e
->xfocus
.window
= None
;
269 g_message("FocusIn on %lx mode %d detail %d", e
->xfocus
.window
,
270 e
->xfocus
.mode
, e
->xfocus
.detail
);
274 if (INVALID_FOCUSOUT(e
)) {
276 g_message("FocusOut on %lx mode %d detail %d IGNORED",
277 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
283 g_message("FocusOut on %lx mode %d detail %d",
284 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
287 /* Try process a FocusIn first, and if a legit one isn't found, then
288 do the fallback shiznit. */
291 gboolean fallback
= TRUE
;
294 if (!XCheckTypedEvent(ob_display
, FocusOut
, &fe
))
295 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
297 if (fe
.type
== FocusOut
) {
299 g_message("found pending FocusOut");
301 if (!INVALID_FOCUSOUT(&fe
)) {
302 /* if there is a VALID FocusOut still coming, don't
303 fallback focus yet, we'll deal with it then */
304 XPutBackEvent(ob_display
, &fe
);
310 g_message("found pending FocusIn");
312 /* once all the FocusOut's have been dealt with, if there
313 is a FocusIn still left and it is valid, then use it */
315 /* secret magic way of event_process telling us that no
316 client was found for the FocusIn event. ^_^ */
317 if (fe
.xfocus
.window
!= None
) {
325 g_message("no valid FocusIn and no FocusOut events found, "
328 focus_fallback(Fallback_NoFocus
);
334 /* NotifyUngrab occurs when a mouse button is released and the event is
335 caused, like when lowering a window */
336 /* NotifyVirtual occurs when ungrabbing the pointer */
337 if (e
->xcrossing
.mode
== NotifyGrab
||
338 e
->xcrossing
.detail
== NotifyInferior
||
339 (e
->xcrossing
.mode
== NotifyUngrab
&&
340 e
->xcrossing
.detail
== NotifyVirtual
))
347 static void event_process(XEvent
*e
)
353 window
= event_get_window(e
);
354 if (!(client
= g_hash_table_lookup(client_map
, &window
)))
355 menu
= g_hash_table_lookup(menu_map
, &window
);
356 event_set_lasttime(e
);
358 if (event_ignore(e
, client
))
361 /* deal with it in the kernel */
363 event_handle_menu(menu
, e
);
366 event_handle_client(client
, e
);
367 else if (window
== ob_root
)
368 event_handle_root(e
);
369 else if (e
->type
== MapRequest
)
370 client_manage(window
);
371 else if (e
->type
== ConfigureRequest
) {
372 /* unhandled configure requests must be used to configure the
376 xwc
.x
= e
->xconfigurerequest
.x
;
377 xwc
.y
= e
->xconfigurerequest
.y
;
378 xwc
.width
= e
->xconfigurerequest
.width
;
379 xwc
.height
= e
->xconfigurerequest
.height
;
380 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
381 xwc
.sibling
= e
->xconfigurerequest
.above
;
382 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
384 /* we are not to be held responsible if someone sends us an
386 xerror_set_ignore(TRUE
);
387 XConfigureWindow(ob_display
, window
,
388 e
->xconfigurerequest
.value_mask
, &xwc
);
389 xerror_set_ignore(FALSE
);
392 if (moveresize_in_progress
)
393 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
394 e
->type
== ButtonPress
||
395 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
397 return; /* no dispatch! */
400 /* user input (action-bound) events */
402 if (e->type == ButtonPress || e->type == ButtonRelease ||
403 e->type == MotionNotify)
404 mouse_event(e, client);
405 else if (e->type == KeyPress || e->type == KeyRelease)
409 /* dispatch the event to registered handlers */
410 dispatch_x(e
, client
);
413 static void event_handle_root(XEvent
*e
)
419 if (e
->xclient
.format
!= 32) break;
421 msgtype
= e
->xclient
.message_type
;
422 if (msgtype
== prop_atoms
.net_current_desktop
) {
423 unsigned int d
= e
->xclient
.data
.l
[0];
424 if (d
< screen_num_desktops
)
425 screen_set_desktop(d
);
426 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
427 unsigned int d
= e
->xclient
.data
.l
[0];
429 screen_set_num_desktops(d
);
430 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
431 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
435 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
436 screen_update_desktop_names();
437 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
438 screen_update_layout();
443 static void event_handle_client(Client
*client
, XEvent
*e
)
452 switch (frame_context(client
, e
->xbutton
.window
)) {
453 case Context_Maximize
:
454 client
->frame
->max_press
= (e
->type
== ButtonPress
);
455 framerender_frame(client
->frame
);
458 client
->frame
->close_press
= (e
->type
== ButtonPress
);
459 framerender_frame(client
->frame
);
461 case Context_Iconify
:
462 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
463 framerender_frame(client
->frame
);
465 case Context_AllDesktops
:
466 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
467 framerender_frame(client
->frame
);
470 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
471 framerender_frame(client
->frame
);
474 /* nothing changes with clicks for any other contexts */
479 focus_set_client(client
);
482 g_message("Focus%s on client for %lx", (e
->type
==FocusIn
?"In":"Out"),
485 /* focus state can affect the stacking layer */
486 client_calc_layer(client
);
487 frame_adjust_focus(client
->frame
);
490 if (client_normal(client
)) {
491 if (ob_state
== State_Starting
) {
492 /* move it to the top of the focus order */
493 guint desktop
= client
->desktop
;
494 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
495 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
497 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
499 } else if (config_focus_follow
) {
501 g_message("EnterNotify on %lx, focusing window",
504 client_focus(client
);
508 case ConfigureRequest
:
510 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
511 ConfigureRequest
, &ce
)) {
513 /* XXX if this causes bad things.. we can compress config req's
514 with the same mask. */
515 e
->xconfigurerequest
.value_mask
|=
516 ce
.xconfigurerequest
.value_mask
;
517 if (ce
.xconfigurerequest
.value_mask
& CWX
)
518 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
519 if (ce
.xconfigurerequest
.value_mask
& CWY
)
520 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
521 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
522 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
523 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
524 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
525 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
526 e
->xconfigurerequest
.border_width
=
527 ce
.xconfigurerequest
.border_width
;
528 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
529 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
532 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
533 if (client
->iconic
|| client
->shaded
) return;
535 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
536 client
->border_width
= e
->xconfigurerequest
.border_width
;
538 /* resize, then move, as specified in the EWMH section 7.7 */
539 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
544 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
545 e
->xconfigurerequest
.x
: client
->area
.x
;
546 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
547 e
->xconfigurerequest
.y
: client
->area
.y
;
548 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
549 e
->xconfigurerequest
.width
: client
->area
.width
;
550 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
551 e
->xconfigurerequest
.height
: client
->area
.height
;
553 switch (client
->gravity
) {
554 case NorthEastGravity
:
556 corner
= Corner_TopRight
;
558 case SouthWestGravity
:
560 corner
= Corner_BottomLeft
;
562 case SouthEastGravity
:
563 corner
= Corner_BottomRight
;
565 default: /* NorthWest, Static, etc */
566 corner
= Corner_TopLeft
;
569 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
572 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
573 switch (e
->xconfigurerequest
.detail
) {
576 stacking_lower(client
);
582 stacking_raise(client
);
588 if (client
->ignore_unmaps
) {
589 client
->ignore_unmaps
--;
592 client_unmanage(client
);
595 client_unmanage(client
);
598 /* this is when the client is first taken captive in the frame */
599 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
602 This event is quite rare and is usually handled in unmapHandler.
603 However, if the window is unmapped when the reparent event occurs,
604 the window manager never sees it because an unmap event is not sent
605 to an already unmapped window.
608 /* we don't want the reparent event, put it back on the stack for the
609 X server to deal with after we unmanage the window */
610 XPutBackEvent(ob_display
, e
);
612 client_unmanage(client
);
615 g_message("MapRequest for 0x%lx", client
->window
);
616 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
617 does, we don't want it! */
618 if (screen_showing_desktop
)
619 screen_show_desktop(FALSE
);
620 client_iconify(client
, FALSE
, TRUE
);
621 if (!client
->frame
->visible
)
622 /* if its not visible still, then don't mess with it */
625 client_shade(client
, FALSE
);
626 client_focus(client
);
627 stacking_raise(client
);
630 /* validate cuz we query stuff off the client here */
631 if (!client_validate(client
)) break;
633 if (e
->xclient
.format
!= 32) return;
635 msgtype
= e
->xclient
.message_type
;
636 if (msgtype
== prop_atoms
.wm_change_state
) {
637 /* compress changes into a single change */
638 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
639 client
->window
, &ce
)) {
640 /* XXX: it would be nice to compress ALL messages of a
641 type, not just messages in a row without other
642 message types between. */
643 if (ce
.xclient
.message_type
!= msgtype
) {
644 XPutBackEvent(ob_display
, &ce
);
647 e
->xclient
= ce
.xclient
;
649 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
650 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
651 /* compress changes into a single change */
652 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
653 client
->window
, &ce
)) {
654 /* XXX: it would be nice to compress ALL messages of a
655 type, not just messages in a row without other
656 message types between. */
657 if (ce
.xclient
.message_type
!= msgtype
) {
658 XPutBackEvent(ob_display
, &ce
);
661 e
->xclient
= ce
.xclient
;
663 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
664 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
665 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
667 } else if (msgtype
== prop_atoms
.net_wm_state
) {
668 /* can't compress these */
669 g_message("net_wm_state %s %ld %ld for 0x%lx",
670 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
671 e
->xclient
.data
.l
[0] == 1 ? "Add" :
672 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
673 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
675 client_set_state(client
, e
->xclient
.data
.l
[0],
676 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
677 } else if (msgtype
== prop_atoms
.net_close_window
) {
678 g_message("net_close_window for 0x%lx", client
->window
);
679 client_close(client
);
680 } else if (msgtype
== prop_atoms
.net_active_window
) {
681 g_message("net_active_window for 0x%lx", client
->window
);
682 if (screen_showing_desktop
)
683 screen_show_desktop(FALSE
);
685 client_iconify(client
, FALSE
, TRUE
);
686 else if (!client
->frame
->visible
)
687 /* if its not visible for other reasons, then don't mess
691 client_shade(client
, FALSE
);
692 client_focus(client
);
693 stacking_raise(client
);
694 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
695 g_message("net_wm_moveresize for 0x%lx", client
->window
);
696 if ((Atom
)e
->xclient
.data
.l
[2] ==
697 prop_atoms
.net_wm_moveresize_size_topleft
||
698 (Atom
)e
->xclient
.data
.l
[2] ==
699 prop_atoms
.net_wm_moveresize_size_top
||
700 (Atom
)e
->xclient
.data
.l
[2] ==
701 prop_atoms
.net_wm_moveresize_size_topright
||
702 (Atom
)e
->xclient
.data
.l
[2] ==
703 prop_atoms
.net_wm_moveresize_size_right
||
704 (Atom
)e
->xclient
.data
.l
[2] ==
705 prop_atoms
.net_wm_moveresize_size_right
||
706 (Atom
)e
->xclient
.data
.l
[2] ==
707 prop_atoms
.net_wm_moveresize_size_bottomright
||
708 (Atom
)e
->xclient
.data
.l
[2] ==
709 prop_atoms
.net_wm_moveresize_size_bottom
||
710 (Atom
)e
->xclient
.data
.l
[2] ==
711 prop_atoms
.net_wm_moveresize_size_bottomleft
||
712 (Atom
)e
->xclient
.data
.l
[2] ==
713 prop_atoms
.net_wm_moveresize_size_left
||
714 (Atom
)e
->xclient
.data
.l
[2] ==
715 prop_atoms
.net_wm_moveresize_move
||
716 (Atom
)e
->xclient
.data
.l
[2] ==
717 prop_atoms
.net_wm_moveresize_size_keyboard
||
718 (Atom
)e
->xclient
.data
.l
[2] ==
719 prop_atoms
.net_wm_moveresize_move_keyboard
) {
721 moveresize_start(client
, e
->xclient
.data
.l
[0],
722 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
723 e
->xclient
.data
.l
[2]);
725 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
726 int oldg
= client
->gravity
;
727 int tmpg
, x
, y
, w
, h
;
729 if (e
->xclient
.data
.l
[0] & 0xff)
730 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
734 if (e
->xclient
.data
.l
[0] & 1 << 8)
735 x
= e
->xclient
.data
.l
[1];
738 if (e
->xclient
.data
.l
[0] & 1 << 9)
739 y
= e
->xclient
.data
.l
[2];
742 if (e
->xclient
.data
.l
[0] & 1 << 10)
743 w
= e
->xclient
.data
.l
[3];
746 if (e
->xclient
.data
.l
[0] & 1 << 11)
747 h
= e
->xclient
.data
.l
[4];
750 client
->gravity
= tmpg
;
751 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
752 client
->gravity
= oldg
;
756 /* validate cuz we query stuff off the client here */
757 if (!client_validate(client
)) break;
759 /* compress changes to a single property into a single change */
760 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
761 client
->window
, &ce
)) {
762 /* XXX: it would be nice to compress ALL changes to a property,
763 not just changes in a row without other props between. */
764 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
765 XPutBackEvent(ob_display
, &ce
);
770 msgtype
= e
->xproperty
.atom
;
771 if (msgtype
== XA_WM_NORMAL_HINTS
) {
772 client_update_normal_hints(client
);
773 /* normal hints can make a window non-resizable */
774 client_setup_decor_and_functions(client
);
776 else if (msgtype
== XA_WM_HINTS
)
777 client_update_wmhints(client
);
778 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
779 client_update_transient_for(client
);
780 client_get_type(client
);
781 /* type may have changed, so update the layer */
782 client_calc_layer(client
);
783 client_setup_decor_and_functions(client
);
785 else if (msgtype
== prop_atoms
.net_wm_name
||
786 msgtype
== prop_atoms
.wm_name
)
787 client_update_title(client
);
788 else if (msgtype
== prop_atoms
.net_wm_icon_name
||
789 msgtype
== prop_atoms
.wm_icon_name
)
790 client_update_icon_title(client
);
791 else if (msgtype
== prop_atoms
.wm_class
)
792 client_update_class(client
);
793 else if (msgtype
== prop_atoms
.wm_protocols
) {
794 client_update_protocols(client
);
795 client_setup_decor_and_functions(client
);
797 else if (msgtype
== prop_atoms
.net_wm_strut
)
798 client_update_strut(client
);
799 else if (msgtype
== prop_atoms
.net_wm_icon
)
800 client_update_icons(client
);
801 else if (msgtype
== prop_atoms
.kwm_win_icon
)
802 client_update_kwm_icon(client
);
806 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
807 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
808 frame_adjust_shape(client
->frame
);
814 static void event_handle_menu(Menu
*menu
, XEvent
*e
)
818 g_message("EVENT %d", e
->type
);
821 if (e
->xbutton
.button
== 3)
825 if (!menu
->shown
) break;
827 /* grab_pointer_window(FALSE, None, menu->frame);*/
829 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
833 guint ujunk
, b
, w
, h
;
834 XGetGeometry(ob_display
, e
->xbutton
.window
,
835 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
836 if (e
->xbutton
.x
>= (signed)-b
&&
837 e
->xbutton
.y
>= (signed)-b
&&
838 e
->xbutton
.x
< (signed)(w
+b
) &&
839 e
->xbutton
.y
< (signed)(h
+b
)) {
840 menu_entry_fire(entry
);
846 g_message("enter/leave");
847 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
849 entry
->hilite
= e
->type
== EnterNotify
;
850 menu_entry_render(entry
);