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)\n",
155 ob_debug_type(OB_DEBUG_FOCUS, "trying a desktop window\n");
156 for (it = focus_order; it; it = g_list_next(it)) {
158 /* fallback focus to a window if:
159 1. it is on the current desktop. this ignores omnipresent
160 windows, which are problematic in their own rite.
161 2. it is a normal type window, don't fall back onto a dock or
162 a splashscreen or a desktop window (save the desktop as a
163 backup fallback though)
165 if (c->type == OB_CLIENT_TYPE_DESKTOP &&
166 (allow_refocus || c != old) &&
167 /* if we're sending focus then try to */
168 ((send_focus && client_focus(c)) ||
169 /* if not just see if we could try, or it's already focused */
170 (!send_focus && (c == old || client_can_focus(c)))))
172 ob_debug_type(OB_DEBUG_FOCUS, "found a desktop window (%d)\n",
181 ObClient* focus_fallback(gboolean allow_refocus)
184 ObClient *old = focus_client;
186 new = focus_fallback_target(allow_refocus, old, FALSE);
187 if (new == old) return;
189 /* unfocus any focused clients.. they can be focused by Pointer events
190 and such, and then when we try focus them, we won't get a FocusIn
191 event at all for them. */
194 new = focus_fallback_target(allow_refocus, old, TRUE);
201 /* Install our own colormap */
202 if (focus_client != NULL) {
203 screen_install_colormap(focus_client, FALSE);
204 screen_install_colormap(NULL, TRUE);
207 /* nothing is focused, update the colormap and _the root property_ */
208 focus_set_client(NULL);
210 /* if there is a grab going on, then we need to cancel it. if we move
211 focus during the grab, applications will get NotifyWhileGrabbed events
214 actions should not rely on being able to move focus during an
217 if (keyboard_interactively_grabbed())
218 keyboard_interactive_cancel();
220 /* when nothing will be focused, send focus to the backup target */
221 XSetInputFocus(ob_display, screen_support_win, RevertToPointerRoot,
225 void focus_order_remove(ObClient *c)
227 focus_order = g_list_remove(focus_order, c);
230 void focus_order_to_top(ObClient *c)
232 focus_order = g_list_remove(focus_order, c);
234 focus_order = g_list_prepend(focus_order, c);
238 /* insert before first iconic window */
239 for (it = focus_order;
240 it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
241 focus_order = g_list_insert_before(focus_order, it, c);
245 void focus_order_to_bottom(ObClient *c)
247 focus_order = g_list_remove(focus_order, c);
249 focus_order = g_list_append(focus_order, c);
253 /* insert before first iconic window */
254 for (it = focus_order;
255 it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
256 focus_order = g_list_insert_before(focus_order, it, c);
260 ObClient *focus_order_find_first(guint desktop)
263 for (it = focus_order; it; it = g_list_next(it)) {
264 ObClient *c = it->data;
265 if (c->desktop == desktop || c->desktop == DESKTOP_ALL)