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
) {
318 g_message("focused window got an Out/In back to "
319 "itself IGNORED both");
324 /* once all the FocusOut's have been dealt with, if there
325 is a FocusIn still left and it is valid, then use it */
327 /* secret magic way of event_process telling us that no
328 client was found for the FocusIn event. ^_^ */
329 if (fe
.xfocus
.window
!= None
) {
337 g_message("no valid FocusIn and no FocusOut events found, "
340 focus_fallback(Fallback_NoFocus
);
346 /* NotifyUngrab occurs when a mouse button is released and the event is
347 caused, like when lowering a window */
348 /* NotifyVirtual occurs when ungrabbing the pointer */
349 if (e
->xcrossing
.mode
== NotifyGrab
||
350 e
->xcrossing
.detail
== NotifyInferior
||
351 (e
->xcrossing
.mode
== NotifyUngrab
&&
352 e
->xcrossing
.detail
== NotifyVirtual
)) {
354 g_message("%sNotify mode %d detail %d on %lx IGNORED",
355 (e
->type
== EnterNotify
? "Enter" : "Leave"),
357 e
->xcrossing
.detail
, client
?client
->window
:0);
362 g_message("%sNotify mode %d detail %d on %lx",
363 (e
->type
== EnterNotify
? "Enter" : "Leave"),
365 e
->xcrossing
.detail
, client
?client
->window
:0);
372 static void event_process(XEvent
*e
)
378 window
= event_get_window(e
);
379 if (!(client
= g_hash_table_lookup(client_map
, &window
)))
380 menu
= g_hash_table_lookup(menu_map
, &window
);
381 event_set_lasttime(e
);
383 if (event_ignore(e
, client
))
386 /* deal with it in the kernel */
388 event_handle_menu(menu
, e
);
391 event_handle_client(client
, e
);
392 else if (window
== ob_root
)
393 event_handle_root(e
);
394 else if (e
->type
== MapRequest
)
395 client_manage(window
);
396 else if (e
->type
== ConfigureRequest
) {
397 /* unhandled configure requests must be used to configure the
401 xwc
.x
= e
->xconfigurerequest
.x
;
402 xwc
.y
= e
->xconfigurerequest
.y
;
403 xwc
.width
= e
->xconfigurerequest
.width
;
404 xwc
.height
= e
->xconfigurerequest
.height
;
405 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
406 xwc
.sibling
= e
->xconfigurerequest
.above
;
407 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
409 /* we are not to be held responsible if someone sends us an
411 xerror_set_ignore(TRUE
);
412 XConfigureWindow(ob_display
, window
,
413 e
->xconfigurerequest
.value_mask
, &xwc
);
414 xerror_set_ignore(FALSE
);
417 if (moveresize_in_progress
)
418 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
419 e
->type
== ButtonPress
||
420 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
423 return; /* no dispatch! */
427 /* user input (action-bound) events */
429 if (e->type == ButtonPress || e->type == ButtonRelease ||
430 e->type == MotionNotify)
431 mouse_event(e, client);
432 else if (e->type == KeyPress || e->type == KeyRelease)
436 /* dispatch the event to registered handlers */
437 dispatch_x(e
, client
);
440 static void event_handle_root(XEvent
*e
)
446 if (e
->xclient
.format
!= 32) break;
448 msgtype
= e
->xclient
.message_type
;
449 if (msgtype
== prop_atoms
.net_current_desktop
) {
450 unsigned int d
= e
->xclient
.data
.l
[0];
451 if (d
< screen_num_desktops
)
452 screen_set_desktop(d
);
453 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
454 unsigned int d
= e
->xclient
.data
.l
[0];
456 screen_set_num_desktops(d
);
457 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
458 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
462 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
463 screen_update_desktop_names();
464 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
465 screen_update_layout();
467 case ConfigureNotify
:
469 XRRUpdateConfiguration(e
);
471 if (e
->xconfigure
.width
!= screen_physical_size
.width
||
472 e
->xconfigure
.height
!= screen_physical_size
.height
)
473 screen_resize(e
->xconfigure
.width
, e
->xconfigure
.height
);
478 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
479 g_message("VIDMODE EVENT");
485 static void event_handle_client(Client
*client
, XEvent
*e
)
494 switch (frame_context(client
, e
->xbutton
.window
)) {
495 case Context_Maximize
:
496 client
->frame
->max_press
= (e
->type
== ButtonPress
);
497 framerender_frame(client
->frame
);
500 client
->frame
->close_press
= (e
->type
== ButtonPress
);
501 framerender_frame(client
->frame
);
503 case Context_Iconify
:
504 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
505 framerender_frame(client
->frame
);
507 case Context_AllDesktops
:
508 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
509 framerender_frame(client
->frame
);
512 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
513 framerender_frame(client
->frame
);
516 /* nothing changes with clicks for any other contexts */
522 g_message("FocusIn on client for %lx", client
->window
);
524 focus_set_client(client
);
525 frame_adjust_focus(client
->frame
, TRUE
);
529 g_message("FocusOut on client for %lx", client
->window
);
531 /* are we a fullscreen window or a transient of one? (checks layer)
532 if we are then we need to be iconified since we are losing focus
534 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
535 !client_search_focus_tree_full(client
))
536 /* iconify fullscreen windows when they and their transients
538 client_iconify(client
, TRUE
, TRUE
);
539 frame_adjust_focus(client
->frame
, FALSE
);
542 if (client_normal(client
)) {
543 if (ob_state
== State_Starting
) {
544 /* move it to the top of the focus order */
545 guint desktop
= client
->desktop
;
546 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
547 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
549 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
551 } else if (config_focus_follow
) {
553 g_message("EnterNotify on %lx, focusing window",
556 client_focus(client
);
560 case ConfigureRequest
:
562 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
563 ConfigureRequest
, &ce
)) {
565 /* XXX if this causes bad things.. we can compress config req's
566 with the same mask. */
567 e
->xconfigurerequest
.value_mask
|=
568 ce
.xconfigurerequest
.value_mask
;
569 if (ce
.xconfigurerequest
.value_mask
& CWX
)
570 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
571 if (ce
.xconfigurerequest
.value_mask
& CWY
)
572 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
573 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
574 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
575 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
576 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
577 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
578 e
->xconfigurerequest
.border_width
=
579 ce
.xconfigurerequest
.border_width
;
580 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
581 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
584 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
585 if (client
->iconic
|| client
->shaded
) return;
587 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
588 client
->border_width
= e
->xconfigurerequest
.border_width
;
590 /* resize, then move, as specified in the EWMH section 7.7 */
591 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
596 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
597 e
->xconfigurerequest
.x
: client
->area
.x
;
598 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
599 e
->xconfigurerequest
.y
: client
->area
.y
;
600 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
601 e
->xconfigurerequest
.width
: client
->area
.width
;
602 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
603 e
->xconfigurerequest
.height
: client
->area
.height
;
605 switch (client
->gravity
) {
606 case NorthEastGravity
:
608 corner
= Corner_TopRight
;
610 case SouthWestGravity
:
612 corner
= Corner_BottomLeft
;
614 case SouthEastGravity
:
615 corner
= Corner_BottomRight
;
617 default: /* NorthWest, Static, etc */
618 corner
= Corner_TopLeft
;
621 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
624 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
625 switch (e
->xconfigurerequest
.detail
) {
628 stacking_lower(client
);
634 stacking_raise(client
);
640 if (client
->ignore_unmaps
) {
641 client
->ignore_unmaps
--;
644 client_unmanage(client
);
647 client_unmanage(client
);
650 /* this is when the client is first taken captive in the frame */
651 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
654 This event is quite rare and is usually handled in unmapHandler.
655 However, if the window is unmapped when the reparent event occurs,
656 the window manager never sees it because an unmap event is not sent
657 to an already unmapped window.
660 /* we don't want the reparent event, put it back on the stack for the
661 X server to deal with after we unmanage the window */
662 XPutBackEvent(ob_display
, e
);
664 client_unmanage(client
);
667 g_message("MapRequest for 0x%lx", client
->window
);
668 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
669 does, we don't want it! */
670 if (screen_showing_desktop
)
671 screen_show_desktop(FALSE
);
672 client_iconify(client
, FALSE
, TRUE
);
673 if (!client
->frame
->visible
)
674 /* if its not visible still, then don't mess with it */
677 client_shade(client
, FALSE
);
678 client_focus(client
);
679 stacking_raise(client
);
682 /* validate cuz we query stuff off the client here */
683 if (!client_validate(client
)) break;
685 if (e
->xclient
.format
!= 32) return;
687 msgtype
= e
->xclient
.message_type
;
688 if (msgtype
== prop_atoms
.wm_change_state
) {
689 /* compress changes into a single change */
690 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
691 client
->window
, &ce
)) {
692 /* XXX: it would be nice to compress ALL messages of a
693 type, not just messages in a row without other
694 message types between. */
695 if (ce
.xclient
.message_type
!= msgtype
) {
696 XPutBackEvent(ob_display
, &ce
);
699 e
->xclient
= ce
.xclient
;
701 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
702 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
703 /* compress changes into a single change */
704 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
705 client
->window
, &ce
)) {
706 /* XXX: it would be nice to compress ALL messages of a
707 type, not just messages in a row without other
708 message types between. */
709 if (ce
.xclient
.message_type
!= msgtype
) {
710 XPutBackEvent(ob_display
, &ce
);
713 e
->xclient
= ce
.xclient
;
715 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
716 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
717 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
719 } else if (msgtype
== prop_atoms
.net_wm_state
) {
720 /* can't compress these */
721 g_message("net_wm_state %s %ld %ld for 0x%lx",
722 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
723 e
->xclient
.data
.l
[0] == 1 ? "Add" :
724 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
725 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
727 client_set_state(client
, e
->xclient
.data
.l
[0],
728 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
729 } else if (msgtype
== prop_atoms
.net_close_window
) {
730 g_message("net_close_window for 0x%lx", client
->window
);
731 client_close(client
);
732 } else if (msgtype
== prop_atoms
.net_active_window
) {
733 g_message("net_active_window for 0x%lx", client
->window
);
734 client_activate(client
);
735 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
736 g_message("net_wm_moveresize for 0x%lx", client
->window
);
737 if ((Atom
)e
->xclient
.data
.l
[2] ==
738 prop_atoms
.net_wm_moveresize_size_topleft
||
739 (Atom
)e
->xclient
.data
.l
[2] ==
740 prop_atoms
.net_wm_moveresize_size_top
||
741 (Atom
)e
->xclient
.data
.l
[2] ==
742 prop_atoms
.net_wm_moveresize_size_topright
||
743 (Atom
)e
->xclient
.data
.l
[2] ==
744 prop_atoms
.net_wm_moveresize_size_right
||
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_bottomright
||
749 (Atom
)e
->xclient
.data
.l
[2] ==
750 prop_atoms
.net_wm_moveresize_size_bottom
||
751 (Atom
)e
->xclient
.data
.l
[2] ==
752 prop_atoms
.net_wm_moveresize_size_bottomleft
||
753 (Atom
)e
->xclient
.data
.l
[2] ==
754 prop_atoms
.net_wm_moveresize_size_left
||
755 (Atom
)e
->xclient
.data
.l
[2] ==
756 prop_atoms
.net_wm_moveresize_move
||
757 (Atom
)e
->xclient
.data
.l
[2] ==
758 prop_atoms
.net_wm_moveresize_size_keyboard
||
759 (Atom
)e
->xclient
.data
.l
[2] ==
760 prop_atoms
.net_wm_moveresize_move_keyboard
) {
762 moveresize_start(client
, e
->xclient
.data
.l
[0],
763 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
764 e
->xclient
.data
.l
[2]);
766 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
767 int oldg
= client
->gravity
;
768 int tmpg
, x
, y
, w
, h
;
770 if (e
->xclient
.data
.l
[0] & 0xff)
771 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
775 if (e
->xclient
.data
.l
[0] & 1 << 8)
776 x
= e
->xclient
.data
.l
[1];
779 if (e
->xclient
.data
.l
[0] & 1 << 9)
780 y
= e
->xclient
.data
.l
[2];
783 if (e
->xclient
.data
.l
[0] & 1 << 10)
784 w
= e
->xclient
.data
.l
[3];
787 if (e
->xclient
.data
.l
[0] & 1 << 11)
788 h
= e
->xclient
.data
.l
[4];
791 client
->gravity
= tmpg
;
792 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
793 client
->gravity
= oldg
;
797 /* validate cuz we query stuff off the client here */
798 if (!client_validate(client
)) break;
800 /* compress changes to a single property into a single change */
801 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
802 client
->window
, &ce
)) {
803 /* XXX: it would be nice to compress ALL changes to a property,
804 not just changes in a row without other props between. */
805 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
806 XPutBackEvent(ob_display
, &ce
);
811 msgtype
= e
->xproperty
.atom
;
812 if (msgtype
== XA_WM_NORMAL_HINTS
) {
813 client_update_normal_hints(client
);
814 /* normal hints can make a window non-resizable */
815 client_setup_decor_and_functions(client
);
817 else if (msgtype
== XA_WM_HINTS
)
818 client_update_wmhints(client
);
819 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
820 client_update_transient_for(client
);
821 client_get_type(client
);
822 /* type may have changed, so update the layer */
823 client_calc_layer(client
);
824 client_setup_decor_and_functions(client
);
826 else if (msgtype
== prop_atoms
.net_wm_name
||
827 msgtype
== prop_atoms
.wm_name
||
828 msgtype
== prop_atoms
.net_wm_icon_name
||
829 msgtype
== prop_atoms
.wm_icon_name
)
830 client_update_title(client
);
831 else if (msgtype
== prop_atoms
.wm_class
)
832 client_update_class(client
);
833 else if (msgtype
== prop_atoms
.wm_protocols
) {
834 client_update_protocols(client
);
835 client_setup_decor_and_functions(client
);
837 else if (msgtype
== prop_atoms
.net_wm_strut
)
838 client_update_strut(client
);
839 else if (msgtype
== prop_atoms
.net_wm_icon
)
840 client_update_icons(client
);
841 else if (msgtype
== prop_atoms
.kwm_win_icon
)
842 client_update_kwm_icon(client
);
846 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
847 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
848 frame_adjust_shape(client
->frame
);
854 static void event_handle_menu(Menu
*menu
, XEvent
*e
)
858 g_message("EVENT %d", e
->type
);
861 if (e
->xbutton
.button
== 3)
865 if (!menu
->shown
) break;
867 /* grab_pointer_window(FALSE, None, menu->frame);*/
869 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
873 guint ujunk
, b
, w
, h
;
874 XGetGeometry(ob_display
, e
->xbutton
.window
,
875 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
876 if (e
->xbutton
.x
>= (signed)-b
&&
877 e
->xbutton
.y
>= (signed)-b
&&
878 e
->xbutton
.x
< (signed)(w
+b
) &&
879 e
->xbutton
.y
< (signed)(h
+b
)) {
880 menu_entry_fire(entry
);
886 g_message("enter/leave");
887 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
889 entry
->hilite
= e
->type
== EnterNotify
;
890 menu_entry_render(entry
);