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
346 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
347 !event_ignore(&fe
, client
)) {
349 if focus_client is not set, then we can't do
350 this. we need the FocusIn. This happens in the
351 case when the set_focus_client(NULL) in the
352 focus_fallback function fires and then
353 focus_fallback picks the currently focused
354 window (such as on a SendToDesktop-esque action.
358 g_message("focused window got an Out/In back to "
359 "itself IGNORED both");
365 g_message("focused window got an Out/In back to "
366 "itself but focus_client was null "
367 "IGNORED just the Out");
373 /* once all the FocusOut's have been dealt with, if there
374 is a FocusIn still left and it is valid, then use it */
376 /* secret magic way of event_process telling us that no
377 client was found for the FocusIn event. ^_^ */
378 if (fe
.xfocus
.window
!= None
) {
386 g_message("no valid FocusIn and no FocusOut events found, "
389 focus_fallback(Fallback_NoFocus
);
395 /* NotifyUngrab occurs when a mouse button is released and the event is
396 caused, like when lowering a window */
397 /* NotifyVirtual occurs when ungrabbing the pointer */
398 if (e
->xcrossing
.mode
== NotifyGrab
||
399 e
->xcrossing
.detail
== NotifyInferior
||
400 (e
->xcrossing
.mode
== NotifyUngrab
&&
401 e
->xcrossing
.detail
== NotifyVirtual
)) {
403 g_message("%sNotify mode %d detail %d on %lx IGNORED",
404 (e
->type
== EnterNotify
? "Enter" : "Leave"),
406 e
->xcrossing
.detail
, client
?client
->window
:0);
411 g_message("%sNotify mode %d detail %d on %lx",
412 (e
->type
== EnterNotify
? "Enter" : "Leave"),
414 e
->xcrossing
.detail
, client
?client
->window
:0);
421 static void event_process(XEvent
*e
)
424 Client
*client
= NULL
;
426 DockApp
*dockapp
= NULL
;
428 ObWindow
*obwin
= NULL
;
430 window
= event_get_window(e
);
431 if ((obwin
= g_hash_table_lookup(window_map
, &window
))) {
432 switch (obwin
->type
) {
434 dock
= WINDOW_AS_DOCK(obwin
);
437 dockapp
= WINDOW_AS_DOCKAPP(obwin
);
440 menu
= WINDOW_AS_MENU(obwin
);
443 client
= WINDOW_AS_CLIENT(obwin
);
445 case Window_Internal
:
446 /* not to be used for events */
447 g_assert_not_reached();
452 event_set_lasttime(e
);
454 if (event_ignore(e
, client
))
457 /* deal with it in the kernel */
459 event_handle_menu(menu
, client
, e
);
462 event_handle_client(client
, e
);
464 event_handle_dockapp(dockapp
, e
);
466 event_handle_dock(dock
, e
);
467 else if (window
== ob_root
)
468 event_handle_root(e
);
469 else if (e
->type
== MapRequest
)
470 client_manage(window
);
471 else if (e
->type
== ConfigureRequest
) {
472 /* unhandled configure requests must be used to configure the
476 xwc
.x
= e
->xconfigurerequest
.x
;
477 xwc
.y
= e
->xconfigurerequest
.y
;
478 xwc
.width
= e
->xconfigurerequest
.width
;
479 xwc
.height
= e
->xconfigurerequest
.height
;
480 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
481 xwc
.sibling
= e
->xconfigurerequest
.above
;
482 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
484 /* we are not to be held responsible if someone sends us an
486 xerror_set_ignore(TRUE
);
487 XConfigureWindow(ob_display
, window
,
488 e
->xconfigurerequest
.value_mask
, &xwc
);
489 xerror_set_ignore(FALSE
);
492 if (moveresize_in_progress
)
493 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
494 e
->type
== ButtonPress
||
495 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
498 return; /* no dispatch! */
502 /* user input (action-bound) events */
504 if (e->type == ButtonPress || e->type == ButtonRelease ||
505 e->type == MotionNotify)
506 mouse_event(e, client);
507 else if (e->type == KeyPress || e->type == KeyRelease)
511 /* dispatch the event to registered handlers */
512 dispatch_x(e
, client
);
515 static void event_handle_root(XEvent
*e
)
521 if (e
->xclient
.format
!= 32) break;
523 msgtype
= e
->xclient
.message_type
;
524 if (msgtype
== prop_atoms
.net_current_desktop
) {
525 unsigned int d
= e
->xclient
.data
.l
[0];
526 if (d
< screen_num_desktops
)
527 screen_set_desktop(d
);
528 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
529 unsigned int d
= e
->xclient
.data
.l
[0];
531 screen_set_num_desktops(d
);
532 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
533 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
537 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
538 screen_update_desktop_names();
539 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
540 screen_update_layout();
542 case ConfigureNotify
:
544 XRRUpdateConfiguration(e
);
546 if (e
->xconfigure
.width
!= screen_physical_size
.width
||
547 e
->xconfigure
.height
!= screen_physical_size
.height
)
548 screen_resize(e
->xconfigure
.width
, e
->xconfigure
.height
);
553 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
554 g_message("VIDMODE EVENT");
560 static void event_handle_client(Client
*client
, XEvent
*e
)
569 /* Wheel buttons don't draw because they are an instant click, so it
570 is a waste of resources to go drawing it. */
571 if (!(e
->xbutton
.button
== 4 || e
->xbutton
.button
== 5)) {
572 switch (frame_context(client
, e
->xbutton
.window
)) {
573 case Context_Maximize
:
574 client
->frame
->max_press
= (e
->type
== ButtonPress
);
575 framerender_frame(client
->frame
);
578 client
->frame
->close_press
= (e
->type
== ButtonPress
);
579 framerender_frame(client
->frame
);
581 case Context_Iconify
:
582 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
583 framerender_frame(client
->frame
);
585 case Context_AllDesktops
:
586 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
587 framerender_frame(client
->frame
);
590 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
591 framerender_frame(client
->frame
);
594 /* nothing changes with clicks for any other contexts */
601 g_message("FocusIn on client for %lx", client
->window
);
603 if (client
!= focus_client
) {
604 focus_set_client(client
);
605 frame_adjust_focus(client
->frame
, TRUE
);
610 g_message("FocusOut on client for %lx", client
->window
);
612 /* are we a fullscreen window or a transient of one? (checks layer)
613 if we are then we need to be iconified since we are losing focus
615 if (client
->layer
== Layer_Fullscreen
&& !client
->iconic
&&
616 !client_search_focus_tree_full(client
))
617 /* iconify fullscreen windows when they and their transients
619 client_iconify(client
, TRUE
, TRUE
);
620 frame_adjust_focus(client
->frame
, FALSE
);
623 if (client_normal(client
)) {
624 if (ob_state
== State_Starting
) {
625 /* move it to the top of the focus order */
626 guint desktop
= client
->desktop
;
627 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
628 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
630 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
632 } else if (config_focus_follow
) {
634 g_message("EnterNotify on %lx, focusing window",
637 client_focus(client
);
641 case ConfigureRequest
:
643 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
644 ConfigureRequest
, &ce
)) {
646 /* XXX if this causes bad things.. we can compress config req's
647 with the same mask. */
648 e
->xconfigurerequest
.value_mask
|=
649 ce
.xconfigurerequest
.value_mask
;
650 if (ce
.xconfigurerequest
.value_mask
& CWX
)
651 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
652 if (ce
.xconfigurerequest
.value_mask
& CWY
)
653 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
654 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
655 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
656 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
657 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
658 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
659 e
->xconfigurerequest
.border_width
=
660 ce
.xconfigurerequest
.border_width
;
661 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
662 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
665 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
666 if (client
->iconic
|| client
->shaded
) return;
668 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
669 client
->border_width
= e
->xconfigurerequest
.border_width
;
671 /* resize, then move, as specified in the EWMH section 7.7 */
672 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
677 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
678 e
->xconfigurerequest
.x
: client
->area
.x
;
679 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
680 e
->xconfigurerequest
.y
: client
->area
.y
;
681 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
682 e
->xconfigurerequest
.width
: client
->area
.width
;
683 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
684 e
->xconfigurerequest
.height
: client
->area
.height
;
686 switch (client
->gravity
) {
687 case NorthEastGravity
:
689 corner
= Corner_TopRight
;
691 case SouthWestGravity
:
693 corner
= Corner_BottomLeft
;
695 case SouthEastGravity
:
696 corner
= Corner_BottomRight
;
698 default: /* NorthWest, Static, etc */
699 corner
= Corner_TopLeft
;
702 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, TRUE
);
705 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
706 switch (e
->xconfigurerequest
.detail
) {
709 stacking_lower(CLIENT_AS_WINDOW(client
));
715 stacking_raise(CLIENT_AS_WINDOW(client
));
721 if (client
->ignore_unmaps
) {
722 client
->ignore_unmaps
--;
725 client_unmanage(client
);
728 client_unmanage(client
);
731 /* this is when the client is first taken captive in the frame */
732 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
735 This event is quite rare and is usually handled in unmapHandler.
736 However, if the window is unmapped when the reparent event occurs,
737 the window manager never sees it because an unmap event is not sent
738 to an already unmapped window.
741 /* we don't want the reparent event, put it back on the stack for the
742 X server to deal with after we unmanage the window */
743 XPutBackEvent(ob_display
, e
);
745 client_unmanage(client
);
748 g_message("MapRequest for 0x%lx", client
->window
);
749 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
750 does, we don't want it! */
751 if (screen_showing_desktop
)
752 screen_show_desktop(FALSE
);
753 client_iconify(client
, FALSE
, TRUE
);
754 if (!client
->frame
->visible
)
755 /* if its not visible still, then don't mess with it */
758 client_shade(client
, FALSE
);
759 client_focus(client
);
760 stacking_raise(CLIENT_AS_WINDOW(client
));
763 /* validate cuz we query stuff off the client here */
764 if (!client_validate(client
)) break;
766 if (e
->xclient
.format
!= 32) return;
768 msgtype
= e
->xclient
.message_type
;
769 if (msgtype
== prop_atoms
.wm_change_state
) {
770 /* compress changes into a single change */
771 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
772 client
->window
, &ce
)) {
773 /* XXX: it would be nice to compress ALL messages of a
774 type, not just messages in a row without other
775 message types between. */
776 if (ce
.xclient
.message_type
!= msgtype
) {
777 XPutBackEvent(ob_display
, &ce
);
780 e
->xclient
= ce
.xclient
;
782 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
783 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
784 /* compress changes into a single change */
785 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
786 client
->window
, &ce
)) {
787 /* XXX: it would be nice to compress ALL messages of a
788 type, not just messages in a row without other
789 message types between. */
790 if (ce
.xclient
.message_type
!= msgtype
) {
791 XPutBackEvent(ob_display
, &ce
);
794 e
->xclient
= ce
.xclient
;
796 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
797 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
798 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
800 } else if (msgtype
== prop_atoms
.net_wm_state
) {
801 /* can't compress these */
802 g_message("net_wm_state %s %ld %ld for 0x%lx",
803 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
804 e
->xclient
.data
.l
[0] == 1 ? "Add" :
805 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
806 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
808 client_set_state(client
, e
->xclient
.data
.l
[0],
809 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
810 } else if (msgtype
== prop_atoms
.net_close_window
) {
811 g_message("net_close_window for 0x%lx", client
->window
);
812 client_close(client
);
813 } else if (msgtype
== prop_atoms
.net_active_window
) {
814 g_message("net_active_window for 0x%lx", client
->window
);
815 client_activate(client
);
816 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
817 g_message("net_wm_moveresize for 0x%lx", client
->window
);
818 if ((Atom
)e
->xclient
.data
.l
[2] ==
819 prop_atoms
.net_wm_moveresize_size_topleft
||
820 (Atom
)e
->xclient
.data
.l
[2] ==
821 prop_atoms
.net_wm_moveresize_size_top
||
822 (Atom
)e
->xclient
.data
.l
[2] ==
823 prop_atoms
.net_wm_moveresize_size_topright
||
824 (Atom
)e
->xclient
.data
.l
[2] ==
825 prop_atoms
.net_wm_moveresize_size_right
||
826 (Atom
)e
->xclient
.data
.l
[2] ==
827 prop_atoms
.net_wm_moveresize_size_right
||
828 (Atom
)e
->xclient
.data
.l
[2] ==
829 prop_atoms
.net_wm_moveresize_size_bottomright
||
830 (Atom
)e
->xclient
.data
.l
[2] ==
831 prop_atoms
.net_wm_moveresize_size_bottom
||
832 (Atom
)e
->xclient
.data
.l
[2] ==
833 prop_atoms
.net_wm_moveresize_size_bottomleft
||
834 (Atom
)e
->xclient
.data
.l
[2] ==
835 prop_atoms
.net_wm_moveresize_size_left
||
836 (Atom
)e
->xclient
.data
.l
[2] ==
837 prop_atoms
.net_wm_moveresize_move
||
838 (Atom
)e
->xclient
.data
.l
[2] ==
839 prop_atoms
.net_wm_moveresize_size_keyboard
||
840 (Atom
)e
->xclient
.data
.l
[2] ==
841 prop_atoms
.net_wm_moveresize_move_keyboard
) {
843 moveresize_start(client
, e
->xclient
.data
.l
[0],
844 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
845 e
->xclient
.data
.l
[2]);
847 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
848 int oldg
= client
->gravity
;
849 int tmpg
, x
, y
, w
, h
;
851 if (e
->xclient
.data
.l
[0] & 0xff)
852 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
856 if (e
->xclient
.data
.l
[0] & 1 << 8)
857 x
= e
->xclient
.data
.l
[1];
860 if (e
->xclient
.data
.l
[0] & 1 << 9)
861 y
= e
->xclient
.data
.l
[2];
864 if (e
->xclient
.data
.l
[0] & 1 << 10)
865 w
= e
->xclient
.data
.l
[3];
868 if (e
->xclient
.data
.l
[0] & 1 << 11)
869 h
= e
->xclient
.data
.l
[4];
872 client
->gravity
= tmpg
;
873 client_configure(client
, Corner_TopLeft
, x
, y
, w
, h
, TRUE
, TRUE
);
874 client
->gravity
= oldg
;
878 /* validate cuz we query stuff off the client here */
879 if (!client_validate(client
)) break;
881 /* compress changes to a single property into a single change */
882 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
883 client
->window
, &ce
)) {
884 /* XXX: it would be nice to compress ALL changes to a property,
885 not just changes in a row without other props between. */
886 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
887 XPutBackEvent(ob_display
, &ce
);
892 msgtype
= e
->xproperty
.atom
;
893 if (msgtype
== XA_WM_NORMAL_HINTS
) {
894 client_update_normal_hints(client
);
895 /* normal hints can make a window non-resizable */
896 client_setup_decor_and_functions(client
);
898 else if (msgtype
== XA_WM_HINTS
)
899 client_update_wmhints(client
);
900 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
901 client_update_transient_for(client
);
902 client_get_type(client
);
903 /* type may have changed, so update the layer */
904 client_calc_layer(client
);
905 client_setup_decor_and_functions(client
);
907 else if (msgtype
== prop_atoms
.net_wm_name
||
908 msgtype
== prop_atoms
.wm_name
||
909 msgtype
== prop_atoms
.net_wm_icon_name
||
910 msgtype
== prop_atoms
.wm_icon_name
)
911 client_update_title(client
);
912 else if (msgtype
== prop_atoms
.wm_class
)
913 client_update_class(client
);
914 else if (msgtype
== prop_atoms
.wm_protocols
) {
915 client_update_protocols(client
);
916 client_setup_decor_and_functions(client
);
918 else if (msgtype
== prop_atoms
.net_wm_strut
)
919 client_update_strut(client
);
920 else if (msgtype
== prop_atoms
.net_wm_icon
||
921 msgtype
== prop_atoms
.kwm_win_icon
)
922 client_update_icons(client
);
926 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
927 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
928 frame_adjust_shape(client
->frame
);
934 static void event_handle_menu(Menu
*menu
, Client
*client
, XEvent
*e
)
938 g_message("EVENT %d", e
->type
);
941 g_message("BUTTON PRESS");
942 if (e
->xbutton
.button
== 3)
944 else if (e
->xbutton
.button
== 1) {
945 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
947 stacking_raise(MENU_AS_WINDOW(menu
));
951 g_message("BUTTON RELEASED");
952 if (!menu
->shown
) break;
954 /* grab_pointer_window(FALSE, None, menu->frame);*/
956 if (e
->xbutton
.button
== 1) {
957 entry
= menu_find_entry(menu
, e
->xbutton
.window
);
961 guint ujunk
, b
, w
, h
;
962 XGetGeometry(ob_display
, e
->xbutton
.window
,
963 &wjunk
, &junk
, &junk
, &w
, &h
, &b
, &ujunk
);
964 if (e
->xbutton
.x
>= (signed)-b
&&
965 e
->xbutton
.y
>= (signed)-b
&&
966 e
->xbutton
.x
< (signed)(w
+b
) &&
967 e
->xbutton
.y
< (signed)(h
+b
)) {
968 menu_entry_fire(entry
);
976 g_message("enter/leave");
977 entry
= menu_find_entry(menu
, e
->xcrossing
.window
);
980 menu
->mouseover(entry
, e
->type
== EnterNotify
);
982 menu_control_mouseover(entry
, e
->type
== EnterNotify
);
984 menu_entry_render(entry
);
990 void event_add_fd_handler(event_fd_handler
*h
) {
991 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
992 FD_SET(h
->fd
, &allset
);
993 max_fd
= MAX(max_fd
, h
->fd
);
996 void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
998 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
1001 void event_remove_fd(int n
)
1005 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
1006 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
, (gpointer
)&tmpmax
);
1007 max_fd
= MAX(x_fd
, tmpmax
);
1010 void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
1012 if (FD_ISSET( (int)n
, &selset
)) {
1013 event_fd_handler
*h
= (event_fd_handler
*)data
;
1014 g_assert(h
->fd
== (int)n
);
1015 h
->handler(h
->fd
, h
->data
);
1019 void fd_event_handle()
1021 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
1024 static void event_handle_dock(Dock
*s
, XEvent
*e
)
1028 stacking_raise(DOCK_AS_WINDOW(s
));
1039 static void event_handle_dockapp(DockApp
*app
, XEvent
*e
)
1043 dock_app_drag(app
, &e
->xmotion
);
1046 if (app
->ignore_unmaps
) {
1047 app
->ignore_unmaps
--;
1050 dock_remove(app
, TRUE
);
1053 dock_remove(app
, FALSE
);
1055 case ReparentNotify
:
1056 dock_remove(app
, FALSE
);
1058 case ConfigureNotify
:
1059 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);