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>
36 #include <X11/ICE/ICElib.h>
39 static void event_process(XEvent
*e
);
40 static void event_handle_root(XEvent
*e
);
41 static void event_handle_dock(Dock
*s
, XEvent
*e
);
42 static void event_handle_dockapp(DockApp
*app
, XEvent
*e
);
43 static void event_handle_client(Client
*c
, XEvent
*e
);
44 static void event_handle_menu(Menu
*menu
, Client
*c
, XEvent
*e
);
45 static void fd_event_handle();
47 static void ice_watch(IceConn conn
, IcePointer data
, Bool opening
,
48 IcePointer
*watch_data
);
50 static void find_max_fd();
52 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
53 (e)->xfocus.detail == NotifyAncestor || \
54 (e)->xfocus.detail > NotifyNonlinearVirtual)
55 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
56 (e)->xfocus.detail == NotifyInferior || \
57 (e)->xfocus.detail == NotifyAncestor || \
58 (e)->xfocus.detail > NotifyNonlinearVirtual)
60 Time event_lasttime
= 0;
62 /*! The value of the mask for the NumLock modifier */
63 unsigned int NumLockMask
;
64 /*! The value of the mask for the ScrollLock modifier */
65 unsigned int ScrollLockMask
;
66 /*! The key codes for the modifier keys */
67 static XModifierKeymap
*modmap
;
68 /*! Table of the constant modifier masks */
69 static const int mask_table
[] = {
70 ShiftMask
, LockMask
, ControlMask
, Mod1Mask
,
71 Mod2Mask
, Mod3Mask
, Mod4Mask
, Mod5Mask
73 static int mask_table_size
;
75 static fd_set selset
, allset
;
77 static IceConn ice_conn
;
80 static int max_fd
, x_fd
;
81 static GData
*fd_handler_list
;
85 static void ice_watch(IceConn conn
, IcePointer data
, Bool opening
,
86 IcePointer
*watch_data
)
89 g_assert (ice_fd
< 0);
91 ice_fd
= IceConnectionNumber(conn
);
92 FD_SET(ice_fd
, &allset
);
94 FD_CLR(ice_fd
, &allset
);
103 mask_table_size
= sizeof(mask_table
) / sizeof(mask_table
[0]);
105 /* get lock masks that are defined by the display (not constant) */
106 modmap
= XGetModifierMapping(ob_display
);
108 if (modmap
&& modmap
->max_keypermod
> 0) {
110 const size_t size
= mask_table_size
* modmap
->max_keypermod
;
111 /* get the values of the keyboard lock modifiers
112 Note: Caps lock is not retrieved the same way as Scroll and Num
113 lock since it doesn't need to be. */
114 const KeyCode num_lock
= XKeysymToKeycode(ob_display
, XK_Num_Lock
);
115 const KeyCode scroll_lock
= XKeysymToKeycode(ob_display
,
118 for (cnt
= 0; cnt
< size
; ++cnt
) {
119 if (! modmap
->modifiermap
[cnt
]) continue;
121 if (num_lock
== modmap
->modifiermap
[cnt
])
122 NumLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
123 if (scroll_lock
== modmap
->modifiermap
[cnt
])
124 ScrollLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
129 max_fd
= x_fd
= ConnectionNumber(ob_display
);
130 FD_SET(x_fd
, &allset
);
134 IceAddConnectionWatch(ice_watch
, NULL
);
137 g_datalist_init(&fd_handler_list
);
140 void event_shutdown()
142 XFreeModifiermap(modmap
);
143 g_datalist_clear(&fd_handler_list
);
149 struct timeval
*wait
;
150 gboolean had_event
= FALSE
;
154 There are slightly different event retrieval semantics here for
155 local (or high bandwidth) versus remote (or low bandwidth)
156 connections to the display/Xserver.
159 if (!XPending(ob_display
))
163 This XSync allows for far more compression of events, which
164 makes things like Motion events perform far far better. Since
165 it also means network traffic for every event instead of every
166 X events (where X is the number retrieved at a time), it
167 probably should not be used for setups where Openbox is
168 running on a remote/low bandwidth display/Xserver.
170 XSync(ob_display
, FALSE
);
171 if (!XEventsQueued(ob_display
, QueuedAlready
))
174 XNextEvent(ob_display
, &e
);
177 sn_display_process_event(ob_sn_display
, &e
);
185 timer_dispatch((GTimeVal
**)&wait
);
187 select(max_fd
+ 1, &selset
, NULL
, NULL
, wait
);
189 /* handle the X events as soon as possible? */
190 if (FD_ISSET(x_fd
, &selset
))
194 if (ice_fd
>= 0 && FD_ISSET(ice_fd
, &selset
)) {
196 IceProcessMessages(ice_conn
, NULL
, &b
);
204 static Window
event_get_window(XEvent
*e
)
211 window
= e
->xmap
.window
;
214 window
= e
->xunmap
.window
;
217 window
= e
->xdestroywindow
.window
;
219 case ConfigureRequest
:
220 window
= e
->xconfigurerequest
.window
;
222 case ConfigureNotify
:
223 window
= e
->xconfigure
.window
;
227 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
228 switch (((XkbAnyEvent
*)&e
)->xkb_type
) {
230 window
= ((XkbBellNotifyEvent
*)&e
)->window
;
236 window
= e
->xany
.window
;
241 static void event_set_lasttime(XEvent
*e
)
243 /* grab the lasttime and hack up the state */
247 event_lasttime
= e
->xbutton
.time
;
250 event_lasttime
= e
->xkey
.time
;
253 event_lasttime
= e
->xkey
.time
;
256 event_lasttime
= e
->xmotion
.time
;
259 event_lasttime
= e
->xproperty
.time
;
263 event_lasttime
= e
->xcrossing
.time
;
266 event_lasttime
= CurrentTime
;
271 #define STRIP_MODS(s) \
272 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
273 /* kill off the Button1Mask etc, only want the modifiers */ \
274 s &= (ControlMask | ShiftMask | Mod1Mask | \
275 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
277 static void event_hack_mods(XEvent *e)
285 STRIP_MODS(e
->xbutton
.state
);
288 STRIP_MODS(e
->xkey
.state
);
291 STRIP_MODS(e
->xkey
.state
);
292 /* remove from the state the mask of the modifier being released, if
293 it is a modifier key being released (this is a little ugly..) */
294 kp
= modmap
->modifiermap
;
295 for (i
= 0; i
< mask_table_size
; ++i
) {
296 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
297 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
298 /* remove the mask for it */
299 e
->xkey
.state
&= ~mask_table
[i
];
300 /* cause the first loop to break; */
302 break; /* get outta here! */
309 STRIP_MODS(e
->xmotion
.state
);
310 /* compress events */
313 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
315 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
316 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
323 static gboolean
event_ignore(XEvent
*e
, Client
*client
)
327 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
328 because of RevertToPointerRoot. If the focus ends up reverting to
329 pointer root on a workspace change, then the FocusIn event that we
330 want will be of type NotifyAncestor. This situation does not occur
331 for FocusOut, so it is safely ignored there.
333 if (INVALID_FOCUSIN(e
) ||
336 g_message("FocusIn on %lx mode %d detail %d IGNORED", e
->xfocus
.window
,
337 e
->xfocus
.mode
, e
->xfocus
.detail
);
339 /* says a client was not found for the event (or a valid FocusIn
342 e
->xfocus
.window
= None
;
347 g_message("FocusIn on %lx mode %d detail %d", e
->xfocus
.window
,
348 e
->xfocus
.mode
, e
->xfocus
.detail
);
352 if (INVALID_FOCUSOUT(e
)) {
354 g_message("FocusOut on %lx mode %d detail %d IGNORED",
355 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
361 g_message("FocusOut on %lx mode %d detail %d",
362 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
367 gboolean fallback
= TRUE
;
370 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
371 e
->xfocus
.window
,&fe
))
372 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
374 if (fe
.type
== FocusOut
) {
376 g_message("found pending FocusOut");
378 if (!INVALID_FOCUSOUT(&fe
)) {
379 /* if there is a VALID FocusOut still coming, don't
380 fallback focus yet, we'll deal with it then */
381 XPutBackEvent(ob_display
, &fe
);
387 g_message("found pending FocusIn");
389 /* is the focused window getting a FocusOut/In back to
392 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
393 !event_ignore(&fe
, client
)) {
395 if focus_client is not set, then we can't do
396 this. we need the FocusIn. This happens in the
397 case when the set_focus_client(NULL) in the
398 focus_fallback function fires and then
399 focus_fallback picks the currently focused
400 window (such as on a SendToDesktop-esque action.
404 g_message("focused window got an Out/In back to "
405 "itself IGNORED both");
411 g_message("focused window got an Out/In back to "
412 "itself but focus_client was null "
413 "IGNORED just the Out");
419 /* once all the FocusOut's have been dealt with, if there
420 is a FocusIn still left and it is valid, then use it */
422 /* secret magic way of event_process telling us that no
423 client was found for the FocusIn event. ^_^ */
424 if (fe
.xfocus
.window
!= None
) {
432 g_message("no valid FocusIn and no FocusOut events found, "
435 focus_fallback(Fallback_NoFocus
);
441 /* NotifyUngrab occurs when a mouse button is released and the event is
442 caused, like when lowering a window */
443 /* NotifyVirtual occurs when ungrabbing the pointer */
444 if (e
->xcrossing
.mode
== NotifyGrab
||
445 e
->xcrossing
.detail
== NotifyInferior
||
446 (e
->xcrossing
.mode
== NotifyUngrab
&&
447 e
->xcrossing
.detail
== NotifyVirtual
)) {
449 g_message("%sNotify mode %d detail %d on %lx IGNORED",
450 (e
->type
== EnterNotify
? "Enter" : "Leave"),
452 e
->xcrossing
.detail
, client
?client
->window
:0);
457 g_message("%sNotify mode %d detail %d on %lx",
458 (e
->type
== EnterNotify
? "Enter" : "Leave"),
460 e
->xcrossing
.detail
, client
?client
->window
:0);
467 static void event_process(XEvent
*e
)
470 Client
*client
= NULL
;
472 DockApp
*dockapp
= NULL
;
474 ObWindow
*obwin
= NULL
;
476 window
= event_get_window(e
);
477 if ((obwin
= g_hash_table_lookup(window_map
, &window
))) {
478 switch (obwin
->type
) {
480 dock
= WINDOW_AS_DOCK(obwin
);
483 dockapp
= WINDOW_AS_DOCKAPP(obwin
);
486 menu
= WINDOW_AS_MENU(obwin
);
489 client
= WINDOW_AS_CLIENT(obwin
);
491 case Window_Internal
:
492 /* not to be used for events */
493 g_assert_not_reached();
498 event_set_lasttime(e
);
500 if (event_ignore(e
, client
))
503 /* deal with it in the kernel */
505 event_handle_menu(menu
, client
, e
);
508 event_handle_client(client
, e
);
510 event_handle_dockapp(dockapp
, e
);
512 event_handle_dock(dock
, e
);
513 else if (window
== ob_root
)
514 event_handle_root(e
);
515 else if (e
->type
== MapRequest
)
516 client_manage(window
);
517 else if (e
->type
== ConfigureRequest
) {
518 /* unhandled configure requests must be used to configure the
522 xwc
.x
= e
->xconfigurerequest
.x
;
523 xwc
.y
= e
->xconfigurerequest
.y
;
524 xwc
.width
= e
->xconfigurerequest
.width
;
525 xwc
.height
= e
->xconfigurerequest
.height
;
526 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
527 xwc
.sibling
= e
->xconfigurerequest
.above
;
528 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
530 /* we are not to be held responsible if someone sends us an
532 xerror_set_ignore(TRUE
);
533 XConfigureWindow(ob_display
, window
,
534 e
->xconfigurerequest
.value_mask
, &xwc
);
535 xerror_set_ignore(FALSE
);
538 if (moveresize_in_progress
)
539 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
540 e
->type
== ButtonPress
||
541 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
544 return; /* no dispatch! */
548 /* user input (action-bound) events */
550 if (e->type == ButtonPress || e->type == ButtonRelease ||
551 e->type == MotionNotify)
552 mouse_event(e, client);
553 else if (e->type == KeyPress || e->type == KeyRelease)
557 /* dispatch the event to registered handlers */
558 dispatch_x(e
, client
);
561 static void event_handle_root(XEvent
*e
)
567 if (e
->xclient
.format
!= 32) break;
569 msgtype
= e
->xclient
.message_type
;
570 if (msgtype
== prop_atoms
.net_current_desktop
) {
571 unsigned int d
= e
->xclient
.data
.l
[0];
572 if (d
< screen_num_desktops
)
573 screen_set_desktop(d
);
574 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
575 unsigned int d
= e
->xclient
.data
.l
[0];
577 screen_set_num_desktops(d
);
578 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
579 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
583 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
584 screen_update_desktop_names();
585 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
586 screen_update_layout();
588 case ConfigureNotify
:
590 XRRUpdateConfiguration(e
);
592 if (e
->xconfigure
.width
!= screen_physical_size
.width
||
593 e
->xconfigure
.height
!= screen_physical_size
.height
)
594 screen_resize(e
->xconfigure
.width
, e
->xconfigure
.height
);
599 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
600 g_message("VIDMODE EVENT");
606 static void event_handle_client(Client
*client
, XEvent
*e
)
615 /* Wheel buttons don't draw because they are an instant click, so it
616 is a waste of resources to go drawing it. */
617 if (!(e
->xbutton
.button
== 4 || e
->xbutton
.button
== 5)) {
618 switch (frame_context(client
, e
->xbutton
.window
)) {
619 case Context_Maximize
:
620 client
->frame
->max_press
= (e
->type
== ButtonPress
);
621 framerender_frame(client
->frame
);
624 client
->frame
->close_press
= (e
->type
== ButtonPress
);
625 framerender_frame(client
->frame
);
627 case Context_Iconify
:
628 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
629 framerender_frame(client
->frame
);
631 case Context_AllDesktops
:
632 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
633 framerender_frame(client
->frame
);
636 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
637 framerender_frame(client
->frame
);
640 /* nothing changes with clicks for any other contexts */
647 g_message("FocusIn on client for %lx", client
->window
);
649 if (client
!= focus_client
) {
650 focus_set_client(client
);
651 frame_adjust_focus(client
->frame
, TRUE
);
656 g_message("FocusOut on client for %lx", client
->window
);
658 /* are we a fullscreen window or a transient of one? (checks layer)
659 if we are then we need to be iconified since we are losing focus
661 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
662 !client_search_focus_tree_full(client
))
663 /* iconify fullscreen windows when they and their transients
665 client_iconify(client
, TRUE
, TRUE
);
666 frame_adjust_focus(client
->frame
, FALSE
);
669 if (client_normal(client
)) {
670 if (ob_state
== State_Starting
) {
671 /* move it to the top of the focus order */
672 guint desktop
= client
->desktop
;
673 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
674 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
676 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
678 } else if (config_focus_follow
) {
680 g_message("EnterNotify on %lx, focusing window",
683 client_focus(client
);
687 case ConfigureRequest
:
689 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
690 ConfigureRequest
, &ce
)) {
692 /* XXX if this causes bad things.. we can compress config req's
693 with the same mask. */
694 e
->xconfigurerequest
.value_mask
|=
695 ce
.xconfigurerequest
.value_mask
;
696 if (ce
.xconfigurerequest
.value_mask
& CWX
)
697 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
698 if (ce
.xconfigurerequest
.value_mask
& CWY
)
699 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
700 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
701 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
702 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
703 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
704 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
705 e
->xconfigurerequest
.border_width
=
706 ce
.xconfigurerequest
.border_width
;
707 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
708 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
711 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
712 if (client
->iconic
|| client
->shaded
) return;
714 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
715 client
->border_width
= e
->xconfigurerequest
.border_width
;
717 /* resize, then move, as specified in the EWMH section 7.7 */
718 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
723 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
724 e
->xconfigurerequest
.x
: client
->area
.x
;
725 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
726 e
->xconfigurerequest
.y
: client
->area
.y
;
727 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
728 e
->xconfigurerequest
.width
: client
->area
.width
;
729 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
730 e
->xconfigurerequest
.height
: client
->area
.height
;
732 switch (client
->gravity
) {
733 case NorthEastGravity
:
735 corner
= Corner_TopRight
;
737 case SouthWestGravity
:
739 corner
= Corner_BottomLeft
;
741 case SouthEastGravity
:
742 corner
= Corner_BottomRight
;
744 default: /* NorthWest, Static, etc */
745 corner
= Corner_TopLeft
;
748 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, TRUE
);
751 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
752 switch (e
->xconfigurerequest
.detail
) {
755 stacking_lower(CLIENT_AS_WINDOW(client
));
761 stacking_raise(CLIENT_AS_WINDOW(client
));
767 if (client
->ignore_unmaps
) {
768 client
->ignore_unmaps
--;
771 client_unmanage(client
);
774 client_unmanage(client
);
777 /* this is when the client is first taken captive in the frame */
778 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
781 This event is quite rare and is usually handled in unmapHandler.
782 However, if the window is unmapped when the reparent event occurs,
783 the window manager never sees it because an unmap event is not sent
784 to an already unmapped window.
787 /* we don't want the reparent event, put it back on the stack for the
788 X server to deal with after we unmanage the window */
789 XPutBackEvent(ob_display
, e
);
791 client_unmanage(client
);
794 g_message("MapRequest for 0x%lx", client
->window
);
795 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
796 does, we don't want it! */
797 if (screen_showing_desktop
)
798 screen_show_desktop(FALSE
);
799 client_iconify(client
, FALSE
, TRUE
);
800 if (!client
->frame
->visible
)
801 /* if its not visible still, then don't mess with it */
804 client_shade(client
, FALSE
);
805 client_focus(client
);
806 stacking_raise(CLIENT_AS_WINDOW(client
));
809 /* validate cuz we query stuff off the client here */
810 if (!client_validate(client
)) break;
812 if (e
->xclient
.format
!= 32) return;
814 msgtype
= e
->xclient
.message_type
;
815 if (msgtype
== prop_atoms
.wm_change_state
) {
816 /* compress changes into a single change */
817 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
818 client
->window
, &ce
)) {
819 /* XXX: it would be nice to compress ALL messages of a
820 type, not just messages in a row without other
821 message types between. */
822 if (ce
.xclient
.message_type
!= msgtype
) {
823 XPutBackEvent(ob_display
, &ce
);
826 e
->xclient
= ce
.xclient
;
828 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
829 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
830 /* compress changes into a single change */
831 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
832 client
->window
, &ce
)) {
833 /* XXX: it would be nice to compress ALL messages of a
834 type, not just messages in a row without other
835 message types between. */
836 if (ce
.xclient
.message_type
!= msgtype
) {
837 XPutBackEvent(ob_display
, &ce
);
840 e
->xclient
= ce
.xclient
;
842 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
843 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
844 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
846 } else if (msgtype
== prop_atoms
.net_wm_state
) {
847 /* can't compress these */
848 g_message("net_wm_state %s %ld %ld for 0x%lx",
849 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
850 e
->xclient
.data
.l
[0] == 1 ? "Add" :
851 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
852 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
854 client_set_state(client
, e
->xclient
.data
.l
[0],
855 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
856 } else if (msgtype
== prop_atoms
.net_close_window
) {
857 g_message("net_close_window for 0x%lx", client
->window
);
858 client_close(client
);
859 } else if (msgtype
== prop_atoms
.net_active_window
) {
860 g_message("net_active_window for 0x%lx", client
->window
);
861 client_activate(client
);
862 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
863 g_message("net_wm_moveresize for 0x%lx", client
->window
);
864 if ((Atom
)e
->xclient
.data
.l
[2] ==
865 prop_atoms
.net_wm_moveresize_size_topleft
||
866 (Atom
)e
->xclient
.data
.l
[2] ==
867 prop_atoms
.net_wm_moveresize_size_top
||
868 (Atom
)e
->xclient
.data
.l
[2] ==
869 prop_atoms
.net_wm_moveresize_size_topright
||
870 (Atom
)e
->xclient
.data
.l
[2] ==
871 prop_atoms
.net_wm_moveresize_size_right
||
872 (Atom
)e
->xclient
.data
.l
[2] ==
873 prop_atoms
.net_wm_moveresize_size_right
||
874 (Atom
)e
->xclient
.data
.l
[2] ==
875 prop_atoms
.net_wm_moveresize_size_bottomright
||
876 (Atom
)e
->xclient
.data
.l
[2] ==
877 prop_atoms
.net_wm_moveresize_size_bottom
||
878 (Atom
)e
->xclient
.data
.l
[2] ==
879 prop_atoms
.net_wm_moveresize_size_bottomleft
||
880 (Atom
)e
->xclient
.data
.l
[2] ==
881 prop_atoms
.net_wm_moveresize_size_left
||
882 (Atom
)e
->xclient
.data
.l
[2] ==
883 prop_atoms
.net_wm_moveresize_move
||
884 (Atom
)e
->xclient
.data
.l
[2] ==
885 prop_atoms
.net_wm_moveresize_size_keyboard
||
886 (Atom
)e
->xclient
.data
.l
[2] ==
887 prop_atoms
.net_wm_moveresize_move_keyboard
) {
889 moveresize_start(client
, e
->xclient
.data
.l
[0],
890 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
891 e
->xclient
.data
.l
[2]);
893 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
894 int oldg
= client
->gravity
;
895 int tmpg
, x
, y
, w
, h
;
897 if (e
->xclient
.data
.l
[0] & 0xff)
898 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
902 if (e
->xclient
.data
.l
[0] & 1 << 8)
903 x
= e
->xclient
.data
.l
[1];
906 if (e
->xclient
.data
.l
[0] & 1 << 9)
907 y
= e
->xclient
.data
.l
[2];
910 if (e
->xclient
.data
.l
[0] & 1 << 10)
911 w
= e
->xclient
.data
.l
[3];
914 if (e
->xclient
.data
.l
[0] & 1 << 11)
915 h
= e
->xclient
.data
.l
[4];
918 client
->gravity
= tmpg
;
919 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, FALSE
, TRUE
);
920 client
->gravity
= oldg
;
924 /* validate cuz we query stuff off the client here */
925 if (!client_validate(client
)) break;
927 /* compress changes to a single property into a single change */
928 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
929 client
->window
, &ce
)) {
930 /* XXX: it would be nice to compress ALL changes to a property,
931 not just changes in a row without other props between. */
932 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
933 XPutBackEvent(ob_display
, &ce
);
938 msgtype
= e
->xproperty
.atom
;
939 if (msgtype
== XA_WM_NORMAL_HINTS
) {
940 client_update_normal_hints(client
);
941 /* normal hints can make a window non-resizable */
942 client_setup_decor_and_functions(client
);
944 else if (msgtype
== XA_WM_HINTS
)
945 client_update_wmhints(client
);
946 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
947 client_update_transient_for(client
);
948 client_get_type(client
);
949 /* type may have changed, so update the layer */
950 client_calc_layer(client
);
951 client_setup_decor_and_functions(client
);
953 else if (msgtype
== prop_atoms
.net_wm_name
||
954 msgtype
== prop_atoms
.wm_name
||
955 msgtype
== prop_atoms
.net_wm_icon_name
||
956 msgtype
== prop_atoms
.wm_icon_name
)
957 client_update_title(client
);
958 else if (msgtype
== prop_atoms
.wm_class
)
959 client_update_class(client
);
960 else if (msgtype
== prop_atoms
.wm_protocols
) {
961 client_update_protocols(client
);
962 client_setup_decor_and_functions(client
);
964 else if (msgtype
== prop_atoms
.net_wm_strut
)
965 client_update_strut(client
);
966 else if (msgtype
== prop_atoms
.net_wm_icon
||
967 msgtype
== prop_atoms
.kwm_win_icon
)
968 client_update_icons(client
);
972 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
973 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
974 frame_adjust_shape(client
->frame
);
980 static void event_handle_menu(Menu
*menu
, Client
*client
, XEvent
*e
)
984 g_message("EVENT %d", e
->type
);
987 g_message("BUTTON PRESS");
988 if (e
->xbutton
.button
== 3)
990 else if (e
->xbutton
.button
== 1) {
991 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
993 stacking_raise(MENU_AS_WINDOW(menu
));
997 g_message("BUTTON RELEASED");
998 if (!menu
->shown
) break;
1000 /* grab_pointer_window(FALSE, None, menu->frame);*/
1002 if (e
->xbutton
.button
== 1) {
1003 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
1007 guint ujunk
, b
, w
, h
;
1008 XGetGeometry(ob_display
, e
->xbutton
.window
,
1009 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
1010 if (e
->xbutton
.x
>= (signed)-b
&&
1011 e
->xbutton
.y
>= (signed)-b
&&
1012 e
->xbutton
.x
< (signed)(w
+b
) &&
1013 e
->xbutton
.y
< (signed)(h
+b
)) {
1014 menu_entry_fire(entry
);
1022 g_message("enter/leave");
1023 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
1025 if (menu
->mouseover
)
1026 menu
->mouseover(entry
, e
->type
== EnterNotify
);
1028 menu_control_mouseover(entry
, e
->type
== EnterNotify
);
1030 menu_entry_render(entry
);
1036 void event_add_fd_handler(event_fd_handler
*h
) {
1037 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
1038 FD_SET(h
->fd
, &allset
);
1039 max_fd
= MAX(max_fd
, h
->fd
);
1042 static void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
1044 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
1047 static void find_max_fd()
1050 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
, (gpointer
)&tmpmax
);
1051 max_fd
= MAX(x_fd
, tmpmax
);
1053 max_fd
= MAX(ice_fd
, tmpmax
);
1057 void event_remove_fd(int n
)
1060 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
1064 static void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
1066 if (FD_ISSET( (int)n
, &selset
)) {
1067 event_fd_handler
*h
= (event_fd_handler
*)data
;
1068 g_assert(h
->fd
== (int)n
);
1069 h
->handler(h
->fd
, h
->data
);
1073 static void fd_event_handle()
1075 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
1078 static void event_handle_dock(Dock
*s
, XEvent
*e
)
1082 stacking_raise(DOCK_AS_WINDOW(s
));
1093 static void event_handle_dockapp(DockApp
*app
, XEvent
*e
)
1097 dock_app_drag(app
, &e
->xmotion
);
1100 if (app
->ignore_unmaps
) {
1101 app
->ignore_unmaps
--;
1104 dock_remove(app
, TRUE
);
1107 dock_remove(app
, FALSE
);
1109 case ReparentNotify
:
1110 dock_remove(app
, FALSE
);
1112 case ConfigureNotify
:
1113 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);