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
)) {
342 g_message("%sNotify mode %d detail %d on %lx IGNORED",
343 (e
->type
== EnterNotify
? "Enter" : "Leave"),
345 e
->xcrossing
.detail
, client
?client
->window
:0);
350 g_message("%sNotify mode %d detail %d on %lx",
351 (e
->type
== EnterNotify
? "Enter" : "Leave"),
353 e
->xcrossing
.detail
, client
?client
->window
:0);
360 static void event_process(XEvent
*e
)
366 window
= event_get_window(e
);
367 if (!(client
= g_hash_table_lookup(client_map
, &window
)))
368 menu
= g_hash_table_lookup(menu_map
, &window
);
369 event_set_lasttime(e
);
371 if (event_ignore(e
, client
))
374 /* deal with it in the kernel */
376 event_handle_menu(menu
, e
);
379 event_handle_client(client
, e
);
380 else if (window
== ob_root
)
381 event_handle_root(e
);
382 else if (e
->type
== MapRequest
)
383 client_manage(window
);
384 else if (e
->type
== ConfigureRequest
) {
385 /* unhandled configure requests must be used to configure the
389 xwc
.x
= e
->xconfigurerequest
.x
;
390 xwc
.y
= e
->xconfigurerequest
.y
;
391 xwc
.width
= e
->xconfigurerequest
.width
;
392 xwc
.height
= e
->xconfigurerequest
.height
;
393 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
394 xwc
.sibling
= e
->xconfigurerequest
.above
;
395 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
397 /* we are not to be held responsible if someone sends us an
399 xerror_set_ignore(TRUE
);
400 XConfigureWindow(ob_display
, window
,
401 e
->xconfigurerequest
.value_mask
, &xwc
);
402 xerror_set_ignore(FALSE
);
405 if (moveresize_in_progress
)
406 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
407 e
->type
== ButtonPress
||
408 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
410 return; /* no dispatch! */
413 /* user input (action-bound) events */
415 if (e->type == ButtonPress || e->type == ButtonRelease ||
416 e->type == MotionNotify)
417 mouse_event(e, client);
418 else if (e->type == KeyPress || e->type == KeyRelease)
422 /* dispatch the event to registered handlers */
423 dispatch_x(e
, client
);
426 static void event_handle_root(XEvent
*e
)
432 if (e
->xclient
.format
!= 32) break;
434 msgtype
= e
->xclient
.message_type
;
435 if (msgtype
== prop_atoms
.net_current_desktop
) {
436 unsigned int d
= e
->xclient
.data
.l
[0];
437 if (d
< screen_num_desktops
)
438 screen_set_desktop(d
);
439 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
440 unsigned int d
= e
->xclient
.data
.l
[0];
442 screen_set_num_desktops(d
);
443 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
444 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
448 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
449 screen_update_desktop_names();
450 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
451 screen_update_layout();
456 static void event_handle_client(Client
*client
, XEvent
*e
)
465 switch (frame_context(client
, e
->xbutton
.window
)) {
466 case Context_Maximize
:
467 client
->frame
->max_press
= (e
->type
== ButtonPress
);
468 framerender_frame(client
->frame
);
471 client
->frame
->close_press
= (e
->type
== ButtonPress
);
472 framerender_frame(client
->frame
);
474 case Context_Iconify
:
475 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
476 framerender_frame(client
->frame
);
478 case Context_AllDesktops
:
479 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
480 framerender_frame(client
->frame
);
483 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
484 framerender_frame(client
->frame
);
487 /* nothing changes with clicks for any other contexts */
492 focus_set_client(client
);
495 g_message("Focus%s on client for %lx", (e
->type
==FocusIn
?"In":"Out"),
498 /* focus state can affect the stacking layer */
499 client_calc_layer(client
);
500 frame_adjust_focus(client
->frame
);
503 if (client_normal(client
)) {
504 if (ob_state
== State_Starting
) {
505 /* move it to the top of the focus order */
506 guint desktop
= client
->desktop
;
507 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
508 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
510 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
512 } else if (config_focus_follow
) {
514 g_message("EnterNotify on %lx, focusing window",
517 client_focus(client
);
521 case ConfigureRequest
:
523 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
524 ConfigureRequest
, &ce
)) {
526 /* XXX if this causes bad things.. we can compress config req's
527 with the same mask. */
528 e
->xconfigurerequest
.value_mask
|=
529 ce
.xconfigurerequest
.value_mask
;
530 if (ce
.xconfigurerequest
.value_mask
& CWX
)
531 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
532 if (ce
.xconfigurerequest
.value_mask
& CWY
)
533 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
534 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
535 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
536 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
537 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
538 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
539 e
->xconfigurerequest
.border_width
=
540 ce
.xconfigurerequest
.border_width
;
541 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
542 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
545 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
546 if (client
->iconic
|| client
->shaded
) return;
548 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
549 client
->border_width
= e
->xconfigurerequest
.border_width
;
551 /* resize, then move, as specified in the EWMH section 7.7 */
552 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
557 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
558 e
->xconfigurerequest
.x
: client
->area
.x
;
559 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
560 e
->xconfigurerequest
.y
: client
->area
.y
;
561 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
562 e
->xconfigurerequest
.width
: client
->area
.width
;
563 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
564 e
->xconfigurerequest
.height
: client
->area
.height
;
566 switch (client
->gravity
) {
567 case NorthEastGravity
:
569 corner
= Corner_TopRight
;
571 case SouthWestGravity
:
573 corner
= Corner_BottomLeft
;
575 case SouthEastGravity
:
576 corner
= Corner_BottomRight
;
578 default: /* NorthWest, Static, etc */
579 corner
= Corner_TopLeft
;
582 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
585 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
586 switch (e
->xconfigurerequest
.detail
) {
589 stacking_lower(client
);
595 stacking_raise(client
);
601 if (client
->ignore_unmaps
) {
602 client
->ignore_unmaps
--;
605 client_unmanage(client
);
608 client_unmanage(client
);
611 /* this is when the client is first taken captive in the frame */
612 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
615 This event is quite rare and is usually handled in unmapHandler.
616 However, if the window is unmapped when the reparent event occurs,
617 the window manager never sees it because an unmap event is not sent
618 to an already unmapped window.
621 /* we don't want the reparent event, put it back on the stack for the
622 X server to deal with after we unmanage the window */
623 XPutBackEvent(ob_display
, e
);
625 client_unmanage(client
);
628 g_message("MapRequest for 0x%lx", client
->window
);
629 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
630 does, we don't want it! */
631 if (screen_showing_desktop
)
632 screen_show_desktop(FALSE
);
633 client_iconify(client
, FALSE
, TRUE
);
634 if (!client
->frame
->visible
)
635 /* if its not visible still, then don't mess with it */
638 client_shade(client
, FALSE
);
639 client_focus(client
);
640 stacking_raise(client
);
643 /* validate cuz we query stuff off the client here */
644 if (!client_validate(client
)) break;
646 if (e
->xclient
.format
!= 32) return;
648 msgtype
= e
->xclient
.message_type
;
649 if (msgtype
== prop_atoms
.wm_change_state
) {
650 /* compress changes into a single change */
651 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
652 client
->window
, &ce
)) {
653 /* XXX: it would be nice to compress ALL messages of a
654 type, not just messages in a row without other
655 message types between. */
656 if (ce
.xclient
.message_type
!= msgtype
) {
657 XPutBackEvent(ob_display
, &ce
);
660 e
->xclient
= ce
.xclient
;
662 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
663 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
664 /* compress changes into a single change */
665 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
666 client
->window
, &ce
)) {
667 /* XXX: it would be nice to compress ALL messages of a
668 type, not just messages in a row without other
669 message types between. */
670 if (ce
.xclient
.message_type
!= msgtype
) {
671 XPutBackEvent(ob_display
, &ce
);
674 e
->xclient
= ce
.xclient
;
676 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
677 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
678 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
680 } else if (msgtype
== prop_atoms
.net_wm_state
) {
681 /* can't compress these */
682 g_message("net_wm_state %s %ld %ld for 0x%lx",
683 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
684 e
->xclient
.data
.l
[0] == 1 ? "Add" :
685 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
686 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
688 client_set_state(client
, e
->xclient
.data
.l
[0],
689 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
690 } else if (msgtype
== prop_atoms
.net_close_window
) {
691 g_message("net_close_window for 0x%lx", client
->window
);
692 client_close(client
);
693 } else if (msgtype
== prop_atoms
.net_active_window
) {
694 g_message("net_active_window for 0x%lx", client
->window
);
695 if (screen_showing_desktop
)
696 screen_show_desktop(FALSE
);
698 client_iconify(client
, FALSE
, TRUE
);
699 else if (!client
->frame
->visible
)
700 /* if its not visible for other reasons, then don't mess
704 client_shade(client
, FALSE
);
705 client_focus(client
);
706 stacking_raise(client
);
707 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
708 g_message("net_wm_moveresize for 0x%lx", client
->window
);
709 if ((Atom
)e
->xclient
.data
.l
[2] ==
710 prop_atoms
.net_wm_moveresize_size_topleft
||
711 (Atom
)e
->xclient
.data
.l
[2] ==
712 prop_atoms
.net_wm_moveresize_size_top
||
713 (Atom
)e
->xclient
.data
.l
[2] ==
714 prop_atoms
.net_wm_moveresize_size_topright
||
715 (Atom
)e
->xclient
.data
.l
[2] ==
716 prop_atoms
.net_wm_moveresize_size_right
||
717 (Atom
)e
->xclient
.data
.l
[2] ==
718 prop_atoms
.net_wm_moveresize_size_right
||
719 (Atom
)e
->xclient
.data
.l
[2] ==
720 prop_atoms
.net_wm_moveresize_size_bottomright
||
721 (Atom
)e
->xclient
.data
.l
[2] ==
722 prop_atoms
.net_wm_moveresize_size_bottom
||
723 (Atom
)e
->xclient
.data
.l
[2] ==
724 prop_atoms
.net_wm_moveresize_size_bottomleft
||
725 (Atom
)e
->xclient
.data
.l
[2] ==
726 prop_atoms
.net_wm_moveresize_size_left
||
727 (Atom
)e
->xclient
.data
.l
[2] ==
728 prop_atoms
.net_wm_moveresize_move
||
729 (Atom
)e
->xclient
.data
.l
[2] ==
730 prop_atoms
.net_wm_moveresize_size_keyboard
||
731 (Atom
)e
->xclient
.data
.l
[2] ==
732 prop_atoms
.net_wm_moveresize_move_keyboard
) {
734 moveresize_start(client
, e
->xclient
.data
.l
[0],
735 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
736 e
->xclient
.data
.l
[2]);
738 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
739 int oldg
= client
->gravity
;
740 int tmpg
, x
, y
, w
, h
;
742 if (e
->xclient
.data
.l
[0] & 0xff)
743 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
747 if (e
->xclient
.data
.l
[0] & 1 << 8)
748 x
= e
->xclient
.data
.l
[1];
751 if (e
->xclient
.data
.l
[0] & 1 << 9)
752 y
= e
->xclient
.data
.l
[2];
755 if (e
->xclient
.data
.l
[0] & 1 << 10)
756 w
= e
->xclient
.data
.l
[3];
759 if (e
->xclient
.data
.l
[0] & 1 << 11)
760 h
= e
->xclient
.data
.l
[4];
763 client
->gravity
= tmpg
;
764 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
765 client
->gravity
= oldg
;
769 /* validate cuz we query stuff off the client here */
770 if (!client_validate(client
)) break;
772 /* compress changes to a single property into a single change */
773 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
774 client
->window
, &ce
)) {
775 /* XXX: it would be nice to compress ALL changes to a property,
776 not just changes in a row without other props between. */
777 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
778 XPutBackEvent(ob_display
, &ce
);
783 msgtype
= e
->xproperty
.atom
;
784 if (msgtype
== XA_WM_NORMAL_HINTS
) {
785 client_update_normal_hints(client
);
786 /* normal hints can make a window non-resizable */
787 client_setup_decor_and_functions(client
);
789 else if (msgtype
== XA_WM_HINTS
)
790 client_update_wmhints(client
);
791 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
792 client_update_transient_for(client
);
793 client_get_type(client
);
794 /* type may have changed, so update the layer */
795 client_calc_layer(client
);
796 client_setup_decor_and_functions(client
);
798 else if (msgtype
== prop_atoms
.net_wm_name
||
799 msgtype
== prop_atoms
.wm_name
)
800 client_update_title(client
);
801 else if (msgtype
== prop_atoms
.net_wm_icon_name
||
802 msgtype
== prop_atoms
.wm_icon_name
)
803 client_update_icon_title(client
);
804 else if (msgtype
== prop_atoms
.wm_class
)
805 client_update_class(client
);
806 else if (msgtype
== prop_atoms
.wm_protocols
) {
807 client_update_protocols(client
);
808 client_setup_decor_and_functions(client
);
810 else if (msgtype
== prop_atoms
.net_wm_strut
)
811 client_update_strut(client
);
812 else if (msgtype
== prop_atoms
.net_wm_icon
)
813 client_update_icons(client
);
814 else if (msgtype
== prop_atoms
.kwm_win_icon
)
815 client_update_kwm_icon(client
);
819 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
820 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
821 frame_adjust_shape(client
->frame
);
827 static void event_handle_menu(Menu
*menu
, XEvent
*e
)
831 g_message("EVENT %d", e
->type
);
834 if (e
->xbutton
.button
== 3)
838 if (!menu
->shown
) break;
840 /* grab_pointer_window(FALSE, None, menu->frame);*/
842 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
846 guint ujunk
, b
, w
, h
;
847 XGetGeometry(ob_display
, e
->xbutton
.window
,
848 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
849 if (e
->xbutton
.x
>= (signed)-b
&&
850 e
->xbutton
.y
>= (signed)-b
&&
851 e
->xbutton
.x
< (signed)(w
+b
) &&
852 e
->xbutton
.y
< (signed)(h
+b
)) {
853 menu_entry_fire(entry
);
859 g_message("enter/leave");
860 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
862 entry
->hilite
= e
->type
== EnterNotify
;
863 menu_entry_render(entry
);