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>
35 #include <X11/ICE/ICElib.h>
37 static void event_process(XEvent
*e
);
38 static void event_handle_root(XEvent
*e
);
39 static void event_handle_dock(Dock
*s
, XEvent
*e
);
40 static void event_handle_dockapp(DockApp
*app
, XEvent
*e
);
41 static void event_handle_client(Client
*c
, XEvent
*e
);
42 static void event_handle_menu(Menu
*menu
, Client
*c
, XEvent
*e
);
43 static void fd_event_handle();
44 static void ice_watch(IceConn conn
, IcePointer data
, Bool opening
,
45 IcePointer
*watch_data
);
46 static void find_max_fd();
48 #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
49 (e)->xfocus.detail == NotifyAncestor || \
50 (e)->xfocus.detail > NotifyNonlinearVirtual)
51 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
52 (e)->xfocus.detail == NotifyInferior || \
53 (e)->xfocus.detail == NotifyAncestor || \
54 (e)->xfocus.detail > NotifyNonlinearVirtual)
56 Time event_lasttime
= 0;
58 /*! The value of the mask for the NumLock modifier */
59 unsigned int NumLockMask
;
60 /*! The value of the mask for the ScrollLock modifier */
61 unsigned int ScrollLockMask
;
62 /*! The key codes for the modifier keys */
63 static XModifierKeymap
*modmap
;
64 /*! Table of the constant modifier masks */
65 static const int mask_table
[] = {
66 ShiftMask
, LockMask
, ControlMask
, Mod1Mask
,
67 Mod2Mask
, Mod3Mask
, Mod4Mask
, Mod5Mask
69 static int mask_table_size
;
71 static fd_set selset
, allset
;
72 static IceConn ice_conn
;
73 static int max_fd
, x_fd
, ice_fd
;
74 static GData
*fd_handler_list
;
77 static void ice_watch(IceConn conn
, IcePointer data
, Bool opening
,
78 IcePointer
*watch_data
)
81 g_assert (ice_fd
< 0);
83 ice_fd
= IceConnectionNumber(conn
);
84 FD_SET(ice_fd
, &allset
);
86 FD_CLR(ice_fd
, &allset
);
94 mask_table_size
= sizeof(mask_table
) / sizeof(mask_table
[0]);
96 /* get lock masks that are defined by the display (not constant) */
97 modmap
= XGetModifierMapping(ob_display
);
99 if (modmap
&& modmap
->max_keypermod
> 0) {
101 const size_t size
= mask_table_size
* modmap
->max_keypermod
;
102 /* get the values of the keyboard lock modifiers
103 Note: Caps lock is not retrieved the same way as Scroll and Num
104 lock since it doesn't need to be. */
105 const KeyCode num_lock
= XKeysymToKeycode(ob_display
, XK_Num_Lock
);
106 const KeyCode scroll_lock
= XKeysymToKeycode(ob_display
,
109 for (cnt
= 0; cnt
< size
; ++cnt
) {
110 if (! modmap
->modifiermap
[cnt
]) continue;
112 if (num_lock
== modmap
->modifiermap
[cnt
])
113 NumLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
114 if (scroll_lock
== modmap
->modifiermap
[cnt
])
115 ScrollLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
120 max_fd
= x_fd
= ConnectionNumber(ob_display
);
121 FD_SET(x_fd
, &allset
);
124 IceAddConnectionWatch(ice_watch
, NULL
);
126 g_datalist_init(&fd_handler_list
);
129 void event_shutdown()
131 XFreeModifiermap(modmap
);
132 g_datalist_clear(&fd_handler_list
);
138 struct timeval
*wait
;
139 gboolean had_event
= FALSE
;
143 There are slightly different event retrieval semantics here for
144 local (or high bandwidth) versus remote (or low bandwidth)
145 connections to the display/Xserver.
148 if (!XPending(ob_display
))
152 This XSync allows for far more compression of events, which
153 makes things like Motion events perform far far better. Since
154 it also means network traffic for every event instead of every
155 X events (where X is the number retrieved at a time), it
156 probably should not be used for setups where Openbox is
157 running on a remote/low bandwidth display/Xserver.
159 XSync(ob_display
, FALSE
);
160 if (!XEventsQueued(ob_display
, QueuedAlready
))
163 XNextEvent(ob_display
, &e
);
166 sn_display_process_event(ob_sn_display
, &e
);
174 timer_dispatch((GTimeVal
**)&wait
);
176 select(max_fd
+ 1, &selset
, NULL
, NULL
, wait
);
178 /* handle the X events as soon as possible? */
179 if (FD_ISSET(x_fd
, &selset
))
182 if (ice_fd
>= 0 && FD_ISSET(ice_fd
, &selset
)) {
184 IceProcessMessages(ice_conn
, NULL
, &b
);
191 static Window
event_get_window(XEvent
*e
)
198 window
= e
->xmap
.window
;
201 window
= e
->xunmap
.window
;
204 window
= e
->xdestroywindow
.window
;
206 case ConfigureRequest
:
207 window
= e
->xconfigurerequest
.window
;
209 case ConfigureNotify
:
210 window
= e
->xconfigure
.window
;
214 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
215 switch (((XkbAnyEvent
*)&e
)->xkb_type
) {
217 window
= ((XkbBellNotifyEvent
*)&e
)->window
;
223 window
= e
->xany
.window
;
228 static void event_set_lasttime(XEvent
*e
)
230 /* grab the lasttime and hack up the state */
234 event_lasttime
= e
->xbutton
.time
;
237 event_lasttime
= e
->xkey
.time
;
240 event_lasttime
= e
->xkey
.time
;
243 event_lasttime
= e
->xmotion
.time
;
246 event_lasttime
= e
->xproperty
.time
;
250 event_lasttime
= e
->xcrossing
.time
;
253 event_lasttime
= CurrentTime
;
258 #define STRIP_MODS(s) \
259 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
260 /* kill off the Button1Mask etc, only want the modifiers */ \
261 s &= (ControlMask | ShiftMask | Mod1Mask | \
262 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
264 static void event_hack_mods(XEvent *e)
272 STRIP_MODS(e
->xbutton
.state
);
275 STRIP_MODS(e
->xkey
.state
);
278 STRIP_MODS(e
->xkey
.state
);
279 /* remove from the state the mask of the modifier being released, if
280 it is a modifier key being released (this is a little ugly..) */
281 kp
= modmap
->modifiermap
;
282 for (i
= 0; i
< mask_table_size
; ++i
) {
283 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
284 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
285 /* remove the mask for it */
286 e
->xkey
.state
&= ~mask_table
[i
];
287 /* cause the first loop to break; */
289 break; /* get outta here! */
296 STRIP_MODS(e
->xmotion
.state
);
297 /* compress events */
300 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
302 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
303 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
310 static gboolean
event_ignore(XEvent
*e
, Client
*client
)
314 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
315 because of RevertToPointerRoot. If the focus ends up reverting to
316 pointer root on a workspace change, then the FocusIn event that we
317 want will be of type NotifyAncestor. This situation does not occur
318 for FocusOut, so it is safely ignored there.
320 if (INVALID_FOCUSIN(e
) ||
323 g_message("FocusIn on %lx mode %d detail %d IGNORED", e
->xfocus
.window
,
324 e
->xfocus
.mode
, e
->xfocus
.detail
);
326 /* says a client was not found for the event (or a valid FocusIn
329 e
->xfocus
.window
= None
;
334 g_message("FocusIn on %lx mode %d detail %d", e
->xfocus
.window
,
335 e
->xfocus
.mode
, e
->xfocus
.detail
);
339 if (INVALID_FOCUSOUT(e
)) {
341 g_message("FocusOut on %lx mode %d detail %d IGNORED",
342 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
348 g_message("FocusOut on %lx mode %d detail %d",
349 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
354 gboolean fallback
= TRUE
;
357 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
358 e
->xfocus
.window
,&fe
))
359 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
361 if (fe
.type
== FocusOut
) {
363 g_message("found pending FocusOut");
365 if (!INVALID_FOCUSOUT(&fe
)) {
366 /* if there is a VALID FocusOut still coming, don't
367 fallback focus yet, we'll deal with it then */
368 XPutBackEvent(ob_display
, &fe
);
374 g_message("found pending FocusIn");
376 /* is the focused window getting a FocusOut/In back to
379 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
380 !event_ignore(&fe
, client
)) {
382 if focus_client is not set, then we can't do
383 this. we need the FocusIn. This happens in the
384 case when the set_focus_client(NULL) in the
385 focus_fallback function fires and then
386 focus_fallback picks the currently focused
387 window (such as on a SendToDesktop-esque action.
391 g_message("focused window got an Out/In back to "
392 "itself IGNORED both");
398 g_message("focused window got an Out/In back to "
399 "itself but focus_client was null "
400 "IGNORED just the Out");
406 /* once all the FocusOut's have been dealt with, if there
407 is a FocusIn still left and it is valid, then use it */
409 /* secret magic way of event_process telling us that no
410 client was found for the FocusIn event. ^_^ */
411 if (fe
.xfocus
.window
!= None
) {
419 g_message("no valid FocusIn and no FocusOut events found, "
422 focus_fallback(Fallback_NoFocus
);
428 /* NotifyUngrab occurs when a mouse button is released and the event is
429 caused, like when lowering a window */
430 /* NotifyVirtual occurs when ungrabbing the pointer */
431 if (e
->xcrossing
.mode
== NotifyGrab
||
432 e
->xcrossing
.detail
== NotifyInferior
||
433 (e
->xcrossing
.mode
== NotifyUngrab
&&
434 e
->xcrossing
.detail
== NotifyVirtual
)) {
436 g_message("%sNotify mode %d detail %d on %lx IGNORED",
437 (e
->type
== EnterNotify
? "Enter" : "Leave"),
439 e
->xcrossing
.detail
, client
?client
->window
:0);
444 g_message("%sNotify mode %d detail %d on %lx",
445 (e
->type
== EnterNotify
? "Enter" : "Leave"),
447 e
->xcrossing
.detail
, client
?client
->window
:0);
454 static void event_process(XEvent
*e
)
457 Client
*client
= NULL
;
459 DockApp
*dockapp
= NULL
;
461 ObWindow
*obwin
= NULL
;
463 window
= event_get_window(e
);
464 if ((obwin
= g_hash_table_lookup(window_map
, &window
))) {
465 switch (obwin
->type
) {
467 dock
= WINDOW_AS_DOCK(obwin
);
470 dockapp
= WINDOW_AS_DOCKAPP(obwin
);
473 menu
= WINDOW_AS_MENU(obwin
);
476 client
= WINDOW_AS_CLIENT(obwin
);
478 case Window_Internal
:
479 /* not to be used for events */
480 g_assert_not_reached();
485 event_set_lasttime(e
);
487 if (event_ignore(e
, client
))
490 /* deal with it in the kernel */
492 event_handle_menu(menu
, client
, e
);
495 event_handle_client(client
, e
);
497 event_handle_dockapp(dockapp
, e
);
499 event_handle_dock(dock
, e
);
500 else if (window
== ob_root
)
501 event_handle_root(e
);
502 else if (e
->type
== MapRequest
)
503 client_manage(window
);
504 else if (e
->type
== ConfigureRequest
) {
505 /* unhandled configure requests must be used to configure the
509 xwc
.x
= e
->xconfigurerequest
.x
;
510 xwc
.y
= e
->xconfigurerequest
.y
;
511 xwc
.width
= e
->xconfigurerequest
.width
;
512 xwc
.height
= e
->xconfigurerequest
.height
;
513 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
514 xwc
.sibling
= e
->xconfigurerequest
.above
;
515 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
517 /* we are not to be held responsible if someone sends us an
519 xerror_set_ignore(TRUE
);
520 XConfigureWindow(ob_display
, window
,
521 e
->xconfigurerequest
.value_mask
, &xwc
);
522 xerror_set_ignore(FALSE
);
525 if (moveresize_in_progress
)
526 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
527 e
->type
== ButtonPress
||
528 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
531 return; /* no dispatch! */
535 /* user input (action-bound) events */
537 if (e->type == ButtonPress || e->type == ButtonRelease ||
538 e->type == MotionNotify)
539 mouse_event(e, client);
540 else if (e->type == KeyPress || e->type == KeyRelease)
544 /* dispatch the event to registered handlers */
545 dispatch_x(e
, client
);
548 static void event_handle_root(XEvent
*e
)
554 if (e
->xclient
.format
!= 32) break;
556 msgtype
= e
->xclient
.message_type
;
557 if (msgtype
== prop_atoms
.net_current_desktop
) {
558 unsigned int d
= e
->xclient
.data
.l
[0];
559 if (d
< screen_num_desktops
)
560 screen_set_desktop(d
);
561 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
562 unsigned int d
= e
->xclient
.data
.l
[0];
564 screen_set_num_desktops(d
);
565 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
566 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
570 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
571 screen_update_desktop_names();
572 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
573 screen_update_layout();
575 case ConfigureNotify
:
577 XRRUpdateConfiguration(e
);
579 if (e
->xconfigure
.width
!= screen_physical_size
.width
||
580 e
->xconfigure
.height
!= screen_physical_size
.height
)
581 screen_resize(e
->xconfigure
.width
, e
->xconfigure
.height
);
586 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
587 g_message("VIDMODE EVENT");
593 static void event_handle_client(Client
*client
, XEvent
*e
)
602 /* Wheel buttons don't draw because they are an instant click, so it
603 is a waste of resources to go drawing it. */
604 if (!(e
->xbutton
.button
== 4 || e
->xbutton
.button
== 5)) {
605 switch (frame_context(client
, e
->xbutton
.window
)) {
606 case Context_Maximize
:
607 client
->frame
->max_press
= (e
->type
== ButtonPress
);
608 framerender_frame(client
->frame
);
611 client
->frame
->close_press
= (e
->type
== ButtonPress
);
612 framerender_frame(client
->frame
);
614 case Context_Iconify
:
615 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
616 framerender_frame(client
->frame
);
618 case Context_AllDesktops
:
619 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
620 framerender_frame(client
->frame
);
623 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
624 framerender_frame(client
->frame
);
627 /* nothing changes with clicks for any other contexts */
634 g_message("FocusIn on client for %lx", client
->window
);
636 if (client
!= focus_client
) {
637 focus_set_client(client
);
638 frame_adjust_focus(client
->frame
, TRUE
);
643 g_message("FocusOut on client for %lx", client
->window
);
645 /* are we a fullscreen window or a transient of one? (checks layer)
646 if we are then we need to be iconified since we are losing focus
648 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
649 !client_search_focus_tree_full(client
))
650 /* iconify fullscreen windows when they and their transients
652 client_iconify(client
, TRUE
, TRUE
);
653 frame_adjust_focus(client
->frame
, FALSE
);
656 if (client_normal(client
)) {
657 if (ob_state
== State_Starting
) {
658 /* move it to the top of the focus order */
659 guint desktop
= client
->desktop
;
660 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
661 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
663 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
665 } else if (config_focus_follow
) {
667 g_message("EnterNotify on %lx, focusing window",
670 client_focus(client
);
674 case ConfigureRequest
:
676 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
677 ConfigureRequest
, &ce
)) {
679 /* XXX if this causes bad things.. we can compress config req's
680 with the same mask. */
681 e
->xconfigurerequest
.value_mask
|=
682 ce
.xconfigurerequest
.value_mask
;
683 if (ce
.xconfigurerequest
.value_mask
& CWX
)
684 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
685 if (ce
.xconfigurerequest
.value_mask
& CWY
)
686 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
687 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
688 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
689 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
690 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
691 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
692 e
->xconfigurerequest
.border_width
=
693 ce
.xconfigurerequest
.border_width
;
694 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
695 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
698 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
699 if (client
->iconic
|| client
->shaded
) return;
701 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
702 client
->border_width
= e
->xconfigurerequest
.border_width
;
704 /* resize, then move, as specified in the EWMH section 7.7 */
705 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
710 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
711 e
->xconfigurerequest
.x
: client
->area
.x
;
712 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
713 e
->xconfigurerequest
.y
: client
->area
.y
;
714 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
715 e
->xconfigurerequest
.width
: client
->area
.width
;
716 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
717 e
->xconfigurerequest
.height
: client
->area
.height
;
719 switch (client
->gravity
) {
720 case NorthEastGravity
:
722 corner
= Corner_TopRight
;
724 case SouthWestGravity
:
726 corner
= Corner_BottomLeft
;
728 case SouthEastGravity
:
729 corner
= Corner_BottomRight
;
731 default: /* NorthWest, Static, etc */
732 corner
= Corner_TopLeft
;
735 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, TRUE
);
738 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
739 switch (e
->xconfigurerequest
.detail
) {
742 stacking_lower(CLIENT_AS_WINDOW(client
));
748 stacking_raise(CLIENT_AS_WINDOW(client
));
754 if (client
->ignore_unmaps
) {
755 client
->ignore_unmaps
--;
758 client_unmanage(client
);
761 client_unmanage(client
);
764 /* this is when the client is first taken captive in the frame */
765 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
768 This event is quite rare and is usually handled in unmapHandler.
769 However, if the window is unmapped when the reparent event occurs,
770 the window manager never sees it because an unmap event is not sent
771 to an already unmapped window.
774 /* we don't want the reparent event, put it back on the stack for the
775 X server to deal with after we unmanage the window */
776 XPutBackEvent(ob_display
, e
);
778 client_unmanage(client
);
781 g_message("MapRequest for 0x%lx", client
->window
);
782 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
783 does, we don't want it! */
784 if (screen_showing_desktop
)
785 screen_show_desktop(FALSE
);
786 client_iconify(client
, FALSE
, TRUE
);
787 if (!client
->frame
->visible
)
788 /* if its not visible still, then don't mess with it */
791 client_shade(client
, FALSE
);
792 client_focus(client
);
793 stacking_raise(CLIENT_AS_WINDOW(client
));
796 /* validate cuz we query stuff off the client here */
797 if (!client_validate(client
)) break;
799 if (e
->xclient
.format
!= 32) return;
801 msgtype
= e
->xclient
.message_type
;
802 if (msgtype
== prop_atoms
.wm_change_state
) {
803 /* compress changes into a single change */
804 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
805 client
->window
, &ce
)) {
806 /* XXX: it would be nice to compress ALL messages of a
807 type, not just messages in a row without other
808 message types between. */
809 if (ce
.xclient
.message_type
!= msgtype
) {
810 XPutBackEvent(ob_display
, &ce
);
813 e
->xclient
= ce
.xclient
;
815 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
816 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
817 /* compress changes into a single change */
818 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
819 client
->window
, &ce
)) {
820 /* XXX: it would be nice to compress ALL messages of a
821 type, not just messages in a row without other
822 message types between. */
823 if (ce
.xclient
.message_type
!= msgtype
) {
824 XPutBackEvent(ob_display
, &ce
);
827 e
->xclient
= ce
.xclient
;
829 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
830 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
831 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
833 } else if (msgtype
== prop_atoms
.net_wm_state
) {
834 /* can't compress these */
835 g_message("net_wm_state %s %ld %ld for 0x%lx",
836 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
837 e
->xclient
.data
.l
[0] == 1 ? "Add" :
838 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
839 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
841 client_set_state(client
, e
->xclient
.data
.l
[0],
842 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
843 } else if (msgtype
== prop_atoms
.net_close_window
) {
844 g_message("net_close_window for 0x%lx", client
->window
);
845 client_close(client
);
846 } else if (msgtype
== prop_atoms
.net_active_window
) {
847 g_message("net_active_window for 0x%lx", client
->window
);
848 client_activate(client
);
849 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
850 g_message("net_wm_moveresize for 0x%lx", client
->window
);
851 if ((Atom
)e
->xclient
.data
.l
[2] ==
852 prop_atoms
.net_wm_moveresize_size_topleft
||
853 (Atom
)e
->xclient
.data
.l
[2] ==
854 prop_atoms
.net_wm_moveresize_size_top
||
855 (Atom
)e
->xclient
.data
.l
[2] ==
856 prop_atoms
.net_wm_moveresize_size_topright
||
857 (Atom
)e
->xclient
.data
.l
[2] ==
858 prop_atoms
.net_wm_moveresize_size_right
||
859 (Atom
)e
->xclient
.data
.l
[2] ==
860 prop_atoms
.net_wm_moveresize_size_right
||
861 (Atom
)e
->xclient
.data
.l
[2] ==
862 prop_atoms
.net_wm_moveresize_size_bottomright
||
863 (Atom
)e
->xclient
.data
.l
[2] ==
864 prop_atoms
.net_wm_moveresize_size_bottom
||
865 (Atom
)e
->xclient
.data
.l
[2] ==
866 prop_atoms
.net_wm_moveresize_size_bottomleft
||
867 (Atom
)e
->xclient
.data
.l
[2] ==
868 prop_atoms
.net_wm_moveresize_size_left
||
869 (Atom
)e
->xclient
.data
.l
[2] ==
870 prop_atoms
.net_wm_moveresize_move
||
871 (Atom
)e
->xclient
.data
.l
[2] ==
872 prop_atoms
.net_wm_moveresize_size_keyboard
||
873 (Atom
)e
->xclient
.data
.l
[2] ==
874 prop_atoms
.net_wm_moveresize_move_keyboard
) {
876 moveresize_start(client
, e
->xclient
.data
.l
[0],
877 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
878 e
->xclient
.data
.l
[2]);
880 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
881 int oldg
= client
->gravity
;
882 int tmpg
, x
, y
, w
, h
;
884 if (e
->xclient
.data
.l
[0] & 0xff)
885 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
889 if (e
->xclient
.data
.l
[0] & 1 << 8)
890 x
= e
->xclient
.data
.l
[1];
893 if (e
->xclient
.data
.l
[0] & 1 << 9)
894 y
= e
->xclient
.data
.l
[2];
897 if (e
->xclient
.data
.l
[0] & 1 << 10)
898 w
= e
->xclient
.data
.l
[3];
901 if (e
->xclient
.data
.l
[0] & 1 << 11)
902 h
= e
->xclient
.data
.l
[4];
905 client
->gravity
= tmpg
;
906 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
907 client
->gravity
= oldg
;
911 /* validate cuz we query stuff off the client here */
912 if (!client_validate(client
)) break;
914 /* compress changes to a single property into a single change */
915 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
916 client
->window
, &ce
)) {
917 /* XXX: it would be nice to compress ALL changes to a property,
918 not just changes in a row without other props between. */
919 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
920 XPutBackEvent(ob_display
, &ce
);
925 msgtype
= e
->xproperty
.atom
;
926 if (msgtype
== XA_WM_NORMAL_HINTS
) {
927 client_update_normal_hints(client
);
928 /* normal hints can make a window non-resizable */
929 client_setup_decor_and_functions(client
);
931 else if (msgtype
== XA_WM_HINTS
)
932 client_update_wmhints(client
);
933 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
934 client_update_transient_for(client
);
935 client_get_type(client
);
936 /* type may have changed, so update the layer */
937 client_calc_layer(client
);
938 client_setup_decor_and_functions(client
);
940 else if (msgtype
== prop_atoms
.net_wm_name
||
941 msgtype
== prop_atoms
.wm_name
||
942 msgtype
== prop_atoms
.net_wm_icon_name
||
943 msgtype
== prop_atoms
.wm_icon_name
)
944 client_update_title(client
);
945 else if (msgtype
== prop_atoms
.wm_class
)
946 client_update_class(client
);
947 else if (msgtype
== prop_atoms
.wm_protocols
) {
948 client_update_protocols(client
);
949 client_setup_decor_and_functions(client
);
951 else if (msgtype
== prop_atoms
.net_wm_strut
)
952 client_update_strut(client
);
953 else if (msgtype
== prop_atoms
.net_wm_icon
||
954 msgtype
== prop_atoms
.kwm_win_icon
)
955 client_update_icons(client
);
959 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
960 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
961 frame_adjust_shape(client
->frame
);
967 static void event_handle_menu(Menu
*menu
, Client
*client
, XEvent
*e
)
971 g_message("EVENT %d", e
->type
);
974 g_message("BUTTON PRESS");
975 if (e
->xbutton
.button
== 3)
977 else if (e
->xbutton
.button
== 1) {
978 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
980 stacking_raise(MENU_AS_WINDOW(menu
));
984 g_message("BUTTON RELEASED");
985 if (!menu
->shown
) break;
987 /* grab_pointer_window(FALSE, None, menu->frame);*/
989 if (e
->xbutton
.button
== 1) {
990 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
994 guint ujunk
, b
, w
, h
;
995 XGetGeometry(ob_display
, e
->xbutton
.window
,
996 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
997 if (e
->xbutton
.x
>= (signed)-b
&&
998 e
->xbutton
.y
>= (signed)-b
&&
999 e
->xbutton
.x
< (signed)(w
+b
) &&
1000 e
->xbutton
.y
< (signed)(h
+b
)) {
1001 menu_entry_fire(entry
);
1009 g_message("enter/leave");
1010 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
1012 if (menu
->mouseover
)
1013 menu
->mouseover(entry
, e
->type
== EnterNotify
);
1015 menu_control_mouseover(entry
, e
->type
== EnterNotify
);
1017 menu_entry_render(entry
);
1023 void event_add_fd_handler(event_fd_handler
*h
) {
1024 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
1025 FD_SET(h
->fd
, &allset
);
1026 max_fd
= MAX(max_fd
, h
->fd
);
1029 static void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
1031 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
1034 static void find_max_fd()
1037 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
, (gpointer
)&tmpmax
);
1038 max_fd
= MAX(x_fd
, tmpmax
);
1039 max_fd
= MAX(ice_fd
, tmpmax
);
1042 void event_remove_fd(int n
)
1045 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
1049 static void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
1051 if (FD_ISSET( (int)n
, &selset
)) {
1052 event_fd_handler
*h
= (event_fd_handler
*)data
;
1053 g_assert(h
->fd
== (int)n
);
1054 h
->handler(h
->fd
, h
->data
);
1058 static void fd_event_handle()
1060 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
1063 static void event_handle_dock(Dock
*s
, XEvent
*e
)
1067 stacking_raise(DOCK_AS_WINDOW(s
));
1078 static void event_handle_dockapp(DockApp
*app
, XEvent
*e
)
1082 dock_app_drag(app
, &e
->xmotion
);
1085 if (app
->ignore_unmaps
) {
1086 app
->ignore_unmaps
--;
1089 dock_remove(app
, TRUE
);
1092 dock_remove(app
, FALSE
);
1094 case ReparentNotify
:
1095 dock_remove(app
, FALSE
);
1097 case ConfigureNotify
:
1098 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);