static guint ignore_enter_focus = 0;
static gboolean menu_can_hide;
static gboolean focus_left_screen = FALSE;
-/*! This variable is used for focus fallback. If we fallback to a window, we
- set this to the window. And when focus goes somewhere after that, it will
- be set to NULL. If between falling back to that window and something
- getting focused, the window gets unmanaged, then if there are no incoming
- FocusIn events, we fallback again because focus has just gotten itself lost.
- */
-static ObClient *focus_tried = NULL;
#ifdef USE_SM
static void ice_handler(gint fd, gpointer conn)
/* These are the ones we want.. */
- if (win == RootWindow(ob_display, ob_screen) && !in_client_only) {
+ if (win == RootWindow(ob_display, ob_screen)) {
+ /* If looking for a focus in on a client, then always return
+ FALSE for focus in's to the root window */
+ if (in_client_only)
+ return FALSE;
/* This means focus reverted off of a client */
- if (detail == NotifyPointerRoot || detail == NotifyDetailNone ||
- detail == NotifyInferior)
+ else if (detail == NotifyPointerRoot ||
+ detail == NotifyDetailNone ||
+ detail == NotifyInferior)
return TRUE;
else
return FALSE;
}
}
-static Bool look_for_focusin(Display *d, XEvent *e, XPointer arg)
+static Bool event_look_for_focusin(Display *d, XEvent *e, XPointer arg)
{
return e->type == FocusIn && wanted_focusevent(e, FALSE);
}
-static Bool look_for_focusin_client(Display *d, XEvent *e, XPointer arg)
+Bool event_look_for_focusin_client(Display *d, XEvent *e, XPointer arg)
{
- return e->type == FocusIn && wanted_focusevent(e, TRUE);
+ return e->type == FocusIn && wanted_focusevent(e, TRUE) &&
+ e->xfocus.window != screen_support_win;
}
static void print_focusevent(XEvent *e)
But if the other focus in is something like PointerRoot then we
still want to fall back.
*/
- if (XCheckIfEvent(ob_display, &ce, look_for_focusin_client, NULL)){
+ 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");
focus_left_screen = FALSE;
if (!focus_left_screen)
- focus_tried = focus_fallback(TRUE);
+ focus_fallback(TRUE);
}
} else if (client && client != focus_client) {
focus_left_screen = FALSE;
focus_set_client(client);
client_calc_layer(client);
client_bring_helper_windows(client);
-
- focus_tried = NULL; /* focus isn't "trying" to go anywhere now */
}
} else if (e->type == FocusOut) {
gboolean nomove = FALSE;
XEvent ce;
/* Look for the followup FocusIn */
- if (!XCheckIfEvent(ob_display, &ce, look_for_focusin, NULL)) {
+ if (!XCheckIfEvent(ob_display, &ce, event_look_for_focusin, NULL)) {
/* There is no FocusIn, this means focus went to a window that
is not being managed, or a window on another screen. */
Window win, root;
ob_debug_type(OB_DEBUG_FOCUS,
"Focus went to an unmanaged window 0x%x !\n",
ce.xfocus.window);
- focus_tried = focus_fallback(TRUE);
+ focus_fallback(TRUE);
}
}
client->window, e->xunmap.event, e->xunmap.from_configure,
client->ignore_unmaps);
client_unmanage(client);
-
- /* we were trying to focus this window but it's gone */
- if (client == focus_tried) {
- ob_debug_type(OB_DEBUG_FOCUS, "Tried to focus window 0x%x and it "
- "is being unmanaged:\n");
- if (XCheckIfEvent(ob_display, &ce, look_for_focusin_client, NULL)){
- XPutBackEvent(ob_display, &ce);
- ob_debug_type(OB_DEBUG_FOCUS,
- " but another FocusIn is coming\n");
- } else {
- ob_debug_type(OB_DEBUG_FOCUS,
- " so falling back focus again.\n");
- focus_tried = focus_fallback(TRUE);
- }
- }
break;
case DestroyNotify:
ob_debug("DestroyNotify for window 0x%x\n", client->window);
client_unmanage(client);
-
- /* we were trying to focus this window but it's gone */
- if (client == focus_tried) {
- ob_debug_type(OB_DEBUG_FOCUS, "Tried to focus window 0x%x and it "
- "is being unmanaged:\n");
- if (XCheckIfEvent(ob_display, &ce, look_for_focusin_client, NULL)){
- XPutBackEvent(ob_display, &ce);
- ob_debug_type(OB_DEBUG_FOCUS,
- " but another FocusIn is coming\n");
- } else {
- ob_debug_type(OB_DEBUG_FOCUS,
- " so falling back focus again.\n");
- focus_tried = focus_fallback(TRUE);
- }
- }
break;
case ReparentNotify:
/* this is when the client is first taken captive in the frame */
ob_debug("ReparentNotify for window 0x%x\n", client->window);
client_unmanage(client);
-
- /* we were trying to focus this window but it's gone */
- if (client == focus_tried) {
- ob_debug_type(OB_DEBUG_FOCUS, "Tried to focus window 0x%x and it "
- "is being unmanaged:\n");
- if (XCheckIfEvent(ob_display, &ce, look_for_focusin_client, NULL)){
- XPutBackEvent(ob_display, &ce);
- ob_debug_type(OB_DEBUG_FOCUS,
- " but another FocusIn is coming\n");
- } else {
- ob_debug_type(OB_DEBUG_FOCUS,
- " so falling back focus again.\n");
- focus_tried = focus_fallback(TRUE);
- }
- }
break;
case MapRequest:
ob_debug("MapRequest for 0x%lx\n", client->window);
GList *focus_order = NULL;
ObClient *focus_cycle_target = NULL;
+/*! This variable is used for focus fallback. If we fallback to a window, we
+ set this to the window. And when focus goes somewhere after that, it will
+ be set to NULL. If between falling back to that window and something
+ getting focused, the window gets unmanaged, then if there are no incoming
+ FocusIn events, we fallback again because focus has just gotten itself lost.
+ */
+static ObClient *focus_tried = NULL;
+
struct {
InternalWindow top;
InternalWindow left;
gboolean dock_windows,
gboolean desktop_windows);
static void focus_cycle_destructor(ObClient *client, gpointer data);
+static void focus_tried_destructor(ObClient *client, gpointer data);
static Window createWindow(Window parent, gulong mask,
XSetWindowAttributes *attrib)
XSetWindowAttributes attr;
client_add_destructor(focus_cycle_destructor, NULL);
+ client_add_destructor(focus_tried_destructor, NULL);
/* start with nothing focused */
focus_nothing();
if (!reconfig) {
client_remove_destructor(focus_cycle_destructor);
+ client_remove_destructor(focus_tried_destructor);
/* reset focus to root */
XSetInputFocus(ob_display, PointerRoot, RevertToNone, CurrentTime);
PROP_SET32(RootWindow(ob_display, ob_screen),
net_active_window, window, active);
}
+
+
+ focus_tried = NULL; /* focus isn't "trying" to go anywhere now */
}
-ObClient* focus_fallback_target(gboolean allow_refocus, ObClient *old)
+static ObClient* focus_fallback_target(gboolean allow_refocus, ObClient *old)
{
GList *it;
ObClient *target = NULL;
ObClient* focus_fallback(gboolean allow_refocus)
{
ObClient *new;
- ObClient *old = focus_client;
+ ObClient *old;
- /* unfocus any focused clients.. they can be focused by Pointer events
- and such, and then when I try focus them, I won't get a FocusIn event
- at all for them.
- */
- focus_nothing();
+ old = focus_client;
+ new = focus_fallback_target(allow_refocus, focus_client);
- if ((new = focus_fallback_target(allow_refocus, old))) {
- client_focus(new);
- return new;
- } else
- return NULL;
+ /* send focus somewhere if it is moving or if it was NULL before,
+ in which case it may not even be on the screen */
+ if (!old || new != old) {
+ /* 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);
+ /* remember that we tried to send focus here */
+ focus_tried = new;
+ }
+ }
+
+ return new;
}
void focus_nothing()
}
focus_client = NULL;
+ focus_tried = NULL; /* focus isn't "trying" to go anywhere now */
/* when nothing will be focused, send focus to the backup target */
XSetInputFocus(ob_display, screen_support_win, RevertToPointerRoot,
}
return NULL;
}
+
+static void focus_tried_destructor(ObClient *client, gpointer data)
+{
+ XEvent ce;
+
+ if (client == focus_tried) {
+ /* we were trying to focus this window but it's gone */
+
+ focus_tried = NULL;
+
+ ob_debug_type(OB_DEBUG_FOCUS, "Tried to focus window 0x%x and it "
+ "is being unmanaged:\n");
+ 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 {
+ ob_debug_type(OB_DEBUG_FOCUS, " so falling back focus again.\n");
+ focus_fallback(TRUE);
+ }
+ }
+}
do this before hiding the windows so if helper windows are coming
with us, they don't get hidden
*/
- if (dofocus && (c = focus_fallback_target(TRUE, focus_client))) {
+ if (dofocus && (c = focus_fallback(TRUE))) {
/* only do the flicker reducing stuff ahead of time if we are going
to call xsetinputfocus on the window ourselves. otherwise there is
no guarantee the window will actually take focus.. */
server FocusIn event */
frame_adjust_focus(c->frame, TRUE);
}
- client_focus(c);
}
/* hide windows from bottom to top */
}
if (show) {
- /* focus desktop */
+ /* focus the desktop */
for (it = focus_order; it; it = g_list_next(it)) {
ObClient *c = it->data;
if (c->type == OB_CLIENT_TYPE_DESKTOP &&
else if (!show_only) {
ObClient *c;
- /* use NULL for the "old" argument because the desktop was focused
- and we don't want to fallback to the desktop by default */
- if ((c = focus_fallback_target(TRUE, NULL)))
- client_focus(c);
+ if ((c = focus_fallback(TRUE))) {
+ /* only do the flicker reducing stuff ahead of time if we are going
+ to call xsetinputfocus on the window ourselves. otherwise there
+ is no guarantee the window will actually take focus.. */
+ if (c->can_focus) {
+ /* reduce flicker by hiliting now rather than waiting for the
+ server FocusIn event */
+ frame_adjust_focus(c->frame, TRUE);
+ }
+ }
}
show = !!show; /* make it boolean */