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_slit(Slit
*s
, XEvent
*e
);
28 static void event_handle_slitapp(SlitApp
*app
, XEvent
*e
);
29 static void event_handle_client(Client
*c
, XEvent
*e
);
30 static void event_handle_menu(Menu
*menu
, XEvent
*e
);
32 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
33 (e)->xfocus.detail > NotifyNonlinearVirtual)
34 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
35 (e)->xfocus.detail == NotifyInferior || \
36 (e)->xfocus.detail == NotifyAncestor || \
37 (e)->xfocus.detail > NotifyNonlinearVirtual)
39 Time event_lasttime
= 0;
41 /*! The value of the mask for the NumLock modifier */
42 unsigned int NumLockMask
;
43 /*! The value of the mask for the ScrollLock modifier */
44 unsigned int ScrollLockMask
;
45 /*! The key codes for the modifier keys */
46 static XModifierKeymap
*modmap
;
47 /*! Table of the constant modifier masks */
48 static const int mask_table
[] = {
49 ShiftMask
, LockMask
, ControlMask
, Mod1Mask
,
50 Mod2Mask
, Mod3Mask
, Mod4Mask
, Mod5Mask
52 static int mask_table_size
;
56 mask_table_size
= sizeof(mask_table
) / sizeof(mask_table
[0]);
58 /* get lock masks that are defined by the display (not constant) */
59 modmap
= XGetModifierMapping(ob_display
);
61 if (modmap
&& modmap
->max_keypermod
> 0) {
63 const size_t size
= mask_table_size
* modmap
->max_keypermod
;
64 /* get the values of the keyboard lock modifiers
65 Note: Caps lock is not retrieved the same way as Scroll and Num
66 lock since it doesn't need to be. */
67 const KeyCode num_lock
= XKeysymToKeycode(ob_display
, XK_Num_Lock
);
68 const KeyCode scroll_lock
= XKeysymToKeycode(ob_display
,
71 for (cnt
= 0; cnt
< size
; ++cnt
) {
72 if (! modmap
->modifiermap
[cnt
]) continue;
74 if (num_lock
== modmap
->modifiermap
[cnt
])
75 NumLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
76 if (scroll_lock
== modmap
->modifiermap
[cnt
])
77 ScrollLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
84 XFreeModifiermap(modmap
);
93 gboolean had_event
= FALSE
;
97 There are slightly different event retrieval semantics here for
98 local (or high bandwidth) versus remote (or low bandwidth)
99 connections to the display/Xserver.
102 if (!XPending(ob_display
))
106 This XSync allows for far more compression of events, which
107 makes things like Motion events perform far far better. Since
108 it also means network traffic for every event instead of every
109 X events (where X is the number retrieved at a time), it
110 probably should not be used for setups where Openbox is
111 running on a remote/low bandwidth display/Xserver.
113 XSync(ob_display
, FALSE
);
114 if (!XEventsQueued(ob_display
, QueuedAlready
))
117 XNextEvent(ob_display
, &e
);
124 timer_dispatch((GTimeVal
**)&wait
);
125 x_fd
= ConnectionNumber(ob_display
);
127 FD_SET(x_fd
, &selset
);
128 select(x_fd
+ 1, &selset
, NULL
, NULL
, wait
);
132 static Window
event_get_window(XEvent
*e
)
139 window
= e
->xmap
.window
;
142 window
= e
->xunmap
.window
;
145 window
= e
->xdestroywindow
.window
;
147 case ConfigureRequest
:
148 window
= e
->xconfigurerequest
.window
;
150 case ConfigureNotify
:
151 window
= e
->xconfigure
.window
;
155 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
156 switch (((XkbAnyEvent
*)&e
)->xkb_type
) {
158 window
= ((XkbBellNotifyEvent
*)&e
)->window
;
164 window
= e
->xany
.window
;
169 static void event_set_lasttime(XEvent
*e
)
171 /* grab the lasttime and hack up the state */
175 event_lasttime
= e
->xbutton
.time
;
178 event_lasttime
= e
->xkey
.time
;
181 event_lasttime
= e
->xkey
.time
;
184 event_lasttime
= e
->xmotion
.time
;
187 event_lasttime
= e
->xproperty
.time
;
191 event_lasttime
= e
->xcrossing
.time
;
194 event_lasttime
= CurrentTime
;
199 #define STRIP_MODS(s) \
200 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
201 /* kill off the Button1Mask etc, only want the modifiers */ \
202 s &= (ControlMask | ShiftMask | Mod1Mask | \
203 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
205 static void event_hack_mods(XEvent *e)
213 STRIP_MODS(e
->xbutton
.state
);
216 STRIP_MODS(e
->xkey
.state
);
219 STRIP_MODS(e
->xkey
.state
);
220 /* remove from the state the mask of the modifier being released, if
221 it is a modifier key being released (this is a little ugly..) */
222 kp
= modmap
->modifiermap
;
223 for (i
= 0; i
< mask_table_size
; ++i
) {
224 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
225 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
226 /* remove the mask for it */
227 e
->xkey
.state
&= ~mask_table
[i
];
228 /* cause the first loop to break; */
230 break; /* get outta here! */
237 STRIP_MODS(e
->xmotion
.state
);
238 /* compress events */
241 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
243 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
244 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
251 static gboolean
event_ignore(XEvent
*e
, Client
*client
)
255 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
256 because of RevertToPointerRoot. If the focus ends up reverting to
257 pointer root on a workspace change, then the FocusIn event that we
258 want will be of type NotifyAncestor. This situation does not occur
259 for FocusOut, so it is safely ignored there.
261 if (INVALID_FOCUSIN(e
) ||
264 g_message("FocusIn on %lx mode %d detail %d IGNORED", e
->xfocus
.window
,
265 e
->xfocus
.mode
, e
->xfocus
.detail
);
267 /* says a client was not found for the event (or a valid FocusIn
270 e
->xfocus
.window
= None
;
275 g_message("FocusIn on %lx mode %d detail %d", e
->xfocus
.window
,
276 e
->xfocus
.mode
, e
->xfocus
.detail
);
280 if (INVALID_FOCUSOUT(e
)) {
282 g_message("FocusOut on %lx mode %d detail %d IGNORED",
283 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
289 g_message("FocusOut on %lx mode %d detail %d",
290 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
295 gboolean fallback
= TRUE
;
298 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
299 e
->xfocus
.window
,&fe
))
300 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
302 if (fe
.type
== FocusOut
) {
304 g_message("found pending FocusOut");
306 if (!INVALID_FOCUSOUT(&fe
)) {
307 /* if there is a VALID FocusOut still coming, don't
308 fallback focus yet, we'll deal with it then */
309 XPutBackEvent(ob_display
, &fe
);
315 g_message("found pending FocusIn");
317 /* is the focused window getting a FocusOut/In back to
319 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
320 !event_ignore(&fe
, client
)) {
322 g_message("focused window got an Out/In back to "
323 "itself IGNORED both");
328 /* once all the FocusOut's have been dealt with, if there
329 is a FocusIn still left and it is valid, then use it */
331 /* secret magic way of event_process telling us that no
332 client was found for the FocusIn event. ^_^ */
333 if (fe
.xfocus
.window
!= None
) {
341 g_message("no valid FocusIn and no FocusOut events found, "
344 focus_fallback(Fallback_NoFocus
);
350 /* NotifyUngrab occurs when a mouse button is released and the event is
351 caused, like when lowering a window */
352 /* NotifyVirtual occurs when ungrabbing the pointer */
353 if (e
->xcrossing
.mode
== NotifyGrab
||
354 e
->xcrossing
.detail
== NotifyInferior
||
355 (e
->xcrossing
.mode
== NotifyUngrab
&&
356 e
->xcrossing
.detail
== NotifyVirtual
)) {
358 g_message("%sNotify mode %d detail %d on %lx IGNORED",
359 (e
->type
== EnterNotify
? "Enter" : "Leave"),
361 e
->xcrossing
.detail
, client
?client
->window
:0);
366 g_message("%sNotify mode %d detail %d on %lx",
367 (e
->type
== EnterNotify
? "Enter" : "Leave"),
369 e
->xcrossing
.detail
, client
?client
->window
:0);
376 static void event_process(XEvent
*e
)
379 Client
*client
= NULL
;
381 SlitApp
*slitapp
= NULL
;
384 window
= event_get_window(e
);
385 if (!(client
= g_hash_table_lookup(client_map
, &window
)))
386 if (!(slitapp
= g_hash_table_lookup(slit_app_map
, &window
)))
387 if (!(slit
= g_hash_table_lookup(slit_map
, &window
)))
388 menu
= g_hash_table_lookup(menu_map
, &window
);
390 event_set_lasttime(e
);
392 if (event_ignore(e
, client
))
395 /* deal with it in the kernel */
397 event_handle_menu(menu
, e
);
400 event_handle_client(client
, e
);
402 event_handle_slitapp(slitapp
, e
);
404 event_handle_slit(slit
, e
);
405 else if (window
== ob_root
)
406 event_handle_root(e
);
407 else if (e
->type
== MapRequest
)
408 client_manage(window
);
409 else if (e
->type
== ConfigureRequest
) {
410 /* unhandled configure requests must be used to configure the
414 xwc
.x
= e
->xconfigurerequest
.x
;
415 xwc
.y
= e
->xconfigurerequest
.y
;
416 xwc
.width
= e
->xconfigurerequest
.width
;
417 xwc
.height
= e
->xconfigurerequest
.height
;
418 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
419 xwc
.sibling
= e
->xconfigurerequest
.above
;
420 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
422 /* we are not to be held responsible if someone sends us an
424 xerror_set_ignore(TRUE
);
425 XConfigureWindow(ob_display
, window
,
426 e
->xconfigurerequest
.value_mask
, &xwc
);
427 xerror_set_ignore(FALSE
);
430 if (moveresize_in_progress
)
431 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
432 e
->type
== ButtonPress
||
433 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
436 return; /* no dispatch! */
440 /* user input (action-bound) events */
442 if (e->type == ButtonPress || e->type == ButtonRelease ||
443 e->type == MotionNotify)
444 mouse_event(e, client);
445 else if (e->type == KeyPress || e->type == KeyRelease)
449 /* dispatch the event to registered handlers */
450 dispatch_x(e
, client
);
453 static void event_handle_root(XEvent
*e
)
459 if (e
->xclient
.format
!= 32) break;
461 msgtype
= e
->xclient
.message_type
;
462 if (msgtype
== prop_atoms
.net_current_desktop
) {
463 unsigned int d
= e
->xclient
.data
.l
[0];
464 if (d
< screen_num_desktops
)
465 screen_set_desktop(d
);
466 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
467 unsigned int d
= e
->xclient
.data
.l
[0];
469 screen_set_num_desktops(d
);
470 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
471 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
475 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
476 screen_update_desktop_names();
477 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
478 screen_update_layout();
480 case ConfigureNotify
:
482 XRRUpdateConfiguration(e
);
484 if (e
->xconfigure
.width
!= screen_physical_size
.width
||
485 e
->xconfigure
.height
!= screen_physical_size
.height
)
486 screen_resize(e
->xconfigure
.width
, e
->xconfigure
.height
);
491 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
492 g_message("VIDMODE EVENT");
498 static void event_handle_client(Client
*client
, XEvent
*e
)
507 switch (frame_context(client
, e
->xbutton
.window
)) {
508 case Context_Maximize
:
509 client
->frame
->max_press
= (e
->type
== ButtonPress
);
510 framerender_frame(client
->frame
);
513 client
->frame
->close_press
= (e
->type
== ButtonPress
);
514 framerender_frame(client
->frame
);
516 case Context_Iconify
:
517 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
518 framerender_frame(client
->frame
);
520 case Context_AllDesktops
:
521 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
522 framerender_frame(client
->frame
);
525 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
526 framerender_frame(client
->frame
);
529 /* nothing changes with clicks for any other contexts */
535 g_message("FocusIn on client for %lx", client
->window
);
537 focus_set_client(client
);
538 frame_adjust_focus(client
->frame
, TRUE
);
542 g_message("FocusOut on client for %lx", client
->window
);
544 /* are we a fullscreen window or a transient of one? (checks layer)
545 if we are then we need to be iconified since we are losing focus
547 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
548 !client_search_focus_tree_full(client
))
549 /* iconify fullscreen windows when they and their transients
551 client_iconify(client
, TRUE
, TRUE
);
552 frame_adjust_focus(client
->frame
, FALSE
);
555 if (client_normal(client
)) {
556 if (ob_state
== State_Starting
) {
557 /* move it to the top of the focus order */
558 guint desktop
= client
->desktop
;
559 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
560 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
562 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
564 } else if (config_focus_follow
) {
566 g_message("EnterNotify on %lx, focusing window",
569 client_focus(client
);
573 case ConfigureRequest
:
575 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
576 ConfigureRequest
, &ce
)) {
578 /* XXX if this causes bad things.. we can compress config req's
579 with the same mask. */
580 e
->xconfigurerequest
.value_mask
|=
581 ce
.xconfigurerequest
.value_mask
;
582 if (ce
.xconfigurerequest
.value_mask
& CWX
)
583 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
584 if (ce
.xconfigurerequest
.value_mask
& CWY
)
585 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
586 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
587 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
588 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
589 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
590 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
591 e
->xconfigurerequest
.border_width
=
592 ce
.xconfigurerequest
.border_width
;
593 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
594 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
597 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
598 if (client
->iconic
|| client
->shaded
) return;
600 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
601 client
->border_width
= e
->xconfigurerequest
.border_width
;
603 /* resize, then move, as specified in the EWMH section 7.7 */
604 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
609 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
610 e
->xconfigurerequest
.x
: client
->area
.x
;
611 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
612 e
->xconfigurerequest
.y
: client
->area
.y
;
613 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
614 e
->xconfigurerequest
.width
: client
->area
.width
;
615 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
616 e
->xconfigurerequest
.height
: client
->area
.height
;
618 switch (client
->gravity
) {
619 case NorthEastGravity
:
621 corner
= Corner_TopRight
;
623 case SouthWestGravity
:
625 corner
= Corner_BottomLeft
;
627 case SouthEastGravity
:
628 corner
= Corner_BottomRight
;
630 default: /* NorthWest, Static, etc */
631 corner
= Corner_TopLeft
;
634 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
637 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
638 switch (e
->xconfigurerequest
.detail
) {
641 stacking_lower(client
);
647 stacking_raise(client
);
653 if (client
->ignore_unmaps
) {
654 client
->ignore_unmaps
--;
657 client_unmanage(client
);
660 client_unmanage(client
);
663 /* this is when the client is first taken captive in the frame */
664 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
667 This event is quite rare and is usually handled in unmapHandler.
668 However, if the window is unmapped when the reparent event occurs,
669 the window manager never sees it because an unmap event is not sent
670 to an already unmapped window.
673 /* we don't want the reparent event, put it back on the stack for the
674 X server to deal with after we unmanage the window */
675 XPutBackEvent(ob_display
, e
);
677 client_unmanage(client
);
680 g_message("MapRequest for 0x%lx", client
->window
);
681 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
682 does, we don't want it! */
683 if (screen_showing_desktop
)
684 screen_show_desktop(FALSE
);
685 client_iconify(client
, FALSE
, TRUE
);
686 if (!client
->frame
->visible
)
687 /* if its not visible still, then don't mess with it */
690 client_shade(client
, FALSE
);
691 client_focus(client
);
692 stacking_raise(client
);
695 /* validate cuz we query stuff off the client here */
696 if (!client_validate(client
)) break;
698 if (e
->xclient
.format
!= 32) return;
700 msgtype
= e
->xclient
.message_type
;
701 if (msgtype
== prop_atoms
.wm_change_state
) {
702 /* compress changes into a single change */
703 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
704 client
->window
, &ce
)) {
705 /* XXX: it would be nice to compress ALL messages of a
706 type, not just messages in a row without other
707 message types between. */
708 if (ce
.xclient
.message_type
!= msgtype
) {
709 XPutBackEvent(ob_display
, &ce
);
712 e
->xclient
= ce
.xclient
;
714 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
715 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
716 /* compress changes into a single change */
717 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
718 client
->window
, &ce
)) {
719 /* XXX: it would be nice to compress ALL messages of a
720 type, not just messages in a row without other
721 message types between. */
722 if (ce
.xclient
.message_type
!= msgtype
) {
723 XPutBackEvent(ob_display
, &ce
);
726 e
->xclient
= ce
.xclient
;
728 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
729 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
730 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
732 } else if (msgtype
== prop_atoms
.net_wm_state
) {
733 /* can't compress these */
734 g_message("net_wm_state %s %ld %ld for 0x%lx",
735 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
736 e
->xclient
.data
.l
[0] == 1 ? "Add" :
737 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
738 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
740 client_set_state(client
, e
->xclient
.data
.l
[0],
741 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
742 } else if (msgtype
== prop_atoms
.net_close_window
) {
743 g_message("net_close_window for 0x%lx", client
->window
);
744 client_close(client
);
745 } else if (msgtype
== prop_atoms
.net_active_window
) {
746 g_message("net_active_window for 0x%lx", client
->window
);
747 client_activate(client
);
748 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
749 g_message("net_wm_moveresize for 0x%lx", client
->window
);
750 if ((Atom
)e
->xclient
.data
.l
[2] ==
751 prop_atoms
.net_wm_moveresize_size_topleft
||
752 (Atom
)e
->xclient
.data
.l
[2] ==
753 prop_atoms
.net_wm_moveresize_size_top
||
754 (Atom
)e
->xclient
.data
.l
[2] ==
755 prop_atoms
.net_wm_moveresize_size_topright
||
756 (Atom
)e
->xclient
.data
.l
[2] ==
757 prop_atoms
.net_wm_moveresize_size_right
||
758 (Atom
)e
->xclient
.data
.l
[2] ==
759 prop_atoms
.net_wm_moveresize_size_right
||
760 (Atom
)e
->xclient
.data
.l
[2] ==
761 prop_atoms
.net_wm_moveresize_size_bottomright
||
762 (Atom
)e
->xclient
.data
.l
[2] ==
763 prop_atoms
.net_wm_moveresize_size_bottom
||
764 (Atom
)e
->xclient
.data
.l
[2] ==
765 prop_atoms
.net_wm_moveresize_size_bottomleft
||
766 (Atom
)e
->xclient
.data
.l
[2] ==
767 prop_atoms
.net_wm_moveresize_size_left
||
768 (Atom
)e
->xclient
.data
.l
[2] ==
769 prop_atoms
.net_wm_moveresize_move
||
770 (Atom
)e
->xclient
.data
.l
[2] ==
771 prop_atoms
.net_wm_moveresize_size_keyboard
||
772 (Atom
)e
->xclient
.data
.l
[2] ==
773 prop_atoms
.net_wm_moveresize_move_keyboard
) {
775 moveresize_start(client
, e
->xclient
.data
.l
[0],
776 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
777 e
->xclient
.data
.l
[2]);
779 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
780 int oldg
= client
->gravity
;
781 int tmpg
, x
, y
, w
, h
;
783 if (e
->xclient
.data
.l
[0] & 0xff)
784 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
788 if (e
->xclient
.data
.l
[0] & 1 << 8)
789 x
= e
->xclient
.data
.l
[1];
792 if (e
->xclient
.data
.l
[0] & 1 << 9)
793 y
= e
->xclient
.data
.l
[2];
796 if (e
->xclient
.data
.l
[0] & 1 << 10)
797 w
= e
->xclient
.data
.l
[3];
800 if (e
->xclient
.data
.l
[0] & 1 << 11)
801 h
= e
->xclient
.data
.l
[4];
804 client
->gravity
= tmpg
;
805 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
806 client
->gravity
= oldg
;
810 /* validate cuz we query stuff off the client here */
811 if (!client_validate(client
)) break;
813 /* compress changes to a single property into a single change */
814 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
815 client
->window
, &ce
)) {
816 /* XXX: it would be nice to compress ALL changes to a property,
817 not just changes in a row without other props between. */
818 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
819 XPutBackEvent(ob_display
, &ce
);
824 msgtype
= e
->xproperty
.atom
;
825 if (msgtype
== XA_WM_NORMAL_HINTS
) {
826 client_update_normal_hints(client
);
827 /* normal hints can make a window non-resizable */
828 client_setup_decor_and_functions(client
);
830 else if (msgtype
== XA_WM_HINTS
)
831 client_update_wmhints(client
);
832 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
833 client_update_transient_for(client
);
834 client_get_type(client
);
835 /* type may have changed, so update the layer */
836 client_calc_layer(client
);
837 client_setup_decor_and_functions(client
);
839 else if (msgtype
== prop_atoms
.net_wm_name
||
840 msgtype
== prop_atoms
.wm_name
||
841 msgtype
== prop_atoms
.net_wm_icon_name
||
842 msgtype
== prop_atoms
.wm_icon_name
)
843 client_update_title(client
);
844 else if (msgtype
== prop_atoms
.wm_class
)
845 client_update_class(client
);
846 else if (msgtype
== prop_atoms
.wm_protocols
) {
847 client_update_protocols(client
);
848 client_setup_decor_and_functions(client
);
850 else if (msgtype
== prop_atoms
.net_wm_strut
)
851 client_update_strut(client
);
852 else if (msgtype
== prop_atoms
.net_wm_icon
)
853 client_update_icons(client
);
854 else if (msgtype
== prop_atoms
.kwm_win_icon
)
855 client_update_kwm_icon(client
);
859 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
860 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
861 frame_adjust_shape(client
->frame
);
867 static void event_handle_menu(Menu
*menu
, XEvent
*e
)
871 g_message("EVENT %d", e
->type
);
874 g_message("BUTTON PRESS");
875 if (e
->xbutton
.button
== 3)
879 g_message("BUTTON RELEASED");
880 if (!menu
->shown
) break;
882 /* grab_pointer_window(FALSE, None, menu->frame);*/
884 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
888 guint ujunk
, b
, w
, h
;
889 XGetGeometry(ob_display
, e
->xbutton
.window
,
890 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
891 if (e
->xbutton
.x
>= (signed)-b
&&
892 e
->xbutton
.y
>= (signed)-b
&&
893 e
->xbutton
.x
< (signed)(w
+b
) &&
894 e
->xbutton
.y
< (signed)(h
+b
)) {
895 menu_entry_fire(entry
);
901 g_message("enter/leave");
902 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
905 menu
->mouseover(entry
, e
->type
== EnterNotify
);
907 menu_control_mouseover(entry
, e
->type
== EnterNotify
);
909 menu_entry_render(entry
);
916 static void event_handle_slit(Slit
*s
, XEvent
*e
)
928 static void event_handle_slitapp(SlitApp
*app
, XEvent
*e
)
932 slit_app_drag(app
, &e
->xmotion
);
935 if (app
->ignore_unmaps
) {
936 app
->ignore_unmaps
--;
939 slit_remove(app
, TRUE
);
942 slit_remove(app
, FALSE
);
945 slit_remove(app
, FALSE
);
947 case ConfigureNotify
:
948 slit_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);