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 (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
295 e
->xfocus
.window
,&fe
))
296 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
298 if (fe
.type
== FocusOut
) {
300 g_message("found pending FocusOut");
302 if (!INVALID_FOCUSOUT(&fe
)) {
303 /* if there is a VALID FocusOut still coming, don't
304 fallback focus yet, we'll deal with it then */
305 XPutBackEvent(ob_display
, &fe
);
311 g_message("found pending FocusIn");
313 /* once all the FocusOut's have been dealt with, if there
314 is a FocusIn still left and it is valid, then use it */
316 /* secret magic way of event_process telling us that no
317 client was found for the FocusIn event. ^_^ */
318 if (fe
.xfocus
.window
!= None
) {
326 g_message("no valid FocusIn and no FocusOut events found, "
329 focus_fallback(Fallback_NoFocus
);
335 /* NotifyUngrab occurs when a mouse button is released and the event is
336 caused, like when lowering a window */
337 /* NotifyVirtual occurs when ungrabbing the pointer */
338 if (e
->xcrossing
.mode
== NotifyGrab
||
339 e
->xcrossing
.detail
== NotifyInferior
||
340 (e
->xcrossing
.mode
== NotifyUngrab
&&
341 e
->xcrossing
.detail
== NotifyVirtual
)) {
343 g_message("%sNotify mode %d detail %d on %lx IGNORED",
344 (e
->type
== EnterNotify
? "Enter" : "Leave"),
346 e
->xcrossing
.detail
, client
?client
->window
:0);
351 g_message("%sNotify mode %d detail %d on %lx",
352 (e
->type
== EnterNotify
? "Enter" : "Leave"),
354 e
->xcrossing
.detail
, client
?client
->window
:0);
361 static void event_process(XEvent
*e
)
367 window
= event_get_window(e
);
368 if (!(client
= g_hash_table_lookup(client_map
, &window
)))
369 menu
= g_hash_table_lookup(menu_map
, &window
);
370 event_set_lasttime(e
);
372 if (event_ignore(e
, client
))
375 /* deal with it in the kernel */
377 event_handle_menu(menu
, e
);
380 event_handle_client(client
, e
);
381 else if (window
== ob_root
)
382 event_handle_root(e
);
383 else if (e
->type
== MapRequest
)
384 client_manage(window
);
385 else if (e
->type
== ConfigureRequest
) {
386 /* unhandled configure requests must be used to configure the
390 xwc
.x
= e
->xconfigurerequest
.x
;
391 xwc
.y
= e
->xconfigurerequest
.y
;
392 xwc
.width
= e
->xconfigurerequest
.width
;
393 xwc
.height
= e
->xconfigurerequest
.height
;
394 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
395 xwc
.sibling
= e
->xconfigurerequest
.above
;
396 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
398 /* we are not to be held responsible if someone sends us an
400 xerror_set_ignore(TRUE
);
401 XConfigureWindow(ob_display
, window
,
402 e
->xconfigurerequest
.value_mask
, &xwc
);
403 xerror_set_ignore(FALSE
);
406 if (moveresize_in_progress
)
407 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
408 e
->type
== ButtonPress
||
409 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
412 return; /* no dispatch! */
416 /* user input (action-bound) events */
418 if (e->type == ButtonPress || e->type == ButtonRelease ||
419 e->type == MotionNotify)
420 mouse_event(e, client);
421 else if (e->type == KeyPress || e->type == KeyRelease)
425 /* dispatch the event to registered handlers */
426 dispatch_x(e
, client
);
429 static void event_handle_root(XEvent
*e
)
435 if (e
->xclient
.format
!= 32) break;
437 msgtype
= e
->xclient
.message_type
;
438 if (msgtype
== prop_atoms
.net_current_desktop
) {
439 unsigned int d
= e
->xclient
.data
.l
[0];
440 if (d
< screen_num_desktops
)
441 screen_set_desktop(d
);
442 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
443 unsigned int d
= e
->xclient
.data
.l
[0];
445 screen_set_num_desktops(d
);
446 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
447 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
451 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
452 screen_update_desktop_names();
453 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
454 screen_update_layout();
459 static void event_handle_client(Client
*client
, XEvent
*e
)
468 switch (frame_context(client
, e
->xbutton
.window
)) {
469 case Context_Maximize
:
470 client
->frame
->max_press
= (e
->type
== ButtonPress
);
471 framerender_frame(client
->frame
);
474 client
->frame
->close_press
= (e
->type
== ButtonPress
);
475 framerender_frame(client
->frame
);
477 case Context_Iconify
:
478 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
479 framerender_frame(client
->frame
);
481 case Context_AllDesktops
:
482 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
483 framerender_frame(client
->frame
);
486 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
487 framerender_frame(client
->frame
);
490 /* nothing changes with clicks for any other contexts */
495 focus_set_client(client
);
498 g_message("Focus%s on client for %lx", (e
->type
==FocusIn
?"In":"Out"),
501 /* focus state can affect the stacking layer */
502 client_calc_layer(client
);
503 frame_adjust_focus(client
->frame
);
506 if (client_normal(client
)) {
507 if (ob_state
== State_Starting
) {
508 /* move it to the top of the focus order */
509 guint desktop
= client
->desktop
;
510 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
511 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
513 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
515 } else if (config_focus_follow
) {
517 g_message("EnterNotify on %lx, focusing window",
520 client_focus(client
);
524 case ConfigureRequest
:
526 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
527 ConfigureRequest
, &ce
)) {
529 /* XXX if this causes bad things.. we can compress config req's
530 with the same mask. */
531 e
->xconfigurerequest
.value_mask
|=
532 ce
.xconfigurerequest
.value_mask
;
533 if (ce
.xconfigurerequest
.value_mask
& CWX
)
534 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
535 if (ce
.xconfigurerequest
.value_mask
& CWY
)
536 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
537 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
538 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
539 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
540 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
541 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
542 e
->xconfigurerequest
.border_width
=
543 ce
.xconfigurerequest
.border_width
;
544 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
545 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
548 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
549 if (client
->iconic
|| client
->shaded
) return;
551 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
552 client
->border_width
= e
->xconfigurerequest
.border_width
;
554 /* resize, then move, as specified in the EWMH section 7.7 */
555 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
560 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
561 e
->xconfigurerequest
.x
: client
->area
.x
;
562 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
563 e
->xconfigurerequest
.y
: client
->area
.y
;
564 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
565 e
->xconfigurerequest
.width
: client
->area
.width
;
566 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
567 e
->xconfigurerequest
.height
: client
->area
.height
;
569 switch (client
->gravity
) {
570 case NorthEastGravity
:
572 corner
= Corner_TopRight
;
574 case SouthWestGravity
:
576 corner
= Corner_BottomLeft
;
578 case SouthEastGravity
:
579 corner
= Corner_BottomRight
;
581 default: /* NorthWest, Static, etc */
582 corner
= Corner_TopLeft
;
585 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
588 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
589 switch (e
->xconfigurerequest
.detail
) {
592 stacking_lower(client
);
598 stacking_raise(client
);
604 if (client
->ignore_unmaps
) {
605 client
->ignore_unmaps
--;
608 client_unmanage(client
);
611 client_unmanage(client
);
614 /* this is when the client is first taken captive in the frame */
615 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
618 This event is quite rare and is usually handled in unmapHandler.
619 However, if the window is unmapped when the reparent event occurs,
620 the window manager never sees it because an unmap event is not sent
621 to an already unmapped window.
624 /* we don't want the reparent event, put it back on the stack for the
625 X server to deal with after we unmanage the window */
626 XPutBackEvent(ob_display
, e
);
628 client_unmanage(client
);
631 g_message("MapRequest for 0x%lx", client
->window
);
632 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
633 does, we don't want it! */
634 if (screen_showing_desktop
)
635 screen_show_desktop(FALSE
);
636 client_iconify(client
, FALSE
, TRUE
);
637 if (!client
->frame
->visible
)
638 /* if its not visible still, then don't mess with it */
641 client_shade(client
, FALSE
);
642 client_focus(client
);
643 stacking_raise(client
);
646 /* validate cuz we query stuff off the client here */
647 if (!client_validate(client
)) break;
649 if (e
->xclient
.format
!= 32) return;
651 msgtype
= e
->xclient
.message_type
;
652 if (msgtype
== prop_atoms
.wm_change_state
) {
653 /* compress changes into a single change */
654 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
655 client
->window
, &ce
)) {
656 /* XXX: it would be nice to compress ALL messages of a
657 type, not just messages in a row without other
658 message types between. */
659 if (ce
.xclient
.message_type
!= msgtype
) {
660 XPutBackEvent(ob_display
, &ce
);
663 e
->xclient
= ce
.xclient
;
665 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
666 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
667 /* compress changes into a single change */
668 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
669 client
->window
, &ce
)) {
670 /* XXX: it would be nice to compress ALL messages of a
671 type, not just messages in a row without other
672 message types between. */
673 if (ce
.xclient
.message_type
!= msgtype
) {
674 XPutBackEvent(ob_display
, &ce
);
677 e
->xclient
= ce
.xclient
;
679 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
680 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
681 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
683 } else if (msgtype
== prop_atoms
.net_wm_state
) {
684 /* can't compress these */
685 g_message("net_wm_state %s %ld %ld for 0x%lx",
686 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
687 e
->xclient
.data
.l
[0] == 1 ? "Add" :
688 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
689 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
691 client_set_state(client
, e
->xclient
.data
.l
[0],
692 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
693 } else if (msgtype
== prop_atoms
.net_close_window
) {
694 g_message("net_close_window for 0x%lx", client
->window
);
695 client_close(client
);
696 } else if (msgtype
== prop_atoms
.net_active_window
) {
697 g_message("net_active_window for 0x%lx", client
->window
);
698 if (screen_showing_desktop
)
699 screen_show_desktop(FALSE
);
701 client_iconify(client
, FALSE
, TRUE
);
702 else if (!client
->frame
->visible
)
703 /* if its not visible for other reasons, then don't mess
707 client_shade(client
, FALSE
);
708 client_focus(client
);
709 stacking_raise(client
);
710 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
711 g_message("net_wm_moveresize for 0x%lx", client
->window
);
712 if ((Atom
)e
->xclient
.data
.l
[2] ==
713 prop_atoms
.net_wm_moveresize_size_topleft
||
714 (Atom
)e
->xclient
.data
.l
[2] ==
715 prop_atoms
.net_wm_moveresize_size_top
||
716 (Atom
)e
->xclient
.data
.l
[2] ==
717 prop_atoms
.net_wm_moveresize_size_topright
||
718 (Atom
)e
->xclient
.data
.l
[2] ==
719 prop_atoms
.net_wm_moveresize_size_right
||
720 (Atom
)e
->xclient
.data
.l
[2] ==
721 prop_atoms
.net_wm_moveresize_size_right
||
722 (Atom
)e
->xclient
.data
.l
[2] ==
723 prop_atoms
.net_wm_moveresize_size_bottomright
||
724 (Atom
)e
->xclient
.data
.l
[2] ==
725 prop_atoms
.net_wm_moveresize_size_bottom
||
726 (Atom
)e
->xclient
.data
.l
[2] ==
727 prop_atoms
.net_wm_moveresize_size_bottomleft
||
728 (Atom
)e
->xclient
.data
.l
[2] ==
729 prop_atoms
.net_wm_moveresize_size_left
||
730 (Atom
)e
->xclient
.data
.l
[2] ==
731 prop_atoms
.net_wm_moveresize_move
||
732 (Atom
)e
->xclient
.data
.l
[2] ==
733 prop_atoms
.net_wm_moveresize_size_keyboard
||
734 (Atom
)e
->xclient
.data
.l
[2] ==
735 prop_atoms
.net_wm_moveresize_move_keyboard
) {
737 moveresize_start(client
, e
->xclient
.data
.l
[0],
738 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
739 e
->xclient
.data
.l
[2]);
741 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
742 int oldg
= client
->gravity
;
743 int tmpg
, x
, y
, w
, h
;
745 if (e
->xclient
.data
.l
[0] & 0xff)
746 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
750 if (e
->xclient
.data
.l
[0] & 1 << 8)
751 x
= e
->xclient
.data
.l
[1];
754 if (e
->xclient
.data
.l
[0] & 1 << 9)
755 y
= e
->xclient
.data
.l
[2];
758 if (e
->xclient
.data
.l
[0] & 1 << 10)
759 w
= e
->xclient
.data
.l
[3];
762 if (e
->xclient
.data
.l
[0] & 1 << 11)
763 h
= e
->xclient
.data
.l
[4];
766 client
->gravity
= tmpg
;
767 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
768 client
->gravity
= oldg
;
772 /* validate cuz we query stuff off the client here */
773 if (!client_validate(client
)) break;
775 /* compress changes to a single property into a single change */
776 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
777 client
->window
, &ce
)) {
778 /* XXX: it would be nice to compress ALL changes to a property,
779 not just changes in a row without other props between. */
780 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
781 XPutBackEvent(ob_display
, &ce
);
786 msgtype
= e
->xproperty
.atom
;
787 if (msgtype
== XA_WM_NORMAL_HINTS
) {
788 client_update_normal_hints(client
);
789 /* normal hints can make a window non-resizable */
790 client_setup_decor_and_functions(client
);
792 else if (msgtype
== XA_WM_HINTS
)
793 client_update_wmhints(client
);
794 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
795 client_update_transient_for(client
);
796 client_get_type(client
);
797 /* type may have changed, so update the layer */
798 client_calc_layer(client
);
799 client_setup_decor_and_functions(client
);
801 else if (msgtype
== prop_atoms
.net_wm_name
||
802 msgtype
== prop_atoms
.wm_name
)
803 client_update_title(client
);
804 else if (msgtype
== prop_atoms
.net_wm_icon_name
||
805 msgtype
== prop_atoms
.wm_icon_name
)
806 client_update_icon_title(client
);
807 else if (msgtype
== prop_atoms
.wm_class
)
808 client_update_class(client
);
809 else if (msgtype
== prop_atoms
.wm_protocols
) {
810 client_update_protocols(client
);
811 client_setup_decor_and_functions(client
);
813 else if (msgtype
== prop_atoms
.net_wm_strut
)
814 client_update_strut(client
);
815 else if (msgtype
== prop_atoms
.net_wm_icon
)
816 client_update_icons(client
);
817 else if (msgtype
== prop_atoms
.kwm_win_icon
)
818 client_update_kwm_icon(client
);
822 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
823 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
824 frame_adjust_shape(client
->frame
);
830 static void event_handle_menu(Menu
*menu
, XEvent
*e
)
834 g_message("EVENT %d", e
->type
);
837 if (e
->xbutton
.button
== 3)
841 if (!menu
->shown
) break;
843 /* grab_pointer_window(FALSE, None, menu->frame);*/
845 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
849 guint ujunk
, b
, w
, h
;
850 XGetGeometry(ob_display
, e
->xbutton
.window
,
851 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
852 if (e
->xbutton
.x
>= (signed)-b
&&
853 e
->xbutton
.y
>= (signed)-b
&&
854 e
->xbutton
.x
< (signed)(w
+b
) &&
855 e
->xbutton
.y
< (signed)(h
+b
)) {
856 menu_entry_fire(entry
);
862 g_message("enter/leave");
863 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
865 entry
->hilite
= e
->type
== EnterNotify
;
866 menu_entry_render(entry
);