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(ObDock
*s
, XEvent
*e
);
42 static void event_handle_dockapp(ObDockApp
*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
;
152 while (XPending(ob_display
)) {
153 XNextEvent(ob_display
, &e
);
156 sn_display_process_event(ob_sn_display
, &e
);
164 timer_dispatch((GTimeVal
**)&wait
);
166 select(max_fd
+ 1, &selset
, NULL
, NULL
, wait
);
168 /* handle the X events as soon as possible? */
169 if (FD_ISSET(x_fd
, &selset
))
173 if (ice_fd
>= 0 && FD_ISSET(ice_fd
, &selset
)) {
175 IceProcessMessages(ice_conn
, NULL
, &b
);
183 static Window
event_get_window(XEvent
*e
)
190 window
= e
->xmap
.window
;
193 window
= e
->xunmap
.window
;
196 window
= e
->xdestroywindow
.window
;
198 case ConfigureRequest
:
199 window
= e
->xconfigurerequest
.window
;
201 case ConfigureNotify
:
202 window
= e
->xconfigure
.window
;
206 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
207 switch (((XkbAnyEvent
*)&e
)->xkb_type
) {
209 window
= ((XkbBellNotifyEvent
*)&e
)->window
;
215 window
= e
->xany
.window
;
220 static void event_set_lasttime(XEvent
*e
)
222 /* grab the lasttime and hack up the state */
226 event_lasttime
= e
->xbutton
.time
;
229 event_lasttime
= e
->xkey
.time
;
232 event_lasttime
= e
->xkey
.time
;
235 event_lasttime
= e
->xmotion
.time
;
238 event_lasttime
= e
->xproperty
.time
;
242 event_lasttime
= e
->xcrossing
.time
;
245 event_lasttime
= CurrentTime
;
250 #define STRIP_MODS(s) \
251 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
252 /* kill off the Button1Mask etc, only want the modifiers */ \
253 s &= (ControlMask | ShiftMask | Mod1Mask | \
254 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
256 static void event_hack_mods(XEvent *e)
264 STRIP_MODS(e
->xbutton
.state
);
267 STRIP_MODS(e
->xkey
.state
);
270 STRIP_MODS(e
->xkey
.state
);
271 /* remove from the state the mask of the modifier being released, if
272 it is a modifier key being released (this is a little ugly..) */
273 kp
= modmap
->modifiermap
;
274 for (i
= 0; i
< mask_table_size
; ++i
) {
275 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
276 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
277 /* remove the mask for it */
278 e
->xkey
.state
&= ~mask_table
[i
];
279 /* cause the first loop to break; */
281 break; /* get outta here! */
288 STRIP_MODS(e
->xmotion
.state
);
289 /* compress events */
292 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
294 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
295 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
302 static gboolean
event_ignore(XEvent
*e
, ObClient
*client
)
306 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
307 because of RevertToPointerRoot. If the focus ends up reverting to
308 pointer root on a workspace change, then the FocusIn event that we
309 want will be of type NotifyAncestor. This situation does not occur
310 for FocusOut, so it is safely ignored there.
312 if (INVALID_FOCUSIN(e
) ||
315 g_message("FocusIn on %lx mode %d detail %d IGNORED", e
->xfocus
.window
,
316 e
->xfocus
.mode
, e
->xfocus
.detail
);
318 /* says a client was not found for the event (or a valid FocusIn
321 e
->xfocus
.window
= None
;
326 g_message("FocusIn on %lx mode %d detail %d", e
->xfocus
.window
,
327 e
->xfocus
.mode
, e
->xfocus
.detail
);
331 if (INVALID_FOCUSOUT(e
)) {
333 g_message("FocusOut on %lx mode %d detail %d IGNORED",
334 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
340 g_message("FocusOut on %lx mode %d detail %d",
341 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
346 gboolean fallback
= TRUE
;
349 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
350 e
->xfocus
.window
,&fe
))
351 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
353 if (fe
.type
== FocusOut
) {
355 g_message("found pending FocusOut");
357 if (!INVALID_FOCUSOUT(&fe
)) {
358 /* if there is a VALID FocusOut still coming, don't
359 fallback focus yet, we'll deal with it then */
360 XPutBackEvent(ob_display
, &fe
);
366 g_message("found pending FocusIn");
368 /* is the focused window getting a FocusOut/In back to
371 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
372 !event_ignore(&fe
, client
)) {
374 if focus_client is not set, then we can't do
375 this. we need the FocusIn. This happens in the
376 case when the set_focus_client(NULL) in the
377 focus_fallback function fires and then
378 focus_fallback picks the currently focused
379 window (such as on a SendToDesktop-esque action.
383 g_message("focused window got an Out/In back to "
384 "itself IGNORED both");
390 g_message("focused window got an Out/In back to "
391 "itself but focus_client was null "
392 "IGNORED just the Out");
398 /* once all the FocusOut's have been dealt with, if there
399 is a FocusIn still left and it is valid, then use it */
401 /* secret magic way of event_process telling us that no
402 client was found for the FocusIn event. ^_^ */
403 if (fe
.xfocus
.window
!= None
) {
411 g_message("no valid FocusIn and no FocusOut events found, "
414 focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS
);
420 /* NotifyUngrab occurs when a mouse button is released and the event is
421 caused, like when lowering a window */
422 /* NotifyVirtual occurs when ungrabbing the pointer */
423 if (e
->xcrossing
.mode
== NotifyGrab
||
424 e
->xcrossing
.detail
== NotifyInferior
||
425 (e
->xcrossing
.mode
== NotifyUngrab
&&
426 e
->xcrossing
.detail
== NotifyVirtual
)) {
428 g_message("%sNotify mode %d detail %d on %lx IGNORED",
429 (e
->type
== EnterNotify
? "Enter" : "Leave"),
431 e
->xcrossing
.detail
, client
?client
->window
:0);
436 g_message("%sNotify mode %d detail %d on %lx",
437 (e
->type
== EnterNotify
? "Enter" : "Leave"),
439 e
->xcrossing
.detail
, client
?client
->window
:0);
446 static void event_process(XEvent
*e
)
449 ObClient
*client
= NULL
;
451 ObDockApp
*dockapp
= NULL
;
453 ObWindow
*obwin
= NULL
;
455 window
= event_get_window(e
);
456 if ((obwin
= g_hash_table_lookup(window_map
, &window
))) {
457 switch (obwin
->type
) {
459 dock
= WINDOW_AS_DOCK(obwin
);
462 dockapp
= WINDOW_AS_DOCKAPP(obwin
);
465 menu
= WINDOW_AS_MENU(obwin
);
468 client
= WINDOW_AS_CLIENT(obwin
);
470 case Window_Internal
:
471 /* not to be used for events */
472 g_assert_not_reached();
477 event_set_lasttime(e
);
479 if (event_ignore(e
, client
))
482 /* deal with it in the kernel */
484 event_handle_client(client
, e
);
486 event_handle_dockapp(dockapp
, e
);
488 event_handle_dock(dock
, e
);
489 else if (window
== RootWindow(ob_display
, ob_screen
))
490 event_handle_root(e
);
491 else if (e
->type
== MapRequest
)
492 client_manage(window
);
493 else if (e
->type
== ConfigureRequest
) {
494 /* unhandled configure requests must be used to configure the
498 xwc
.x
= e
->xconfigurerequest
.x
;
499 xwc
.y
= e
->xconfigurerequest
.y
;
500 xwc
.width
= e
->xconfigurerequest
.width
;
501 xwc
.height
= e
->xconfigurerequest
.height
;
502 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
503 xwc
.sibling
= e
->xconfigurerequest
.above
;
504 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
506 /* we are not to be held responsible if someone sends us an
508 xerror_set_ignore(TRUE
);
509 XConfigureWindow(ob_display
, window
,
510 e
->xconfigurerequest
.value_mask
, &xwc
);
511 xerror_set_ignore(FALSE
);
515 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
516 e
->type
== ButtonPress
||
517 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
518 event_handle_menu(client
, e
);
520 return; /* no dispatch! */
523 if (moveresize_in_progress
)
524 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
525 e
->type
== ButtonPress
||
526 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
529 return; /* no dispatch! */
533 /* user input (action-bound) events */
535 if (e->type == ButtonPress || e->type == ButtonRelease ||
536 e->type == MotionNotify)
537 mouse_event(e, client);
538 else if (e->type == KeyPress || e->type == KeyRelease)
542 /* dispatch the event to registered handlers */
543 dispatch_x(e
, client
);
546 static void event_handle_root(XEvent
*e
)
552 if (e
->xclient
.format
!= 32) break;
554 msgtype
= e
->xclient
.message_type
;
555 if (msgtype
== prop_atoms
.net_current_desktop
) {
556 unsigned int d
= e
->xclient
.data
.l
[0];
557 if (d
< screen_num_desktops
)
558 screen_set_desktop(d
);
559 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
560 unsigned int d
= e
->xclient
.data
.l
[0];
562 screen_set_num_desktops(d
);
563 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
564 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
568 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
569 screen_update_desktop_names();
570 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
571 screen_update_layout();
573 case ConfigureNotify
:
575 XRRUpdateConfiguration(e
);
582 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
583 g_message("VIDMODE EVENT");
589 static void event_handle_client(ObClient
*client
, XEvent
*e
)
598 /* Wheel buttons don't draw because they are an instant click, so it
599 is a waste of resources to go drawing it. */
600 if (!(e
->xbutton
.button
== 4 || e
->xbutton
.button
== 5)) {
601 switch (frame_context(client
, e
->xbutton
.window
)) {
602 case OB_FRAME_CONTEXT_MAXIMIZE
:
603 client
->frame
->max_press
= (e
->type
== ButtonPress
);
604 framerender_frame(client
->frame
);
606 case OB_FRAME_CONTEXT_CLOSE
:
607 client
->frame
->close_press
= (e
->type
== ButtonPress
);
608 framerender_frame(client
->frame
);
610 case OB_FRAME_CONTEXT_ICONIFY
:
611 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
612 framerender_frame(client
->frame
);
614 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
615 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
616 framerender_frame(client
->frame
);
618 case OB_FRAME_CONTEXT_SHADE
:
619 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
620 framerender_frame(client
->frame
);
623 /* nothing changes with clicks for any other contexts */
630 g_message("FocusIn on client for %lx", client
->window
);
632 if (client
!= focus_client
) {
633 focus_set_client(client
);
634 frame_adjust_focus(client
->frame
, TRUE
);
639 g_message("FocusOut on client for %lx", client
->window
);
641 /* are we a fullscreen window or a transient of one? (checks layer)
642 if we are then we need to be iconified since we are losing focus
644 if (client
->layer
== OB_STACKING_LAYER_FULLSCREEN
&& !client
->iconic
&&
645 !client_search_focus_tree_full(client
))
646 /* iconify fullscreen windows when they and their transients
648 client_iconify(client
, TRUE
, TRUE
);
649 frame_adjust_focus(client
->frame
, FALSE
);
652 if (client_normal(client
)) {
653 if (ob_state() == OB_STATE_STARTING
) {
654 /* move it to the top of the focus order */
655 guint desktop
= client
->desktop
;
656 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
657 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
659 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
661 } else if (config_focus_follow
) {
663 g_message("EnterNotify on %lx, focusing window",
666 client_focus(client
);
670 case ConfigureRequest
:
672 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
673 ConfigureRequest
, &ce
)) {
675 /* XXX if this causes bad things.. we can compress config req's
676 with the same mask. */
677 e
->xconfigurerequest
.value_mask
|=
678 ce
.xconfigurerequest
.value_mask
;
679 if (ce
.xconfigurerequest
.value_mask
& CWX
)
680 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
681 if (ce
.xconfigurerequest
.value_mask
& CWY
)
682 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
683 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
684 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
685 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
686 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
687 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
688 e
->xconfigurerequest
.border_width
=
689 ce
.xconfigurerequest
.border_width
;
690 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
691 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
694 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
695 if (client
->iconic
|| client
->shaded
) return;
697 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
698 client
->border_width
= e
->xconfigurerequest
.border_width
;
700 /* resize, then move, as specified in the EWMH section 7.7 */
701 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
706 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
707 e
->xconfigurerequest
.x
: client
->area
.x
;
708 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
709 e
->xconfigurerequest
.y
: client
->area
.y
;
710 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
711 e
->xconfigurerequest
.width
: client
->area
.width
;
712 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
713 e
->xconfigurerequest
.height
: client
->area
.height
;
715 switch (client
->gravity
) {
716 case NorthEastGravity
:
718 corner
= OB_CORNER_TOPRIGHT
;
720 case SouthWestGravity
:
722 corner
= OB_CORNER_BOTTOMLEFT
;
724 case SouthEastGravity
:
725 corner
= OB_CORNER_BOTTOMRIGHT
;
727 default: /* NorthWest, Static, etc */
728 corner
= OB_CORNER_TOPLEFT
;
731 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, TRUE
);
734 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
735 switch (e
->xconfigurerequest
.detail
) {
738 stacking_lower(CLIENT_AS_WINDOW(client
));
744 stacking_raise(CLIENT_AS_WINDOW(client
));
750 if (client
->ignore_unmaps
) {
751 client
->ignore_unmaps
--;
754 client_unmanage(client
);
757 client_unmanage(client
);
760 /* this is when the client is first taken captive in the frame */
761 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
764 This event is quite rare and is usually handled in unmapHandler.
765 However, if the window is unmapped when the reparent event occurs,
766 the window manager never sees it because an unmap event is not sent
767 to an already unmapped window.
770 /* we don't want the reparent event, put it back on the stack for the
771 X server to deal with after we unmanage the window */
772 XPutBackEvent(ob_display
, e
);
774 client_unmanage(client
);
777 g_message("MapRequest for 0x%lx", client
->window
);
778 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
779 does, we don't want it! */
780 if (screen_showing_desktop
)
781 screen_show_desktop(FALSE
);
782 client_iconify(client
, FALSE
, TRUE
);
783 if (!client
->frame
->visible
)
784 /* if its not visible still, then don't mess with it */
787 client_shade(client
, FALSE
);
788 client_focus(client
);
789 stacking_raise(CLIENT_AS_WINDOW(client
));
792 /* validate cuz we query stuff off the client here */
793 if (!client_validate(client
)) break;
795 if (e
->xclient
.format
!= 32) return;
797 msgtype
= e
->xclient
.message_type
;
798 if (msgtype
== prop_atoms
.wm_change_state
) {
799 /* compress changes into a single change */
800 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
801 client
->window
, &ce
)) {
802 /* XXX: it would be nice to compress ALL messages of a
803 type, not just messages in a row without other
804 message types between. */
805 if (ce
.xclient
.message_type
!= msgtype
) {
806 XPutBackEvent(ob_display
, &ce
);
809 e
->xclient
= ce
.xclient
;
811 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
812 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
813 /* compress changes into a single change */
814 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
815 client
->window
, &ce
)) {
816 /* XXX: it would be nice to compress ALL messages of a
817 type, not just messages in a row without other
818 message types between. */
819 if (ce
.xclient
.message_type
!= msgtype
) {
820 XPutBackEvent(ob_display
, &ce
);
823 e
->xclient
= ce
.xclient
;
825 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
826 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
827 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
829 } else if (msgtype
== prop_atoms
.net_wm_state
) {
830 /* can't compress these */
831 g_message("net_wm_state %s %ld %ld for 0x%lx",
832 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
833 e
->xclient
.data
.l
[0] == 1 ? "Add" :
834 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
835 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
837 client_set_state(client
, e
->xclient
.data
.l
[0],
838 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
839 } else if (msgtype
== prop_atoms
.net_close_window
) {
840 g_message("net_close_window for 0x%lx", client
->window
);
841 client_close(client
);
842 } else if (msgtype
== prop_atoms
.net_active_window
) {
843 g_message("net_active_window for 0x%lx", client
->window
);
844 client_activate(client
);
845 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
846 g_message("net_wm_moveresize for 0x%lx", client
->window
);
847 if ((Atom
)e
->xclient
.data
.l
[2] ==
848 prop_atoms
.net_wm_moveresize_size_topleft
||
849 (Atom
)e
->xclient
.data
.l
[2] ==
850 prop_atoms
.net_wm_moveresize_size_top
||
851 (Atom
)e
->xclient
.data
.l
[2] ==
852 prop_atoms
.net_wm_moveresize_size_topright
||
853 (Atom
)e
->xclient
.data
.l
[2] ==
854 prop_atoms
.net_wm_moveresize_size_right
||
855 (Atom
)e
->xclient
.data
.l
[2] ==
856 prop_atoms
.net_wm_moveresize_size_right
||
857 (Atom
)e
->xclient
.data
.l
[2] ==
858 prop_atoms
.net_wm_moveresize_size_bottomright
||
859 (Atom
)e
->xclient
.data
.l
[2] ==
860 prop_atoms
.net_wm_moveresize_size_bottom
||
861 (Atom
)e
->xclient
.data
.l
[2] ==
862 prop_atoms
.net_wm_moveresize_size_bottomleft
||
863 (Atom
)e
->xclient
.data
.l
[2] ==
864 prop_atoms
.net_wm_moveresize_size_left
||
865 (Atom
)e
->xclient
.data
.l
[2] ==
866 prop_atoms
.net_wm_moveresize_move
||
867 (Atom
)e
->xclient
.data
.l
[2] ==
868 prop_atoms
.net_wm_moveresize_size_keyboard
||
869 (Atom
)e
->xclient
.data
.l
[2] ==
870 prop_atoms
.net_wm_moveresize_move_keyboard
) {
872 moveresize_start(client
, e
->xclient
.data
.l
[0],
873 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
874 e
->xclient
.data
.l
[2]);
876 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
877 int oldg
= client
->gravity
;
878 int tmpg
, x
, y
, w
, h
;
880 if (e
->xclient
.data
.l
[0] & 0xff)
881 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
885 if (e
->xclient
.data
.l
[0] & 1 << 8)
886 x
= e
->xclient
.data
.l
[1];
889 if (e
->xclient
.data
.l
[0] & 1 << 9)
890 y
= e
->xclient
.data
.l
[2];
893 if (e
->xclient
.data
.l
[0] & 1 << 10)
894 w
= e
->xclient
.data
.l
[3];
897 if (e
->xclient
.data
.l
[0] & 1 << 11)
898 h
= e
->xclient
.data
.l
[4];
901 client
->gravity
= tmpg
;
902 client_configure(client
, OB_CORNER_TOPLEFT
,
903 x
, y
, w
, h
, FALSE
, TRUE
);
904 client
->gravity
= oldg
;
908 /* validate cuz we query stuff off the client here */
909 if (!client_validate(client
)) break;
911 /* compress changes to a single property into a single change */
912 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
913 client
->window
, &ce
)) {
914 /* XXX: it would be nice to compress ALL changes to a property,
915 not just changes in a row without other props between. */
916 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
917 XPutBackEvent(ob_display
, &ce
);
922 msgtype
= e
->xproperty
.atom
;
923 if (msgtype
== XA_WM_NORMAL_HINTS
) {
924 client_update_normal_hints(client
);
925 /* normal hints can make a window non-resizable */
926 client_setup_decor_and_functions(client
);
928 else if (msgtype
== XA_WM_HINTS
)
929 client_update_wmhints(client
);
930 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
931 client_update_transient_for(client
);
932 client_get_type(client
);
933 /* type may have changed, so update the layer */
934 client_calc_layer(client
);
935 client_setup_decor_and_functions(client
);
937 else if (msgtype
== prop_atoms
.net_wm_name
||
938 msgtype
== prop_atoms
.wm_name
||
939 msgtype
== prop_atoms
.net_wm_icon_name
||
940 msgtype
== prop_atoms
.wm_icon_name
)
941 client_update_title(client
);
942 else if (msgtype
== prop_atoms
.wm_class
)
943 client_update_class(client
);
944 else if (msgtype
== prop_atoms
.wm_protocols
) {
945 client_update_protocols(client
);
946 client_setup_decor_and_functions(client
);
948 else if (msgtype
== prop_atoms
.net_wm_strut
)
949 client_update_strut(client
);
950 else if (msgtype
== prop_atoms
.net_wm_icon
||
951 msgtype
== prop_atoms
.kwm_win_icon
)
952 client_update_icons(client
);
956 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
957 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
958 frame_adjust_shape(client
->frame
);
964 static void event_handle_menu(ObClient
*client
, XEvent
*e
)
966 static ObMenuEntry
*over
= NULL
;
971 top
= g_list_nth_data(menu_visible
, 0);
973 g_message("EVENT %d", e
->type
);
976 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_DOWN
))
977 over
= menu_control_keyboard_nav(over
, OB_KEY_DOWN
);
978 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_UP
))
979 over
= menu_control_keyboard_nav(over
, OB_KEY_UP
);
980 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RETURN
))
981 over
= menu_control_keyboard_nav(over
, OB_KEY_RETURN
);
982 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_ESCAPE
))
983 over
= menu_control_keyboard_nav(over
, OB_KEY_ESCAPE
);
986 if (over
->parent
->mouseover
)
987 over
->parent
->mouseover(over
, FALSE
);
989 menu_control_mouseover(over
, FALSE
);
990 menu_entry_render(over
);
1002 if (e
->xbutton
.button
> 3) break;
1004 g_message("BUTTON PRESS");
1007 if (e
->xbutton
.button
> 3) break;
1009 g_message("BUTTON RELEASED");
1011 for (it
= menu_visible
; it
; it
= g_list_next(it
)) {
1012 ObMenu
*m
= it
->data
;
1013 if (e
->xbutton
.x_root
>= m
->location
.x
- ob_rr_theme
->bwidth
&&
1014 e
->xbutton
.y_root
>= m
->location
.y
- ob_rr_theme
->bwidth
&&
1015 e
->xbutton
.x_root
< m
->location
.x
+ m
->size
.width
+
1016 ob_rr_theme
->bwidth
&&
1017 e
->xbutton
.y_root
< m
->location
.y
+ m
->size
.height
+
1018 ob_rr_theme
->bwidth
) {
1019 if ((entry
= menu_find_entry_by_pos(it
->data
,
1025 if (over
->parent
->mouseover
)
1026 over
->parent
->mouseover(over
, FALSE
);
1028 menu_control_mouseover(over
, FALSE
);
1029 menu_entry_render(over
);
1031 /* this hides the menu */
1032 menu_entry_fire(entry
);
1040 if (over
->parent
->mouseover
)
1041 over
->parent
->mouseover(over
, FALSE
);
1043 menu_control_mouseover(over
, FALSE
);
1044 menu_entry_render(over
);
1057 g_message("motion");
1058 for (it
= menu_visible
; it
; it
= g_list_next(it
)) {
1059 ObMenu
*m
= it
->data
;
1060 if ((entry
= menu_find_entry_by_pos(it
->data
,
1065 if (over
&& entry
!= over
) {
1066 if (over
->parent
->mouseover
)
1067 over
->parent
->mouseover(over
, FALSE
);
1069 menu_control_mouseover(over
, FALSE
);
1070 menu_entry_render(over
);
1074 if (over
->parent
->mouseover
)
1075 over
->parent
->mouseover(over
, TRUE
);
1077 menu_control_mouseover(over
, TRUE
);
1078 menu_entry_render(over
);
1083 if (over
->parent
->mouseover
)
1084 over
->parent
->mouseover(over
, FALSE
);
1086 menu_control_mouseover(over
, FALSE
);
1087 menu_entry_render(over
);
1094 void event_add_fd_handler(event_fd_handler
*h
) {
1095 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
1096 FD_SET(h
->fd
, &allset
);
1097 max_fd
= MAX(max_fd
, h
->fd
);
1100 static void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
1102 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
1105 static void find_max_fd()
1108 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
,
1110 max_fd
= MAX(x_fd
, tmpmax
);
1112 max_fd
= MAX(ice_fd
, tmpmax
);
1116 void event_remove_fd(int n
)
1119 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
1123 static void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
1125 if (FD_ISSET( (int)n
, &selset
)) {
1126 event_fd_handler
*h
= (event_fd_handler
*)data
;
1127 g_assert(h
->fd
== (int)n
);
1128 h
->handler(h
->fd
, h
->data
);
1132 static void fd_event_handle()
1134 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
1137 static void event_handle_dock(ObDock
*s
, XEvent
*e
)
1141 stacking_raise(DOCK_AS_WINDOW(s
));
1152 static void event_handle_dockapp(ObDockApp
*app
, XEvent
*e
)
1156 dock_app_drag(app
, &e
->xmotion
);
1159 if (app
->ignore_unmaps
) {
1160 app
->ignore_unmaps
--;
1163 dock_remove(app
, TRUE
);
1166 dock_remove(app
, FALSE
);
1168 case ReparentNotify
:
1169 dock_remove(app
, FALSE
);
1171 case ConfigureNotify
:
1172 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);