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_dock(Dock
*s
, XEvent
*e
);
31 static void event_handle_dockapp(DockApp
*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 DockApp
*dockapp
= NULL
;
400 ObWindow
*obwin
= NULL
;
402 window
= event_get_window(e
);
403 if ((obwin
= g_hash_table_lookup(window_map
, &window
))) {
404 switch (obwin
->type
) {
406 dock
= WINDOW_AS_DOCK(obwin
);
409 dockapp
= WINDOW_AS_DOCKAPP(obwin
);
412 menu
= WINDOW_AS_MENU(obwin
);
415 client
= WINDOW_AS_CLIENT(obwin
);
417 case Window_Internal
:
418 /* not to be used for events */
419 g_assert_not_reached();
424 event_set_lasttime(e
);
426 if (event_ignore(e
, client
))
429 /* deal with it in the kernel */
431 event_handle_menu(menu
, e
);
434 event_handle_client(client
, e
);
436 event_handle_dockapp(dockapp
, e
);
438 event_handle_dock(dock
, e
);
439 else if (window
== ob_root
)
440 event_handle_root(e
);
441 else if (e
->type
== MapRequest
)
442 client_manage(window
);
443 else if (e
->type
== ConfigureRequest
) {
444 /* unhandled configure requests must be used to configure the
448 xwc
.x
= e
->xconfigurerequest
.x
;
449 xwc
.y
= e
->xconfigurerequest
.y
;
450 xwc
.width
= e
->xconfigurerequest
.width
;
451 xwc
.height
= e
->xconfigurerequest
.height
;
452 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
453 xwc
.sibling
= e
->xconfigurerequest
.above
;
454 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
456 /* we are not to be held responsible if someone sends us an
458 xerror_set_ignore(TRUE
);
459 XConfigureWindow(ob_display
, window
,
460 e
->xconfigurerequest
.value_mask
, &xwc
);
461 xerror_set_ignore(FALSE
);
464 if (moveresize_in_progress
)
465 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
466 e
->type
== ButtonPress
||
467 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
470 return; /* no dispatch! */
474 /* user input (action-bound) events */
476 if (e->type == ButtonPress || e->type == ButtonRelease ||
477 e->type == MotionNotify)
478 mouse_event(e, client);
479 else if (e->type == KeyPress || e->type == KeyRelease)
483 /* dispatch the event to registered handlers */
484 dispatch_x(e
, client
);
487 static void event_handle_root(XEvent
*e
)
493 if (e
->xclient
.format
!= 32) break;
495 msgtype
= e
->xclient
.message_type
;
496 if (msgtype
== prop_atoms
.net_current_desktop
) {
497 unsigned int d
= e
->xclient
.data
.l
[0];
498 if (d
< screen_num_desktops
)
499 screen_set_desktop(d
);
500 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
501 unsigned int d
= e
->xclient
.data
.l
[0];
503 screen_set_num_desktops(d
);
504 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
505 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
509 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
510 screen_update_desktop_names();
511 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
512 screen_update_layout();
514 case ConfigureNotify
:
516 XRRUpdateConfiguration(e
);
518 if (e
->xconfigure
.width
!= screen_physical_size
.width
||
519 e
->xconfigure
.height
!= screen_physical_size
.height
)
520 screen_resize(e
->xconfigure
.width
, e
->xconfigure
.height
);
525 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
526 g_message("VIDMODE EVENT");
532 static void event_handle_client(Client
*client
, XEvent
*e
)
541 switch (frame_context(client
, e
->xbutton
.window
)) {
542 case Context_Maximize
:
543 client
->frame
->max_press
= (e
->type
== ButtonPress
);
544 framerender_frame(client
->frame
);
547 client
->frame
->close_press
= (e
->type
== ButtonPress
);
548 framerender_frame(client
->frame
);
550 case Context_Iconify
:
551 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
552 framerender_frame(client
->frame
);
554 case Context_AllDesktops
:
555 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
556 framerender_frame(client
->frame
);
559 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
560 framerender_frame(client
->frame
);
563 /* nothing changes with clicks for any other contexts */
569 g_message("FocusIn on client for %lx", client
->window
);
571 focus_set_client(client
);
572 frame_adjust_focus(client
->frame
, TRUE
);
576 g_message("FocusOut on client for %lx", client
->window
);
578 /* are we a fullscreen window or a transient of one? (checks layer)
579 if we are then we need to be iconified since we are losing focus
581 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
582 !client_search_focus_tree_full(client
))
583 /* iconify fullscreen windows when they and their transients
585 client_iconify(client
, TRUE
, TRUE
);
586 frame_adjust_focus(client
->frame
, FALSE
);
589 if (client_normal(client
)) {
590 if (ob_state
== State_Starting
) {
591 /* move it to the top of the focus order */
592 guint desktop
= client
->desktop
;
593 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
594 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
596 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
598 } else if (config_focus_follow
) {
600 g_message("EnterNotify on %lx, focusing window",
603 client_focus(client
);
607 case ConfigureRequest
:
609 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
610 ConfigureRequest
, &ce
)) {
612 /* XXX if this causes bad things.. we can compress config req's
613 with the same mask. */
614 e
->xconfigurerequest
.value_mask
|=
615 ce
.xconfigurerequest
.value_mask
;
616 if (ce
.xconfigurerequest
.value_mask
& CWX
)
617 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
618 if (ce
.xconfigurerequest
.value_mask
& CWY
)
619 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
620 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
621 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
622 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
623 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
624 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
625 e
->xconfigurerequest
.border_width
=
626 ce
.xconfigurerequest
.border_width
;
627 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
628 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
631 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
632 if (client
->iconic
|| client
->shaded
) return;
634 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
635 client
->border_width
= e
->xconfigurerequest
.border_width
;
637 /* resize, then move, as specified in the EWMH section 7.7 */
638 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
643 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
644 e
->xconfigurerequest
.x
: client
->area
.x
;
645 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
646 e
->xconfigurerequest
.y
: client
->area
.y
;
647 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
648 e
->xconfigurerequest
.width
: client
->area
.width
;
649 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
650 e
->xconfigurerequest
.height
: client
->area
.height
;
652 switch (client
->gravity
) {
653 case NorthEastGravity
:
655 corner
= Corner_TopRight
;
657 case SouthWestGravity
:
659 corner
= Corner_BottomLeft
;
661 case SouthEastGravity
:
662 corner
= Corner_BottomRight
;
664 default: /* NorthWest, Static, etc */
665 corner
= Corner_TopLeft
;
668 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
671 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
672 switch (e
->xconfigurerequest
.detail
) {
675 stacking_lower(CLIENT_AS_WINDOW(client
));
681 stacking_raise(CLIENT_AS_WINDOW(client
));
687 if (client
->ignore_unmaps
) {
688 client
->ignore_unmaps
--;
691 client_unmanage(client
);
694 client_unmanage(client
);
697 /* this is when the client is first taken captive in the frame */
698 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
701 This event is quite rare and is usually handled in unmapHandler.
702 However, if the window is unmapped when the reparent event occurs,
703 the window manager never sees it because an unmap event is not sent
704 to an already unmapped window.
707 /* we don't want the reparent event, put it back on the stack for the
708 X server to deal with after we unmanage the window */
709 XPutBackEvent(ob_display
, e
);
711 client_unmanage(client
);
714 g_message("MapRequest for 0x%lx", client
->window
);
715 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
716 does, we don't want it! */
717 if (screen_showing_desktop
)
718 screen_show_desktop(FALSE
);
719 client_iconify(client
, FALSE
, TRUE
);
720 if (!client
->frame
->visible
)
721 /* if its not visible still, then don't mess with it */
724 client_shade(client
, FALSE
);
725 client_focus(client
);
726 stacking_raise(CLIENT_AS_WINDOW(client
));
729 /* validate cuz we query stuff off the client here */
730 if (!client_validate(client
)) break;
732 if (e
->xclient
.format
!= 32) return;
734 msgtype
= e
->xclient
.message_type
;
735 if (msgtype
== prop_atoms
.wm_change_state
) {
736 /* compress changes into a single change */
737 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
738 client
->window
, &ce
)) {
739 /* XXX: it would be nice to compress ALL messages of a
740 type, not just messages in a row without other
741 message types between. */
742 if (ce
.xclient
.message_type
!= msgtype
) {
743 XPutBackEvent(ob_display
, &ce
);
746 e
->xclient
= ce
.xclient
;
748 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
749 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
750 /* compress changes into a single change */
751 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
752 client
->window
, &ce
)) {
753 /* XXX: it would be nice to compress ALL messages of a
754 type, not just messages in a row without other
755 message types between. */
756 if (ce
.xclient
.message_type
!= msgtype
) {
757 XPutBackEvent(ob_display
, &ce
);
760 e
->xclient
= ce
.xclient
;
762 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
763 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
764 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
766 } else if (msgtype
== prop_atoms
.net_wm_state
) {
767 /* can't compress these */
768 g_message("net_wm_state %s %ld %ld for 0x%lx",
769 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
770 e
->xclient
.data
.l
[0] == 1 ? "Add" :
771 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
772 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
774 client_set_state(client
, e
->xclient
.data
.l
[0],
775 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
776 } else if (msgtype
== prop_atoms
.net_close_window
) {
777 g_message("net_close_window for 0x%lx", client
->window
);
778 client_close(client
);
779 } else if (msgtype
== prop_atoms
.net_active_window
) {
780 g_message("net_active_window for 0x%lx", client
->window
);
781 client_activate(client
);
782 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
783 g_message("net_wm_moveresize for 0x%lx", client
->window
);
784 if ((Atom
)e
->xclient
.data
.l
[2] ==
785 prop_atoms
.net_wm_moveresize_size_topleft
||
786 (Atom
)e
->xclient
.data
.l
[2] ==
787 prop_atoms
.net_wm_moveresize_size_top
||
788 (Atom
)e
->xclient
.data
.l
[2] ==
789 prop_atoms
.net_wm_moveresize_size_topright
||
790 (Atom
)e
->xclient
.data
.l
[2] ==
791 prop_atoms
.net_wm_moveresize_size_right
||
792 (Atom
)e
->xclient
.data
.l
[2] ==
793 prop_atoms
.net_wm_moveresize_size_right
||
794 (Atom
)e
->xclient
.data
.l
[2] ==
795 prop_atoms
.net_wm_moveresize_size_bottomright
||
796 (Atom
)e
->xclient
.data
.l
[2] ==
797 prop_atoms
.net_wm_moveresize_size_bottom
||
798 (Atom
)e
->xclient
.data
.l
[2] ==
799 prop_atoms
.net_wm_moveresize_size_bottomleft
||
800 (Atom
)e
->xclient
.data
.l
[2] ==
801 prop_atoms
.net_wm_moveresize_size_left
||
802 (Atom
)e
->xclient
.data
.l
[2] ==
803 prop_atoms
.net_wm_moveresize_move
||
804 (Atom
)e
->xclient
.data
.l
[2] ==
805 prop_atoms
.net_wm_moveresize_size_keyboard
||
806 (Atom
)e
->xclient
.data
.l
[2] ==
807 prop_atoms
.net_wm_moveresize_move_keyboard
) {
809 moveresize_start(client
, e
->xclient
.data
.l
[0],
810 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
811 e
->xclient
.data
.l
[2]);
813 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
814 int oldg
= client
->gravity
;
815 int tmpg
, x
, y
, w
, h
;
817 if (e
->xclient
.data
.l
[0] & 0xff)
818 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
822 if (e
->xclient
.data
.l
[0] & 1 << 8)
823 x
= e
->xclient
.data
.l
[1];
826 if (e
->xclient
.data
.l
[0] & 1 << 9)
827 y
= e
->xclient
.data
.l
[2];
830 if (e
->xclient
.data
.l
[0] & 1 << 10)
831 w
= e
->xclient
.data
.l
[3];
834 if (e
->xclient
.data
.l
[0] & 1 << 11)
835 h
= e
->xclient
.data
.l
[4];
838 client
->gravity
= tmpg
;
839 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
840 client
->gravity
= oldg
;
844 /* validate cuz we query stuff off the client here */
845 if (!client_validate(client
)) break;
847 /* compress changes to a single property into a single change */
848 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
849 client
->window
, &ce
)) {
850 /* XXX: it would be nice to compress ALL changes to a property,
851 not just changes in a row without other props between. */
852 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
853 XPutBackEvent(ob_display
, &ce
);
858 msgtype
= e
->xproperty
.atom
;
859 if (msgtype
== XA_WM_NORMAL_HINTS
) {
860 client_update_normal_hints(client
);
861 /* normal hints can make a window non-resizable */
862 client_setup_decor_and_functions(client
);
864 else if (msgtype
== XA_WM_HINTS
)
865 client_update_wmhints(client
);
866 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
867 client_update_transient_for(client
);
868 client_get_type(client
);
869 /* type may have changed, so update the layer */
870 client_calc_layer(client
);
871 client_setup_decor_and_functions(client
);
873 else if (msgtype
== prop_atoms
.net_wm_name
||
874 msgtype
== prop_atoms
.wm_name
||
875 msgtype
== prop_atoms
.net_wm_icon_name
||
876 msgtype
== prop_atoms
.wm_icon_name
)
877 client_update_title(client
);
878 else if (msgtype
== prop_atoms
.wm_class
)
879 client_update_class(client
);
880 else if (msgtype
== prop_atoms
.wm_protocols
) {
881 client_update_protocols(client
);
882 client_setup_decor_and_functions(client
);
884 else if (msgtype
== prop_atoms
.net_wm_strut
)
885 client_update_strut(client
);
886 else if (msgtype
== prop_atoms
.net_wm_icon
)
887 client_update_icons(client
);
888 else if (msgtype
== prop_atoms
.kwm_win_icon
)
889 client_update_kwm_icon(client
);
893 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
894 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
895 frame_adjust_shape(client
->frame
);
901 static void event_handle_menu(Menu
*menu
, XEvent
*e
)
905 g_message("EVENT %d", e
->type
);
908 g_message("BUTTON PRESS");
909 if (e
->xbutton
.button
== 3)
911 else if (e
->xbutton
.button
== 1) {
912 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
914 stacking_raise(MENU_AS_WINDOW(menu
));
918 g_message("BUTTON RELEASED");
919 if (!menu
->shown
) break;
921 /* grab_pointer_window(FALSE, None, menu->frame);*/
923 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
927 guint ujunk
, b
, w
, h
;
928 XGetGeometry(ob_display
, e
->xbutton
.window
,
929 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
930 if (e
->xbutton
.x
>= (signed)-b
&&
931 e
->xbutton
.y
>= (signed)-b
&&
932 e
->xbutton
.x
< (signed)(w
+b
) &&
933 e
->xbutton
.y
< (signed)(h
+b
)) {
934 menu_entry_fire(entry
);
941 g_message("enter/leave");
942 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
945 menu
->mouseover(entry
, e
->type
== EnterNotify
);
947 menu_control_mouseover(entry
, e
->type
== EnterNotify
);
949 menu_entry_render(entry
);
955 void event_add_fd_handler(event_fd_handler
*h
) {
956 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
957 FD_SET(h
->fd
, &allset
);
958 max_fd
= MAX(max_fd
, h
->fd
);
961 void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
963 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
966 void event_remove_fd(int n
)
970 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
971 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
, (gpointer
)&tmpmax
);
972 max_fd
= MAX(x_fd
, tmpmax
);
975 void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
977 if (FD_ISSET( (int)n
, &selset
)) {
978 event_fd_handler
*h
= (event_fd_handler
*)data
;
979 g_assert(h
->fd
== (int)n
);
980 h
->handler(h
->fd
, h
->data
);
984 void fd_event_handle()
986 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
989 static void event_handle_dock(Dock
*s
, XEvent
*e
)
993 stacking_raise(DOCK_AS_WINDOW(s
));
1003 static void event_handle_dockapp(DockApp
*app
, XEvent
*e
)
1007 dock_app_drag(app
, &e
->xmotion
);
1010 if (app
->ignore_unmaps
) {
1011 app
->ignore_unmaps
--;
1014 dock_remove(app
, TRUE
);
1017 dock_remove(app
, FALSE
);
1019 case ReparentNotify
:
1020 dock_remove(app
, FALSE
);
1022 case ConfigureNotify
:
1023 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);