10 #include "framerender.h"
12 #include "moveresize.h"
14 #include "extensions.h"
20 #include <X11/keysym.h>
21 #include <X11/Xatom.h>
24 #ifdef HAVE_SYS_SELECT_H
25 # include <sys/select.h>
28 static void event_process(XEvent
*e
);
29 static void event_handle_root(XEvent
*e
);
30 static void event_handle_slit(Slit
*s
, XEvent
*e
);
31 static void event_handle_slitapp(SlitApp
*app
, XEvent
*e
);
32 static void event_handle_client(Client
*c
, XEvent
*e
);
33 static void event_handle_menu(Menu
*menu
, XEvent
*e
);
35 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
36 (e)->xfocus.detail > NotifyNonlinearVirtual)
37 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
38 (e)->xfocus.detail == NotifyInferior || \
39 (e)->xfocus.detail == NotifyAncestor || \
40 (e)->xfocus.detail > NotifyNonlinearVirtual)
42 Time event_lasttime
= 0;
44 /*! The value of the mask for the NumLock modifier */
45 unsigned int NumLockMask
;
46 /*! The value of the mask for the ScrollLock modifier */
47 unsigned int ScrollLockMask
;
48 /*! The key codes for the modifier keys */
49 static XModifierKeymap
*modmap
;
50 /*! Table of the constant modifier masks */
51 static const int mask_table
[] = {
52 ShiftMask
, LockMask
, ControlMask
, Mod1Mask
,
53 Mod2Mask
, Mod3Mask
, Mod4Mask
, Mod5Mask
55 static int mask_table_size
;
57 static fd_set selset
, allset
;
58 static int max_fd
, x_fd
;
59 static GData
*fd_handler_list
;
61 void fd_event_handle();
65 mask_table_size
= sizeof(mask_table
) / sizeof(mask_table
[0]);
67 /* get lock masks that are defined by the display (not constant) */
68 modmap
= XGetModifierMapping(ob_display
);
70 if (modmap
&& modmap
->max_keypermod
> 0) {
72 const size_t size
= mask_table_size
* modmap
->max_keypermod
;
73 /* get the values of the keyboard lock modifiers
74 Note: Caps lock is not retrieved the same way as Scroll and Num
75 lock since it doesn't need to be. */
76 const KeyCode num_lock
= XKeysymToKeycode(ob_display
, XK_Num_Lock
);
77 const KeyCode scroll_lock
= XKeysymToKeycode(ob_display
,
80 for (cnt
= 0; cnt
< size
; ++cnt
) {
81 if (! modmap
->modifiermap
[cnt
]) continue;
83 if (num_lock
== modmap
->modifiermap
[cnt
])
84 NumLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
85 if (scroll_lock
== modmap
->modifiermap
[cnt
])
86 ScrollLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
91 max_fd
= x_fd
= ConnectionNumber(ob_display
);
92 FD_SET(x_fd
, &allset
);
93 g_datalist_init(&fd_handler_list
);
98 XFreeModifiermap(modmap
);
99 g_datalist_clear(&fd_handler_list
);
105 struct timeval
*wait
;
106 gboolean had_event
= FALSE
;
110 There are slightly different event retrieval semantics here for
111 local (or high bandwidth) versus remote (or low bandwidth)
112 connections to the display/Xserver.
115 if (!XPending(ob_display
))
119 This XSync allows for far more compression of events, which
120 makes things like Motion events perform far far better. Since
121 it also means network traffic for every event instead of every
122 X events (where X is the number retrieved at a time), it
123 probably should not be used for setups where Openbox is
124 running on a remote/low bandwidth display/Xserver.
126 XSync(ob_display
, FALSE
);
127 if (!XEventsQueued(ob_display
, QueuedAlready
))
130 XNextEvent(ob_display
, &e
);
137 timer_dispatch((GTimeVal
**)&wait
);
139 select(max_fd
+ 1, &selset
, NULL
, NULL
, wait
);
141 /* handle the X events as soon as possible? */
142 if (FD_ISSET(x_fd
, &selset
))
149 static Window
event_get_window(XEvent
*e
)
156 window
= e
->xmap
.window
;
159 window
= e
->xunmap
.window
;
162 window
= e
->xdestroywindow
.window
;
164 case ConfigureRequest
:
165 window
= e
->xconfigurerequest
.window
;
167 case ConfigureNotify
:
168 window
= e
->xconfigure
.window
;
172 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
173 switch (((XkbAnyEvent
*)&e
)->xkb_type
) {
175 window
= ((XkbBellNotifyEvent
*)&e
)->window
;
181 window
= e
->xany
.window
;
186 static void event_set_lasttime(XEvent
*e
)
188 /* grab the lasttime and hack up the state */
192 event_lasttime
= e
->xbutton
.time
;
195 event_lasttime
= e
->xkey
.time
;
198 event_lasttime
= e
->xkey
.time
;
201 event_lasttime
= e
->xmotion
.time
;
204 event_lasttime
= e
->xproperty
.time
;
208 event_lasttime
= e
->xcrossing
.time
;
211 event_lasttime
= CurrentTime
;
216 #define STRIP_MODS(s) \
217 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
218 /* kill off the Button1Mask etc, only want the modifiers */ \
219 s &= (ControlMask | ShiftMask | Mod1Mask | \
220 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
222 static void event_hack_mods(XEvent *e)
230 STRIP_MODS(e
->xbutton
.state
);
233 STRIP_MODS(e
->xkey
.state
);
236 STRIP_MODS(e
->xkey
.state
);
237 /* remove from the state the mask of the modifier being released, if
238 it is a modifier key being released (this is a little ugly..) */
239 kp
= modmap
->modifiermap
;
240 for (i
= 0; i
< mask_table_size
; ++i
) {
241 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
242 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
243 /* remove the mask for it */
244 e
->xkey
.state
&= ~mask_table
[i
];
245 /* cause the first loop to break; */
247 break; /* get outta here! */
254 STRIP_MODS(e
->xmotion
.state
);
255 /* compress events */
258 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
260 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
261 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
268 static gboolean
event_ignore(XEvent
*e
, Client
*client
)
272 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
273 because of RevertToPointerRoot. If the focus ends up reverting to
274 pointer root on a workspace change, then the FocusIn event that we
275 want will be of type NotifyAncestor. This situation does not occur
276 for FocusOut, so it is safely ignored there.
278 if (INVALID_FOCUSIN(e
) ||
281 g_message("FocusIn on %lx mode %d detail %d IGNORED", e
->xfocus
.window
,
282 e
->xfocus
.mode
, e
->xfocus
.detail
);
284 /* says a client was not found for the event (or a valid FocusIn
287 e
->xfocus
.window
= None
;
292 g_message("FocusIn on %lx mode %d detail %d", e
->xfocus
.window
,
293 e
->xfocus
.mode
, e
->xfocus
.detail
);
297 if (INVALID_FOCUSOUT(e
)) {
299 g_message("FocusOut on %lx mode %d detail %d IGNORED",
300 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
306 g_message("FocusOut on %lx mode %d detail %d",
307 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
312 gboolean fallback
= TRUE
;
315 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
316 e
->xfocus
.window
,&fe
))
317 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
319 if (fe
.type
== FocusOut
) {
321 g_message("found pending FocusOut");
323 if (!INVALID_FOCUSOUT(&fe
)) {
324 /* if there is a VALID FocusOut still coming, don't
325 fallback focus yet, we'll deal with it then */
326 XPutBackEvent(ob_display
, &fe
);
332 g_message("found pending FocusIn");
334 /* is the focused window getting a FocusOut/In back to
336 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
337 !event_ignore(&fe
, client
)) {
339 g_message("focused window got an Out/In back to "
340 "itself IGNORED both");
345 /* once all the FocusOut's have been dealt with, if there
346 is a FocusIn still left and it is valid, then use it */
348 /* secret magic way of event_process telling us that no
349 client was found for the FocusIn event. ^_^ */
350 if (fe
.xfocus
.window
!= None
) {
358 g_message("no valid FocusIn and no FocusOut events found, "
361 focus_fallback(Fallback_NoFocus
);
367 /* NotifyUngrab occurs when a mouse button is released and the event is
368 caused, like when lowering a window */
369 /* NotifyVirtual occurs when ungrabbing the pointer */
370 if (e
->xcrossing
.mode
== NotifyGrab
||
371 e
->xcrossing
.detail
== NotifyInferior
||
372 (e
->xcrossing
.mode
== NotifyUngrab
&&
373 e
->xcrossing
.detail
== NotifyVirtual
)) {
375 g_message("%sNotify mode %d detail %d on %lx IGNORED",
376 (e
->type
== EnterNotify
? "Enter" : "Leave"),
378 e
->xcrossing
.detail
, client
?client
->window
:0);
383 g_message("%sNotify mode %d detail %d on %lx",
384 (e
->type
== EnterNotify
? "Enter" : "Leave"),
386 e
->xcrossing
.detail
, client
?client
->window
:0);
393 static void event_process(XEvent
*e
)
396 Client
*client
= NULL
;
398 SlitApp
*slitapp
= NULL
;
401 window
= event_get_window(e
);
402 if (!(client
= g_hash_table_lookup(client_map
, &window
)))
403 if (!(slitapp
= g_hash_table_lookup(slit_app_map
, &window
)))
404 if (!(slit
= g_hash_table_lookup(slit_map
, &window
)))
405 menu
= g_hash_table_lookup(menu_map
, &window
);
407 event_set_lasttime(e
);
409 if (event_ignore(e
, client
))
412 /* deal with it in the kernel */
414 event_handle_menu(menu
, e
);
417 event_handle_client(client
, e
);
419 event_handle_slitapp(slitapp
, e
);
421 event_handle_slit(slit
, e
);
422 else if (window
== ob_root
)
423 event_handle_root(e
);
424 else if (e
->type
== MapRequest
)
425 client_manage(window
);
426 else if (e
->type
== ConfigureRequest
) {
427 /* unhandled configure requests must be used to configure the
431 xwc
.x
= e
->xconfigurerequest
.x
;
432 xwc
.y
= e
->xconfigurerequest
.y
;
433 xwc
.width
= e
->xconfigurerequest
.width
;
434 xwc
.height
= e
->xconfigurerequest
.height
;
435 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
436 xwc
.sibling
= e
->xconfigurerequest
.above
;
437 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
439 /* we are not to be held responsible if someone sends us an
441 xerror_set_ignore(TRUE
);
442 XConfigureWindow(ob_display
, window
,
443 e
->xconfigurerequest
.value_mask
, &xwc
);
444 xerror_set_ignore(FALSE
);
447 if (moveresize_in_progress
)
448 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
449 e
->type
== ButtonPress
||
450 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
453 return; /* no dispatch! */
457 /* user input (action-bound) events */
459 if (e->type == ButtonPress || e->type == ButtonRelease ||
460 e->type == MotionNotify)
461 mouse_event(e, client);
462 else if (e->type == KeyPress || e->type == KeyRelease)
466 /* dispatch the event to registered handlers */
467 dispatch_x(e
, client
);
470 static void event_handle_root(XEvent
*e
)
476 if (e
->xclient
.format
!= 32) break;
478 msgtype
= e
->xclient
.message_type
;
479 if (msgtype
== prop_atoms
.net_current_desktop
) {
480 unsigned int d
= e
->xclient
.data
.l
[0];
481 if (d
< screen_num_desktops
)
482 screen_set_desktop(d
);
483 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
484 unsigned int d
= e
->xclient
.data
.l
[0];
486 screen_set_num_desktops(d
);
487 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
488 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
492 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
493 screen_update_desktop_names();
494 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
495 screen_update_layout();
497 case ConfigureNotify
:
499 XRRUpdateConfiguration(e
);
501 if (e
->xconfigure
.width
!= screen_physical_size
.width
||
502 e
->xconfigure
.height
!= screen_physical_size
.height
)
503 screen_resize(e
->xconfigure
.width
, e
->xconfigure
.height
);
508 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
509 g_message("VIDMODE EVENT");
515 static void event_handle_client(Client
*client
, XEvent
*e
)
524 switch (frame_context(client
, e
->xbutton
.window
)) {
525 case Context_Maximize
:
526 client
->frame
->max_press
= (e
->type
== ButtonPress
);
527 framerender_frame(client
->frame
);
530 client
->frame
->close_press
= (e
->type
== ButtonPress
);
531 framerender_frame(client
->frame
);
533 case Context_Iconify
:
534 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
535 framerender_frame(client
->frame
);
537 case Context_AllDesktops
:
538 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
539 framerender_frame(client
->frame
);
542 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
543 framerender_frame(client
->frame
);
546 /* nothing changes with clicks for any other contexts */
552 g_message("FocusIn on client for %lx", client
->window
);
554 focus_set_client(client
);
555 frame_adjust_focus(client
->frame
, TRUE
);
559 g_message("FocusOut on client for %lx", client
->window
);
561 /* are we a fullscreen window or a transient of one? (checks layer)
562 if we are then we need to be iconified since we are losing focus
564 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
565 !client_search_focus_tree_full(client
))
566 /* iconify fullscreen windows when they and their transients
568 client_iconify(client
, TRUE
, TRUE
);
569 frame_adjust_focus(client
->frame
, FALSE
);
572 if (client_normal(client
)) {
573 if (ob_state
== State_Starting
) {
574 /* move it to the top of the focus order */
575 guint desktop
= client
->desktop
;
576 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
577 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
579 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
581 } else if (config_focus_follow
) {
583 g_message("EnterNotify on %lx, focusing window",
586 client_focus(client
);
590 case ConfigureRequest
:
592 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
593 ConfigureRequest
, &ce
)) {
595 /* XXX if this causes bad things.. we can compress config req's
596 with the same mask. */
597 e
->xconfigurerequest
.value_mask
|=
598 ce
.xconfigurerequest
.value_mask
;
599 if (ce
.xconfigurerequest
.value_mask
& CWX
)
600 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
601 if (ce
.xconfigurerequest
.value_mask
& CWY
)
602 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
603 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
604 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
605 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
606 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
607 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
608 e
->xconfigurerequest
.border_width
=
609 ce
.xconfigurerequest
.border_width
;
610 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
611 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
614 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
615 if (client
->iconic
|| client
->shaded
) return;
617 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
618 client
->border_width
= e
->xconfigurerequest
.border_width
;
620 /* resize, then move, as specified in the EWMH section 7.7 */
621 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
626 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
627 e
->xconfigurerequest
.x
: client
->area
.x
;
628 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
629 e
->xconfigurerequest
.y
: client
->area
.y
;
630 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
631 e
->xconfigurerequest
.width
: client
->area
.width
;
632 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
633 e
->xconfigurerequest
.height
: client
->area
.height
;
635 switch (client
->gravity
) {
636 case NorthEastGravity
:
638 corner
= Corner_TopRight
;
640 case SouthWestGravity
:
642 corner
= Corner_BottomLeft
;
644 case SouthEastGravity
:
645 corner
= Corner_BottomRight
;
647 default: /* NorthWest, Static, etc */
648 corner
= Corner_TopLeft
;
651 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
654 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
655 switch (e
->xconfigurerequest
.detail
) {
658 stacking_lower(CLIENT_AS_WINDOW(client
));
664 stacking_raise(CLIENT_AS_WINDOW(client
));
670 if (client
->ignore_unmaps
) {
671 client
->ignore_unmaps
--;
674 client_unmanage(client
);
677 client_unmanage(client
);
680 /* this is when the client is first taken captive in the frame */
681 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
684 This event is quite rare and is usually handled in unmapHandler.
685 However, if the window is unmapped when the reparent event occurs,
686 the window manager never sees it because an unmap event is not sent
687 to an already unmapped window.
690 /* we don't want the reparent event, put it back on the stack for the
691 X server to deal with after we unmanage the window */
692 XPutBackEvent(ob_display
, e
);
694 client_unmanage(client
);
697 g_message("MapRequest for 0x%lx", client
->window
);
698 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
699 does, we don't want it! */
700 if (screen_showing_desktop
)
701 screen_show_desktop(FALSE
);
702 client_iconify(client
, FALSE
, TRUE
);
703 if (!client
->frame
->visible
)
704 /* if its not visible still, then don't mess with it */
707 client_shade(client
, FALSE
);
708 client_focus(client
);
709 stacking_raise(CLIENT_AS_WINDOW(client
));
712 /* validate cuz we query stuff off the client here */
713 if (!client_validate(client
)) break;
715 if (e
->xclient
.format
!= 32) return;
717 msgtype
= e
->xclient
.message_type
;
718 if (msgtype
== prop_atoms
.wm_change_state
) {
719 /* compress changes into a single change */
720 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
721 client
->window
, &ce
)) {
722 /* XXX: it would be nice to compress ALL messages of a
723 type, not just messages in a row without other
724 message types between. */
725 if (ce
.xclient
.message_type
!= msgtype
) {
726 XPutBackEvent(ob_display
, &ce
);
729 e
->xclient
= ce
.xclient
;
731 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
732 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
733 /* compress changes into a single change */
734 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
735 client
->window
, &ce
)) {
736 /* XXX: it would be nice to compress ALL messages of a
737 type, not just messages in a row without other
738 message types between. */
739 if (ce
.xclient
.message_type
!= msgtype
) {
740 XPutBackEvent(ob_display
, &ce
);
743 e
->xclient
= ce
.xclient
;
745 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
746 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
747 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
749 } else if (msgtype
== prop_atoms
.net_wm_state
) {
750 /* can't compress these */
751 g_message("net_wm_state %s %ld %ld for 0x%lx",
752 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
753 e
->xclient
.data
.l
[0] == 1 ? "Add" :
754 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
755 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
757 client_set_state(client
, e
->xclient
.data
.l
[0],
758 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
759 } else if (msgtype
== prop_atoms
.net_close_window
) {
760 g_message("net_close_window for 0x%lx", client
->window
);
761 client_close(client
);
762 } else if (msgtype
== prop_atoms
.net_active_window
) {
763 g_message("net_active_window for 0x%lx", client
->window
);
764 client_activate(client
);
765 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
766 g_message("net_wm_moveresize for 0x%lx", client
->window
);
767 if ((Atom
)e
->xclient
.data
.l
[2] ==
768 prop_atoms
.net_wm_moveresize_size_topleft
||
769 (Atom
)e
->xclient
.data
.l
[2] ==
770 prop_atoms
.net_wm_moveresize_size_top
||
771 (Atom
)e
->xclient
.data
.l
[2] ==
772 prop_atoms
.net_wm_moveresize_size_topright
||
773 (Atom
)e
->xclient
.data
.l
[2] ==
774 prop_atoms
.net_wm_moveresize_size_right
||
775 (Atom
)e
->xclient
.data
.l
[2] ==
776 prop_atoms
.net_wm_moveresize_size_right
||
777 (Atom
)e
->xclient
.data
.l
[2] ==
778 prop_atoms
.net_wm_moveresize_size_bottomright
||
779 (Atom
)e
->xclient
.data
.l
[2] ==
780 prop_atoms
.net_wm_moveresize_size_bottom
||
781 (Atom
)e
->xclient
.data
.l
[2] ==
782 prop_atoms
.net_wm_moveresize_size_bottomleft
||
783 (Atom
)e
->xclient
.data
.l
[2] ==
784 prop_atoms
.net_wm_moveresize_size_left
||
785 (Atom
)e
->xclient
.data
.l
[2] ==
786 prop_atoms
.net_wm_moveresize_move
||
787 (Atom
)e
->xclient
.data
.l
[2] ==
788 prop_atoms
.net_wm_moveresize_size_keyboard
||
789 (Atom
)e
->xclient
.data
.l
[2] ==
790 prop_atoms
.net_wm_moveresize_move_keyboard
) {
792 moveresize_start(client
, e
->xclient
.data
.l
[0],
793 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
794 e
->xclient
.data
.l
[2]);
796 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
797 int oldg
= client
->gravity
;
798 int tmpg
, x
, y
, w
, h
;
800 if (e
->xclient
.data
.l
[0] & 0xff)
801 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
805 if (e
->xclient
.data
.l
[0] & 1 << 8)
806 x
= e
->xclient
.data
.l
[1];
809 if (e
->xclient
.data
.l
[0] & 1 << 9)
810 y
= e
->xclient
.data
.l
[2];
813 if (e
->xclient
.data
.l
[0] & 1 << 10)
814 w
= e
->xclient
.data
.l
[3];
817 if (e
->xclient
.data
.l
[0] & 1 << 11)
818 h
= e
->xclient
.data
.l
[4];
821 client
->gravity
= tmpg
;
822 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
823 client
->gravity
= oldg
;
827 /* validate cuz we query stuff off the client here */
828 if (!client_validate(client
)) break;
830 /* compress changes to a single property into a single change */
831 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
832 client
->window
, &ce
)) {
833 /* XXX: it would be nice to compress ALL changes to a property,
834 not just changes in a row without other props between. */
835 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
836 XPutBackEvent(ob_display
, &ce
);
841 msgtype
= e
->xproperty
.atom
;
842 if (msgtype
== XA_WM_NORMAL_HINTS
) {
843 client_update_normal_hints(client
);
844 /* normal hints can make a window non-resizable */
845 client_setup_decor_and_functions(client
);
847 else if (msgtype
== XA_WM_HINTS
)
848 client_update_wmhints(client
);
849 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
850 client_update_transient_for(client
);
851 client_get_type(client
);
852 /* type may have changed, so update the layer */
853 client_calc_layer(client
);
854 client_setup_decor_and_functions(client
);
856 else if (msgtype
== prop_atoms
.net_wm_name
||
857 msgtype
== prop_atoms
.wm_name
||
858 msgtype
== prop_atoms
.net_wm_icon_name
||
859 msgtype
== prop_atoms
.wm_icon_name
)
860 client_update_title(client
);
861 else if (msgtype
== prop_atoms
.wm_class
)
862 client_update_class(client
);
863 else if (msgtype
== prop_atoms
.wm_protocols
) {
864 client_update_protocols(client
);
865 client_setup_decor_and_functions(client
);
867 else if (msgtype
== prop_atoms
.net_wm_strut
)
868 client_update_strut(client
);
869 else if (msgtype
== prop_atoms
.net_wm_icon
)
870 client_update_icons(client
);
871 else if (msgtype
== prop_atoms
.kwm_win_icon
)
872 client_update_kwm_icon(client
);
876 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
877 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
878 frame_adjust_shape(client
->frame
);
884 static void event_handle_menu(Menu
*menu
, XEvent
*e
)
888 g_message("EVENT %d", e
->type
);
891 g_message("BUTTON PRESS");
892 if (e
->xbutton
.button
== 3)
894 else if (e
->xbutton
.button
== 1) {
895 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
897 stacking_raise(MENU_AS_WINDOW(menu
));
901 g_message("BUTTON RELEASED");
902 if (!menu
->shown
) break;
904 /* grab_pointer_window(FALSE, None, menu->frame);*/
906 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
910 guint ujunk
, b
, w
, h
;
911 XGetGeometry(ob_display
, e
->xbutton
.window
,
912 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
913 if (e
->xbutton
.x
>= (signed)-b
&&
914 e
->xbutton
.y
>= (signed)-b
&&
915 e
->xbutton
.x
< (signed)(w
+b
) &&
916 e
->xbutton
.y
< (signed)(h
+b
)) {
917 menu_entry_fire(entry
);
924 g_message("enter/leave");
925 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
928 menu
->mouseover(entry
, e
->type
== EnterNotify
);
930 menu_control_mouseover(entry
, e
->type
== EnterNotify
);
932 menu_entry_render(entry
);
938 static void event_handle_slit(Slit
*s
, XEvent
*e
)
942 stacking_raise(SLIT_AS_WINDOW(s
));
952 void event_add_fd_handler(event_fd_handler
*h
) {
953 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
954 FD_SET(h
->fd
, &allset
);
955 max_fd
= MAX(max_fd
, h
->fd
);
958 void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
960 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
963 void event_remove_fd(int n
)
967 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
968 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
, (gpointer
)&tmpmax
);
969 max_fd
= MAX(x_fd
, tmpmax
);
972 void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
974 if (FD_ISSET( (int)n
, &selset
)) {
975 event_fd_handler
*h
= (event_fd_handler
*)data
;
976 g_assert(h
->fd
== (int)n
);
977 h
->handler(h
->fd
, h
->data
);
981 void fd_event_handle()
983 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
986 static void event_handle_slitapp(SlitApp
*app
, XEvent
*e
)
990 slit_app_drag(app
, &e
->xmotion
);
993 if (app
->ignore_unmaps
) {
994 app
->ignore_unmaps
--;
997 slit_remove(app
, TRUE
);
1000 slit_remove(app
, FALSE
);
1002 case ReparentNotify
:
1003 slit_remove(app
, FALSE
);
1005 case ConfigureNotify
:
1006 slit_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);