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
= RootWindow(ob_display
, ob_screen
);
193 window
= e
->xmap
.window
;
196 window
= e
->xunmap
.window
;
199 window
= e
->xdestroywindow
.window
;
201 case ConfigureRequest
:
202 window
= e
->xconfigurerequest
.window
;
204 case ConfigureNotify
:
205 window
= e
->xconfigure
.window
;
209 if (extensions_xkb
&& e
->type
== extensions_xkb_event_basep
) {
210 switch (((XkbAnyEvent
*)&e
)->xkb_type
) {
212 window
= ((XkbBellNotifyEvent
*)&e
)->window
;
218 window
= e
->xany
.window
;
223 static void event_set_lasttime(XEvent
*e
)
225 /* grab the lasttime and hack up the state */
229 event_lasttime
= e
->xbutton
.time
;
232 event_lasttime
= e
->xkey
.time
;
235 event_lasttime
= e
->xkey
.time
;
238 event_lasttime
= e
->xmotion
.time
;
241 event_lasttime
= e
->xproperty
.time
;
245 event_lasttime
= e
->xcrossing
.time
;
248 event_lasttime
= CurrentTime
;
253 #define STRIP_MODS(s) \
254 s &= ~(LockMask | NumLockMask | ScrollLockMask), \
255 /* kill off the Button1Mask etc, only want the modifiers */ \
256 s &= (ControlMask | ShiftMask | Mod1Mask | \
257 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
259 static void event_hack_mods(XEvent *e)
267 STRIP_MODS(e
->xbutton
.state
);
270 STRIP_MODS(e
->xkey
.state
);
273 STRIP_MODS(e
->xkey
.state
);
274 /* remove from the state the mask of the modifier being released, if
275 it is a modifier key being released (this is a little ugly..) */
276 kp
= modmap
->modifiermap
;
277 for (i
= 0; i
< mask_table_size
; ++i
) {
278 for (k
= 0; k
< modmap
->max_keypermod
; ++k
) {
279 if (*kp
== e
->xkey
.keycode
) { /* found the keycode */
280 /* remove the mask for it */
281 e
->xkey
.state
&= ~mask_table
[i
];
282 /* cause the first loop to break; */
284 break; /* get outta here! */
291 STRIP_MODS(e
->xmotion
.state
);
292 /* compress events */
295 while (XCheckTypedWindowEvent(ob_display
, e
->xmotion
.window
,
297 e
->xmotion
.x_root
= ce
.xmotion
.x_root
;
298 e
->xmotion
.y_root
= ce
.xmotion
.y_root
;
305 static gboolean
event_ignore(XEvent
*e
, ObClient
*client
)
309 /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
310 because of RevertToPointerRoot. If the focus ends up reverting to
311 pointer root on a workspace change, then the FocusIn event that we
312 want will be of type NotifyAncestor. This situation does not occur
313 for FocusOut, so it is safely ignored there.
315 if (INVALID_FOCUSIN(e
) ||
318 g_message("FocusIn on %lx mode %d detail %d IGNORED", e
->xfocus
.window
,
319 e
->xfocus
.mode
, e
->xfocus
.detail
);
321 /* says a client was not found for the event (or a valid FocusIn
324 e
->xfocus
.window
= None
;
329 g_message("FocusIn on %lx mode %d detail %d", e
->xfocus
.window
,
330 e
->xfocus
.mode
, e
->xfocus
.detail
);
334 if (INVALID_FOCUSOUT(e
)) {
336 g_message("FocusOut on %lx mode %d detail %d IGNORED",
337 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
343 g_message("FocusOut on %lx mode %d detail %d",
344 e
->xfocus
.window
, e
->xfocus
.mode
, e
->xfocus
.detail
);
349 gboolean fallback
= TRUE
;
352 if (!XCheckTypedWindowEvent(ob_display
, FocusOut
,
353 e
->xfocus
.window
,&fe
))
354 if (!XCheckTypedEvent(ob_display
, FocusIn
, &fe
))
356 if (fe
.type
== FocusOut
) {
358 g_message("found pending FocusOut");
360 if (!INVALID_FOCUSOUT(&fe
)) {
361 /* if there is a VALID FocusOut still coming, don't
362 fallback focus yet, we'll deal with it then */
363 XPutBackEvent(ob_display
, &fe
);
369 g_message("found pending FocusIn");
371 /* is the focused window getting a FocusOut/In back to
374 if (fe
.xfocus
.window
== e
->xfocus
.window
&&
375 !event_ignore(&fe
, client
)) {
377 if focus_client is not set, then we can't do
378 this. we need the FocusIn. This happens in the
379 case when the set_focus_client(NULL) in the
380 focus_fallback function fires and then
381 focus_fallback picks the currently focused
382 window (such as on a SendToDesktop-esque action.
386 g_message("focused window got an Out/In back to "
387 "itself IGNORED both");
393 g_message("focused window got an Out/In back to "
394 "itself but focus_client was null "
395 "IGNORED just the Out");
401 /* once all the FocusOut's have been dealt with, if there
402 is a FocusIn still left and it is valid, then use it */
404 /* secret magic way of event_process telling us that no
405 client was found for the FocusIn event. ^_^ */
406 if (fe
.xfocus
.window
!= None
) {
414 g_message("no valid FocusIn and no FocusOut events found, "
417 focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS
);
423 /* NotifyUngrab occurs when a mouse button is released and the event is
424 caused, like when lowering a window */
425 /* NotifyVirtual occurs when ungrabbing the pointer */
426 if (e
->xcrossing
.mode
== NotifyGrab
||
427 e
->xcrossing
.detail
== NotifyInferior
||
428 (e
->xcrossing
.mode
== NotifyUngrab
&&
429 e
->xcrossing
.detail
== NotifyVirtual
)) {
431 g_message("%sNotify mode %d detail %d on %lx IGNORED",
432 (e
->type
== EnterNotify
? "Enter" : "Leave"),
434 e
->xcrossing
.detail
, client
?client
->window
:0);
439 g_message("%sNotify mode %d detail %d on %lx",
440 (e
->type
== EnterNotify
? "Enter" : "Leave"),
442 e
->xcrossing
.detail
, client
?client
->window
:0);
449 static void event_process(XEvent
*e
)
452 ObClient
*client
= NULL
;
454 ObDockApp
*dockapp
= NULL
;
456 ObWindow
*obwin
= NULL
;
458 window
= event_get_window(e
);
459 if ((obwin
= g_hash_table_lookup(window_map
, &window
))) {
460 switch (obwin
->type
) {
462 dock
= WINDOW_AS_DOCK(obwin
);
465 dockapp
= WINDOW_AS_DOCKAPP(obwin
);
468 menu
= WINDOW_AS_MENU(obwin
);
471 client
= WINDOW_AS_CLIENT(obwin
);
473 case Window_Internal
:
474 /* not to be used for events */
475 g_assert_not_reached();
480 event_set_lasttime(e
);
482 if (event_ignore(e
, client
))
485 /* deal with it in the kernel */
487 event_handle_client(client
, e
);
489 event_handle_dockapp(dockapp
, e
);
491 event_handle_dock(dock
, e
);
492 else if (window
== RootWindow(ob_display
, ob_screen
))
493 event_handle_root(e
);
494 else if (e
->type
== MapRequest
)
495 client_manage(window
);
496 else if (e
->type
== ConfigureRequest
) {
497 /* unhandled configure requests must be used to configure the
501 xwc
.x
= e
->xconfigurerequest
.x
;
502 xwc
.y
= e
->xconfigurerequest
.y
;
503 xwc
.width
= e
->xconfigurerequest
.width
;
504 xwc
.height
= e
->xconfigurerequest
.height
;
505 xwc
.border_width
= e
->xconfigurerequest
.border_width
;
506 xwc
.sibling
= e
->xconfigurerequest
.above
;
507 xwc
.stack_mode
= e
->xconfigurerequest
.detail
;
509 /* we are not to be held responsible if someone sends us an
511 xerror_set_ignore(TRUE
);
512 XConfigureWindow(ob_display
, window
,
513 e
->xconfigurerequest
.value_mask
, &xwc
);
514 xerror_set_ignore(FALSE
);
518 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
519 e
->type
== ButtonPress
||
520 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
521 event_handle_menu(client
, e
);
523 return; /* no dispatch! */
526 if (moveresize_in_progress
)
527 if (e
->type
== MotionNotify
|| e
->type
== ButtonRelease
||
528 e
->type
== ButtonPress
||
529 e
->type
== KeyPress
|| e
->type
== KeyRelease
) {
532 return; /* no dispatch! */
536 /* user input (action-bound) events */
538 if (e->type == ButtonPress || e->type == ButtonRelease ||
539 e->type == MotionNotify)
540 mouse_event(e, client);
541 else if (e->type == KeyPress || e->type == KeyRelease)
545 /* dispatch the event to registered handlers */
546 dispatch_x(e
, client
);
549 static void event_handle_root(XEvent
*e
)
555 g_message("Another WM has requested to replace us. Exiting.");
560 if (e
->xclient
.format
!= 32) break;
562 msgtype
= e
->xclient
.message_type
;
563 if (msgtype
== prop_atoms
.net_current_desktop
) {
564 unsigned int d
= e
->xclient
.data
.l
[0];
565 if (d
< screen_num_desktops
)
566 screen_set_desktop(d
);
567 } else if (msgtype
== prop_atoms
.net_number_of_desktops
) {
568 unsigned int d
= e
->xclient
.data
.l
[0];
570 screen_set_num_desktops(d
);
571 } else if (msgtype
== prop_atoms
.net_showing_desktop
) {
572 screen_show_desktop(e
->xclient
.data
.l
[0] != 0);
576 if (e
->xproperty
.atom
== prop_atoms
.net_desktop_names
)
577 screen_update_desktop_names();
578 else if (e
->xproperty
.atom
== prop_atoms
.net_desktop_layout
)
579 screen_update_layout();
581 case ConfigureNotify
:
583 XRRUpdateConfiguration(e
);
590 if (extensions_vidmode
&& e
->type
== extensions_vidmode_event_basep
) {
591 g_message("VIDMODE EVENT");
597 static void event_handle_client(ObClient
*client
, XEvent
*e
)
606 /* Wheel buttons don't draw because they are an instant click, so it
607 is a waste of resources to go drawing it. */
608 if (!(e
->xbutton
.button
== 4 || e
->xbutton
.button
== 5)) {
609 switch (frame_context(client
, e
->xbutton
.window
)) {
610 case OB_FRAME_CONTEXT_MAXIMIZE
:
611 client
->frame
->max_press
= (e
->type
== ButtonPress
);
612 framerender_frame(client
->frame
);
614 case OB_FRAME_CONTEXT_CLOSE
:
615 client
->frame
->close_press
= (e
->type
== ButtonPress
);
616 framerender_frame(client
->frame
);
618 case OB_FRAME_CONTEXT_ICONIFY
:
619 client
->frame
->iconify_press
= (e
->type
== ButtonPress
);
620 framerender_frame(client
->frame
);
622 case OB_FRAME_CONTEXT_ALLDESKTOPS
:
623 client
->frame
->desk_press
= (e
->type
== ButtonPress
);
624 framerender_frame(client
->frame
);
626 case OB_FRAME_CONTEXT_SHADE
:
627 client
->frame
->shade_press
= (e
->type
== ButtonPress
);
628 framerender_frame(client
->frame
);
631 /* nothing changes with clicks for any other contexts */
638 g_message("FocusIn on client for %lx", client
->window
);
640 if (client
!= focus_client
) {
641 focus_set_client(client
);
642 frame_adjust_focus(client
->frame
, TRUE
);
647 g_message("FocusOut on client for %lx", client
->window
);
649 /* are we a fullscreen window or a transient of one? (checks layer)
650 if we are then we need to be iconified since we are losing focus
652 if (client
->layer
== OB_STACKING_LAYER_FULLSCREEN
&& !client
->iconic
&&
653 !client_search_focus_tree_full(client
))
654 /* iconify fullscreen windows when they and their transients
656 client_iconify(client
, TRUE
, TRUE
);
657 frame_adjust_focus(client
->frame
, FALSE
);
660 if (client_normal(client
)) {
661 if (ob_state() == OB_STATE_STARTING
) {
662 /* move it to the top of the focus order */
663 guint desktop
= client
->desktop
;
664 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
665 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
],
667 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
],
669 } else if (config_focus_follow
) {
671 g_message("EnterNotify on %lx, focusing window",
674 client_focus(client
);
678 case ConfigureRequest
:
680 while (XCheckTypedWindowEvent(ob_display
, client
->window
,
681 ConfigureRequest
, &ce
)) {
683 /* XXX if this causes bad things.. we can compress config req's
684 with the same mask. */
685 e
->xconfigurerequest
.value_mask
|=
686 ce
.xconfigurerequest
.value_mask
;
687 if (ce
.xconfigurerequest
.value_mask
& CWX
)
688 e
->xconfigurerequest
.x
= ce
.xconfigurerequest
.x
;
689 if (ce
.xconfigurerequest
.value_mask
& CWY
)
690 e
->xconfigurerequest
.y
= ce
.xconfigurerequest
.y
;
691 if (ce
.xconfigurerequest
.value_mask
& CWWidth
)
692 e
->xconfigurerequest
.width
= ce
.xconfigurerequest
.width
;
693 if (ce
.xconfigurerequest
.value_mask
& CWHeight
)
694 e
->xconfigurerequest
.height
= ce
.xconfigurerequest
.height
;
695 if (ce
.xconfigurerequest
.value_mask
& CWBorderWidth
)
696 e
->xconfigurerequest
.border_width
=
697 ce
.xconfigurerequest
.border_width
;
698 if (ce
.xconfigurerequest
.value_mask
& CWStackMode
)
699 e
->xconfigurerequest
.detail
= ce
.xconfigurerequest
.detail
;
702 /* if we are iconic (or shaded (fvwm does this)) ignore the event */
703 if (client
->iconic
|| client
->shaded
) return;
705 if (e
->xconfigurerequest
.value_mask
& CWBorderWidth
)
706 client
->border_width
= e
->xconfigurerequest
.border_width
;
708 /* resize, then move, as specified in the EWMH section 7.7 */
709 if (e
->xconfigurerequest
.value_mask
& (CWWidth
| CWHeight
|
714 x
= (e
->xconfigurerequest
.value_mask
& CWX
) ?
715 e
->xconfigurerequest
.x
: client
->area
.x
;
716 y
= (e
->xconfigurerequest
.value_mask
& CWY
) ?
717 e
->xconfigurerequest
.y
: client
->area
.y
;
718 w
= (e
->xconfigurerequest
.value_mask
& CWWidth
) ?
719 e
->xconfigurerequest
.width
: client
->area
.width
;
720 h
= (e
->xconfigurerequest
.value_mask
& CWHeight
) ?
721 e
->xconfigurerequest
.height
: client
->area
.height
;
723 switch (client
->gravity
) {
724 case NorthEastGravity
:
726 corner
= OB_CORNER_TOPRIGHT
;
728 case SouthWestGravity
:
730 corner
= OB_CORNER_BOTTOMLEFT
;
732 case SouthEastGravity
:
733 corner
= OB_CORNER_BOTTOMRIGHT
;
735 default: /* NorthWest, Static, etc */
736 corner
= OB_CORNER_TOPLEFT
;
739 client_configure(client
, corner
, x
, y
, w
, h
, FALSE
, TRUE
);
742 if (e
->xconfigurerequest
.value_mask
& CWStackMode
) {
743 switch (e
->xconfigurerequest
.detail
) {
746 stacking_lower(CLIENT_AS_WINDOW(client
));
752 stacking_raise(CLIENT_AS_WINDOW(client
));
758 if (client
->ignore_unmaps
) {
759 client
->ignore_unmaps
--;
762 client_unmanage(client
);
765 client_unmanage(client
);
768 /* this is when the client is first taken captive in the frame */
769 if (e
->xreparent
.parent
== client
->frame
->plate
) break;
772 This event is quite rare and is usually handled in unmapHandler.
773 However, if the window is unmapped when the reparent event occurs,
774 the window manager never sees it because an unmap event is not sent
775 to an already unmapped window.
778 /* we don't want the reparent event, put it back on the stack for the
779 X server to deal with after we unmanage the window */
780 XPutBackEvent(ob_display
, e
);
782 client_unmanage(client
);
785 g_message("MapRequest for 0x%lx", client
->window
);
786 if (!client
->iconic
) break; /* this normally doesn't happen, but if it
787 does, we don't want it! */
788 if (screen_showing_desktop
)
789 screen_show_desktop(FALSE
);
790 client_iconify(client
, FALSE
, TRUE
);
791 if (!client
->frame
->visible
)
792 /* if its not visible still, then don't mess with it */
795 client_shade(client
, FALSE
);
796 client_focus(client
);
797 stacking_raise(CLIENT_AS_WINDOW(client
));
800 /* validate cuz we query stuff off the client here */
801 if (!client_validate(client
)) break;
803 if (e
->xclient
.format
!= 32) return;
805 msgtype
= e
->xclient
.message_type
;
806 if (msgtype
== prop_atoms
.wm_change_state
) {
807 /* compress changes into a single change */
808 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
809 client
->window
, &ce
)) {
810 /* XXX: it would be nice to compress ALL messages of a
811 type, not just messages in a row without other
812 message types between. */
813 if (ce
.xclient
.message_type
!= msgtype
) {
814 XPutBackEvent(ob_display
, &ce
);
817 e
->xclient
= ce
.xclient
;
819 client_set_wm_state(client
, e
->xclient
.data
.l
[0]);
820 } else if (msgtype
== prop_atoms
.net_wm_desktop
) {
821 /* compress changes into a single change */
822 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
823 client
->window
, &ce
)) {
824 /* XXX: it would be nice to compress ALL messages of a
825 type, not just messages in a row without other
826 message types between. */
827 if (ce
.xclient
.message_type
!= msgtype
) {
828 XPutBackEvent(ob_display
, &ce
);
831 e
->xclient
= ce
.xclient
;
833 if ((unsigned)e
->xclient
.data
.l
[0] < screen_num_desktops
||
834 (unsigned)e
->xclient
.data
.l
[0] == DESKTOP_ALL
)
835 client_set_desktop(client
, (unsigned)e
->xclient
.data
.l
[0],
837 } else if (msgtype
== prop_atoms
.net_wm_state
) {
838 /* can't compress these */
839 g_message("net_wm_state %s %ld %ld for 0x%lx",
840 (e
->xclient
.data
.l
[0] == 0 ? "Remove" :
841 e
->xclient
.data
.l
[0] == 1 ? "Add" :
842 e
->xclient
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
843 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2],
845 client_set_state(client
, e
->xclient
.data
.l
[0],
846 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[2]);
847 } else if (msgtype
== prop_atoms
.net_close_window
) {
848 g_message("net_close_window for 0x%lx", client
->window
);
849 client_close(client
);
850 } else if (msgtype
== prop_atoms
.net_active_window
) {
851 g_message("net_active_window for 0x%lx", client
->window
);
852 client_activate(client
);
853 } else if (msgtype
== prop_atoms
.net_wm_moveresize
) {
854 g_message("net_wm_moveresize for 0x%lx", client
->window
);
855 if ((Atom
)e
->xclient
.data
.l
[2] ==
856 prop_atoms
.net_wm_moveresize_size_topleft
||
857 (Atom
)e
->xclient
.data
.l
[2] ==
858 prop_atoms
.net_wm_moveresize_size_top
||
859 (Atom
)e
->xclient
.data
.l
[2] ==
860 prop_atoms
.net_wm_moveresize_size_topright
||
861 (Atom
)e
->xclient
.data
.l
[2] ==
862 prop_atoms
.net_wm_moveresize_size_right
||
863 (Atom
)e
->xclient
.data
.l
[2] ==
864 prop_atoms
.net_wm_moveresize_size_right
||
865 (Atom
)e
->xclient
.data
.l
[2] ==
866 prop_atoms
.net_wm_moveresize_size_bottomright
||
867 (Atom
)e
->xclient
.data
.l
[2] ==
868 prop_atoms
.net_wm_moveresize_size_bottom
||
869 (Atom
)e
->xclient
.data
.l
[2] ==
870 prop_atoms
.net_wm_moveresize_size_bottomleft
||
871 (Atom
)e
->xclient
.data
.l
[2] ==
872 prop_atoms
.net_wm_moveresize_size_left
||
873 (Atom
)e
->xclient
.data
.l
[2] ==
874 prop_atoms
.net_wm_moveresize_move
||
875 (Atom
)e
->xclient
.data
.l
[2] ==
876 prop_atoms
.net_wm_moveresize_size_keyboard
||
877 (Atom
)e
->xclient
.data
.l
[2] ==
878 prop_atoms
.net_wm_moveresize_move_keyboard
) {
880 moveresize_start(client
, e
->xclient
.data
.l
[0],
881 e
->xclient
.data
.l
[1], e
->xclient
.data
.l
[3],
882 e
->xclient
.data
.l
[2]);
884 } else if (msgtype
== prop_atoms
.net_moveresize_window
) {
885 int oldg
= client
->gravity
;
886 int tmpg
, x
, y
, w
, h
;
888 if (e
->xclient
.data
.l
[0] & 0xff)
889 tmpg
= e
->xclient
.data
.l
[0] & 0xff;
893 if (e
->xclient
.data
.l
[0] & 1 << 8)
894 x
= e
->xclient
.data
.l
[1];
897 if (e
->xclient
.data
.l
[0] & 1 << 9)
898 y
= e
->xclient
.data
.l
[2];
901 if (e
->xclient
.data
.l
[0] & 1 << 10)
902 w
= e
->xclient
.data
.l
[3];
905 if (e
->xclient
.data
.l
[0] & 1 << 11)
906 h
= e
->xclient
.data
.l
[4];
909 client
->gravity
= tmpg
;
910 client_configure(client
, OB_CORNER_TOPLEFT
,
911 x
, y
, w
, h
, FALSE
, TRUE
);
912 client
->gravity
= oldg
;
916 /* validate cuz we query stuff off the client here */
917 if (!client_validate(client
)) break;
919 /* compress changes to a single property into a single change */
920 while (XCheckTypedWindowEvent(ob_display
, e
->type
,
921 client
->window
, &ce
)) {
922 /* XXX: it would be nice to compress ALL changes to a property,
923 not just changes in a row without other props between. */
924 if (ce
.xproperty
.atom
!= e
->xproperty
.atom
) {
925 XPutBackEvent(ob_display
, &ce
);
930 msgtype
= e
->xproperty
.atom
;
931 if (msgtype
== XA_WM_NORMAL_HINTS
) {
932 client_update_normal_hints(client
);
933 /* normal hints can make a window non-resizable */
934 client_setup_decor_and_functions(client
);
936 else if (msgtype
== XA_WM_HINTS
)
937 client_update_wmhints(client
);
938 else if (msgtype
== XA_WM_TRANSIENT_FOR
) {
939 client_update_transient_for(client
);
940 client_get_type(client
);
941 /* type may have changed, so update the layer */
942 client_calc_layer(client
);
943 client_setup_decor_and_functions(client
);
945 else if (msgtype
== prop_atoms
.net_wm_name
||
946 msgtype
== prop_atoms
.wm_name
||
947 msgtype
== prop_atoms
.net_wm_icon_name
||
948 msgtype
== prop_atoms
.wm_icon_name
)
949 client_update_title(client
);
950 else if (msgtype
== prop_atoms
.wm_class
)
951 client_update_class(client
);
952 else if (msgtype
== prop_atoms
.wm_protocols
) {
953 client_update_protocols(client
);
954 client_setup_decor_and_functions(client
);
956 else if (msgtype
== prop_atoms
.net_wm_strut
)
957 client_update_strut(client
);
958 else if (msgtype
== prop_atoms
.net_wm_icon
||
959 msgtype
== prop_atoms
.kwm_win_icon
)
960 client_update_icons(client
);
964 if (extensions_shape
&& e
->type
== extensions_shape_event_basep
) {
965 client
->shaped
= ((XShapeEvent
*)e
)->shaped
;
966 frame_adjust_shape(client
->frame
);
972 static void event_handle_menu(ObClient
*client
, XEvent
*e
)
974 static ObMenuEntry
*over
= NULL
;
979 top
= g_list_nth_data(menu_visible
, 0);
981 g_message("EVENT %d", e
->type
);
984 if (e
->xkey
.keycode
== ob_keycode(OB_KEY_DOWN
))
985 over
= menu_control_keyboard_nav(over
, OB_KEY_DOWN
);
986 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_UP
))
987 over
= menu_control_keyboard_nav(over
, OB_KEY_UP
);
988 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_RETURN
))
989 over
= menu_control_keyboard_nav(over
, OB_KEY_RETURN
);
990 else if (e
->xkey
.keycode
== ob_keycode(OB_KEY_ESCAPE
))
991 over
= menu_control_keyboard_nav(over
, OB_KEY_ESCAPE
);
994 if (over
->parent
->mouseover
)
995 over
->parent
->mouseover(over
, FALSE
);
997 menu_control_mouseover(over
, FALSE
);
998 menu_entry_render(over
);
1010 if (e
->xbutton
.button
> 3) break;
1012 g_message("BUTTON PRESS");
1015 if (e
->xbutton
.button
> 3) break;
1017 g_message("BUTTON RELEASED");
1019 for (it
= menu_visible
; it
; it
= g_list_next(it
)) {
1020 ObMenu
*m
= it
->data
;
1021 if (e
->xbutton
.x_root
>= m
->location
.x
- ob_rr_theme
->bwidth
&&
1022 e
->xbutton
.y_root
>= m
->location
.y
- ob_rr_theme
->bwidth
&&
1023 e
->xbutton
.x_root
< m
->location
.x
+ m
->size
.width
+
1024 ob_rr_theme
->bwidth
&&
1025 e
->xbutton
.y_root
< m
->location
.y
+ m
->size
.height
+
1026 ob_rr_theme
->bwidth
) {
1027 if ((entry
= menu_find_entry_by_pos(it
->data
,
1033 if (over
->parent
->mouseover
)
1034 over
->parent
->mouseover(over
, FALSE
);
1036 menu_control_mouseover(over
, FALSE
);
1037 menu_entry_render(over
);
1039 /* this hides the menu */
1040 menu_entry_fire(entry
);
1048 if (over
->parent
->mouseover
)
1049 over
->parent
->mouseover(over
, FALSE
);
1051 menu_control_mouseover(over
, FALSE
);
1052 menu_entry_render(over
);
1065 g_message("motion");
1066 for (it
= menu_visible
; it
; it
= g_list_next(it
)) {
1067 ObMenu
*m
= it
->data
;
1068 if ((entry
= menu_find_entry_by_pos(it
->data
,
1073 if (over
&& entry
!= over
) {
1074 if (over
->parent
->mouseover
)
1075 over
->parent
->mouseover(over
, FALSE
);
1077 menu_control_mouseover(over
, FALSE
);
1078 menu_entry_render(over
);
1082 if (over
->parent
->mouseover
)
1083 over
->parent
->mouseover(over
, TRUE
);
1085 menu_control_mouseover(over
, TRUE
);
1086 menu_entry_render(over
);
1091 if (over
->parent
->mouseover
)
1092 over
->parent
->mouseover(over
, FALSE
);
1094 menu_control_mouseover(over
, FALSE
);
1095 menu_entry_render(over
);
1102 void event_add_fd_handler(event_fd_handler
*h
) {
1103 g_datalist_id_set_data(&fd_handler_list
, h
->fd
, h
);
1104 FD_SET(h
->fd
, &allset
);
1105 max_fd
= MAX(max_fd
, h
->fd
);
1108 static void find_max_fd_foreach(GQuark n
, gpointer data
, gpointer max
)
1110 *((unsigned int *)max
) = MAX(*((unsigned int *)max
), n
);
1113 static void find_max_fd()
1116 g_datalist_foreach(&fd_handler_list
, find_max_fd_foreach
,
1118 max_fd
= MAX(x_fd
, tmpmax
);
1120 max_fd
= MAX(ice_fd
, tmpmax
);
1124 void event_remove_fd(int n
)
1127 g_datalist_id_remove_data(&fd_handler_list
, (GQuark
)n
);
1131 static void fd_event_handle_foreach(GQuark n
, gpointer data
, gpointer user_data
)
1133 if (FD_ISSET( (int)n
, &selset
)) {
1134 event_fd_handler
*h
= (event_fd_handler
*)data
;
1135 g_assert(h
->fd
== (int)n
);
1136 h
->handler(h
->fd
, h
->data
);
1140 static void fd_event_handle()
1142 g_datalist_foreach(&fd_handler_list
, fd_event_handle_foreach
, NULL
);
1145 static void event_handle_dock(ObDock
*s
, XEvent
*e
)
1149 stacking_raise(DOCK_AS_WINDOW(s
));
1160 static void event_handle_dockapp(ObDockApp
*app
, XEvent
*e
)
1164 dock_app_drag(app
, &e
->xmotion
);
1167 if (app
->ignore_unmaps
) {
1168 app
->ignore_unmaps
--;
1171 dock_remove(app
, TRUE
);
1174 dock_remove(app
, FALSE
);
1176 case ReparentNotify
:
1177 dock_remove(app
, FALSE
);
1179 case ConfigureNotify
:
1180 dock_app_configure(app
, e
->xconfigure
.width
, e
->xconfigure
.height
);