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 == NotifyAncestor || \
41 (e)->xfocus.detail > NotifyNonlinearVirtual)
42 #define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
43 (e)->xfocus.detail == NotifyInferior || \
44 (e)->xfocus.detail == NotifyAncestor || \
45 (e)->xfocus.detail > NotifyNonlinearVirtual)
47 Time event_lasttime
= 0;
49 /*! The value of the mask for the NumLock modifier */
50 unsigned int NumLockMask
;
51 /*! The value of the mask for the ScrollLock modifier */
52 unsigned int ScrollLockMask
;
53 /*! The key codes for the modifier keys */
54 static XModifierKeymap
*modmap
;
55 /*! Table of the constant modifier masks */
56 static const int mask_table
[] = {
57 ShiftMask
, LockMask
, ControlMask
, Mod1Mask
,
58 Mod2Mask
, Mod3Mask
, Mod4Mask
, Mod5Mask
60 static int mask_table_size
;
62 static fd_set selset
, allset
;
63 static int max_fd
, x_fd
;
64 static GData
*fd_handler_list
;
66 void fd_event_handle();
70 mask_table_size
= sizeof(mask_table
) / sizeof(mask_table
[0]);
72 /* get lock masks that are defined by the display (not constant) */
73 modmap
= XGetModifierMapping(ob_display
);
75 if (modmap
&& modmap
->max_keypermod
> 0) {
77 const size_t size
= mask_table_size
* modmap
->max_keypermod
;
78 /* get the values of the keyboard lock modifiers
79 Note: Caps lock is not retrieved the same way as Scroll and Num
80 lock since it doesn't need to be. */
81 const KeyCode num_lock
= XKeysymToKeycode(ob_display
, XK_Num_Lock
);
82 const KeyCode scroll_lock
= XKeysymToKeycode(ob_display
,
85 for (cnt
= 0; cnt
< size
; ++cnt
) {
86 if (! modmap
->modifiermap
[cnt
]) continue;
88 if (num_lock
== modmap
->modifiermap
[cnt
])
89 NumLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
90 if (scroll_lock
== modmap
->modifiermap
[cnt
])
91 ScrollLockMask
= mask_table
[cnt
/ modmap
->max_keypermod
];
96 max_fd
= x_fd
= ConnectionNumber(ob_display
);
97 FD_SET(x_fd
, &allset
);
98 g_datalist_init(&fd_handler_list
);
101 void event_shutdown()
103 XFreeModifiermap(modmap
);
104 g_datalist_clear(&fd_handler_list
);
110 struct timeval
*wait
;
111 gboolean had_event
= FALSE
;
115 There are slightly different event retrieval semantics here for
116 local (or high bandwidth) versus remote (or low bandwidth)
117 connections to the display/Xserver.
120 if (!XPending(ob_display
))
124 This XSync allows for far more compression of events, which
125 makes things like Motion events perform far far better. Since
126 it also means network traffic for every event instead of every
127 X events (where X is the number retrieved at a time), it
128 probably should not be used for setups where Openbox is
129 running on a remote/low bandwidth display/Xserver.
131 XSync(ob_display
, FALSE
);
132 if (!XEventsQueued(ob_display
, QueuedAlready
))
135 XNextEvent(ob_display
, &e
);
138 sn_display_process_event(ob_sn_display
, &e
);
146 timer_dispatch((GTimeVal
**)&wait
);
148 select(max_fd
+ 1, &selset
, NULL
, NULL
, wait
);
150 /* handle the X events as soon as possible? */
151 if (FD_ISSET(x_fd
, &selset
))
158 static Window
event_get_window(XEvent
*e
)
165 window
= e
->xmap
.window
;
168 window
= e
->xunmap
.window
;
171 window
= e
->xdestroywindow
.window
;
173 case ConfigureRequest
:
174 window
= e
->xconfigurerequest
.window
;
176 case ConfigureNotify
:
177 window
= e
->xconfigure
.window
;
181 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
182 switch (((XkbAnyEvent
*)&e
)->xkb_type
) {
184 window
= ((XkbBellNotifyEvent
*)&e
)->window
;
190 window
= e
->xany
.window
;
195 static void event_set_lasttime(XEvent
*e
)
197 /* grab the lasttime and hack up the state */
201 event_lasttime
= e
->xbutton
.time
;
204 event_lasttime
= e
->xkey
.time
;
207 event_lasttime
= e
->xkey
.time
;
210 event_lasttime
= e
->xmotion
.time
;
213 event_lasttime
= e
->xproperty
.time
;
217 event_lasttime
= e
->xcrossing
.time
;
220 event_lasttime
= CurrentTime
;
225 #define STRIP_MODS(s) \
226 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
227 /* kill off the Button1Mask etc, only want the modifiers */ \
228 s &= (ControlMask | ShiftMask | Mod1Mask | \
229 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
231 static void event_hack_mods(XEvent *e)
239 STRIP_MODS(e
->xbutton
.state
);
242 STRIP_MODS(e
->xkey
.state
);
245 STRIP_MODS(e
->xkey
.state
);
246 /* remove from the state the mask of the modifier being released, if
247 it is a modifier key being released (this is a little ugly..) */
248 kp
= modmap
->modifiermap
;
249 for (i
= 0; i
< mask_table_size
; ++i
) {
250 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
251 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
252 /* remove the mask for it */
253 e
->xkey
.state
&= ~mask_table
[i
];
254 /* cause the first loop to break; */
256 break; /* get outta here! */
263 STRIP_MODS(e
->xmotion
.state
);
264 /* compress events */
267 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
269 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
270 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
277 static gboolean
event_ignore(XEvent
*e
, Client
*client
)
281 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
282 because of RevertToPointerRoot. If the focus ends up reverting to
283 pointer root on a workspace change, then the FocusIn event that we
284 want will be of type NotifyAncestor. This situation does not occur
285 for FocusOut, so it is safely ignored there.
287 if (INVALID_FOCUSIN(e
) ||
290 g_message("FocusIn on %lx mode %d detail %d IGNORED", e
->xfocus
.window
,
291 e
->xfocus
.mode
, e
->xfocus
.detail
);
293 /* says a client was not found for the event (or a valid FocusIn
296 e
->xfocus
.window
= None
;
301 g_message("FocusIn on %lx mode %d detail %d", e
->xfocus
.window
,
302 e
->xfocus
.mode
, e
->xfocus
.detail
);
306 if (INVALID_FOCUSOUT(e
)) {
308 g_message("FocusOut on %lx mode %d detail %d IGNORED",
309 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
315 g_message("FocusOut on %lx mode %d detail %d",
316 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
321 gboolean fallback
= TRUE
;
324 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
325 e
->xfocus
.window
,&fe
))
326 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
328 if (fe
.type
== FocusOut
) {
330 g_message("found pending FocusOut");
332 if (!INVALID_FOCUSOUT(&fe
)) {
333 /* if there is a VALID FocusOut still coming, don't
334 fallback focus yet, we'll deal with it then */
335 XPutBackEvent(ob_display
, &fe
);
341 g_message("found pending FocusIn");
343 /* is the focused window getting a FocusOut/In back to
345 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
346 !event_ignore(&fe
, client
)) {
348 g_message("focused window got an Out/In back to "
349 "itself IGNORED both");
354 /* once all the FocusOut's have been dealt with, if there
355 is a FocusIn still left and it is valid, then use it */
357 /* secret magic way of event_process telling us that no
358 client was found for the FocusIn event. ^_^ */
359 if (fe
.xfocus
.window
!= None
) {
367 g_message("no valid FocusIn and no FocusOut events found, "
370 focus_fallback(Fallback_NoFocus
);
376 /* NotifyUngrab occurs when a mouse button is released and the event is
377 caused, like when lowering a window */
378 /* NotifyVirtual occurs when ungrabbing the pointer */
379 if (e
->xcrossing
.mode
== NotifyGrab
||
380 e
->xcrossing
.detail
== NotifyInferior
||
381 (e
->xcrossing
.mode
== NotifyUngrab
&&
382 e
->xcrossing
.detail
== NotifyVirtual
)) {
384 g_message("%sNotify mode %d detail %d on %lx IGNORED",
385 (e
->type
== EnterNotify
? "Enter" : "Leave"),
387 e
->xcrossing
.detail
, client
?client
->window
:0);
392 g_message("%sNotify mode %d detail %d on %lx",
393 (e
->type
== EnterNotify
? "Enter" : "Leave"),
395 e
->xcrossing
.detail
, client
?client
->window
:0);
402 static void event_process(XEvent
*e
)
405 Client
*client
= NULL
;
407 DockApp
*dockapp
= NULL
;
409 ObWindow
*obwin
= NULL
;
411 window
= event_get_window(e
);
412 if ((obwin
= g_hash_table_lookup(window_map
, &window
))) {
413 switch (obwin
->type
) {
415 dock
= WINDOW_AS_DOCK(obwin
);
418 dockapp
= WINDOW_AS_DOCKAPP(obwin
);
421 menu
= WINDOW_AS_MENU(obwin
);
424 client
= WINDOW_AS_CLIENT(obwin
);
426 case Window_Internal
:
427 /* not to be used for events */
428 g_assert_not_reached();
433 event_set_lasttime(e
);
435 if (event_ignore(e
, client
))
438 /* deal with it in the kernel */
440 event_handle_menu(menu
, client
, e
);
443 event_handle_client(client
, e
);
445 event_handle_dockapp(dockapp
, e
);
447 event_handle_dock(dock
, e
);
448 else if (window
== ob_root
)
449 event_handle_root(e
);
450 else if (e
->type
== MapRequest
)
451 client_manage(window
);
452 else if (e
->type
== ConfigureRequest
) {
453 /* unhandled configure requests must be used to configure the
457 xwc
.x
= e
->xconfigurerequest
.x
;
458 xwc
.y
= e
->xconfigurerequest
.y
;
459 xwc
.width
= e
->xconfigurerequest
.width
;
460 xwc
.height
= e
->xconfigurerequest
.height
;
461 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
462 xwc
.sibling
= e
->xconfigurerequest
.above
;
463 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
465 /* we are not to be held responsible if someone sends us an
467 xerror_set_ignore(TRUE
);
468 XConfigureWindow(ob_display
, window
,
469 e
->xconfigurerequest
.value_mask
, &xwc
);
470 xerror_set_ignore(FALSE
);
473 if (moveresize_in_progress
)
474 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
475 e
->type
== ButtonPress
||
476 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
479 return; /* no dispatch! */
483 /* user input (action-bound) events */
485 if (e->type == ButtonPress || e->type == ButtonRelease ||
486 e->type == MotionNotify)
487 mouse_event(e, client);
488 else if (e->type == KeyPress || e->type == KeyRelease)
492 /* dispatch the event to registered handlers */
493 dispatch_x(e
, client
);
496 static void event_handle_root(XEvent
*e
)
502 if (e
->xclient
.format
!= 32) break;
504 msgtype
= e
->xclient
.message_type
;
505 if (msgtype
== prop_atoms
.net_current_desktop
) {
506 unsigned int d
= e
->xclient
.data
.l
[0];
507 if (d
< screen_num_desktops
)
508 screen_set_desktop(d
);
509 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
510 unsigned int d
= e
->xclient
.data
.l
[0];
512 screen_set_num_desktops(d
);
513 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
514 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
518 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
519 screen_update_desktop_names();
520 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
521 screen_update_layout();
523 case ConfigureNotify
:
525 XRRUpdateConfiguration(e
);
527 if (e
->xconfigure
.width
!= screen_physical_size
.width
||
528 e
->xconfigure
.height
!= screen_physical_size
.height
)
529 screen_resize(e
->xconfigure
.width
, e
->xconfigure
.height
);
534 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
535 g_message("VIDMODE EVENT");
541 static void event_handle_client(Client
*client
, XEvent
*e
)
550 /* Wheel buttons don't draw because they are an instant click, so it
551 is a waste of resources to go drawing it. */
552 if (!(e
->xbutton
.button
== 4 || e
->xbutton
.button
== 5)) {
553 switch (frame_context(client
, e
->xbutton
.window
)) {
554 case Context_Maximize
:
555 client
->frame
->max_press
= (e
->type
== ButtonPress
);
556 framerender_frame(client
->frame
);
559 client
->frame
->close_press
= (e
->type
== ButtonPress
);
560 framerender_frame(client
->frame
);
562 case Context_Iconify
:
563 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
564 framerender_frame(client
->frame
);
566 case Context_AllDesktops
:
567 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
568 framerender_frame(client
->frame
);
571 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
572 framerender_frame(client
->frame
);
575 /* nothing changes with clicks for any other contexts */
582 g_message("FocusIn on client for %lx", client
->window
);
584 if (client
!= focus_client
) {
585 focus_set_client(client
);
586 frame_adjust_focus(client
->frame
, TRUE
);
591 g_message("FocusOut on client for %lx", client
->window
);
593 /* are we a fullscreen window or a transient of one? (checks layer)
594 if we are then we need to be iconified since we are losing focus
596 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
597 !client_search_focus_tree_full(client
))
598 /* iconify fullscreen windows when they and their transients
600 client_iconify(client
, TRUE
, TRUE
);
601 frame_adjust_focus(client
->frame
, FALSE
);
604 if (client_normal(client
)) {
605 if (ob_state
== State_Starting
) {
606 /* move it to the top of the focus order */
607 guint desktop
= client
->desktop
;
608 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
609 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
611 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
613 } else if (config_focus_follow
) {
615 g_message("EnterNotify on %lx, focusing window",
618 client_focus(client
);
622 case ConfigureRequest
:
624 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
625 ConfigureRequest
, &ce
)) {
627 /* XXX if this causes bad things.. we can compress config req's
628 with the same mask. */
629 e
->xconfigurerequest
.value_mask
|=
630 ce
.xconfigurerequest
.value_mask
;
631 if (ce
.xconfigurerequest
.value_mask
& CWX
)
632 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
633 if (ce
.xconfigurerequest
.value_mask
& CWY
)
634 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
635 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
636 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
637 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
638 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
639 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
640 e
->xconfigurerequest
.border_width
=
641 ce
.xconfigurerequest
.border_width
;
642 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
643 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
646 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
647 if (client
->iconic
|| client
->shaded
) return;
649 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
650 client
->border_width
= e
->xconfigurerequest
.border_width
;
652 /* resize, then move, as specified in the EWMH section 7.7 */
653 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
658 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
659 e
->xconfigurerequest
.x
: client
->area
.x
;
660 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
661 e
->xconfigurerequest
.y
: client
->area
.y
;
662 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
663 e
->xconfigurerequest
.width
: client
->area
.width
;
664 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
665 e
->xconfigurerequest
.height
: client
->area
.height
;
667 switch (client
->gravity
) {
668 case NorthEastGravity
:
670 corner
= Corner_TopRight
;
672 case SouthWestGravity
:
674 corner
= Corner_BottomLeft
;
676 case SouthEastGravity
:
677 corner
= Corner_BottomRight
;
679 default: /* NorthWest, Static, etc */
680 corner
= Corner_TopLeft
;
683 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, FALSE
);
686 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
687 switch (e
->xconfigurerequest
.detail
) {
690 stacking_lower(CLIENT_AS_WINDOW(client
));
696 stacking_raise(CLIENT_AS_WINDOW(client
));
702 if (client
->ignore_unmaps
) {
703 client
->ignore_unmaps
--;
706 client_unmanage(client
);
709 client_unmanage(client
);
712 /* this is when the client is first taken captive in the frame */
713 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
716 This event is quite rare and is usually handled in unmapHandler.
717 However, if the window is unmapped when the reparent event occurs,
718 the window manager never sees it because an unmap event is not sent
719 to an already unmapped window.
722 /* we don't want the reparent event, put it back on the stack for the
723 X server to deal with after we unmanage the window */
724 XPutBackEvent(ob_display
, e
);
726 client_unmanage(client
);
729 g_message("MapRequest for 0x%lx", client
->window
);
730 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
731 does, we don't want it! */
732 if (screen_showing_desktop
)
733 screen_show_desktop(FALSE
);
734 client_iconify(client
, FALSE
, TRUE
);
735 if (!client
->frame
->visible
)
736 /* if its not visible still, then don't mess with it */
739 client_shade(client
, FALSE
);
740 client_focus(client
);
741 stacking_raise(CLIENT_AS_WINDOW(client
));
744 /* validate cuz we query stuff off the client here */
745 if (!client_validate(client
)) break;
747 if (e
->xclient
.format
!= 32) return;
749 msgtype
= e
->xclient
.message_type
;
750 if (msgtype
== prop_atoms
.wm_change_state
) {
751 /* compress changes into a single change */
752 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
753 client
->window
, &ce
)) {
754 /* XXX: it would be nice to compress ALL messages of a
755 type, not just messages in a row without other
756 message types between. */
757 if (ce
.xclient
.message_type
!= msgtype
) {
758 XPutBackEvent(ob_display
, &ce
);
761 e
->xclient
= ce
.xclient
;
763 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
764 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
765 /* compress changes into a single change */
766 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
767 client
->window
, &ce
)) {
768 /* XXX: it would be nice to compress ALL messages of a
769 type, not just messages in a row without other
770 message types between. */
771 if (ce
.xclient
.message_type
!= msgtype
) {
772 XPutBackEvent(ob_display
, &ce
);
775 e
->xclient
= ce
.xclient
;
777 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
778 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
779 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
781 } else if (msgtype
== prop_atoms
.net_wm_state
) {
782 /* can't compress these */
783 g_message("net_wm_state %s %ld %ld for 0x%lx",
784 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
785 e
->xclient
.data
.l
[0] == 1 ? "Add" :
786 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
787 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
789 client_set_state(client
, e
->xclient
.data
.l
[0],
790 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
791 } else if (msgtype
== prop_atoms
.net_close_window
) {
792 g_message("net_close_window for 0x%lx", client
->window
);
793 client_close(client
);
794 } else if (msgtype
== prop_atoms
.net_active_window
) {
795 g_message("net_active_window for 0x%lx", client
->window
);
796 client_activate(client
);
797 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
798 g_message("net_wm_moveresize for 0x%lx", client
->window
);
799 if ((Atom
)e
->xclient
.data
.l
[2] ==
800 prop_atoms
.net_wm_moveresize_size_topleft
||
801 (Atom
)e
->xclient
.data
.l
[2] ==
802 prop_atoms
.net_wm_moveresize_size_top
||
803 (Atom
)e
->xclient
.data
.l
[2] ==
804 prop_atoms
.net_wm_moveresize_size_topright
||
805 (Atom
)e
->xclient
.data
.l
[2] ==
806 prop_atoms
.net_wm_moveresize_size_right
||
807 (Atom
)e
->xclient
.data
.l
[2] ==
808 prop_atoms
.net_wm_moveresize_size_right
||
809 (Atom
)e
->xclient
.data
.l
[2] ==
810 prop_atoms
.net_wm_moveresize_size_bottomright
||
811 (Atom
)e
->xclient
.data
.l
[2] ==
812 prop_atoms
.net_wm_moveresize_size_bottom
||
813 (Atom
)e
->xclient
.data
.l
[2] ==
814 prop_atoms
.net_wm_moveresize_size_bottomleft
||
815 (Atom
)e
->xclient
.data
.l
[2] ==
816 prop_atoms
.net_wm_moveresize_size_left
||
817 (Atom
)e
->xclient
.data
.l
[2] ==
818 prop_atoms
.net_wm_moveresize_move
||
819 (Atom
)e
->xclient
.data
.l
[2] ==
820 prop_atoms
.net_wm_moveresize_size_keyboard
||
821 (Atom
)e
->xclient
.data
.l
[2] ==
822 prop_atoms
.net_wm_moveresize_move_keyboard
) {
824 moveresize_start(client
, e
->xclient
.data
.l
[0],
825 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
826 e
->xclient
.data
.l
[2]);
828 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
829 int oldg
= client
->gravity
;
830 int tmpg
, x
, y
, w
, h
;
832 if (e
->xclient
.data
.l
[0] & 0xff)
833 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
837 if (e
->xclient
.data
.l
[0] & 1 << 8)
838 x
= e
->xclient
.data
.l
[1];
841 if (e
->xclient
.data
.l
[0] & 1 << 9)
842 y
= e
->xclient
.data
.l
[2];
845 if (e
->xclient
.data
.l
[0] & 1 << 10)
846 w
= e
->xclient
.data
.l
[3];
849 if (e
->xclient
.data
.l
[0] & 1 << 11)
850 h
= e
->xclient
.data
.l
[4];
853 client
->gravity
= tmpg
;
854 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
855 client
->gravity
= oldg
;
859 /* validate cuz we query stuff off the client here */
860 if (!client_validate(client
)) break;
862 /* compress changes to a single property into a single change */
863 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
864 client
->window
, &ce
)) {
865 /* XXX: it would be nice to compress ALL changes to a property,
866 not just changes in a row without other props between. */
867 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
868 XPutBackEvent(ob_display
, &ce
);
873 msgtype
= e
->xproperty
.atom
;
874 if (msgtype
== XA_WM_NORMAL_HINTS
) {
875 client_update_normal_hints(client
);
876 /* normal hints can make a window non-resizable */
877 client_setup_decor_and_functions(client
);
879 else if (msgtype
== XA_WM_HINTS
)
880 client_update_wmhints(client
);
881 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
882 client_update_transient_for(client
);
883 client_get_type(client
);
884 /* type may have changed, so update the layer */
885 client_calc_layer(client
);
886 client_setup_decor_and_functions(client
);
888 else if (msgtype
== prop_atoms
.net_wm_name
||
889 msgtype
== prop_atoms
.wm_name
||
890 msgtype
== prop_atoms
.net_wm_icon_name
||
891 msgtype
== prop_atoms
.wm_icon_name
)
892 client_update_title(client
);
893 else if (msgtype
== prop_atoms
.wm_class
)
894 client_update_class(client
);
895 else if (msgtype
== prop_atoms
.wm_protocols
) {
896 client_update_protocols(client
);
897 client_setup_decor_and_functions(client
);
899 else if (msgtype
== prop_atoms
.net_wm_strut
)
900 client_update_strut(client
);
901 else if (msgtype
== prop_atoms
.net_wm_icon
||
902 msgtype
== prop_atoms
.kwm_win_icon
)
903 client_update_icons(client
);
907 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
908 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
909 frame_adjust_shape(client
->frame
);
915 static void event_handle_menu(Menu
*menu
, Client
*client
, XEvent
*e
)
919 g_message("EVENT %d", e
->type
);
922 g_message("BUTTON PRESS");
923 if (e
->xbutton
.button
== 3)
925 else if (e
->xbutton
.button
== 1) {
926 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
928 stacking_raise(MENU_AS_WINDOW(menu
));
932 g_message("BUTTON RELEASED");
933 if (!menu
->shown
) break;
935 /* grab_pointer_window(FALSE, None, menu->frame);*/
937 if (e
->xbutton
.button
== 1) {
938 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
942 guint ujunk
, b
, w
, h
;
943 XGetGeometry(ob_display
, e
->xbutton
.window
,
944 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
945 if (e
->xbutton
.x
>= (signed)-b
&&
946 e
->xbutton
.y
>= (signed)-b
&&
947 e
->xbutton
.x
< (signed)(w
+b
) &&
948 e
->xbutton
.y
< (signed)(h
+b
)) {
949 menu_entry_fire(entry
);
957 g_message("enter/leave");
958 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
961 menu
->mouseover(entry
, e
->type
== EnterNotify
);
963 menu_control_mouseover(entry
, e
->type
== EnterNotify
);
965 menu_entry_render(entry
);
971 void event_add_fd_handler(event_fd_handler
*h
) {
972 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
973 FD_SET(h
->fd
, &allset
);
974 max_fd
= MAX(max_fd
, h
->fd
);
977 void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
979 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
982 void event_remove_fd(int n
)
986 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
987 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
, (gpointer
)&tmpmax
);
988 max_fd
= MAX(x_fd
, tmpmax
);
991 void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
993 if (FD_ISSET( (int)n
, &selset
)) {
994 event_fd_handler
*h
= (event_fd_handler
*)data
;
995 g_assert(h
->fd
== (int)n
);
996 h
->handler(h
->fd
, h
->data
);
1000 void fd_event_handle()
1002 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
1005 static void event_handle_dock(Dock
*s
, XEvent
*e
)
1009 stacking_raise(DOCK_AS_WINDOW(s
));
1020 static void event_handle_dockapp(DockApp
*app
, XEvent
*e
)
1024 dock_app_drag(app
, &e
->xmotion
);
1027 if (app
->ignore_unmaps
) {
1028 app
->ignore_unmaps
--;
1031 dock_remove(app
, TRUE
);
1034 dock_remove(app
, FALSE
);
1036 case ReparentNotify
:
1037 dock_remove(app
, FALSE
);
1039 case ConfigureNotify
:
1040 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);