X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fevent.c;h=a38a331fce77b3a16001d92284acf81268eb8516;hb=e0aa54a8912e34e94d42872dba95ade0fda7fdca;hp=051e29c03556edb0b13b230afaeec05c4024d1dc;hpb=16f46c296d1fcd3f27fc62a18e71c55fb3fd3e88;p=chaz%2Fopenbox diff --git a/openbox/event.c b/openbox/event.c index 051e29c0..a38a331f 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -1,6 +1,7 @@ /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- event.c for the Openbox window manager + Copyright (c) 2004 Mikael Magnusson Copyright (c) 2003 Ben Jansens This program is free software; you can redistribute it and/or modify @@ -16,7 +17,9 @@ See the COPYING file for a copy of the GNU General Public License. */ +#include "event.h" #include "debug.h" +#include "window.h" #include "openbox.h" #include "dock.h" #include "client.h" @@ -36,7 +39,6 @@ #include "group.h" #include "stacking.h" #include "extensions.h" -#include "event.h" #include #include @@ -49,6 +51,9 @@ #ifdef HAVE_SIGNAL_H # include #endif +#ifdef XKB +# include +#endif #ifdef USE_SM #include @@ -60,6 +65,7 @@ typedef struct } ObEventData; static void event_process(const XEvent *e, gpointer data); +static void event_client_dest(ObClient *client, gpointer data); static void event_handle_root(XEvent *e); static void event_handle_menu(XEvent *e); static void event_handle_dock(ObDock *s, XEvent *e); @@ -68,7 +74,7 @@ static void event_handle_client(ObClient *c, XEvent *e); static void event_handle_group(ObGroup *g, XEvent *e); static gboolean focus_delay_func(gpointer data); -static void focus_delay_client_dest(gpointer data); +static void focus_delay_client_dest(ObClient *client, gpointer data); static gboolean menu_hide_delay_func(gpointer data); @@ -83,24 +89,24 @@ static gboolean menu_hide_delay_func(gpointer data); Time event_lasttime = 0; /*! The value of the mask for the NumLock modifier */ -unsigned int NumLockMask; +guint NumLockMask; /*! The value of the mask for the ScrollLock modifier */ -unsigned int ScrollLockMask; +guint ScrollLockMask; /*! The key codes for the modifier keys */ static XModifierKeymap *modmap; /*! Table of the constant modifier masks */ -static const int mask_table[] = { +static const gint mask_table[] = { ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; -static int mask_table_size; +static gint mask_table_size; -static ObClient *focus_delay_client; +static guint ignore_enter_focus = 0; static gboolean menu_can_hide; #ifdef USE_SM -static void ice_handler(int fd, gpointer conn) +static void ice_handler(gint fd, gpointer conn) { Bool b; IceProcessMessages(conn, NULL, &b); @@ -131,23 +137,23 @@ void event_startup(gboolean reconfig) modmap = XGetModifierMapping(ob_display); g_assert(modmap); if (modmap && modmap->max_keypermod > 0) { - size_t cnt; - const size_t size = mask_table_size * modmap->max_keypermod; - /* get the values of the keyboard lock modifiers - Note: Caps lock is not retrieved the same way as Scroll and Num - lock since it doesn't need to be. */ - const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock); - const KeyCode scroll_lock = XKeysymToKeycode(ob_display, - XK_Scroll_Lock); - - for (cnt = 0; cnt < size; ++cnt) { - if (! modmap->modifiermap[cnt]) continue; - - if (num_lock == modmap->modifiermap[cnt]) - NumLockMask = mask_table[cnt / modmap->max_keypermod]; - if (scroll_lock == modmap->modifiermap[cnt]) - ScrollLockMask = mask_table[cnt / modmap->max_keypermod]; - } + size_t cnt; + const size_t size = mask_table_size * modmap->max_keypermod; + /* get the values of the keyboard lock modifiers + Note: Caps lock is not retrieved the same way as Scroll and Num + lock since it doesn't need to be. */ + const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock); + const KeyCode scroll_lock = XKeysymToKeycode(ob_display, + XK_Scroll_Lock); + + for (cnt = 0; cnt < size; ++cnt) { + if (! modmap->modifiermap[cnt]) continue; + + if (num_lock == modmap->modifiermap[cnt]) + NumLockMask = mask_table[cnt / modmap->max_keypermod]; + if (scroll_lock == modmap->modifiermap[cnt]) + ScrollLockMask = mask_table[cnt / modmap->max_keypermod]; + } } ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL); @@ -156,7 +162,8 @@ void event_startup(gboolean reconfig) IceAddConnectionWatch(ice_watch, NULL); #endif - client_add_destructor(focus_delay_client_dest); + client_add_destructor(focus_delay_client_dest, NULL); + client_add_destructor(event_client_dest, NULL); } void event_shutdown(gboolean reconfig) @@ -181,29 +188,29 @@ static Window event_get_window(XEvent *e) window = RootWindow(ob_display, ob_screen); break; case MapRequest: - window = e->xmap.window; - break; + window = e->xmap.window; + break; case UnmapNotify: - window = e->xunmap.window; - break; + window = e->xunmap.window; + break; case DestroyNotify: - window = e->xdestroywindow.window; - break; + window = e->xdestroywindow.window; + break; case ConfigureRequest: - window = e->xconfigurerequest.window; - break; + window = e->xconfigurerequest.window; + break; case ConfigureNotify: window = e->xconfigure.window; break; default: #ifdef XKB - if (extensions_xkb && e->type == extensions_xkb_event_basep) { - switch (((XkbAnyEvent*)e)->xkb_type) { - case XkbBellNotify: - window = ((XkbBellNotifyEvent*)e)->window; - default: - window = None; - } + if (extensions_xkb && e->type == extensions_xkb_event_basep) { + switch (((XkbAnyEvent*)e)->xkb_type) { + case XkbBellNotify: + window = ((XkbBellNotifyEvent*)e)->window; + default: + window = None; + } } else #endif window = e->xany.window; @@ -219,24 +226,24 @@ static void event_set_lasttime(XEvent *e) switch (e->type) { case ButtonPress: case ButtonRelease: - t = e->xbutton.time; - break; + t = e->xbutton.time; + break; case KeyPress: - t = e->xkey.time; - break; + t = e->xkey.time; + break; case KeyRelease: - t = e->xkey.time; - break; + t = e->xkey.time; + break; case MotionNotify: - t = e->xmotion.time; - break; + t = e->xmotion.time; + break; case PropertyNotify: - t = e->xproperty.time; - break; + t = e->xproperty.time; + break; case EnterNotify: case LeaveNotify: - t = e->xcrossing.time; - break; + t = e->xcrossing.time; + break; default: /* if more event types are anticipated, get their timestamp explicitly */ @@ -248,45 +255,54 @@ static void event_set_lasttime(XEvent *e) } #define STRIP_MODS(s) \ - s &= ~(LockMask | NumLockMask | ScrollLockMask), \ - /* kill off the Button1Mask etc, only want the modifiers */ \ - s &= (ControlMask | ShiftMask | Mod1Mask | \ + s &= ~(LockMask | NumLockMask | ScrollLockMask), \ + /* kill off the Button1Mask etc, only want the modifiers */ \ + s &= (ControlMask | ShiftMask | Mod1Mask | \ Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \ static void event_hack_mods(XEvent *e) { +#ifdef XKB + XkbStateRec xkb_state; +#endif KeyCode *kp; - int i, k; + gint i, k; switch (e->type) { case ButtonPress: case ButtonRelease: STRIP_MODS(e->xbutton.state); - break; + break; case KeyPress: STRIP_MODS(e->xkey.state); - break; + break; case KeyRelease: STRIP_MODS(e->xkey.state); - /* remove from the state the mask of the modifier being released, if - it is a modifier key being released (this is a little ugly..) */ - kp = modmap->modifiermap; - for (i = 0; i < mask_table_size; ++i) { - for (k = 0; k < modmap->max_keypermod; ++k) { - if (*kp == e->xkey.keycode) { /* found the keycode */ - /* remove the mask for it */ - e->xkey.state &= ~mask_table[i]; - /* cause the first loop to break; */ - i = mask_table_size; - break; /* get outta here! */ - } - ++kp; - } - } - break; + /* remove from the state the mask of the modifier being released, if + it is a modifier key being released (this is a little ugly..) */ +#ifdef XKB + if (XkbGetState(ob_display, XkbUseCoreKbd, &xkb_state) == Success) { + e->xkey.state = xkb_state.compat_state; + break; + } +#endif + kp = modmap->modifiermap; + for (i = 0; i < mask_table_size; ++i) { + for (k = 0; k < modmap->max_keypermod; ++k) { + if (*kp == e->xkey.keycode) { /* found the keycode */ + /* remove the mask for it */ + e->xkey.state &= ~mask_table[i]; + /* cause the first loop to break; */ + i = mask_table_size; + break; /* get outta here! */ + } + ++kp; + } + } + break; case MotionNotify: STRIP_MODS(e->xmotion.state); - /* compress events */ + /* compress events */ { XEvent ce; while (XCheckTypedWindowEvent(ob_display, e->xmotion.window, @@ -294,14 +310,19 @@ static void event_hack_mods(XEvent *e) e->xmotion.x_root = ce.xmotion.x_root; e->xmotion.y_root = ce.xmotion.y_root; } - } - break; + } + break; } } static gboolean event_ignore(XEvent *e, ObClient *client) { switch(e->type) { + case EnterNotify: + case LeaveNotify: + if (e->xcrossing.detail == NotifyInferior) + return TRUE; + break; case FocusIn: /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut because of RevertToPointerRoot. If the focus ends up reverting to @@ -309,7 +330,7 @@ static gboolean event_ignore(XEvent *e, ObClient *client) want will be of type NotifyAncestor. This situation does not occur for FocusOut, so it is safely ignored there. */ - if (INVALID_FOCUSIN(e) || + if (INVALID_FOCUSIN(e) || client == NULL) { #ifdef DEBUG_FOCUS ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n", @@ -328,7 +349,7 @@ static gboolean event_ignore(XEvent *e, ObClient *client) #endif break; case FocusOut: - if (INVALID_FOCUSOUT(e)) { + if (INVALID_FOCUSOUT(e)) { #ifdef DEBUG_FOCUS ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n", e->xfocus.window, e->xfocus.mode, e->xfocus.detail); @@ -340,7 +361,6 @@ static gboolean event_ignore(XEvent *e, ObClient *client) ob_debug("FocusOut on %lx mode %d detail %d\n", e->xfocus.window, e->xfocus.mode, e->xfocus.detail); #endif - { XEvent fe; gboolean fallback = TRUE; @@ -420,34 +440,7 @@ static gboolean event_ignore(XEvent *e, ObClient *client) focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS); } } - break; - case EnterNotify: - case LeaveNotify: - /* NotifyUngrab occurs when a mouse button is released and the event is - caused, like when lowering a window */ - /* NotifyVirtual and NotifyAncestor occurs when ungrabbing the - pointer (Ancestor happens when the pointer is on a window border) */ - if (e->xcrossing.mode == NotifyGrab || - e->xcrossing.detail == NotifyInferior || - (e->xcrossing.mode == NotifyUngrab && - (e->xcrossing.detail == NotifyAncestor || - e->xcrossing.detail == NotifyNonlinearVirtual || - e->xcrossing.detail == NotifyVirtual))) { -#ifdef DEBUG_FOCUS - ob_debug("%sNotify mode %d detail %d on %lx IGNORED\n", - (e->type == EnterNotify ? "Enter" : "Leave"), - e->xcrossing.mode, - e->xcrossing.detail, client?client->window:0); -#endif - return TRUE; - } -#ifdef DEBUG_FOCUS - ob_debug("%sNotify mode %d detail %d on %lx\n", - (e->type == EnterNotify ? "Enter" : "Leave"), - e->xcrossing.mode, - e->xcrossing.detail, client?client->window:0); -#endif - break; + break; } return FALSE; } @@ -500,36 +493,36 @@ static void event_process(const XEvent *ec, gpointer data) /* deal with it in the kernel */ if (group) - event_handle_group(group, e); + event_handle_group(group, e); else if (client) - event_handle_client(client, e); + event_handle_client(client, e); else if (dockapp) - event_handle_dockapp(dockapp, e); + event_handle_dockapp(dockapp, e); else if (dock) - event_handle_dock(dock, e); + event_handle_dock(dock, e); else if (window == RootWindow(ob_display, ob_screen)) - event_handle_root(e); + event_handle_root(e); else if (e->type == MapRequest) - client_manage(window); + client_manage(window); else if (e->type == ConfigureRequest) { - /* unhandled configure requests must be used to configure the - window directly */ - XWindowChanges xwc; - - xwc.x = e->xconfigurerequest.x; - xwc.y = e->xconfigurerequest.y; - xwc.width = e->xconfigurerequest.width; - xwc.height = e->xconfigurerequest.height; - xwc.border_width = e->xconfigurerequest.border_width; - xwc.sibling = e->xconfigurerequest.above; - xwc.stack_mode = e->xconfigurerequest.detail; + /* unhandled configure requests must be used to configure the + window directly */ + XWindowChanges xwc; + + xwc.x = e->xconfigurerequest.x; + xwc.y = e->xconfigurerequest.y; + xwc.width = e->xconfigurerequest.width; + xwc.height = e->xconfigurerequest.height; + xwc.border_width = e->xconfigurerequest.border_width; + xwc.sibling = e->xconfigurerequest.above; + xwc.stack_mode = e->xconfigurerequest.detail; - /* we are not to be held responsible if someone sends us an - invalid request! */ - xerror_set_ignore(TRUE); - XConfigureWindow(ob_display, window, - e->xconfigurerequest.value_mask, &xwc); - xerror_set_ignore(FALSE); + /* we are not to be held responsible if someone sends us an + invalid request! */ + xerror_set_ignore(TRUE); + XConfigureWindow(ob_display, window, + e->xconfigurerequest.value_mask, &xwc); + xerror_set_ignore(FALSE); } /* user input (action-bound) events */ @@ -541,12 +534,17 @@ static void event_process(const XEvent *ec, gpointer data) event_handle_menu(e); else { if (!keyboard_process_interactive_grab(e, &client)) { - if (moveresize_in_progress) + if (moveresize_in_progress) { moveresize_event(e); + /* make further actions work on the client being + moved/resized */ + client = moveresize_client; + } + menu_can_hide = FALSE; ob_main_loop_timeout_add(ob_main_loop, - G_USEC_PER_SEC / 4, + config_menu_hide_delay * 1000, menu_hide_delay_func, NULL, NULL); @@ -554,12 +552,9 @@ static void event_process(const XEvent *ec, gpointer data) e->type == MotionNotify) mouse_event(client, e); else if (e->type == KeyPress) - /* when in the middle of a focus cycling action, this - causes the window which appears to be focused to be - the one on which the actions will be executed */ - keyboard_event((focus_cycle_target ? - focus_cycle_target : - (client ? client : focus_client)), e); + keyboard_event((focus_cycle_target ? focus_cycle_target : + (focus_hilite ? focus_hilite : client)), + e); } } } @@ -576,27 +571,27 @@ static void event_handle_root(XEvent *e) break; case ClientMessage: - if (e->xclient.format != 32) break; - - msgtype = e->xclient.message_type; - if (msgtype == prop_atoms.net_current_desktop) { - unsigned int d = e->xclient.data.l[0]; - if (d < screen_num_desktops) - screen_set_desktop(d); - } else if (msgtype == prop_atoms.net_number_of_desktops) { - unsigned int d = e->xclient.data.l[0]; - if (d > 0) - screen_set_num_desktops(d); - } else if (msgtype == prop_atoms.net_showing_desktop) { - screen_show_desktop(e->xclient.data.l[0] != 0); - } - break; + if (e->xclient.format != 32) break; + + msgtype = e->xclient.message_type; + if (msgtype == prop_atoms.net_current_desktop) { + guint d = e->xclient.data.l[0]; + if (d < screen_num_desktops) + screen_set_desktop(d); + } else if (msgtype == prop_atoms.net_number_of_desktops) { + guint d = e->xclient.data.l[0]; + if (d > 0) + screen_set_num_desktops(d); + } else if (msgtype == prop_atoms.net_showing_desktop) { + screen_show_desktop(e->xclient.data.l[0] != 0); + } + break; case PropertyNotify: - if (e->xproperty.atom == prop_atoms.net_desktop_names) - screen_update_desktop_names(); - else if (e->xproperty.atom == prop_atoms.net_desktop_layout) - screen_update_layout(); - break; + if (e->xproperty.atom == prop_atoms.net_desktop_names) + screen_update_desktop_names(); + else if (e->xproperty.atom == prop_atoms.net_desktop_layout) + screen_update_layout(); + break; case ConfigureNotify: #ifdef XRANDR XRRUpdateConfiguration(e); @@ -605,11 +600,6 @@ static void event_handle_root(XEvent *e) break; default: ; -#ifdef VIDMODE - if (extensions_vidmode && e->type == extensions_vidmode_event_basep) { - ob_debug("VIDMODE EVENT\n"); - } -#endif } } @@ -623,11 +613,27 @@ static void event_handle_group(ObGroup *group, XEvent *e) event_handle_client(it->data, e); } +void event_enter_client(ObClient *client) +{ + g_assert(config_focus_follow); + + if (client_normal(client) && client_can_focus(client)) { + if (config_focus_delay) { + ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func); + ob_main_loop_timeout_add(ob_main_loop, + config_focus_delay, + focus_delay_func, + client, NULL); + } else + focus_delay_func(client); + } +} + static void event_handle_client(ObClient *client, XEvent *e) { XEvent ce; Atom msgtype; - int i=0; + gint i=0; ObFrameContext con; switch (e->type) { @@ -670,27 +676,26 @@ static void event_handle_client(ObClient *client, XEvent *e) break; case FocusIn: #ifdef DEBUG_FOCUS - ob_debug("FocusIn on client for %lx\n", client->window); + ob_debug("FocusIn on client for %lx (client %lx) mode %d detail %d\n", + e->xfocus.window, client->window, + e->xfocus.mode, e->xfocus.detail); #endif if (client != focus_client) { focus_set_client(client); frame_adjust_focus(client->frame, TRUE); + client_calc_layer(client); } break; case FocusOut: #ifdef DEBUG_FOCUS - ob_debug("FocusOut on client for %lx\n", client->window); + ob_debug("FocusOut on client for %lx (client %lx) mode %d detail %d\n", + e->xfocus.window, client->window, + e->xfocus.mode, e->xfocus.detail); #endif - /* are we a fullscreen window or a transient of one? (checks layer) - if we are then we need to be iconified since we are losing focus - */ - if (client->layer == OB_STACKING_LAYER_FULLSCREEN && !client->iconic && - !client_search_focus_tree_full(client)) - /* iconify fullscreen windows when they and their transients - aren't focused */ - client_iconify(client, TRUE, TRUE); + focus_hilite = NULL; frame_adjust_focus(client->frame, FALSE); - break; + client_calc_layer(client); + break; case LeaveNotify: con = frame_context(client, e->xcrossing.window); switch (con) { @@ -715,19 +720,24 @@ static void event_handle_client(ObClient *client, XEvent *e) frame_adjust_state(client->frame); break; case OB_FRAME_CONTEXT_FRAME: - /* XXX if doing a 'reconfigure' make sure you kill this timer, - maybe all timers.. */ - if (config_focus_delay && client == focus_delay_client) { + if (config_focus_follow && config_focus_delay) ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, - focus_delay_client); - focus_delay_client = NULL; - } + client); + break; default: break; } break; case EnterNotify: + { + gboolean nofocus = FALSE; + + if (ignore_enter_focus) { + ignore_enter_focus--; + nofocus = TRUE; + } + con = frame_context(client, e->xcrossing.window); switch (con) { case OB_FRAME_CONTEXT_MAXIMIZE: @@ -751,80 +761,86 @@ static void event_handle_client(ObClient *client, XEvent *e) frame_adjust_state(client->frame); break; case OB_FRAME_CONTEXT_FRAME: - if (client_normal(client)) { - if (config_focus_follow) { + if (e->xcrossing.mode == NotifyGrab || + e->xcrossing.mode == NotifyUngrab) + { #ifdef DEBUG_FOCUS - ob_debug("EnterNotify on %lx, focusing window\n", - client->window); + ob_debug("%sNotify mode %d detail %d on %lx IGNORED\n", + (e->type == EnterNotify ? "Enter" : "Leave"), + e->xcrossing.mode, + e->xcrossing.detail, client?client->window:0); #endif - if (config_focus_delay) { - ob_main_loop_timeout_add(ob_main_loop, - config_focus_delay, - focus_delay_func, - client, NULL); - focus_delay_client = client; - } else - client_focus(client); - } + } else { +#ifdef DEBUG_FOCUS + ob_debug("%sNotify mode %d detail %d on %lx, " + "focusing window: %d\n", + (e->type == EnterNotify ? "Enter" : "Leave"), + e->xcrossing.mode, + e->xcrossing.detail, (client?client->window:0), + !nofocus); +#endif + if (!nofocus && config_focus_follow) + event_enter_client(client); } break; default: break; } break; + } case ConfigureRequest: - /* compress these */ - while (XCheckTypedWindowEvent(ob_display, client->window, - ConfigureRequest, &ce)) { + /* compress these */ + while (XCheckTypedWindowEvent(ob_display, client->window, + ConfigureRequest, &ce)) { ++i; - /* XXX if this causes bad things.. we can compress config req's - with the same mask. */ - e->xconfigurerequest.value_mask |= - ce.xconfigurerequest.value_mask; - if (ce.xconfigurerequest.value_mask & CWX) - e->xconfigurerequest.x = ce.xconfigurerequest.x; - if (ce.xconfigurerequest.value_mask & CWY) - e->xconfigurerequest.y = ce.xconfigurerequest.y; - if (ce.xconfigurerequest.value_mask & CWWidth) - e->xconfigurerequest.width = ce.xconfigurerequest.width; - if (ce.xconfigurerequest.value_mask & CWHeight) - e->xconfigurerequest.height = ce.xconfigurerequest.height; - if (ce.xconfigurerequest.value_mask & CWBorderWidth) - e->xconfigurerequest.border_width = - ce.xconfigurerequest.border_width; - if (ce.xconfigurerequest.value_mask & CWStackMode) - e->xconfigurerequest.detail = ce.xconfigurerequest.detail; - } - - /* if we are iconic (or shaded (fvwm does this)) ignore the event */ - if (client->iconic || client->shaded) return; - - /* resize, then move, as specified in the EWMH section 7.7 */ - if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight | - CWX | CWY | + /* XXX if this causes bad things.. we can compress config req's + with the same mask. */ + e->xconfigurerequest.value_mask |= + ce.xconfigurerequest.value_mask; + if (ce.xconfigurerequest.value_mask & CWX) + e->xconfigurerequest.x = ce.xconfigurerequest.x; + if (ce.xconfigurerequest.value_mask & CWY) + e->xconfigurerequest.y = ce.xconfigurerequest.y; + if (ce.xconfigurerequest.value_mask & CWWidth) + e->xconfigurerequest.width = ce.xconfigurerequest.width; + if (ce.xconfigurerequest.value_mask & CWHeight) + e->xconfigurerequest.height = ce.xconfigurerequest.height; + if (ce.xconfigurerequest.value_mask & CWBorderWidth) + e->xconfigurerequest.border_width = + ce.xconfigurerequest.border_width; + if (ce.xconfigurerequest.value_mask & CWStackMode) + e->xconfigurerequest.detail = ce.xconfigurerequest.detail; + } + + /* if we are iconic (or shaded (fvwm does this)) ignore the event */ + if (client->iconic || client->shaded) return; + + /* resize, then move, as specified in the EWMH section 7.7 */ + if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight | + CWX | CWY | CWBorderWidth)) { - int x, y, w, h; - ObCorner corner; + gint x, y, w, h; + ObCorner corner; if (e->xconfigurerequest.value_mask & CWBorderWidth) client->border_width = e->xconfigurerequest.border_width; - x = (e->xconfigurerequest.value_mask & CWX) ? - e->xconfigurerequest.x : client->area.x; - y = (e->xconfigurerequest.value_mask & CWY) ? - e->xconfigurerequest.y : client->area.y; - w = (e->xconfigurerequest.value_mask & CWWidth) ? - e->xconfigurerequest.width : client->area.width; - h = (e->xconfigurerequest.value_mask & CWHeight) ? - e->xconfigurerequest.height : client->area.height; + x = (e->xconfigurerequest.value_mask & CWX) ? + e->xconfigurerequest.x : client->area.x; + y = (e->xconfigurerequest.value_mask & CWY) ? + e->xconfigurerequest.y : client->area.y; + w = (e->xconfigurerequest.value_mask & CWWidth) ? + e->xconfigurerequest.width : client->area.width; + h = (e->xconfigurerequest.value_mask & CWHeight) ? + e->xconfigurerequest.height : client->area.height; { - int newx = x; - int newy = y; - int fw = w + - client->frame->size.left + client->frame->size.right; - int fh = h + - client->frame->size.top + client->frame->size.bottom; + gint newx = x; + gint newy = y; + gint fw = w + + client->frame->size.left + client->frame->size.right; + gint fh = h + + client->frame->size.top + client->frame->size.bottom; client_find_onscreen(client, &newx, &newy, fw, fh, client_normal(client)); if (e->xconfigurerequest.value_mask & CWX) @@ -832,140 +848,134 @@ static void event_handle_client(ObClient *client, XEvent *e) if (e->xconfigurerequest.value_mask & CWY) y = newy; } - - switch (client->gravity) { - case NorthEastGravity: - case EastGravity: - corner = OB_CORNER_TOPRIGHT; - break; - case SouthWestGravity: - case SouthGravity: - corner = OB_CORNER_BOTTOMLEFT; - break; - case SouthEastGravity: - corner = OB_CORNER_BOTTOMRIGHT; - break; - default: /* NorthWest, Static, etc */ - corner = OB_CORNER_TOPLEFT; - } - - client_configure_full(client, corner, x, y, w, h, FALSE, TRUE, + + switch (client->gravity) { + case NorthEastGravity: + case EastGravity: + corner = OB_CORNER_TOPRIGHT; + break; + case SouthWestGravity: + case SouthGravity: + corner = OB_CORNER_BOTTOMLEFT; + break; + case SouthEastGravity: + corner = OB_CORNER_BOTTOMRIGHT; + break; + default: /* NorthWest, Static, etc */ + corner = OB_CORNER_TOPLEFT; + } + + client_configure_full(client, corner, x, y, w, h, FALSE, TRUE, TRUE); - } - - if (e->xconfigurerequest.value_mask & CWStackMode) { - switch (e->xconfigurerequest.detail) { - case Below: - case BottomIf: - stacking_lower(CLIENT_AS_WINDOW(client)); - break; - - case Above: - case TopIf: - default: - stacking_raise(CLIENT_AS_WINDOW(client)); - break; - } - } - break; + } + + if (e->xconfigurerequest.value_mask & CWStackMode) { + switch (e->xconfigurerequest.detail) { + case Below: + case BottomIf: + client_lower(client); + break; + + case Above: + case TopIf: + default: + client_raise(client); + break; + } + } + break; case UnmapNotify: - if (client->ignore_unmaps) { - client->ignore_unmaps--; - break; - } - client_unmanage(client); - break; + if (client->ignore_unmaps) { + client->ignore_unmaps--; + break; + } + client_unmanage(client); + break; case DestroyNotify: - client_unmanage(client); - break; + client_unmanage(client); + break; case ReparentNotify: - /* this is when the client is first taken captive in the frame */ - if (e->xreparent.parent == client->frame->plate) break; - - /* - This event is quite rare and is usually handled in unmapHandler. - However, if the window is unmapped when the reparent event occurs, - the window manager never sees it because an unmap event is not sent - to an already unmapped window. - */ - - /* we don't want the reparent event, put it back on the stack for the - X server to deal with after we unmanage the window */ - XPutBackEvent(ob_display, e); + /* this is when the client is first taken captive in the frame */ + if (e->xreparent.parent == client->frame->plate) break; + + /* + This event is quite rare and is usually handled in unmapHandler. + However, if the window is unmapped when the reparent event occurs, + the window manager never sees it because an unmap event is not sent + to an already unmapped window. + */ + + /* we don't want the reparent event, put it back on the stack for the + X server to deal with after we unmanage the window */ + XPutBackEvent(ob_display, e); - client_unmanage(client); - break; + client_unmanage(client); + break; case MapRequest: ob_debug("MapRequest for 0x%lx\n", client->window); if (!client->iconic) break; /* this normally doesn't happen, but if it - does, we don't want it! */ - if (screen_showing_desktop) - screen_show_desktop(FALSE); - client_iconify(client, FALSE, TRUE); - if (!client->frame->visible) - /* if its not visible still, then don't mess with it */ - break; - if (client->shaded) - client_shade(client, FALSE); - client_focus(client); - stacking_raise(CLIENT_AS_WINDOW(client)); - break; + does, we don't want it! + it can happen now when the window is on + another desktop, but we still don't + want it! */ + client_activate(client, FALSE); + break; case ClientMessage: - /* validate cuz we query stuff off the client here */ - if (!client_validate(client)) break; - - if (e->xclient.format != 32) return; - - msgtype = e->xclient.message_type; - if (msgtype == prop_atoms.wm_change_state) { - /* compress changes into a single change */ - while (XCheckTypedWindowEvent(ob_display, client->window, - e->type, &ce)) { - /* XXX: it would be nice to compress ALL messages of a - type, not just messages in a row without other - message types between. */ - if (ce.xclient.message_type != msgtype) { - XPutBackEvent(ob_display, &ce); - break; - } - e->xclient = ce.xclient; - } - client_set_wm_state(client, e->xclient.data.l[0]); - } else if (msgtype == prop_atoms.net_wm_desktop) { - /* compress changes into a single change */ - while (XCheckTypedWindowEvent(ob_display, client->window, - e->type, &ce)) { - /* XXX: it would be nice to compress ALL messages of a - type, not just messages in a row without other - message types between. */ - if (ce.xclient.message_type != msgtype) { - XPutBackEvent(ob_display, &ce); - break; - } - e->xclient = ce.xclient; - } + /* validate cuz we query stuff off the client here */ + if (!client_validate(client)) break; + + if (e->xclient.format != 32) return; + + msgtype = e->xclient.message_type; + if (msgtype == prop_atoms.wm_change_state) { + /* compress changes into a single change */ + while (XCheckTypedWindowEvent(ob_display, client->window, + e->type, &ce)) { + /* XXX: it would be nice to compress ALL messages of a + type, not just messages in a row without other + message types between. */ + if (ce.xclient.message_type != msgtype) { + XPutBackEvent(ob_display, &ce); + break; + } + e->xclient = ce.xclient; + } + client_set_wm_state(client, e->xclient.data.l[0]); + } else if (msgtype == prop_atoms.net_wm_desktop) { + /* compress changes into a single change */ + while (XCheckTypedWindowEvent(ob_display, client->window, + e->type, &ce)) { + /* XXX: it would be nice to compress ALL messages of a + type, not just messages in a row without other + message types between. */ + if (ce.xclient.message_type != msgtype) { + XPutBackEvent(ob_display, &ce); + break; + } + e->xclient = ce.xclient; + } if ((unsigned)e->xclient.data.l[0] < screen_num_desktops || (unsigned)e->xclient.data.l[0] == DESKTOP_ALL) client_set_desktop(client, (unsigned)e->xclient.data.l[0], FALSE); - } else if (msgtype == prop_atoms.net_wm_state) { - /* can't compress these */ - ob_debug("net_wm_state %s %ld %ld for 0x%lx\n", + } else if (msgtype == prop_atoms.net_wm_state) { + /* can't compress these */ + ob_debug("net_wm_state %s %ld %ld for 0x%lx\n", (e->xclient.data.l[0] == 0 ? "Remove" : e->xclient.data.l[0] == 1 ? "Add" : e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"), e->xclient.data.l[1], e->xclient.data.l[2], client->window); - client_set_state(client, e->xclient.data.l[0], - e->xclient.data.l[1], e->xclient.data.l[2]); - } else if (msgtype == prop_atoms.net_close_window) { - ob_debug("net_close_window for 0x%lx\n", client->window); - client_close(client); - } else if (msgtype == prop_atoms.net_active_window) { - ob_debug("net_active_window for 0x%lx\n", client->window); + client_set_state(client, e->xclient.data.l[0], + e->xclient.data.l[1], e->xclient.data.l[2]); + } else if (msgtype == prop_atoms.net_close_window) { + ob_debug("net_close_window for 0x%lx\n", client->window); + client_close(client); + } else if (msgtype == prop_atoms.net_active_window) { + ob_debug("net_active_window for 0x%lx\n", client->window); client_activate(client, FALSE); - } else if (msgtype == prop_atoms.net_wm_moveresize) { - ob_debug("net_wm_moveresize for 0x%lx\n", client->window); + } else if (msgtype == prop_atoms.net_wm_moveresize) { + ob_debug("net_wm_moveresize for 0x%lx\n", client->window); if ((Atom)e->xclient.data.l[2] == prop_atoms.net_wm_moveresize_size_topleft || (Atom)e->xclient.data.l[2] == @@ -996,8 +1006,8 @@ static void event_handle_client(ObClient *client, XEvent *e) e->xclient.data.l[2]); } } else if (msgtype == prop_atoms.net_moveresize_window) { - int oldg = client->gravity; - int tmpg, x, y, w, h; + gint oldg = client->gravity; + gint tmpg, x, y, w, h; if (e->xclient.data.l[0] & 0xff) tmpg = e->xclient.data.l[0] & 0xff; @@ -1023,12 +1033,12 @@ static void event_handle_client(ObClient *client, XEvent *e) client->gravity = tmpg; { - int newx = x; - int newy = y; - int fw = w + - client->frame->size.left + client->frame->size.right; - int fh = h + - client->frame->size.top + client->frame->size.bottom; + gint newx = x; + gint newy = y; + gint fw = w + + client->frame->size.left + client->frame->size.right; + gint fh = h + + client->frame->size.top + client->frame->size.bottom; client_find_onscreen(client, &newx, &newy, fw, fh, client_normal(client)); if (e->xclient.data.l[0] & 1 << 8) @@ -1036,24 +1046,24 @@ static void event_handle_client(ObClient *client, XEvent *e) if (e->xclient.data.l[0] & 1 << 9) y = newy; } - + client_configure(client, OB_CORNER_TOPLEFT, x, y, w, h, FALSE, TRUE); client->gravity = oldg; } - break; + break; case PropertyNotify: - /* validate cuz we query stuff off the client here */ - if (!client_validate(client)) break; + /* validate cuz we query stuff off the client here */ + if (!client_validate(client)) break; - /* compress changes to a single property into a single change */ - while (XCheckTypedWindowEvent(ob_display, client->window, - e->type, &ce)) { + /* compress changes to a single property into a single change */ + while (XCheckTypedWindowEvent(ob_display, client->window, + e->type, &ce)) { Atom a, b; /* XXX: it would be nice to compress ALL changes to a property, - not just changes in a row without other props between. */ + not just changes in a row without other props between. */ a = ce.xproperty.atom; b = e->xproperty.atom; @@ -1080,38 +1090,38 @@ static void event_handle_client(ObClient *client, XEvent *e) XPutBackEvent(ob_display, &ce); break; - } - - msgtype = e->xproperty.atom; - if (msgtype == XA_WM_NORMAL_HINTS) { - client_update_normal_hints(client); - /* normal hints can make a window non-resizable */ - client_setup_decor_and_functions(client); - } else if (msgtype == XA_WM_HINTS) { - client_update_wmhints(client); - } else if (msgtype == XA_WM_TRANSIENT_FOR) { - client_update_transient_for(client); - client_get_type(client); - /* type may have changed, so update the layer */ - client_calc_layer(client); - client_setup_decor_and_functions(client); - } else if (msgtype == prop_atoms.net_wm_name || + } + + msgtype = e->xproperty.atom; + if (msgtype == XA_WM_NORMAL_HINTS) { + client_update_normal_hints(client); + /* normal hints can make a window non-resizable */ + client_setup_decor_and_functions(client); + } else if (msgtype == XA_WM_HINTS) { + client_update_wmhints(client); + } else if (msgtype == XA_WM_TRANSIENT_FOR) { + client_update_transient_for(client); + client_get_type(client); + /* type may have changed, so update the layer */ + client_calc_layer(client); + client_setup_decor_and_functions(client); + } else if (msgtype == prop_atoms.net_wm_name || msgtype == prop_atoms.wm_name || msgtype == prop_atoms.net_wm_icon_name || msgtype == prop_atoms.wm_icon_name) { - client_update_title(client); - } else if (msgtype == prop_atoms.wm_class) { - client_update_class(client); + client_update_title(client); + } else if (msgtype == prop_atoms.wm_class) { + client_update_class(client); } else if (msgtype == prop_atoms.wm_protocols) { - client_update_protocols(client); - client_setup_decor_and_functions(client); - } - else if (msgtype == prop_atoms.net_wm_strut) { - client_update_strut(client); + client_update_protocols(client); + client_setup_decor_and_functions(client); + } + else if (msgtype == prop_atoms.net_wm_strut) { + client_update_strut(client); } - else if (msgtype == prop_atoms.net_wm_icon || + else if (msgtype == prop_atoms.net_wm_icon || msgtype == prop_atoms.kwm_win_icon) { - client_update_icons(client); + client_update_icons(client); } else if (msgtype == prop_atoms.sm_client_id) { client_update_sm_client_id(client); @@ -1131,7 +1141,10 @@ static void event_handle_dock(ObDock *s, XEvent *e) { switch (e->type) { case ButtonPress: - stacking_raise(DOCK_AS_WINDOW(s)); + if (e->xbutton.button == 1) + stacking_raise(DOCK_AS_WINDOW(s), FALSE); + else if (e->xbutton.button == 2) + stacking_lower(DOCK_AS_WINDOW(s), FALSE); break; case EnterNotify: dock_hide(FALSE); @@ -1149,18 +1162,18 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e) dock_app_drag(app, &e->xmotion); break; case UnmapNotify: - if (app->ignore_unmaps) { - app->ignore_unmaps--; - break; - } - dock_remove(app, TRUE); - break; + if (app->ignore_unmaps) { + app->ignore_unmaps--; + break; + } + dock_remove(app, TRUE); + break; case DestroyNotify: - dock_remove(app, FALSE); - break; + dock_remove(app, FALSE); + break; case ReparentNotify: - dock_remove(app, FALSE); - break; + dock_remove(app, FALSE); + break; case ConfigureNotify: dock_app_configure(app, e->xconfigure.width, e->xconfigure.height); break; @@ -1170,14 +1183,25 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e) ObMenuFrame* find_active_menu() { GList *it; - ObMenuFrame *f; + ObMenuFrame *ret = NULL; for (it = menu_frame_visible; it; it = g_list_next(it)) { - f = it->data; - if (f->selected) + ret = it->data; + if (ret->selected) break; + ret = NULL; } - return it ? it->data : NULL; + return ret; +} + +ObMenuFrame* find_active_or_last_menu() +{ + ObMenuFrame *ret = NULL; + + ret = find_active_menu(); + if (!ret && menu_frame_visible) + ret = menu_frame_visible->data; + return ret; } static void event_handle_menu(XEvent *ev) @@ -1187,11 +1211,13 @@ static void event_handle_menu(XEvent *ev) switch (ev->type) { case ButtonRelease: - if ((e = menu_entry_frame_under(ev->xbutton.x_root, - ev->xbutton.y_root))) - menu_entry_frame_execute(e, ev->xbutton.state); - else if (menu_can_hide) - menu_frame_hide_all(); + if (menu_can_hide) { + if ((e = menu_entry_frame_under(ev->xbutton.x_root, + ev->xbutton.y_root))) + menu_entry_frame_execute(e, ev->xbutton.state); + else + menu_frame_hide_all(); + } break; case MotionNotify: if ((f = menu_frame_under(ev->xmotion.x_root, @@ -1221,19 +1247,19 @@ static void event_handle_menu(XEvent *ev) menu_entry_frame_execute(f->selected, ev->xkey.state); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) { ObMenuFrame *f; - if ((f = find_active_menu()) && f->parent) + if ((f = find_active_or_last_menu()) && f->parent) menu_frame_select(f, NULL); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) { ObMenuFrame *f; - if ((f = find_active_menu()) && f->child) + if ((f = find_active_or_last_menu()) && f->child) menu_frame_select_next(f->child); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_UP)) { ObMenuFrame *f; - if ((f = find_active_menu())) + if ((f = find_active_or_last_menu())) menu_frame_select_previous(f); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_DOWN)) { ObMenuFrame *f; - if ((f = find_active_menu())) + if ((f = find_active_or_last_menu())) menu_frame_select_next(f); } break; @@ -1248,16 +1274,59 @@ static gboolean menu_hide_delay_func(gpointer data) static gboolean focus_delay_func(gpointer data) { - client_focus(focus_delay_client); + ObClient *c = data; + + if (focus_client != c) { + client_focus(c); + if (config_focus_raise) + client_raise(c); + } return FALSE; /* no repeat */ } -static void focus_delay_client_dest(gpointer data) +static void focus_delay_client_dest(ObClient *client, gpointer data) { - ObClient *c = data; - if (c == focus_delay_client) { - ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, - focus_delay_client); - focus_delay_client = NULL; + ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, client); +} + +static void event_client_dest(ObClient *client, gpointer data) +{ + if (client == focus_hilite) + focus_hilite = NULL; +} + +void event_halt_focus_delay() +{ + ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func); +} + +void event_ignore_queued_enters() +{ + GSList *saved = NULL, *it; + XEvent *e; + + XSync(ob_display, FALSE); + + /* count the events */ + while (TRUE) { + e = g_new(XEvent, 1); + if (XCheckTypedEvent(ob_display, EnterNotify, e)) { + ObWindow *win; + + win = g_hash_table_lookup(window_map, &e->xany.window); + if (win && WINDOW_IS_CLIENT(win)) + ++ignore_enter_focus; + + saved = g_slist_append(saved, e); + } else { + g_free(e); + break; + } + } + /* put the events back */ + for (it = saved; it; it = g_slist_next(it)) { + XPutBackEvent(ob_display, it->data); + g_free(it->data); } + g_slist_free(saved); }