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
);
382 event_set_lasttime(e
);
384 if (event_ignore(e
, client
))
387 /* deal with it in the kernel */
389 event_handle_menu(menu
, e
);
392 event_handle_client(client
, e
);
393 else if (window
== ob_root
)
394 event_handle_root(e
);
395 else if (e
->type
== MapRequest
)
396 client_manage(window
);
397 else if (e
->type
== ConfigureRequest
) {
398 /* unhandled configure requests must be used to configure the
402 xwc
.x
= e
->xconfigurerequest
.x
;
403 xwc
.y
= e
->xconfigurerequest
.y
;
404 xwc
.width
= e
->xconfigurerequest
.width
;
405 xwc
.height
= e
->xconfigurerequest
.height
;
406 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
407 xwc
.sibling
= e
->xconfigurerequest
.above
;
408 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
410 /* we are not to be held responsible if someone sends us an
412 xerror_set_ignore(TRUE
);
413 XConfigureWindow(ob_display
, window
,
414 e
->xconfigurerequest
.value_mask
, &xwc
);
415 xerror_set_ignore(FALSE
);
418 if (moveresize_in_progress
)
419 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
420 e
->type
== ButtonPress
||
421 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
424 return; /* no dispatch! */
428 /* user input (action-bound) events */
430 if (e->type == ButtonPress || e->type == ButtonRelease ||
431 e->type == MotionNotify)
432 mouse_event(e, client);
433 else if (e->type == KeyPress || e->type == KeyRelease)
437 /* dispatch the event to registered handlers */
438 dispatch_x(e
, client
);
441 static void event_handle_root(XEvent
*e
)
447 if (e
->xclient
.format
!= 32) break;
449 msgtype
= e
->xclient
.message_type
;
450 if (msgtype
== prop_atoms
.net_current_desktop
) {
451 unsigned int d
= e
->xclient
.data
.l
[0];
452 if (d
< screen_num_desktops
)
453 screen_set_desktop(d
);
454 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
455 unsigned int d
= e
->xclient
.data
.l
[0];
457 screen_set_num_desktops(d
);
458 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
459 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
463 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
464 screen_update_desktop_names();
465 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
466 screen_update_layout();
468 case ConfigureNotify
:
470 XRRUpdateConfiguration(e
);
472 if (e
->xconfigure
.width
!= screen_physical_size
.width
||
473 e
->xconfigure
.height
!= screen_physical_size
.height
)
474 screen_resize(e
->xconfigure
.width
, e
->xconfigure
.height
);
479 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
480 g_message("VIDMODE EVENT");
486 static void event_handle_client(Client
*client
, XEvent
*e
)
495 switch (frame_context(client
, e
->xbutton
.window
)) {
496 case Context_Maximize
:
497 client
->frame
->max_press
= (e
->type
== ButtonPress
);
498 framerender_frame(client
->frame
);
501 client
->frame
->close_press
= (e
->type
== ButtonPress
);
502 framerender_frame(client
->frame
);
504 case Context_Iconify
:
505 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
506 framerender_frame(client
->frame
);
508 case Context_AllDesktops
:
509 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
510 framerender_frame(client
->frame
);
513 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
514 framerender_frame(client
->frame
);
517 /* nothing changes with clicks for any other contexts */
523 g_message("FocusIn on client for %lx", client
->window
);
525 focus_set_client(client
);
526 frame_adjust_focus(client
->frame
, TRUE
);
530 g_message("FocusOut on client for %lx", client
->window
);
532 /* are we a fullscreen window or a transient of one? (checks layer)
533 if we are then we need to be iconified since we are losing focus
535 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
536 !client_search_focus_tree_full(client
))
537 /* iconify fullscreen windows when they and their transients
539 client_iconify(client
, TRUE
, TRUE
);
540 frame_adjust_focus(client
->frame
, FALSE
);
543 if (client_normal(client
)) {
544 if (ob_state
== State_Starting
) {
545 /* move it to the top of the focus order */
546 guint desktop
= client
->desktop
;
547 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
548 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
550 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
552 } else if (config_focus_follow
) {
554 g_message("EnterNotify on %lx, focusing window",
557 client_focus(client
);
561 case ConfigureRequest
:
563 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
564 ConfigureRequest
, &ce
)) {
566 /* XXX if this causes bad things.. we can compress config req's
567 with the same mask. */
568 e
->xconfigurerequest
.value_mask
|=
569 ce
.xconfigurerequest
.value_mask
;
570 if (ce
.xconfigurerequest
.value_mask
& CWX
)
571 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
572 if (ce
.xconfigurerequest
.value_mask
& CWY
)
573 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
574 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
575 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
576 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
577 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
578 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
579 e
->xconfigurerequest
.border_width
=
580 ce
.xconfigurerequest
.border_width
;
581 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
582 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
585 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
586 if (client
->iconic
|| client
->shaded
) return;
588 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
589 client
->border_width
= e
->xconfigurerequest
.border_width
;
591 /* resize, then move, as specified in the EWMH section 7.7 */
592 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
597 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
598 e
->xconfigurerequest
.x
: client
->area
.x
;
599 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
600 e
->xconfigurerequest
.y
: client
->area
.y
;
601 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
602 e
->xconfigurerequest
.width
: client
->area
.width
;
603 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
604 e
->xconfigurerequest
.height
: client
->area
.height
;
606 switch (client
->gravity
) {
607 case NorthEastGravity
:
609 corner
= Corner_TopRight
;
611 case SouthWestGravity
:
613 corner
= Corner_BottomLeft
;
615 case SouthEastGravity
:
616 corner
= Corner_BottomRight
;
618 default: /* NorthWest, Static, etc */
619 corner
= Corner_TopLeft
;
622 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
625 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
626 switch (e
->xconfigurerequest
.detail
) {
629 stacking_lower(client
);
635 stacking_raise(client
);
641 if (client
->ignore_unmaps
) {
642 client
->ignore_unmaps
--;
645 client_unmanage(client
);
648 client_unmanage(client
);
651 /* this is when the client is first taken captive in the frame */
652 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
655 This event is quite rare and is usually handled in unmapHandler.
656 However, if the window is unmapped when the reparent event occurs,
657 the window manager never sees it because an unmap event is not sent
658 to an already unmapped window.
661 /* we don't want the reparent event, put it back on the stack for the
662 X server to deal with after we unmanage the window */
663 XPutBackEvent(ob_display
, e
);
665 client_unmanage(client
);
668 g_message("MapRequest for 0x%lx", client
->window
);
669 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
670 does, we don't want it! */
671 if (screen_showing_desktop
)
672 screen_show_desktop(FALSE
);
673 client_iconify(client
, FALSE
, TRUE
);
674 if (!client
->frame
->visible
)
675 /* if its not visible still, then don't mess with it */
678 client_shade(client
, FALSE
);
679 client_focus(client
);
680 stacking_raise(client
);
683 /* validate cuz we query stuff off the client here */
684 if (!client_validate(client
)) break;
686 if (e
->xclient
.format
!= 32) return;
688 msgtype
= e
->xclient
.message_type
;
689 if (msgtype
== prop_atoms
.wm_change_state
) {
690 /* compress changes into a single change */
691 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
692 client
->window
, &ce
)) {
693 /* XXX: it would be nice to compress ALL messages of a
694 type, not just messages in a row without other
695 message types between. */
696 if (ce
.xclient
.message_type
!= msgtype
) {
697 XPutBackEvent(ob_display
, &ce
);
700 e
->xclient
= ce
.xclient
;
702 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
703 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
704 /* compress changes into a single change */
705 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
706 client
->window
, &ce
)) {
707 /* XXX: it would be nice to compress ALL messages of a
708 type, not just messages in a row without other
709 message types between. */
710 if (ce
.xclient
.message_type
!= msgtype
) {
711 XPutBackEvent(ob_display
, &ce
);
714 e
->xclient
= ce
.xclient
;
716 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
717 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
718 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
720 } else if (msgtype
== prop_atoms
.net_wm_state
) {
721 /* can't compress these */
722 g_message("net_wm_state %s %ld %ld for 0x%lx",
723 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
724 e
->xclient
.data
.l
[0] == 1 ? "Add" :
725 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
726 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
728 client_set_state(client
, e
->xclient
.data
.l
[0],
729 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
730 } else if (msgtype
== prop_atoms
.net_close_window
) {
731 g_message("net_close_window for 0x%lx", client
->window
);
732 client_close(client
);
733 } else if (msgtype
== prop_atoms
.net_active_window
) {
734 g_message("net_active_window for 0x%lx", client
->window
);
735 client_activate(client
);
736 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
737 g_message("net_wm_moveresize for 0x%lx", client
->window
);
738 if ((Atom
)e
->xclient
.data
.l
[2] ==
739 prop_atoms
.net_wm_moveresize_size_topleft
||
740 (Atom
)e
->xclient
.data
.l
[2] ==
741 prop_atoms
.net_wm_moveresize_size_top
||
742 (Atom
)e
->xclient
.data
.l
[2] ==
743 prop_atoms
.net_wm_moveresize_size_topright
||
744 (Atom
)e
->xclient
.data
.l
[2] ==
745 prop_atoms
.net_wm_moveresize_size_right
||
746 (Atom
)e
->xclient
.data
.l
[2] ==
747 prop_atoms
.net_wm_moveresize_size_right
||
748 (Atom
)e
->xclient
.data
.l
[2] ==
749 prop_atoms
.net_wm_moveresize_size_bottomright
||
750 (Atom
)e
->xclient
.data
.l
[2] ==
751 prop_atoms
.net_wm_moveresize_size_bottom
||
752 (Atom
)e
->xclient
.data
.l
[2] ==
753 prop_atoms
.net_wm_moveresize_size_bottomleft
||
754 (Atom
)e
->xclient
.data
.l
[2] ==
755 prop_atoms
.net_wm_moveresize_size_left
||
756 (Atom
)e
->xclient
.data
.l
[2] ==
757 prop_atoms
.net_wm_moveresize_move
||
758 (Atom
)e
->xclient
.data
.l
[2] ==
759 prop_atoms
.net_wm_moveresize_size_keyboard
||
760 (Atom
)e
->xclient
.data
.l
[2] ==
761 prop_atoms
.net_wm_moveresize_move_keyboard
) {
763 moveresize_start(client
, e
->xclient
.data
.l
[0],
764 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
765 e
->xclient
.data
.l
[2]);
767 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
768 int oldg
= client
->gravity
;
769 int tmpg
, x
, y
, w
, h
;
771 if (e
->xclient
.data
.l
[0] & 0xff)
772 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
776 if (e
->xclient
.data
.l
[0] & 1 << 8)
777 x
= e
->xclient
.data
.l
[1];
780 if (e
->xclient
.data
.l
[0] & 1 << 9)
781 y
= e
->xclient
.data
.l
[2];
784 if (e
->xclient
.data
.l
[0] & 1 << 10)
785 w
= e
->xclient
.data
.l
[3];
788 if (e
->xclient
.data
.l
[0] & 1 << 11)
789 h
= e
->xclient
.data
.l
[4];
792 client
->gravity
= tmpg
;
793 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
794 client
->gravity
= oldg
;
798 /* validate cuz we query stuff off the client here */
799 if (!client_validate(client
)) break;
801 /* compress changes to a single property into a single change */
802 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
803 client
->window
, &ce
)) {
804 /* XXX: it would be nice to compress ALL changes to a property,
805 not just changes in a row without other props between. */
806 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
807 XPutBackEvent(ob_display
, &ce
);
812 msgtype
= e
->xproperty
.atom
;
813 if (msgtype
== XA_WM_NORMAL_HINTS
) {
814 client_update_normal_hints(client
);
815 /* normal hints can make a window non-resizable */
816 client_setup_decor_and_functions(client
);
818 else if (msgtype
== XA_WM_HINTS
)
819 client_update_wmhints(client
);
820 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
821 client_update_transient_for(client
);
822 client_get_type(client
);
823 /* type may have changed, so update the layer */
824 client_calc_layer(client
);
825 client_setup_decor_and_functions(client
);
827 else if (msgtype
== prop_atoms
.net_wm_name
||
828 msgtype
== prop_atoms
.wm_name
||
829 msgtype
== prop_atoms
.net_wm_icon_name
||
830 msgtype
== prop_atoms
.wm_icon_name
)
831 client_update_title(client
);
832 else if (msgtype
== prop_atoms
.wm_class
)
833 client_update_class(client
);
834 else if (msgtype
== prop_atoms
.wm_protocols
) {
835 client_update_protocols(client
);
836 client_setup_decor_and_functions(client
);
838 else if (msgtype
== prop_atoms
.net_wm_strut
)
839 client_update_strut(client
);
840 else if (msgtype
== prop_atoms
.net_wm_icon
)
841 client_update_icons(client
);
842 else if (msgtype
== prop_atoms
.kwm_win_icon
)
843 client_update_kwm_icon(client
);
847 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
848 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
849 frame_adjust_shape(client
->frame
);
855 static void event_handle_menu(Menu
*menu
, XEvent
*e
)
859 g_message("EVENT %d", e
->type
);
862 g_message("BUTTON PRESS");
863 if (e
->xbutton
.button
== 3)
867 g_message("BUTTON RELEASED");
868 if (!menu
->shown
) break;
870 /* grab_pointer_window(FALSE, None, menu->frame);*/
872 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
876 guint ujunk
, b
, w
, h
;
877 XGetGeometry(ob_display
, e
->xbutton
.window
,
878 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
879 if (e
->xbutton
.x
>= (signed)-b
&&
880 e
->xbutton
.y
>= (signed)-b
&&
881 e
->xbutton
.x
< (signed)(w
+b
) &&
882 e
->xbutton
.y
< (signed)(h
+b
)) {
883 menu_entry_fire(entry
);
889 g_message("enter/leave");
890 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
893 menu
->mouseover(entry
, e
->type
== EnterNotify
);
895 menu_control_mouseover(entry
, e
->type
== EnterNotify
);
897 menu_entry_render(entry
);