10 #include "framerender.h"
12 #include "moveresize.h"
14 #include "extensions.h"
19 #include <X11/keysym.h>
20 #include <X11/Xatom.h>
21 #ifdef HAVE_SYS_SELECT_H
22 # include <sys/select.h>
25 static void event_process(XEvent
*e
);
26 static void event_handle_root(XEvent
*e
);
27 static void event_handle_slitapp(SlitApp
*app
, XEvent
*e
);
28 static void event_handle_client(Client
*c
, XEvent
*e
);
29 static void event_handle_menu(Menu
*menu
, XEvent
*e
);
31 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
32 (e)->xfocus.detail > NotifyNonlinearVirtual)
33 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
34 (e)->xfocus.detail == NotifyInferior || \
35 (e)->xfocus.detail == NotifyAncestor || \
36 (e)->xfocus.detail > NotifyNonlinearVirtual)
38 Time event_lasttime
= 0;
40 /*! The value of the mask for the NumLock modifier */
41 unsigned int NumLockMask
;
42 /*! The value of the mask for the ScrollLock modifier */
43 unsigned int ScrollLockMask
;
44 /*! The key codes for the modifier keys */
45 static XModifierKeymap
*modmap
;
46 /*! Table of the constant modifier masks */
47 static const int mask_table
[] = {
48 ShiftMask
, LockMask
, ControlMask
, Mod1Mask
,
49 Mod2Mask
, Mod3Mask
, Mod4Mask
, Mod5Mask
51 static int mask_table_size
;
55 mask_table_size
= sizeof(mask_table
) / sizeof(mask_table
[0]);
57 /* get lock masks that are defined by the display (not constant) */
58 modmap
= XGetModifierMapping(ob_display
);
60 if (modmap
&& modmap
->max_keypermod
> 0) {
62 const size_t size
= mask_table_size
* modmap
->max_keypermod
;
63 /* get the values of the keyboard lock modifiers
64 Note: Caps lock is not retrieved the same way as Scroll and Num
65 lock since it doesn't need to be. */
66 const KeyCode num_lock
= XKeysymToKeycode(ob_display
, XK_Num_Lock
);
67 const KeyCode scroll_lock
= XKeysymToKeycode(ob_display
,
70 for (cnt
= 0; cnt
< size
; ++cnt
) {
71 if (! modmap
->modifiermap
[cnt
]) continue;
73 if (num_lock
== modmap
->modifiermap
[cnt
])
74 NumLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
75 if (scroll_lock
== modmap
->modifiermap
[cnt
])
76 ScrollLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
83 XFreeModifiermap(modmap
);
92 gboolean had_event
= FALSE
;
96 There are slightly different event retrieval semantics here for
97 local (or high bandwidth) versus remote (or low bandwidth)
98 connections to the display/Xserver.
101 if (!XPending(ob_display
))
105 This XSync allows for far more compression of events, which
106 makes things like Motion events perform far far better. Since
107 it also means network traffic for every event instead of every
108 X events (where X is the number retrieved at a time), it
109 probably should not be used for setups where Openbox is
110 running on a remote/low bandwidth display/Xserver.
112 XSync(ob_display
, FALSE
);
113 if (!XEventsQueued(ob_display
, QueuedAlready
))
116 XNextEvent(ob_display
, &e
);
123 timer_dispatch((GTimeVal
**)&wait
);
124 x_fd
= ConnectionNumber(ob_display
);
126 FD_SET(x_fd
, &selset
);
127 select(x_fd
+ 1, &selset
, NULL
, NULL
, wait
);
131 static Window
event_get_window(XEvent
*e
)
138 window
= e
->xmap
.window
;
141 window
= e
->xunmap
.window
;
144 window
= e
->xdestroywindow
.window
;
146 case ConfigureRequest
:
147 window
= e
->xconfigurerequest
.window
;
149 case ConfigureNotify
:
150 window
= e
->xconfigure
.window
;
154 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
155 switch (((XkbAnyEvent
*)&e
)->xkb_type
) {
157 window
= ((XkbBellNotifyEvent
*)&e
)->window
;
163 window
= e
->xany
.window
;
168 static void event_set_lasttime(XEvent
*e
)
170 /* grab the lasttime and hack up the state */
174 event_lasttime
= e
->xbutton
.time
;
177 event_lasttime
= e
->xkey
.time
;
180 event_lasttime
= e
->xkey
.time
;
183 event_lasttime
= e
->xmotion
.time
;
186 event_lasttime
= e
->xproperty
.time
;
190 event_lasttime
= e
->xcrossing
.time
;
193 event_lasttime
= CurrentTime
;
198 #define STRIP_MODS(s) \
199 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
200 /* kill off the Button1Mask etc, only want the modifiers */ \
201 s &= (ControlMask | ShiftMask | Mod1Mask | \
202 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
204 static void event_hack_mods(XEvent *e)
212 STRIP_MODS(e
->xbutton
.state
);
215 STRIP_MODS(e
->xkey
.state
);
218 STRIP_MODS(e
->xkey
.state
);
219 /* remove from the state the mask of the modifier being released, if
220 it is a modifier key being released (this is a little ugly..) */
221 kp
= modmap
->modifiermap
;
222 for (i
= 0; i
< mask_table_size
; ++i
) {
223 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
224 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
225 /* remove the mask for it */
226 e
->xkey
.state
&= ~mask_table
[i
];
227 /* cause the first loop to break; */
229 break; /* get outta here! */
236 STRIP_MODS(e
->xmotion
.state
);
237 /* compress events */
240 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
242 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
243 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
250 static gboolean
event_ignore(XEvent
*e
, Client
*client
)
254 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
255 because of RevertToPointerRoot. If the focus ends up reverting to
256 pointer root on a workspace change, then the FocusIn event that we
257 want will be of type NotifyAncestor. This situation does not occur
258 for FocusOut, so it is safely ignored there.
260 if (INVALID_FOCUSIN(e
) ||
263 g_message("FocusIn on %lx mode %d detail %d IGNORED", e
->xfocus
.window
,
264 e
->xfocus
.mode
, e
->xfocus
.detail
);
266 /* says a client was not found for the event (or a valid FocusIn
269 e
->xfocus
.window
= None
;
274 g_message("FocusIn on %lx mode %d detail %d", e
->xfocus
.window
,
275 e
->xfocus
.mode
, e
->xfocus
.detail
);
279 if (INVALID_FOCUSOUT(e
)) {
281 g_message("FocusOut on %lx mode %d detail %d IGNORED",
282 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
288 g_message("FocusOut on %lx mode %d detail %d",
289 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
294 gboolean fallback
= TRUE
;
297 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
298 e
->xfocus
.window
,&fe
))
299 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
301 if (fe
.type
== FocusOut
) {
303 g_message("found pending FocusOut");
305 if (!INVALID_FOCUSOUT(&fe
)) {
306 /* if there is a VALID FocusOut still coming, don't
307 fallback focus yet, we'll deal with it then */
308 XPutBackEvent(ob_display
, &fe
);
314 g_message("found pending FocusIn");
316 /* is the focused window getting a FocusOut/In back to
318 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
319 !event_ignore(&fe
, client
)) {
321 g_message("focused window got an Out/In back to "
322 "itself IGNORED both");
327 /* once all the FocusOut's have been dealt with, if there
328 is a FocusIn still left and it is valid, then use it */
330 /* secret magic way of event_process telling us that no
331 client was found for the FocusIn event. ^_^ */
332 if (fe
.xfocus
.window
!= None
) {
340 g_message("no valid FocusIn and no FocusOut events found, "
343 focus_fallback(Fallback_NoFocus
);
349 /* NotifyUngrab occurs when a mouse button is released and the event is
350 caused, like when lowering a window */
351 /* NotifyVirtual occurs when ungrabbing the pointer */
352 if (e
->xcrossing
.mode
== NotifyGrab
||
353 e
->xcrossing
.detail
== NotifyInferior
||
354 (e
->xcrossing
.mode
== NotifyUngrab
&&
355 e
->xcrossing
.detail
== NotifyVirtual
)) {
357 g_message("%sNotify mode %d detail %d on %lx IGNORED",
358 (e
->type
== EnterNotify
? "Enter" : "Leave"),
360 e
->xcrossing
.detail
, client
?client
->window
:0);
365 g_message("%sNotify mode %d detail %d on %lx",
366 (e
->type
== EnterNotify
? "Enter" : "Leave"),
368 e
->xcrossing
.detail
, client
?client
->window
:0);
375 static void event_process(XEvent
*e
)
378 Client
*client
= NULL
;
379 SlitApp
*slitapp
= NULL
;
382 window
= event_get_window(e
);
383 if (!(client
= g_hash_table_lookup(client_map
, &window
)))
384 if (!(slitapp
= g_hash_table_lookup(slit_app_map
, &window
)))
385 menu
= g_hash_table_lookup(menu_map
, &window
);
387 event_set_lasttime(e
);
389 if (event_ignore(e
, client
))
392 /* deal with it in the kernel */
394 event_handle_menu(menu
, e
);
397 event_handle_client(client
, e
);
399 event_handle_slitapp(slitapp
, e
);
400 else if (window
== ob_root
)
401 event_handle_root(e
);
402 else if (e
->type
== MapRequest
)
403 client_manage(window
);
404 else if (e
->type
== ConfigureRequest
) {
405 /* unhandled configure requests must be used to configure the
409 xwc
.x
= e
->xconfigurerequest
.x
;
410 xwc
.y
= e
->xconfigurerequest
.y
;
411 xwc
.width
= e
->xconfigurerequest
.width
;
412 xwc
.height
= e
->xconfigurerequest
.height
;
413 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
414 xwc
.sibling
= e
->xconfigurerequest
.above
;
415 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
417 /* we are not to be held responsible if someone sends us an
419 xerror_set_ignore(TRUE
);
420 XConfigureWindow(ob_display
, window
,
421 e
->xconfigurerequest
.value_mask
, &xwc
);
422 xerror_set_ignore(FALSE
);
425 if (moveresize_in_progress
)
426 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
427 e
->type
== ButtonPress
||
428 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
431 return; /* no dispatch! */
435 /* user input (action-bound) events */
437 if (e->type == ButtonPress || e->type == ButtonRelease ||
438 e->type == MotionNotify)
439 mouse_event(e, client);
440 else if (e->type == KeyPress || e->type == KeyRelease)
444 /* dispatch the event to registered handlers */
445 dispatch_x(e
, client
);
448 static void event_handle_root(XEvent
*e
)
454 if (e
->xclient
.format
!= 32) break;
456 msgtype
= e
->xclient
.message_type
;
457 if (msgtype
== prop_atoms
.net_current_desktop
) {
458 unsigned int d
= e
->xclient
.data
.l
[0];
459 if (d
< screen_num_desktops
)
460 screen_set_desktop(d
);
461 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
462 unsigned int d
= e
->xclient
.data
.l
[0];
464 screen_set_num_desktops(d
);
465 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
466 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
470 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
471 screen_update_desktop_names();
472 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
473 screen_update_layout();
475 case ConfigureNotify
:
477 XRRUpdateConfiguration(e
);
479 if (e
->xconfigure
.width
!= screen_physical_size
.width
||
480 e
->xconfigure
.height
!= screen_physical_size
.height
)
481 screen_resize(e
->xconfigure
.width
, e
->xconfigure
.height
);
486 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
487 g_message("VIDMODE EVENT");
493 static void event_handle_client(Client
*client
, XEvent
*e
)
502 switch (frame_context(client
, e
->xbutton
.window
)) {
503 case Context_Maximize
:
504 client
->frame
->max_press
= (e
->type
== ButtonPress
);
505 framerender_frame(client
->frame
);
508 client
->frame
->close_press
= (e
->type
== ButtonPress
);
509 framerender_frame(client
->frame
);
511 case Context_Iconify
:
512 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
513 framerender_frame(client
->frame
);
515 case Context_AllDesktops
:
516 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
517 framerender_frame(client
->frame
);
520 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
521 framerender_frame(client
->frame
);
524 /* nothing changes with clicks for any other contexts */
530 g_message("FocusIn on client for %lx", client
->window
);
532 focus_set_client(client
);
533 frame_adjust_focus(client
->frame
, TRUE
);
537 g_message("FocusOut on client for %lx", client
->window
);
539 /* are we a fullscreen window or a transient of one? (checks layer)
540 if we are then we need to be iconified since we are losing focus
542 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
543 !client_search_focus_tree_full(client
))
544 /* iconify fullscreen windows when they and their transients
546 client_iconify(client
, TRUE
, TRUE
);
547 frame_adjust_focus(client
->frame
, FALSE
);
550 if (client_normal(client
)) {
551 if (ob_state
== State_Starting
) {
552 /* move it to the top of the focus order */
553 guint desktop
= client
->desktop
;
554 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
555 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
557 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
559 } else if (config_focus_follow
) {
561 g_message("EnterNotify on %lx, focusing window",
564 client_focus(client
);
568 case ConfigureRequest
:
570 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
571 ConfigureRequest
, &ce
)) {
573 /* XXX if this causes bad things.. we can compress config req's
574 with the same mask. */
575 e
->xconfigurerequest
.value_mask
|=
576 ce
.xconfigurerequest
.value_mask
;
577 if (ce
.xconfigurerequest
.value_mask
& CWX
)
578 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
579 if (ce
.xconfigurerequest
.value_mask
& CWY
)
580 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
581 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
582 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
583 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
584 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
585 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
586 e
->xconfigurerequest
.border_width
=
587 ce
.xconfigurerequest
.border_width
;
588 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
589 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
592 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
593 if (client
->iconic
|| client
->shaded
) return;
595 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
596 client
->border_width
= e
->xconfigurerequest
.border_width
;
598 /* resize, then move, as specified in the EWMH section 7.7 */
599 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
604 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
605 e
->xconfigurerequest
.x
: client
->area
.x
;
606 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
607 e
->xconfigurerequest
.y
: client
->area
.y
;
608 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
609 e
->xconfigurerequest
.width
: client
->area
.width
;
610 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
611 e
->xconfigurerequest
.height
: client
->area
.height
;
613 switch (client
->gravity
) {
614 case NorthEastGravity
:
616 corner
= Corner_TopRight
;
618 case SouthWestGravity
:
620 corner
= Corner_BottomLeft
;
622 case SouthEastGravity
:
623 corner
= Corner_BottomRight
;
625 default: /* NorthWest, Static, etc */
626 corner
= Corner_TopLeft
;
629 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
632 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
633 switch (e
->xconfigurerequest
.detail
) {
636 stacking_lower(client
);
642 stacking_raise(client
);
648 if (client
->ignore_unmaps
) {
649 client
->ignore_unmaps
--;
652 client_unmanage(client
);
655 client_unmanage(client
);
658 /* this is when the client is first taken captive in the frame */
659 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
662 This event is quite rare and is usually handled in unmapHandler.
663 However, if the window is unmapped when the reparent event occurs,
664 the window manager never sees it because an unmap event is not sent
665 to an already unmapped window.
668 /* we don't want the reparent event, put it back on the stack for the
669 X server to deal with after we unmanage the window */
670 XPutBackEvent(ob_display
, e
);
672 client_unmanage(client
);
675 g_message("MapRequest for 0x%lx", client
->window
);
676 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
677 does, we don't want it! */
678 if (screen_showing_desktop
)
679 screen_show_desktop(FALSE
);
680 client_iconify(client
, FALSE
, TRUE
);
681 if (!client
->frame
->visible
)
682 /* if its not visible still, then don't mess with it */
685 client_shade(client
, FALSE
);
686 client_focus(client
);
687 stacking_raise(client
);
690 /* validate cuz we query stuff off the client here */
691 if (!client_validate(client
)) break;
693 if (e
->xclient
.format
!= 32) return;
695 msgtype
= e
->xclient
.message_type
;
696 if (msgtype
== prop_atoms
.wm_change_state
) {
697 /* compress changes into a single change */
698 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
699 client
->window
, &ce
)) {
700 /* XXX: it would be nice to compress ALL messages of a
701 type, not just messages in a row without other
702 message types between. */
703 if (ce
.xclient
.message_type
!= msgtype
) {
704 XPutBackEvent(ob_display
, &ce
);
707 e
->xclient
= ce
.xclient
;
709 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
710 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
711 /* compress changes into a single change */
712 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
713 client
->window
, &ce
)) {
714 /* XXX: it would be nice to compress ALL messages of a
715 type, not just messages in a row without other
716 message types between. */
717 if (ce
.xclient
.message_type
!= msgtype
) {
718 XPutBackEvent(ob_display
, &ce
);
721 e
->xclient
= ce
.xclient
;
723 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
724 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
725 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
727 } else if (msgtype
== prop_atoms
.net_wm_state
) {
728 /* can't compress these */
729 g_message("net_wm_state %s %ld %ld for 0x%lx",
730 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
731 e
->xclient
.data
.l
[0] == 1 ? "Add" :
732 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
733 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
735 client_set_state(client
, e
->xclient
.data
.l
[0],
736 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
737 } else if (msgtype
== prop_atoms
.net_close_window
) {
738 g_message("net_close_window for 0x%lx", client
->window
);
739 client_close(client
);
740 } else if (msgtype
== prop_atoms
.net_active_window
) {
741 g_message("net_active_window for 0x%lx", client
->window
);
742 client_activate(client
);
743 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
744 g_message("net_wm_moveresize for 0x%lx", client
->window
);
745 if ((Atom
)e
->xclient
.data
.l
[2] ==
746 prop_atoms
.net_wm_moveresize_size_topleft
||
747 (Atom
)e
->xclient
.data
.l
[2] ==
748 prop_atoms
.net_wm_moveresize_size_top
||
749 (Atom
)e
->xclient
.data
.l
[2] ==
750 prop_atoms
.net_wm_moveresize_size_topright
||
751 (Atom
)e
->xclient
.data
.l
[2] ==
752 prop_atoms
.net_wm_moveresize_size_right
||
753 (Atom
)e
->xclient
.data
.l
[2] ==
754 prop_atoms
.net_wm_moveresize_size_right
||
755 (Atom
)e
->xclient
.data
.l
[2] ==
756 prop_atoms
.net_wm_moveresize_size_bottomright
||
757 (Atom
)e
->xclient
.data
.l
[2] ==
758 prop_atoms
.net_wm_moveresize_size_bottom
||
759 (Atom
)e
->xclient
.data
.l
[2] ==
760 prop_atoms
.net_wm_moveresize_size_bottomleft
||
761 (Atom
)e
->xclient
.data
.l
[2] ==
762 prop_atoms
.net_wm_moveresize_size_left
||
763 (Atom
)e
->xclient
.data
.l
[2] ==
764 prop_atoms
.net_wm_moveresize_move
||
765 (Atom
)e
->xclient
.data
.l
[2] ==
766 prop_atoms
.net_wm_moveresize_size_keyboard
||
767 (Atom
)e
->xclient
.data
.l
[2] ==
768 prop_atoms
.net_wm_moveresize_move_keyboard
) {
770 moveresize_start(client
, e
->xclient
.data
.l
[0],
771 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
772 e
->xclient
.data
.l
[2]);
774 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
775 int oldg
= client
->gravity
;
776 int tmpg
, x
, y
, w
, h
;
778 if (e
->xclient
.data
.l
[0] & 0xff)
779 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
783 if (e
->xclient
.data
.l
[0] & 1 << 8)
784 x
= e
->xclient
.data
.l
[1];
787 if (e
->xclient
.data
.l
[0] & 1 << 9)
788 y
= e
->xclient
.data
.l
[2];
791 if (e
->xclient
.data
.l
[0] & 1 << 10)
792 w
= e
->xclient
.data
.l
[3];
795 if (e
->xclient
.data
.l
[0] & 1 << 11)
796 h
= e
->xclient
.data
.l
[4];
799 client
->gravity
= tmpg
;
800 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
801 client
->gravity
= oldg
;
805 /* validate cuz we query stuff off the client here */
806 if (!client_validate(client
)) break;
808 /* compress changes to a single property into a single change */
809 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
810 client
->window
, &ce
)) {
811 /* XXX: it would be nice to compress ALL changes to a property,
812 not just changes in a row without other props between. */
813 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
814 XPutBackEvent(ob_display
, &ce
);
819 msgtype
= e
->xproperty
.atom
;
820 if (msgtype
== XA_WM_NORMAL_HINTS
) {
821 client_update_normal_hints(client
);
822 /* normal hints can make a window non-resizable */
823 client_setup_decor_and_functions(client
);
825 else if (msgtype
== XA_WM_HINTS
)
826 client_update_wmhints(client
);
827 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
828 client_update_transient_for(client
);
829 client_get_type(client
);
830 /* type may have changed, so update the layer */
831 client_calc_layer(client
);
832 client_setup_decor_and_functions(client
);
834 else if (msgtype
== prop_atoms
.net_wm_name
||
835 msgtype
== prop_atoms
.wm_name
||
836 msgtype
== prop_atoms
.net_wm_icon_name
||
837 msgtype
== prop_atoms
.wm_icon_name
)
838 client_update_title(client
);
839 else if (msgtype
== prop_atoms
.wm_class
)
840 client_update_class(client
);
841 else if (msgtype
== prop_atoms
.wm_protocols
) {
842 client_update_protocols(client
);
843 client_setup_decor_and_functions(client
);
845 else if (msgtype
== prop_atoms
.net_wm_strut
)
846 client_update_strut(client
);
847 else if (msgtype
== prop_atoms
.net_wm_icon
)
848 client_update_icons(client
);
849 else if (msgtype
== prop_atoms
.kwm_win_icon
)
850 client_update_kwm_icon(client
);
854 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
855 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
856 frame_adjust_shape(client
->frame
);
862 static void event_handle_menu(Menu
*menu
, XEvent
*e
)
866 g_message("EVENT %d", e
->type
);
869 g_message("BUTTON PRESS");
870 if (e
->xbutton
.button
== 3)
874 g_message("BUTTON RELEASED");
875 if (!menu
->shown
) break;
877 /* grab_pointer_window(FALSE, None, menu->frame);*/
879 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
883 guint ujunk
, b
, w
, h
;
884 XGetGeometry(ob_display
, e
->xbutton
.window
,
885 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
886 if (e
->xbutton
.x
>= (signed)-b
&&
887 e
->xbutton
.y
>= (signed)-b
&&
888 e
->xbutton
.x
< (signed)(w
+b
) &&
889 e
->xbutton
.y
< (signed)(h
+b
)) {
890 menu_entry_fire(entry
);
896 g_message("enter/leave");
897 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
900 menu
->mouseover(entry
, e
->type
== EnterNotify
);
902 menu_control_mouseover(entry
, e
->type
== EnterNotify
);
904 menu_entry_render(entry
);
911 static void event_handle_slitapp(SlitApp
*app
, XEvent
*e
)
915 if (app
->ignore_unmaps
) {
916 app
->ignore_unmaps
--;
919 slit_remove(app
, TRUE
);
922 slit_remove(app
, FALSE
);
925 slit_remove(app
, FALSE
);
927 case ConfigureNotify
:
928 slit_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);