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(ObClient
*c
, XEvent
*e
);
44 static void event_handle_menu(ObClient
*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
, ObClient
*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 ObClient
*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_client(client
, e
);
507 event_handle_dockapp(dockapp
, e
);
509 event_handle_dock(dock
, e
);
510 else if (window
== ob_root
)
511 event_handle_root(e
);
512 else if (e
->type
== MapRequest
)
513 client_manage(window
);
514 else if (e
->type
== ConfigureRequest
) {
515 /* unhandled configure requests must be used to configure the
519 xwc
.x
= e
->xconfigurerequest
.x
;
520 xwc
.y
= e
->xconfigurerequest
.y
;
521 xwc
.width
= e
->xconfigurerequest
.width
;
522 xwc
.height
= e
->xconfigurerequest
.height
;
523 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
524 xwc
.sibling
= e
->xconfigurerequest
.above
;
525 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
527 /* we are not to be held responsible if someone sends us an
529 xerror_set_ignore(TRUE
);
530 XConfigureWindow(ob_display
, window
,
531 e
->xconfigurerequest
.value_mask
, &xwc
);
532 xerror_set_ignore(FALSE
);
536 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
537 e
->type
== ButtonPress
||
538 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
539 event_handle_menu(client
, e
);
541 return; /* no dispatch! */
544 if (moveresize_in_progress
)
545 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
546 e
->type
== ButtonPress
||
547 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
550 return; /* no dispatch! */
554 /* user input (action-bound) events */
556 if (e->type == ButtonPress || e->type == ButtonRelease ||
557 e->type == MotionNotify)
558 mouse_event(e, client);
559 else if (e->type == KeyPress || e->type == KeyRelease)
563 /* dispatch the event to registered handlers */
564 dispatch_x(e
, client
);
567 static void event_handle_root(XEvent
*e
)
573 if (e
->xclient
.format
!= 32) break;
575 msgtype
= e
->xclient
.message_type
;
576 if (msgtype
== prop_atoms
.net_current_desktop
) {
577 unsigned int d
= e
->xclient
.data
.l
[0];
578 if (d
< screen_num_desktops
)
579 screen_set_desktop(d
);
580 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
581 unsigned int d
= e
->xclient
.data
.l
[0];
583 screen_set_num_desktops(d
);
584 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
585 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
589 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
590 screen_update_desktop_names();
591 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
592 screen_update_layout();
594 case ConfigureNotify
:
596 XRRUpdateConfiguration(e
);
603 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
604 g_message("VIDMODE EVENT");
610 static void event_handle_client(ObClient
*client
, XEvent
*e
)
619 /* Wheel buttons don't draw because they are an instant click, so it
620 is a waste of resources to go drawing it. */
621 if (!(e
->xbutton
.button
== 4 || e
->xbutton
.button
== 5)) {
622 switch (frame_context(client
, e
->xbutton
.window
)) {
623 case OB_FRAME_CONTEXT_MAXIMIZE
:
624 client
->frame
->max_press
= (e
->type
== ButtonPress
);
625 framerender_frame(client
->frame
);
627 case OB_FRAME_CONTEXT_CLOSE
:
628 client
->frame
->close_press
= (e
->type
== ButtonPress
);
629 framerender_frame(client
->frame
);
631 case OB_FRAME_CONTEXT_ICONIFY
:
632 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
633 framerender_frame(client
->frame
);
635 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
636 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
637 framerender_frame(client
->frame
);
639 case OB_FRAME_CONTEXT_SHADE
:
640 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
641 framerender_frame(client
->frame
);
644 /* nothing changes with clicks for any other contexts */
651 g_message("FocusIn on client for %lx", client
->window
);
653 if (client
!= focus_client
) {
654 focus_set_client(client
);
655 frame_adjust_focus(client
->frame
, TRUE
);
660 g_message("FocusOut on client for %lx", client
->window
);
662 /* are we a fullscreen window or a transient of one? (checks layer)
663 if we are then we need to be iconified since we are losing focus
665 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
666 !client_search_focus_tree_full(client
))
667 /* iconify fullscreen windows when they and their transients
669 client_iconify(client
, TRUE
, TRUE
);
670 frame_adjust_focus(client
->frame
, FALSE
);
673 if (client_normal(client
)) {
674 if (ob_state
== OB_STATE_STARTING
) {
675 /* move it to the top of the focus order */
676 guint desktop
= client
->desktop
;
677 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
678 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
680 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
682 } else if (config_focus_follow
) {
684 g_message("EnterNotify on %lx, focusing window",
687 client_focus(client
);
691 case ConfigureRequest
:
693 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
694 ConfigureRequest
, &ce
)) {
696 /* XXX if this causes bad things.. we can compress config req's
697 with the same mask. */
698 e
->xconfigurerequest
.value_mask
|=
699 ce
.xconfigurerequest
.value_mask
;
700 if (ce
.xconfigurerequest
.value_mask
& CWX
)
701 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
702 if (ce
.xconfigurerequest
.value_mask
& CWY
)
703 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
704 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
705 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
706 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
707 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
708 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
709 e
->xconfigurerequest
.border_width
=
710 ce
.xconfigurerequest
.border_width
;
711 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
712 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
715 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
716 if (client
->iconic
|| client
->shaded
) return;
718 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
719 client
->border_width
= e
->xconfigurerequest
.border_width
;
721 /* resize, then move, as specified in the EWMH section 7.7 */
722 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
727 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
728 e
->xconfigurerequest
.x
: client
->area
.x
;
729 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
730 e
->xconfigurerequest
.y
: client
->area
.y
;
731 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
732 e
->xconfigurerequest
.width
: client
->area
.width
;
733 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
734 e
->xconfigurerequest
.height
: client
->area
.height
;
736 switch (client
->gravity
) {
737 case NorthEastGravity
:
739 corner
= OB_CORNER_TOPRIGHT
;
741 case SouthWestGravity
:
743 corner
= OB_CORNER_BOTTOMLEFT
;
745 case SouthEastGravity
:
746 corner
= OB_CORNER_BOTTOMRIGHT
;
748 default: /* NorthWest, Static, etc */
749 corner
= OB_CORNER_TOPLEFT
;
752 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, TRUE
);
755 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
756 switch (e
->xconfigurerequest
.detail
) {
759 stacking_lower(CLIENT_AS_WINDOW(client
));
765 stacking_raise(CLIENT_AS_WINDOW(client
));
771 if (client
->ignore_unmaps
) {
772 client
->ignore_unmaps
--;
775 client_unmanage(client
);
778 client_unmanage(client
);
781 /* this is when the client is first taken captive in the frame */
782 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
785 This event is quite rare and is usually handled in unmapHandler.
786 However, if the window is unmapped when the reparent event occurs,
787 the window manager never sees it because an unmap event is not sent
788 to an already unmapped window.
791 /* we don't want the reparent event, put it back on the stack for the
792 X server to deal with after we unmanage the window */
793 XPutBackEvent(ob_display
, e
);
795 client_unmanage(client
);
798 g_message("MapRequest for 0x%lx", client
->window
);
799 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
800 does, we don't want it! */
801 if (screen_showing_desktop
)
802 screen_show_desktop(FALSE
);
803 client_iconify(client
, FALSE
, TRUE
);
804 if (!client
->frame
->visible
)
805 /* if its not visible still, then don't mess with it */
808 client_shade(client
, FALSE
);
809 client_focus(client
);
810 stacking_raise(CLIENT_AS_WINDOW(client
));
813 /* validate cuz we query stuff off the client here */
814 if (!client_validate(client
)) break;
816 if (e
->xclient
.format
!= 32) return;
818 msgtype
= e
->xclient
.message_type
;
819 if (msgtype
== prop_atoms
.wm_change_state
) {
820 /* compress changes into a single change */
821 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
822 client
->window
, &ce
)) {
823 /* XXX: it would be nice to compress ALL messages of a
824 type, not just messages in a row without other
825 message types between. */
826 if (ce
.xclient
.message_type
!= msgtype
) {
827 XPutBackEvent(ob_display
, &ce
);
830 e
->xclient
= ce
.xclient
;
832 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
833 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
834 /* compress changes into a single change */
835 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
836 client
->window
, &ce
)) {
837 /* XXX: it would be nice to compress ALL messages of a
838 type, not just messages in a row without other
839 message types between. */
840 if (ce
.xclient
.message_type
!= msgtype
) {
841 XPutBackEvent(ob_display
, &ce
);
844 e
->xclient
= ce
.xclient
;
846 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
847 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
848 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
850 } else if (msgtype
== prop_atoms
.net_wm_state
) {
851 /* can't compress these */
852 g_message("net_wm_state %s %ld %ld for 0x%lx",
853 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
854 e
->xclient
.data
.l
[0] == 1 ? "Add" :
855 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
856 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
858 client_set_state(client
, e
->xclient
.data
.l
[0],
859 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
860 } else if (msgtype
== prop_atoms
.net_close_window
) {
861 g_message("net_close_window for 0x%lx", client
->window
);
862 client_close(client
);
863 } else if (msgtype
== prop_atoms
.net_active_window
) {
864 g_message("net_active_window for 0x%lx", client
->window
);
865 client_activate(client
);
866 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
867 g_message("net_wm_moveresize for 0x%lx", client
->window
);
868 if ((Atom
)e
->xclient
.data
.l
[2] ==
869 prop_atoms
.net_wm_moveresize_size_topleft
||
870 (Atom
)e
->xclient
.data
.l
[2] ==
871 prop_atoms
.net_wm_moveresize_size_top
||
872 (Atom
)e
->xclient
.data
.l
[2] ==
873 prop_atoms
.net_wm_moveresize_size_topright
||
874 (Atom
)e
->xclient
.data
.l
[2] ==
875 prop_atoms
.net_wm_moveresize_size_right
||
876 (Atom
)e
->xclient
.data
.l
[2] ==
877 prop_atoms
.net_wm_moveresize_size_right
||
878 (Atom
)e
->xclient
.data
.l
[2] ==
879 prop_atoms
.net_wm_moveresize_size_bottomright
||
880 (Atom
)e
->xclient
.data
.l
[2] ==
881 prop_atoms
.net_wm_moveresize_size_bottom
||
882 (Atom
)e
->xclient
.data
.l
[2] ==
883 prop_atoms
.net_wm_moveresize_size_bottomleft
||
884 (Atom
)e
->xclient
.data
.l
[2] ==
885 prop_atoms
.net_wm_moveresize_size_left
||
886 (Atom
)e
->xclient
.data
.l
[2] ==
887 prop_atoms
.net_wm_moveresize_move
||
888 (Atom
)e
->xclient
.data
.l
[2] ==
889 prop_atoms
.net_wm_moveresize_size_keyboard
||
890 (Atom
)e
->xclient
.data
.l
[2] ==
891 prop_atoms
.net_wm_moveresize_move_keyboard
) {
893 moveresize_start(client
, e
->xclient
.data
.l
[0],
894 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
895 e
->xclient
.data
.l
[2]);
897 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
898 int oldg
= client
->gravity
;
899 int tmpg
, x
, y
, w
, h
;
901 if (e
->xclient
.data
.l
[0] & 0xff)
902 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
906 if (e
->xclient
.data
.l
[0] & 1 << 8)
907 x
= e
->xclient
.data
.l
[1];
910 if (e
->xclient
.data
.l
[0] & 1 << 9)
911 y
= e
->xclient
.data
.l
[2];
914 if (e
->xclient
.data
.l
[0] & 1 << 10)
915 w
= e
->xclient
.data
.l
[3];
918 if (e
->xclient
.data
.l
[0] & 1 << 11)
919 h
= e
->xclient
.data
.l
[4];
922 client
->gravity
= tmpg
;
923 client_configure(client
, OB_CORNER_TOPLEFT
,
924 x
, y
, w
, h
, FALSE
, TRUE
);
925 client
->gravity
= oldg
;
929 /* validate cuz we query stuff off the client here */
930 if (!client_validate(client
)) break;
932 /* compress changes to a single property into a single change */
933 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
934 client
->window
, &ce
)) {
935 /* XXX: it would be nice to compress ALL changes to a property,
936 not just changes in a row without other props between. */
937 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
938 XPutBackEvent(ob_display
, &ce
);
943 msgtype
= e
->xproperty
.atom
;
944 if (msgtype
== XA_WM_NORMAL_HINTS
) {
945 client_update_normal_hints(client
);
946 /* normal hints can make a window non-resizable */
947 client_setup_decor_and_functions(client
);
949 else if (msgtype
== XA_WM_HINTS
)
950 client_update_wmhints(client
);
951 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
952 client_update_transient_for(client
);
953 client_get_type(client
);
954 /* type may have changed, so update the layer */
955 client_calc_layer(client
);
956 client_setup_decor_and_functions(client
);
958 else if (msgtype
== prop_atoms
.net_wm_name
||
959 msgtype
== prop_atoms
.wm_name
||
960 msgtype
== prop_atoms
.net_wm_icon_name
||
961 msgtype
== prop_atoms
.wm_icon_name
)
962 client_update_title(client
);
963 else if (msgtype
== prop_atoms
.wm_class
)
964 client_update_class(client
);
965 else if (msgtype
== prop_atoms
.wm_protocols
) {
966 client_update_protocols(client
);
967 client_setup_decor_and_functions(client
);
969 else if (msgtype
== prop_atoms
.net_wm_strut
)
970 client_update_strut(client
);
971 else if (msgtype
== prop_atoms
.net_wm_icon
||
972 msgtype
== prop_atoms
.kwm_win_icon
)
973 client_update_icons(client
);
977 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
978 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
979 frame_adjust_shape(client
->frame
);
985 static void event_handle_menu(ObClient
*client
, XEvent
*e
)
987 static MenuEntry
*over
= NULL
;
992 top
= g_slist_nth_data(menu_visible
, 0);
994 g_message("EVENT %d", e
->type
);
998 if (over
->parent
->mouseover
)
999 over
->parent
->mouseover(over
, FALSE
);
1001 menu_control_mouseover(over
, FALSE
);
1002 menu_entry_render(over
);
1013 if (e
->xbutton
.button
> 3) break;
1015 g_message("BUTTON PRESS");
1018 if (e
->xbutton
.button
> 3) break;
1020 g_message("BUTTON RELEASED");
1022 for (it
= menu_visible
; it
; it
= g_slist_next(it
)) {
1024 if (e
->xbutton
.x_root
>= m
->location
.x
- ob_rr_theme
->bwidth
&&
1025 e
->xbutton
.y_root
>= m
->location
.y
- ob_rr_theme
->bwidth
&&
1026 e
->xbutton
.x_root
< m
->location
.x
+ m
->size
.width
+
1027 ob_rr_theme
->bwidth
&&
1028 e
->xbutton
.y_root
< m
->location
.y
+ m
->size
.height
+
1029 ob_rr_theme
->bwidth
) {
1030 if ((entry
= menu_find_entry_by_pos(it
->data
,
1036 if (over
->parent
->mouseover
)
1037 over
->parent
->mouseover(over
, FALSE
);
1039 menu_control_mouseover(over
, FALSE
);
1040 menu_entry_render(over
);
1042 /* this hides the menu */
1043 menu_entry_fire(entry
);
1051 if (over
->parent
->mouseover
)
1052 over
->parent
->mouseover(over
, FALSE
);
1054 menu_control_mouseover(over
, FALSE
);
1055 menu_entry_render(over
);
1068 g_message("motion");
1069 for (it
= menu_visible
; it
; it
= g_slist_next(it
)) {
1071 if ((entry
= menu_find_entry_by_pos(it
->data
,
1076 if (over
&& entry
!= over
) {
1077 if (over
->parent
->mouseover
)
1078 over
->parent
->mouseover(over
, FALSE
);
1080 menu_control_mouseover(over
, FALSE
);
1081 menu_entry_render(over
);
1085 if (over
->parent
->mouseover
)
1086 over
->parent
->mouseover(over
, TRUE
);
1088 menu_control_mouseover(over
, TRUE
);
1089 menu_entry_render(over
);
1094 if (over
->parent
->mouseover
)
1095 over
->parent
->mouseover(over
, FALSE
);
1097 menu_control_mouseover(over
, FALSE
);
1098 menu_entry_render(over
);
1105 void event_add_fd_handler(event_fd_handler
*h
) {
1106 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
1107 FD_SET(h
->fd
, &allset
);
1108 max_fd
= MAX(max_fd
, h
->fd
);
1111 static void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
1113 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
1116 static void find_max_fd()
1119 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
,
1121 max_fd
= MAX(x_fd
, tmpmax
);
1123 max_fd
= MAX(ice_fd
, tmpmax
);
1127 void event_remove_fd(int n
)
1130 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
1134 static void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
1136 if (FD_ISSET( (int)n
, &selset
)) {
1137 event_fd_handler
*h
= (event_fd_handler
*)data
;
1138 g_assert(h
->fd
== (int)n
);
1139 h
->handler(h
->fd
, h
->data
);
1143 static void fd_event_handle()
1145 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
1148 static void event_handle_dock(Dock
*s
, XEvent
*e
)
1152 stacking_raise(DOCK_AS_WINDOW(s
));
1163 static void event_handle_dockapp(DockApp
*app
, XEvent
*e
)
1167 dock_app_drag(app
, &e
->xmotion
);
1170 if (app
->ignore_unmaps
) {
1171 app
->ignore_unmaps
--;
1174 dock_remove(app
, TRUE
);
1177 dock_remove(app
, FALSE
);
1179 case ReparentNotify
:
1180 dock_remove(app
, FALSE
);
1182 case ConfigureNotify
:
1183 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);