10 #include "framerender.h"
12 #include "moveresize.h"
14 #include "extensions.h"
20 #include <X11/keysym.h>
21 #include <X11/Xatom.h>
25 # include <libsn/sn.h>
28 #ifdef HAVE_SYS_SELECT_H
29 # include <sys/select.h>
32 static void event_process(XEvent
*e
);
33 static void event_handle_root(XEvent
*e
);
34 static void event_handle_dock(Dock
*s
, XEvent
*e
);
35 static void event_handle_dockapp(DockApp
*app
, XEvent
*e
);
36 static void event_handle_client(Client
*c
, XEvent
*e
);
37 static void event_handle_menu(Menu
*menu
, Client
*c
, XEvent
*e
);
39 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
40 (e)->xfocus.detail > NotifyNonlinearVirtual)
41 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
42 (e)->xfocus.detail == NotifyInferior || \
43 (e)->xfocus.detail == NotifyAncestor || \
44 (e)->xfocus.detail > NotifyNonlinearVirtual)
46 Time event_lasttime
= 0;
48 /*! The value of the mask for the NumLock modifier */
49 unsigned int NumLockMask
;
50 /*! The value of the mask for the ScrollLock modifier */
51 unsigned int ScrollLockMask
;
52 /*! The key codes for the modifier keys */
53 static XModifierKeymap
*modmap
;
54 /*! Table of the constant modifier masks */
55 static const int mask_table
[] = {
56 ShiftMask
, LockMask
, ControlMask
, Mod1Mask
,
57 Mod2Mask
, Mod3Mask
, Mod4Mask
, Mod5Mask
59 static int mask_table_size
;
61 static fd_set selset
, allset
;
62 static int max_fd
, x_fd
;
63 static GData
*fd_handler_list
;
65 void fd_event_handle();
69 mask_table_size
= sizeof(mask_table
) / sizeof(mask_table
[0]);
71 /* get lock masks that are defined by the display (not constant) */
72 modmap
= XGetModifierMapping(ob_display
);
74 if (modmap
&& modmap
->max_keypermod
> 0) {
76 const size_t size
= mask_table_size
* modmap
->max_keypermod
;
77 /* get the values of the keyboard lock modifiers
78 Note: Caps lock is not retrieved the same way as Scroll and Num
79 lock since it doesn't need to be. */
80 const KeyCode num_lock
= XKeysymToKeycode(ob_display
, XK_Num_Lock
);
81 const KeyCode scroll_lock
= XKeysymToKeycode(ob_display
,
84 for (cnt
= 0; cnt
< size
; ++cnt
) {
85 if (! modmap
->modifiermap
[cnt
]) continue;
87 if (num_lock
== modmap
->modifiermap
[cnt
])
88 NumLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
89 if (scroll_lock
== modmap
->modifiermap
[cnt
])
90 ScrollLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
95 max_fd
= x_fd
= ConnectionNumber(ob_display
);
96 FD_SET(x_fd
, &allset
);
97 g_datalist_init(&fd_handler_list
);
100 void event_shutdown()
102 XFreeModifiermap(modmap
);
103 g_datalist_clear(&fd_handler_list
);
109 struct timeval
*wait
;
110 gboolean had_event
= FALSE
;
114 There are slightly different event retrieval semantics here for
115 local (or high bandwidth) versus remote (or low bandwidth)
116 connections to the display/Xserver.
119 if (!XPending(ob_display
))
123 This XSync allows for far more compression of events, which
124 makes things like Motion events perform far far better. Since
125 it also means network traffic for every event instead of every
126 X events (where X is the number retrieved at a time), it
127 probably should not be used for setups where Openbox is
128 running on a remote/low bandwidth display/Xserver.
130 XSync(ob_display
, FALSE
);
131 if (!XEventsQueued(ob_display
, QueuedAlready
))
134 XNextEvent(ob_display
, &e
);
137 sn_display_process_event(ob_sn_display
, &e
);
145 timer_dispatch((GTimeVal
**)&wait
);
147 select(max_fd
+ 1, &selset
, NULL
, NULL
, wait
);
149 /* handle the X events as soon as possible? */
150 if (FD_ISSET(x_fd
, &selset
))
157 static Window
event_get_window(XEvent
*e
)
164 window
= e
->xmap
.window
;
167 window
= e
->xunmap
.window
;
170 window
= e
->xdestroywindow
.window
;
172 case ConfigureRequest
:
173 window
= e
->xconfigurerequest
.window
;
175 case ConfigureNotify
:
176 window
= e
->xconfigure
.window
;
180 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
181 switch (((XkbAnyEvent
*)&e
)->xkb_type
) {
183 window
= ((XkbBellNotifyEvent
*)&e
)->window
;
189 window
= e
->xany
.window
;
194 static void event_set_lasttime(XEvent
*e
)
196 /* grab the lasttime and hack up the state */
200 event_lasttime
= e
->xbutton
.time
;
203 event_lasttime
= e
->xkey
.time
;
206 event_lasttime
= e
->xkey
.time
;
209 event_lasttime
= e
->xmotion
.time
;
212 event_lasttime
= e
->xproperty
.time
;
216 event_lasttime
= e
->xcrossing
.time
;
219 event_lasttime
= CurrentTime
;
224 #define STRIP_MODS(s) \
225 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
226 /* kill off the Button1Mask etc, only want the modifiers */ \
227 s &= (ControlMask | ShiftMask | Mod1Mask | \
228 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
230 static void event_hack_mods(XEvent *e)
238 STRIP_MODS(e
->xbutton
.state
);
241 STRIP_MODS(e
->xkey
.state
);
244 STRIP_MODS(e
->xkey
.state
);
245 /* remove from the state the mask of the modifier being released, if
246 it is a modifier key being released (this is a little ugly..) */
247 kp
= modmap
->modifiermap
;
248 for (i
= 0; i
< mask_table_size
; ++i
) {
249 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
250 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
251 /* remove the mask for it */
252 e
->xkey
.state
&= ~mask_table
[i
];
253 /* cause the first loop to break; */
255 break; /* get outta here! */
262 STRIP_MODS(e
->xmotion
.state
);
263 /* compress events */
266 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
268 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
269 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
276 static gboolean
event_ignore(XEvent
*e
, Client
*client
)
280 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
281 because of RevertToPointerRoot. If the focus ends up reverting to
282 pointer root on a workspace change, then the FocusIn event that we
283 want will be of type NotifyAncestor. This situation does not occur
284 for FocusOut, so it is safely ignored there.
286 if (INVALID_FOCUSIN(e
) ||
289 g_message("FocusIn on %lx mode %d detail %d IGNORED", e
->xfocus
.window
,
290 e
->xfocus
.mode
, e
->xfocus
.detail
);
292 /* says a client was not found for the event (or a valid FocusIn
295 e
->xfocus
.window
= None
;
300 g_message("FocusIn on %lx mode %d detail %d", e
->xfocus
.window
,
301 e
->xfocus
.mode
, e
->xfocus
.detail
);
305 if (INVALID_FOCUSOUT(e
)) {
307 g_message("FocusOut on %lx mode %d detail %d IGNORED",
308 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
314 g_message("FocusOut on %lx mode %d detail %d",
315 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
320 gboolean fallback
= TRUE
;
323 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
324 e
->xfocus
.window
,&fe
))
325 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
327 if (fe
.type
== FocusOut
) {
329 g_message("found pending FocusOut");
331 if (!INVALID_FOCUSOUT(&fe
)) {
332 /* if there is a VALID FocusOut still coming, don't
333 fallback focus yet, we'll deal with it then */
334 XPutBackEvent(ob_display
, &fe
);
340 g_message("found pending FocusIn");
342 /* is the focused window getting a FocusOut/In back to
344 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
345 !event_ignore(&fe
, client
)) {
347 g_message("focused window got an Out/In back to "
348 "itself IGNORED both");
353 /* once all the FocusOut's have been dealt with, if there
354 is a FocusIn still left and it is valid, then use it */
356 /* secret magic way of event_process telling us that no
357 client was found for the FocusIn event. ^_^ */
358 if (fe
.xfocus
.window
!= None
) {
366 g_message("no valid FocusIn and no FocusOut events found, "
369 focus_fallback(Fallback_NoFocus
);
375 /* NotifyUngrab occurs when a mouse button is released and the event is
376 caused, like when lowering a window */
377 /* NotifyVirtual occurs when ungrabbing the pointer */
378 if (e
->xcrossing
.mode
== NotifyGrab
||
379 e
->xcrossing
.detail
== NotifyInferior
||
380 (e
->xcrossing
.mode
== NotifyUngrab
&&
381 e
->xcrossing
.detail
== NotifyVirtual
)) {
383 g_message("%sNotify mode %d detail %d on %lx IGNORED",
384 (e
->type
== EnterNotify
? "Enter" : "Leave"),
386 e
->xcrossing
.detail
, client
?client
->window
:0);
391 g_message("%sNotify mode %d detail %d on %lx",
392 (e
->type
== EnterNotify
? "Enter" : "Leave"),
394 e
->xcrossing
.detail
, client
?client
->window
:0);
401 static void event_process(XEvent
*e
)
404 Client
*client
= NULL
;
406 DockApp
*dockapp
= NULL
;
408 ObWindow
*obwin
= NULL
;
410 window
= event_get_window(e
);
411 if ((obwin
= g_hash_table_lookup(window_map
, &window
))) {
412 switch (obwin
->type
) {
414 dock
= WINDOW_AS_DOCK(obwin
);
417 dockapp
= WINDOW_AS_DOCKAPP(obwin
);
420 menu
= WINDOW_AS_MENU(obwin
);
423 client
= WINDOW_AS_CLIENT(obwin
);
425 case Window_Internal
:
426 /* not to be used for events */
427 g_assert_not_reached();
432 event_set_lasttime(e
);
434 if (event_ignore(e
, client
))
437 /* deal with it in the kernel */
439 event_handle_menu(menu
, client
, e
);
442 event_handle_client(client
, e
);
444 event_handle_dockapp(dockapp
, e
);
446 event_handle_dock(dock
, e
);
447 else if (window
== ob_root
)
448 event_handle_root(e
);
449 else if (e
->type
== MapRequest
)
450 client_manage(window
);
451 else if (e
->type
== ConfigureRequest
) {
452 /* unhandled configure requests must be used to configure the
456 xwc
.x
= e
->xconfigurerequest
.x
;
457 xwc
.y
= e
->xconfigurerequest
.y
;
458 xwc
.width
= e
->xconfigurerequest
.width
;
459 xwc
.height
= e
->xconfigurerequest
.height
;
460 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
461 xwc
.sibling
= e
->xconfigurerequest
.above
;
462 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
464 /* we are not to be held responsible if someone sends us an
466 xerror_set_ignore(TRUE
);
467 XConfigureWindow(ob_display
, window
,
468 e
->xconfigurerequest
.value_mask
, &xwc
);
469 xerror_set_ignore(FALSE
);
472 if (moveresize_in_progress
)
473 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
474 e
->type
== ButtonPress
||
475 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
478 return; /* no dispatch! */
482 /* user input (action-bound) events */
484 if (e->type == ButtonPress || e->type == ButtonRelease ||
485 e->type == MotionNotify)
486 mouse_event(e, client);
487 else if (e->type == KeyPress || e->type == KeyRelease)
491 /* dispatch the event to registered handlers */
492 dispatch_x(e
, client
);
495 static void event_handle_root(XEvent
*e
)
501 if (e
->xclient
.format
!= 32) break;
503 msgtype
= e
->xclient
.message_type
;
504 if (msgtype
== prop_atoms
.net_current_desktop
) {
505 unsigned int d
= e
->xclient
.data
.l
[0];
506 if (d
< screen_num_desktops
)
507 screen_set_desktop(d
);
508 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
509 unsigned int d
= e
->xclient
.data
.l
[0];
511 screen_set_num_desktops(d
);
512 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
513 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
517 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
518 screen_update_desktop_names();
519 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
520 screen_update_layout();
522 case ConfigureNotify
:
524 XRRUpdateConfiguration(e
);
526 if (e
->xconfigure
.width
!= screen_physical_size
.width
||
527 e
->xconfigure
.height
!= screen_physical_size
.height
)
528 screen_resize(e
->xconfigure
.width
, e
->xconfigure
.height
);
533 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
534 g_message("VIDMODE EVENT");
540 static void event_handle_client(Client
*client
, XEvent
*e
)
549 /* Wheel buttons don't draw because they are an instant click, so it
550 is a waste of resources to go drawing it. */
551 if (!(e
->xbutton
.button
== 4 || e
->xbutton
.button
== 5)) {
552 switch (frame_context(client
, e
->xbutton
.window
)) {
553 case Context_Maximize
:
554 client
->frame
->max_press
= (e
->type
== ButtonPress
);
555 framerender_frame(client
->frame
);
558 client
->frame
->close_press
= (e
->type
== ButtonPress
);
559 framerender_frame(client
->frame
);
561 case Context_Iconify
:
562 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
563 framerender_frame(client
->frame
);
565 case Context_AllDesktops
:
566 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
567 framerender_frame(client
->frame
);
570 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
571 framerender_frame(client
->frame
);
574 /* nothing changes with clicks for any other contexts */
581 g_message("FocusIn on client for %lx", client
->window
);
583 focus_set_client(client
);
584 frame_adjust_focus(client
->frame
, TRUE
);
588 g_message("FocusOut on client for %lx", client
->window
);
590 /* are we a fullscreen window or a transient of one? (checks layer)
591 if we are then we need to be iconified since we are losing focus
593 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
594 !client_search_focus_tree_full(client
))
595 /* iconify fullscreen windows when they and their transients
597 client_iconify(client
, TRUE
, TRUE
);
598 frame_adjust_focus(client
->frame
, FALSE
);
601 if (client_normal(client
)) {
602 if (ob_state
== State_Starting
) {
603 /* move it to the top of the focus order */
604 guint desktop
= client
->desktop
;
605 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
606 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
608 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
610 } else if (config_focus_follow
) {
612 g_message("EnterNotify on %lx, focusing window",
615 client_focus(client
);
619 case ConfigureRequest
:
621 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
622 ConfigureRequest
, &ce
)) {
624 /* XXX if this causes bad things.. we can compress config req's
625 with the same mask. */
626 e
->xconfigurerequest
.value_mask
|=
627 ce
.xconfigurerequest
.value_mask
;
628 if (ce
.xconfigurerequest
.value_mask
& CWX
)
629 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
630 if (ce
.xconfigurerequest
.value_mask
& CWY
)
631 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
632 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
633 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
634 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
635 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
636 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
637 e
->xconfigurerequest
.border_width
=
638 ce
.xconfigurerequest
.border_width
;
639 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
640 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
643 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
644 if (client
->iconic
|| client
->shaded
) return;
646 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
647 client
->border_width
= e
->xconfigurerequest
.border_width
;
649 /* resize, then move, as specified in the EWMH section 7.7 */
650 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
655 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
656 e
->xconfigurerequest
.x
: client
->area
.x
;
657 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
658 e
->xconfigurerequest
.y
: client
->area
.y
;
659 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
660 e
->xconfigurerequest
.width
: client
->area
.width
;
661 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
662 e
->xconfigurerequest
.height
: client
->area
.height
;
664 switch (client
->gravity
) {
665 case NorthEastGravity
:
667 corner
= Corner_TopRight
;
669 case SouthWestGravity
:
671 corner
= Corner_BottomLeft
;
673 case SouthEastGravity
:
674 corner
= Corner_BottomRight
;
676 default: /* NorthWest, Static, etc */
677 corner
= Corner_TopLeft
;
680 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
683 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
684 switch (e
->xconfigurerequest
.detail
) {
687 stacking_lower(CLIENT_AS_WINDOW(client
));
693 stacking_raise(CLIENT_AS_WINDOW(client
));
699 if (client
->ignore_unmaps
) {
700 client
->ignore_unmaps
--;
703 client_unmanage(client
);
706 client_unmanage(client
);
709 /* this is when the client is first taken captive in the frame */
710 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
713 This event is quite rare and is usually handled in unmapHandler.
714 However, if the window is unmapped when the reparent event occurs,
715 the window manager never sees it because an unmap event is not sent
716 to an already unmapped window.
719 /* we don't want the reparent event, put it back on the stack for the
720 X server to deal with after we unmanage the window */
721 XPutBackEvent(ob_display
, e
);
723 client_unmanage(client
);
726 g_message("MapRequest for 0x%lx", client
->window
);
727 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
728 does, we don't want it! */
729 if (screen_showing_desktop
)
730 screen_show_desktop(FALSE
);
731 client_iconify(client
, FALSE
, TRUE
);
732 if (!client
->frame
->visible
)
733 /* if its not visible still, then don't mess with it */
736 client_shade(client
, FALSE
);
737 client_focus(client
);
738 stacking_raise(CLIENT_AS_WINDOW(client
));
741 /* validate cuz we query stuff off the client here */
742 if (!client_validate(client
)) break;
744 if (e
->xclient
.format
!= 32) return;
746 msgtype
= e
->xclient
.message_type
;
747 if (msgtype
== prop_atoms
.wm_change_state
) {
748 /* compress changes into a single change */
749 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
750 client
->window
, &ce
)) {
751 /* XXX: it would be nice to compress ALL messages of a
752 type, not just messages in a row without other
753 message types between. */
754 if (ce
.xclient
.message_type
!= msgtype
) {
755 XPutBackEvent(ob_display
, &ce
);
758 e
->xclient
= ce
.xclient
;
760 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
761 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
762 /* compress changes into a single change */
763 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
764 client
->window
, &ce
)) {
765 /* XXX: it would be nice to compress ALL messages of a
766 type, not just messages in a row without other
767 message types between. */
768 if (ce
.xclient
.message_type
!= msgtype
) {
769 XPutBackEvent(ob_display
, &ce
);
772 e
->xclient
= ce
.xclient
;
774 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
775 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
776 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
778 } else if (msgtype
== prop_atoms
.net_wm_state
) {
779 /* can't compress these */
780 g_message("net_wm_state %s %ld %ld for 0x%lx",
781 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
782 e
->xclient
.data
.l
[0] == 1 ? "Add" :
783 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
784 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
786 client_set_state(client
, e
->xclient
.data
.l
[0],
787 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
788 } else if (msgtype
== prop_atoms
.net_close_window
) {
789 g_message("net_close_window for 0x%lx", client
->window
);
790 client_close(client
);
791 } else if (msgtype
== prop_atoms
.net_active_window
) {
792 g_message("net_active_window for 0x%lx", client
->window
);
793 client_activate(client
);
794 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
795 g_message("net_wm_moveresize for 0x%lx", client
->window
);
796 if ((Atom
)e
->xclient
.data
.l
[2] ==
797 prop_atoms
.net_wm_moveresize_size_topleft
||
798 (Atom
)e
->xclient
.data
.l
[2] ==
799 prop_atoms
.net_wm_moveresize_size_top
||
800 (Atom
)e
->xclient
.data
.l
[2] ==
801 prop_atoms
.net_wm_moveresize_size_topright
||
802 (Atom
)e
->xclient
.data
.l
[2] ==
803 prop_atoms
.net_wm_moveresize_size_right
||
804 (Atom
)e
->xclient
.data
.l
[2] ==
805 prop_atoms
.net_wm_moveresize_size_right
||
806 (Atom
)e
->xclient
.data
.l
[2] ==
807 prop_atoms
.net_wm_moveresize_size_bottomright
||
808 (Atom
)e
->xclient
.data
.l
[2] ==
809 prop_atoms
.net_wm_moveresize_size_bottom
||
810 (Atom
)e
->xclient
.data
.l
[2] ==
811 prop_atoms
.net_wm_moveresize_size_bottomleft
||
812 (Atom
)e
->xclient
.data
.l
[2] ==
813 prop_atoms
.net_wm_moveresize_size_left
||
814 (Atom
)e
->xclient
.data
.l
[2] ==
815 prop_atoms
.net_wm_moveresize_move
||
816 (Atom
)e
->xclient
.data
.l
[2] ==
817 prop_atoms
.net_wm_moveresize_size_keyboard
||
818 (Atom
)e
->xclient
.data
.l
[2] ==
819 prop_atoms
.net_wm_moveresize_move_keyboard
) {
821 moveresize_start(client
, e
->xclient
.data
.l
[0],
822 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
823 e
->xclient
.data
.l
[2]);
825 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
826 int oldg
= client
->gravity
;
827 int tmpg
, x
, y
, w
, h
;
829 if (e
->xclient
.data
.l
[0] & 0xff)
830 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
834 if (e
->xclient
.data
.l
[0] & 1 << 8)
835 x
= e
->xclient
.data
.l
[1];
838 if (e
->xclient
.data
.l
[0] & 1 << 9)
839 y
= e
->xclient
.data
.l
[2];
842 if (e
->xclient
.data
.l
[0] & 1 << 10)
843 w
= e
->xclient
.data
.l
[3];
846 if (e
->xclient
.data
.l
[0] & 1 << 11)
847 h
= e
->xclient
.data
.l
[4];
850 client
->gravity
= tmpg
;
851 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
852 client
->gravity
= oldg
;
856 /* validate cuz we query stuff off the client here */
857 if (!client_validate(client
)) break;
859 /* compress changes to a single property into a single change */
860 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
861 client
->window
, &ce
)) {
862 /* XXX: it would be nice to compress ALL changes to a property,
863 not just changes in a row without other props between. */
864 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
865 XPutBackEvent(ob_display
, &ce
);
870 msgtype
= e
->xproperty
.atom
;
871 if (msgtype
== XA_WM_NORMAL_HINTS
) {
872 client_update_normal_hints(client
);
873 /* normal hints can make a window non-resizable */
874 client_setup_decor_and_functions(client
);
876 else if (msgtype
== XA_WM_HINTS
)
877 client_update_wmhints(client
);
878 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
879 client_update_transient_for(client
);
880 client_get_type(client
);
881 /* type may have changed, so update the layer */
882 client_calc_layer(client
);
883 client_setup_decor_and_functions(client
);
885 else if (msgtype
== prop_atoms
.net_wm_name
||
886 msgtype
== prop_atoms
.wm_name
||
887 msgtype
== prop_atoms
.net_wm_icon_name
||
888 msgtype
== prop_atoms
.wm_icon_name
)
889 client_update_title(client
);
890 else if (msgtype
== prop_atoms
.wm_class
)
891 client_update_class(client
);
892 else if (msgtype
== prop_atoms
.wm_protocols
) {
893 client_update_protocols(client
);
894 client_setup_decor_and_functions(client
);
896 else if (msgtype
== prop_atoms
.net_wm_strut
)
897 client_update_strut(client
);
898 else if (msgtype
== prop_atoms
.net_wm_icon
||
899 msgtype
== prop_atoms
.kwm_win_icon
)
900 client_update_icons(client
);
904 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
905 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
906 frame_adjust_shape(client
->frame
);
912 static void event_handle_menu(Menu
*menu
, Client
*client
, XEvent
*e
)
916 g_message("EVENT %d", e
->type
);
919 g_message("BUTTON PRESS");
920 if (e
->xbutton
.button
== 3)
922 else if (e
->xbutton
.button
== 1) {
923 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
925 stacking_raise(MENU_AS_WINDOW(menu
));
929 g_message("BUTTON RELEASED");
930 if (!menu
->shown
) break;
932 /* grab_pointer_window(FALSE, None, menu->frame);*/
934 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
938 guint ujunk
, b
, w
, h
;
939 XGetGeometry(ob_display
, e
->xbutton
.window
,
940 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
941 if (e
->xbutton
.x
>= (signed)-b
&&
942 e
->xbutton
.y
>= (signed)-b
&&
943 e
->xbutton
.x
< (signed)(w
+b
) &&
944 e
->xbutton
.y
< (signed)(h
+b
)) {
945 menu_entry_fire(entry
);
952 g_message("enter/leave");
953 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
956 menu
->mouseover(entry
, e
->type
== EnterNotify
);
958 menu_control_mouseover(entry
, e
->type
== EnterNotify
);
960 menu_entry_render(entry
);
966 void event_add_fd_handler(event_fd_handler
*h
) {
967 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
968 FD_SET(h
->fd
, &allset
);
969 max_fd
= MAX(max_fd
, h
->fd
);
972 void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
974 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
977 void event_remove_fd(int n
)
981 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
982 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
, (gpointer
)&tmpmax
);
983 max_fd
= MAX(x_fd
, tmpmax
);
986 void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
988 if (FD_ISSET( (int)n
, &selset
)) {
989 event_fd_handler
*h
= (event_fd_handler
*)data
;
990 g_assert(h
->fd
== (int)n
);
991 h
->handler(h
->fd
, h
->data
);
995 void fd_event_handle()
997 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
1000 static void event_handle_dock(Dock
*s
, XEvent
*e
)
1004 stacking_raise(DOCK_AS_WINDOW(s
));
1015 static void event_handle_dockapp(DockApp
*app
, XEvent
*e
)
1019 dock_app_drag(app
, &e
->xmotion
);
1022 if (app
->ignore_unmaps
) {
1023 app
->ignore_unmaps
--;
1026 dock_remove(app
, TRUE
);
1029 dock_remove(app
, FALSE
);
1031 case ReparentNotify
:
1032 dock_remove(app
, FALSE
);
1034 case ConfigureNotify
:
1035 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);