1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 focus.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
26 #include "focus_cycle.h"
36 #define FOCUS_INDICATOR_WIDTH 6
38 ObClient *focus_client = NULL;
39 GList *focus_order = NULL;
41 void focus_startup(gboolean reconfig)
45 /* start with nothing focused */
49 void focus_shutdown(gboolean reconfig)
53 /* reset focus to root */
54 XSetInputFocus(ob_display, PointerRoot, RevertToNone, CurrentTime);
57 static void push_to_top(ObClient *client)
59 focus_order = g_list_remove(focus_order, client);
60 focus_order = g_list_prepend(focus_order, client);
63 void focus_set_client(ObClient *client)
67 ob_debug_type(OB_DEBUG_FOCUS,
68 "focus_set_client 0x%lx\n", client ? client->window : 0);
70 if (focus_client == client)
73 /* uninstall the old colormap, and install the new one */
74 screen_install_colormap(focus_client, FALSE);
75 screen_install_colormap(client, TRUE);
77 /* in the middle of cycling..? kill it. CurrentTime is fine, time won't
82 focus_client = client;
85 /* move to the top of the list */
87 /* remove hiliting from the window when it gets focused */
88 client_hilite(client, FALSE);
91 /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
92 if (ob_state() != OB_STATE_EXITING) {
93 active = client ? client->window : None;
94 PROP_SET32(RootWindow(ob_display, ob_screen),
95 net_active_window, window, active);
99 static ObClient* focus_fallback_target(gboolean allow_refocus)
103 ObClient *old = focus_client;
105 ob_debug_type(OB_DEBUG_FOCUS, "trying pointer stuff\n");
106 if (config_focus_follow && !config_focus_last)
107 if ((c = client_under_pointer()) &&
108 (allow_refocus || c != old) &&
112 ob_debug_type(OB_DEBUG_FOCUS, "found in pointer stuff\n");
116 ob_debug_type(OB_DEBUG_FOCUS, "trying omnipresentness\n");
117 if (allow_refocus && old &&
118 old->desktop == DESKTOP_ALL &&
119 client_normal(old) &&
122 ob_debug_type(OB_DEBUG_FOCUS, "found in omnipresentness\n");
127 ob_debug_type(OB_DEBUG_FOCUS, "trying the focus order\n");
128 for (it = focus_order; it; it = g_list_next(it)) {
130 /* fallback focus to a window if:
131 1. it is on the current desktop. this ignores omnipresent
132 windows, which are problematic in their own rite.
133 2. it is a normal type window, don't fall back onto a dock or
134 a splashscreen or a desktop window (save the desktop as a
135 backup fallback though)
137 if (c->desktop == screen_desktop &&
139 (allow_refocus || c != old) &&
142 ob_debug_type(OB_DEBUG_FOCUS, "found in focus order\n");
147 ob_debug_type(OB_DEBUG_FOCUS, "trying a desktop window\n");
148 for (it = focus_order; it; it = g_list_next(it)) {
150 /* fallback focus to a window if:
151 1. it is on the current desktop. this ignores omnipresent
152 windows, which are problematic in their own rite.
153 2. it is a normal type window, don't fall back onto a dock or
154 a splashscreen or a desktop window (save the desktop as a
155 backup fallback though)
157 if (c->type == OB_CLIENT_TYPE_DESKTOP &&
158 (allow_refocus || c != old) &&
161 ob_debug_type(OB_DEBUG_FOCUS, "found a desktop window\n");
169 ObClient* focus_fallback(gboolean allow_refocus)
173 /* unfocus any focused clients.. they can be focused by Pointer events
174 and such, and then when we try focus them, we won't get a FocusIn
175 event at all for them. */
178 new = focus_fallback_target(allow_refocus);
185 /* Install our own colormap */
186 if (focus_client != NULL) {
187 screen_install_colormap(focus_client, FALSE);
188 screen_install_colormap(NULL, TRUE);
191 /* Don't set focus_client to NULL here. It will be set to NULL when the
192 FocusOut event comes. Otherwise, if we focus nothing and then focus the
193 same window again, The focus code says nothing changed, but focus_client
194 ends up being NULL anyways.
198 /* if there is a grab going on, then we need to cancel it. if we move
199 focus during the grab, applications will get NotifyWhileGrabbed events
202 actions should not rely on being able to move focus during an
205 if (keyboard_interactively_grabbed())
206 keyboard_interactive_cancel();
208 /* when nothing will be focused, send focus to the backup target */
209 XSetInputFocus(ob_display, screen_support_win, RevertToPointerRoot,
213 void focus_order_remove(ObClient *c)
215 focus_order = g_list_remove(focus_order, c);
218 void focus_order_to_top(ObClient *c)
220 focus_order = g_list_remove(focus_order, c);
222 focus_order = g_list_prepend(focus_order, c);
226 /* insert before first iconic window */
227 for (it = focus_order;
228 it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
229 focus_order = g_list_insert_before(focus_order, it, c);
233 void focus_order_to_bottom(ObClient *c)
235 focus_order = g_list_remove(focus_order, c);
237 focus_order = g_list_append(focus_order, c);
241 /* insert before first iconic window */
242 for (it = focus_order;
243 it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
244 focus_order = g_list_insert_before(focus_order, it, c);
248 ObClient *focus_order_find_first(guint desktop)
251 for (it = focus_order; it; it = g_list_next(it)) {
252 ObClient *c = it->data;
253 if (c->desktop == desktop || c->desktop == DESKTOP_ALL)