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. */
80 focus_client = client;
83 /* move to the top of the list */
85 /* remove hiliting from the window when it gets focused */
86 client_hilite(client, FALSE);
89 /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
90 if (ob_state() != OB_STATE_EXITING) {
91 active = client ? client->window : None;
92 PROP_SET32(RootWindow(ob_display, ob_screen),
93 net_active_window, window, active);
97 static ObClient* focus_fallback_target(gboolean allow_refocus, ObClient *old,
103 ob_debug_type(OB_DEBUG_FOCUS, "trying pointer stuff\n");
104 if (config_focus_follow && !config_focus_last)
105 if ((c = client_under_pointer()) &&
106 (allow_refocus || c != old) &&
108 /* if we're sending focus then try to */
109 ((send_focus && client_focus(c)) ||
110 /* if not just see if we could try, or it's already focused */
111 (!send_focus && (c == old || client_can_focus(c)))))
113 ob_debug_type(OB_DEBUG_FOCUS, "found in pointer stuff (%d)\n",
118 ob_debug_type(OB_DEBUG_FOCUS, "trying omnipresentness\n");
119 if (allow_refocus && old &&
120 old->desktop == DESKTOP_ALL &&
121 client_normal(old) &&
122 /* this one is only for when not sending focus, to keep it there */
125 ob_debug_type(OB_DEBUG_FOCUS, "found in omnipresentness (%d)\n",
131 ob_debug_type(OB_DEBUG_FOCUS, "trying the focus order\n");
132 for (it = focus_order; it; it = g_list_next(it)) {
134 /* fallback focus to a window if:
135 1. it is on the current desktop. this ignores omnipresent
136 windows, which are problematic in their own rite.
137 2. it is a normal type window, don't fall back onto a dock or
138 a splashscreen or a desktop window (save the desktop as a
139 backup fallback though)
141 if (c->desktop == screen_desktop &&
143 (allow_refocus || c != old) &&
144 /* if we're sending focus then try to */
145 ((send_focus && client_focus(c)) ||
146 /* if not just see if we could try, or it's already focused */
147 (!send_focus && (c == old || client_can_focus(c)))))
149 ob_debug_type(OB_DEBUG_FOCUS, "found in focus order (%d) 0x%x "
156 ob_debug_type(OB_DEBUG_FOCUS, "trying a desktop window\n");
157 for (it = focus_order; it; it = g_list_next(it)) {
159 /* fallback focus to a window if:
160 1. it is on the current desktop. this ignores omnipresent
161 windows, which are problematic in their own rite.
162 2. it is a normal type window, don't fall back onto a dock or
163 a splashscreen or a desktop window (save the desktop as a
164 backup fallback though)
166 if (c->type == OB_CLIENT_TYPE_DESKTOP &&
167 (allow_refocus || c != old) &&
168 /* if we're sending focus then try to */
169 ((send_focus && client_focus(c)) ||
170 /* if not just see if we could try, or it's already focused */
171 (!send_focus && (c == old || client_can_focus(c)))))
173 ob_debug_type(OB_DEBUG_FOCUS, "found a desktop window (%d)\n",
182 ObClient* focus_fallback(gboolean allow_refocus)
185 ObClient *old = focus_client;
187 new = focus_fallback_target(allow_refocus, old, FALSE);
188 if (new == old) return;
190 /* unfocus any focused clients.. they can be focused by Pointer events
191 and such, and then when we try focus them, we won't get a FocusIn
192 event at all for them. */
195 new = focus_fallback_target(allow_refocus, old, TRUE);
202 /* Install our own colormap */
203 if (focus_client != NULL) {
204 screen_install_colormap(focus_client, FALSE);
205 screen_install_colormap(NULL, TRUE);
208 /* nothing is focused, update the colormap and _the root property_ */
209 focus_set_client(NULL);
211 /* if there is a grab going on, then we need to cancel it. if we move
212 focus during the grab, applications will get NotifyWhileGrabbed events
215 actions should not rely on being able to move focus during an
218 if (keyboard_interactively_grabbed())
219 keyboard_interactive_cancel();
221 /* when nothing will be focused, send focus to the backup target */
222 XSetInputFocus(ob_display, screen_support_win, RevertToPointerRoot,
226 void focus_order_remove(ObClient *c)
228 focus_order = g_list_remove(focus_order, c);
231 void focus_order_to_top(ObClient *c)
233 focus_order = g_list_remove(focus_order, c);
235 focus_order = g_list_prepend(focus_order, c);
239 /* insert before first iconic window */
240 for (it = focus_order;
241 it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
242 focus_order = g_list_insert_before(focus_order, it, c);
246 void focus_order_to_bottom(ObClient *c)
248 focus_order = g_list_remove(focus_order, c);
250 focus_order = g_list_append(focus_order, c);
254 /* insert before first iconic window */
255 for (it = focus_order;
256 it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
257 focus_order = g_list_insert_before(focus_order, it, c);
261 ObClient *focus_order_find_first(guint desktop)
264 for (it = focus_order; it; it = g_list_next(it)) {
265 ObClient *c = it->data;
266 if (c->desktop == desktop || c->desktop == DESKTOP_ALL)