From 361bf6af5c7de09f30f3cf4a220b3f84a3fe451d Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Tue, 15 May 2007 04:32:59 +0000 Subject: [PATCH] simplify focus handling a bit. no need to listen to focus going to the frame because if it ever does that, the window is unmapping and the frame will just unmap and send it to root. make focus fallback a lil more robust, it checks for errors when it sets focus on the window, and if an error occured it will focus the next option. --- openbox/action.c | 2 +- openbox/client.c | 22 ++++----- openbox/client.h | 7 +-- openbox/event.c | 33 ++------------ openbox/focus.c | 111 ++++++++++++++++++++++------------------------ openbox/openbox.c | 2 +- openbox/screen.c | 2 +- 7 files changed, 73 insertions(+), 106 deletions(-) diff --git a/openbox/action.c b/openbox/action.c index 3f43a238..50191859 100644 --- a/openbox/action.c +++ b/openbox/action.c @@ -1296,7 +1296,7 @@ void action_focus(union ActionData *data) go moving on us */ event_halt_focus_delay(); - client_focus(data->client.any.c); + client_focus(data->client.any.c, FALSE); } } else { /* focus action on something other than a client, make keybindings diff --git a/openbox/client.c b/openbox/client.c index 837dd019..fa4aae95 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -2842,7 +2842,7 @@ void client_fullscreen(ObClient *self, gboolean fs) if (fs) { /* try focus us when we go into fullscreen mode */ - client_focus(self); + client_focus(self, FALSE); } } @@ -3336,10 +3336,8 @@ gboolean client_can_focus(ObClient *self) return TRUE; } -gboolean client_focus(ObClient *self) +gboolean client_focus(ObClient *self, gboolean checkinvalid) { - gboolean error; - /* choose the correct target */ self = client_focus_target(self); @@ -3365,8 +3363,9 @@ gboolean client_focus(ObClient *self) if (keyboard_interactively_grabbed()) keyboard_interactive_cancel(); - error = FALSE; - xerror_set_ignore(TRUE); + if (checkinvalid) + xerror_set_ignore(TRUE); + xerror_occured = FALSE; if (self->can_focus) { /* This can cause a BadMatch error with CurrentTime, or if an app @@ -3390,13 +3389,10 @@ gboolean client_focus(ObClient *self) XSendEvent(ob_display, self->window, FALSE, NoEventMask, &ce); } - /* This calls XSync, which will cause the FocusIn to come back to us. - That's important for desktop switches, since otherwise we'll have no - FocusIn on the queue and end up falling back again. */ - xerror_set_ignore(FALSE); - if (!xerror_occured) error = TRUE; + if (checkinvalid) + xerror_set_ignore(FALSE); - return !error; + return !xerror_occured; } /*! Present the client to the user. @@ -3430,7 +3426,7 @@ static void client_present(ObClient *self, gboolean here, gboolean raise) if (raise) stacking_raise(CLIENT_AS_WINDOW(self)); - client_focus(self); + client_focus(self, FALSE); } void client_activate(ObClient *self, gboolean here, gboolean user) diff --git a/openbox/client.h b/openbox/client.h index 5526c282..9019c62d 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -532,9 +532,10 @@ ObClient *client_focus_target(ObClient *self); gboolean client_can_focus(ObClient *self); /*! Attempt to focus the client window - NOTE: You should validate the client before calling this !! (client_validate) -*/ -gboolean client_focus(ObClient *self); + If you care if focus actually went to the window or not, pass checkinvalid + as TRUE. + */ +gboolean client_focus(ObClient *self, gboolean checkinvalid); /*! Activates the client for use, focusing, uniconifying it, etc. To be used when the user deliberately selects a window for use. diff --git a/openbox/event.c b/openbox/event.c index a2571f0e..9d10698b 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -307,10 +307,6 @@ static gboolean wanted_focusevent(XEvent *e, gboolean in_client_only) return FALSE; } - /* This means focus moved to the frame window */ - if (detail == NotifyInferior && !in_client_only) - return TRUE; - /* It was on a client, was it a valid one? It's possible to get a FocusIn event for a client that was managed but has disappeared. @@ -351,9 +347,6 @@ static gboolean wanted_focusevent(XEvent *e, gboolean in_client_only) /* This means focus moved from one client to another */ if (detail == NotifyNonlinearVirtual) return TRUE; - /* This means focus had moved to our frame window and now moved off */ - if (detail == NotifyNonlinear) - return TRUE; /* Otherwise.. */ return FALSE; @@ -484,9 +477,7 @@ static void event_process(const XEvent *ec, gpointer data) { XEvent ce; - ob_debug_type(OB_DEBUG_FOCUS, - "Focus went to pointer root/none or to our frame " - "window\n"); + ob_debug_type(OB_DEBUG_FOCUS, "Focus went to pointer root/none\n"); /* If another FocusIn is in the queue then don't fallback yet. This fixes the fun case of: @@ -508,40 +499,24 @@ static void event_process(const XEvent *ec, gpointer data) ob_debug_type(OB_DEBUG_FOCUS, " but another FocusIn is coming\n"); } else { - /* Focus has been reverted to the root window, nothing, or to - our frame window. + /* Focus has been reverted to the root window or nothing. FocusOut events come after UnmapNotify, so we don't need to worry about focusing an invalid window */ - /* In this case we know focus is in our screen */ - if (e->xfocus.detail == NotifyInferior) - focus_left_screen = FALSE; - if (!focus_left_screen) focus_fallback(TRUE); } } else if (!client) { - XEvent ce; - ob_debug_type(OB_DEBUG_FOCUS, "Focus went to a window that is already gone\n"); /* If you send focus to a window and then it disappears, you can get the FocusIn FocusOut for it, after it is unmanaged. - */ - if (XCheckIfEvent(ob_display, &ce, event_look_for_focusin_client, - NULL)) - { - XPutBackEvent(ob_display, &ce); - ob_debug_type(OB_DEBUG_FOCUS, - " but another FocusIn is coming\n"); - } else { - focus_fallback(TRUE); - } + Just wait for the next FocusOut/FocusIn pair. */ } else if (client != focus_client) { focus_left_screen = FALSE; @@ -1718,7 +1693,7 @@ static gboolean focus_delay_func(gpointer data) event_curtime = d->time; if (focus_client != d->client) { - if (client_focus(d->client) && config_focus_raise) + if (client_focus(d->client, FALSE) && config_focus_raise) stacking_raise(CLIENT_AS_WINDOW(d->client)); } event_curtime = old; diff --git a/openbox/focus.c b/openbox/focus.c index 47c3846f..60e6ea99 100644 --- a/openbox/focus.c +++ b/openbox/focus.c @@ -190,91 +190,86 @@ void focus_set_client(ObClient *client) } } -static ObClient* focus_fallback_target(gboolean allow_refocus, ObClient *old) +static ObClient* focus_fallback_target(gboolean allow_refocus) { GList *it; - ObClient *target = NULL; - ObClient *desktop = NULL; + ObClient *c; + ObClient *old = focus_client; ob_debug_type(OB_DEBUG_FOCUS, "trying pointer stuff\n"); if (config_focus_follow && !config_focus_last) - { - if ((target = client_under_pointer())) - if (allow_refocus || target != old) - if (client_normal(target) && client_can_focus(target)) { - ob_debug_type(OB_DEBUG_FOCUS, "found in pointer stuff\n"); - return target; - } - } - -#if 0 - /* try for group relations */ - if (old->group) { - GSList *sit; - - for (it = focus_order[screen_desktop]; it; it = g_list_next(it)) - for (sit = old->group->members; sit; sit = g_slist_next(sit)) - if (sit->data == it->data) - if (sit->data != old && client_normal(sit->data)) - if (client_can_focus(sit->data)) - return sit->data; + if ((c = client_under_pointer()) && + (allow_refocus || c != old) && + (client_normal(c) && + client_focus(c, TRUE))) + { + ob_debug_type(OB_DEBUG_FOCUS, "found in pointer stuff\n"); + return c; } -#endif ob_debug_type(OB_DEBUG_FOCUS, "trying omnipresentness\n"); - if (allow_refocus && old && old->desktop == DESKTOP_ALL && - client_normal(old)) + if (allow_refocus && old && + old->desktop == DESKTOP_ALL && + client_normal(old) && + client_focus(old, TRUE)) { + ob_debug_type(OB_DEBUG_FOCUS, "found in omnipresentness\n"); return old; } ob_debug_type(OB_DEBUG_FOCUS, "trying the focus order\n"); - for (it = focus_order; it; it = g_list_next(it)) - if (allow_refocus || it->data != old) { - ObClient *c = it->data; - /* fallback focus to a window if: - 1. it is actually focusable, cuz if it's not then we're sending - focus off to nothing. this includes if it is visible right now - 2. it is on the current desktop. this ignores omnipresent - windows, which are problematic in their own rite. - 3. it is a normal type window, don't fall back onto a dock or - a splashscreen or a desktop window (save the desktop as a - backup fallback though) - */ - if (client_can_focus(c)) - { - if (c->desktop == screen_desktop && client_normal(c)) { - ob_debug_type(OB_DEBUG_FOCUS, "found in focus order\n"); - return it->data; - } else if (c->type == OB_CLIENT_TYPE_DESKTOP && - desktop == NULL) - desktop = c; - } + for (it = focus_order; it; it = g_list_next(it)) { + c = it->data; + /* fallback focus to a window if: + 1. it is on the current desktop. this ignores omnipresent + windows, which are problematic in their own rite. + 2. it is a normal type window, don't fall back onto a dock or + a splashscreen or a desktop window (save the desktop as a + backup fallback though) + */ + if (c->desktop == screen_desktop && + client_normal(c) && + (allow_refocus || c != old) && + client_focus(c, TRUE)) + { + ob_debug_type(OB_DEBUG_FOCUS, "found in focus order\n"); + return c; } + } - /* as a last resort fallback to the desktop window if there is one. - (if there's more than one, then the one most recently focused.) - */ - ob_debug_type(OB_DEBUG_FOCUS, "found desktop: \n", !!desktop); - return desktop; + ob_debug_type(OB_DEBUG_FOCUS, "trying a desktop window\n"); + for (it = focus_order; it; it = g_list_next(it)) { + c = it->data; + /* fallback focus to a window if: + 1. it is on the current desktop. this ignores omnipresent + windows, which are problematic in their own rite. + 2. it is a normal type window, don't fall back onto a dock or + a splashscreen or a desktop window (save the desktop as a + backup fallback though) + */ + if (c->type == OB_CLIENT_TYPE_DESKTOP && + (allow_refocus || c != old) && + client_focus(c, TRUE)) + { + ob_debug_type(OB_DEBUG_FOCUS, "found a desktop window\n"); + return c; + } + } + + return NULL; } ObClient* focus_fallback(gboolean allow_refocus) { ObClient *new; - ObClient *old; - - old = focus_client; - new = focus_fallback_target(allow_refocus, focus_client); /* unfocus any focused clients.. they can be focused by Pointer events and such, and then when we try focus them, we won't get a FocusIn event at all for them. */ focus_nothing(); - if (new) - client_focus(new); + new = focus_fallback_target(allow_refocus); return new; } diff --git a/openbox/openbox.c b/openbox/openbox.c index 78b53223..419d2b55 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -311,7 +311,7 @@ gint main(gint argc, gchar **argv) (w = g_hash_table_lookup(window_map, &xid)) && WINDOW_IS_CLIENT(w)) { - client_focus(WINDOW_AS_CLIENT(w)); + client_focus(WINDOW_AS_CLIENT(w), FALSE); } } else { GList *it; diff --git a/openbox/screen.c b/openbox/screen.c index 45246297..23821301 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -942,7 +942,7 @@ void screen_show_desktop(gboolean show, ObClient *show_only) ObClient *c = it->data; if (c->type == OB_CLIENT_TYPE_DESKTOP && (c->desktop == screen_desktop || c->desktop == DESKTOP_ALL) && - client_focus(it->data)) + client_focus(it->data, FALSE)) break; } } -- 2.39.2