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.
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
if (fs) {
/* try focus us when we go into fullscreen mode */
- client_focus(self);
+ client_focus(self, FALSE);
}
}
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);
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
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.
if (raise)
stacking_raise(CLIENT_AS_WINDOW(self));
- client_focus(self);
+ client_focus(self, FALSE);
}
void client_activate(ObClient *self, gboolean here, gboolean user)
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.
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.
/* 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;
{
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:
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;
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;
}
}
-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;
}
(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;
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;
}
}