]> Dogcows Code - chaz/openbox/blob - openbox/focus.c
80f15217da66f58b1735baa920a72ed773f268e1
[chaz/openbox] / openbox / focus.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 focus.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
6
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.
11
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.
16
17 See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "debug.h"
21 #include "event.h"
22 #include "openbox.h"
23 #include "grab.h"
24 #include "client.h"
25 #include "config.h"
26 #include "focus_cycle.h"
27 #include "screen.h"
28 #include "prop.h"
29 #include "keyboard.h"
30 #include "focus.h"
31 #include "stacking.h"
32
33 #include <X11/Xlib.h>
34 #include <glib.h>
35
36 #define FOCUS_INDICATOR_WIDTH 6
37
38 ObClient *focus_client = NULL;
39 GList *focus_order = NULL;
40
41 void focus_startup(gboolean reconfig)
42 {
43 if (reconfig) return;
44
45 /* start with nothing focused */
46 focus_nothing();
47 }
48
49 void focus_shutdown(gboolean reconfig)
50 {
51 if (reconfig) return;
52
53 /* reset focus to root */
54 XSetInputFocus(ob_display, PointerRoot, RevertToNone, CurrentTime);
55 }
56
57 static void push_to_top(ObClient *client)
58 {
59 focus_order = g_list_remove(focus_order, client);
60 focus_order = g_list_prepend(focus_order, client);
61 }
62
63 void focus_set_client(ObClient *client)
64 {
65 Window active;
66
67 ob_debug_type(OB_DEBUG_FOCUS,
68 "focus_set_client 0x%lx\n", client ? client->window : 0);
69
70 if (focus_client == client)
71 return;
72
73 /* uninstall the old colormap, and install the new one */
74 screen_install_colormap(focus_client, FALSE);
75 screen_install_colormap(client, TRUE);
76
77 /* in the middle of cycling..? kill it. CurrentTime is fine, time won't
78 be used.
79 */
80 focus_cycle_stop();
81
82 focus_client = client;
83
84 if (client != NULL) {
85 /* move to the top of the list */
86 push_to_top(client);
87 /* remove hiliting from the window when it gets focused */
88 client_hilite(client, FALSE);
89 }
90
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);
96 }
97 }
98
99 static ObClient* focus_fallback_target(gboolean allow_refocus)
100 {
101 GList *it;
102 ObClient *c;
103 ObClient *old = focus_client;
104
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) &&
109 (client_normal(c) &&
110 client_focus(c)))
111 {
112 ob_debug_type(OB_DEBUG_FOCUS, "found in pointer stuff\n");
113 return c;
114 }
115
116 ob_debug_type(OB_DEBUG_FOCUS, "trying omnipresentness\n");
117 if (allow_refocus && old &&
118 old->desktop == DESKTOP_ALL &&
119 client_normal(old) &&
120 client_focus(old))
121 {
122 ob_debug_type(OB_DEBUG_FOCUS, "found in omnipresentness\n");
123 return old;
124 }
125
126
127 ob_debug_type(OB_DEBUG_FOCUS, "trying the focus order\n");
128 for (it = focus_order; it; it = g_list_next(it)) {
129 c = it->data;
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)
136 */
137 if (c->desktop == screen_desktop &&
138 client_normal(c) &&
139 (allow_refocus || c != old) &&
140 client_focus(c))
141 {
142 ob_debug_type(OB_DEBUG_FOCUS, "found in focus order\n");
143 return c;
144 }
145 }
146
147 ob_debug_type(OB_DEBUG_FOCUS, "trying a desktop window\n");
148 for (it = focus_order; it; it = g_list_next(it)) {
149 c = it->data;
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)
156 */
157 if (c->type == OB_CLIENT_TYPE_DESKTOP &&
158 (allow_refocus || c != old) &&
159 client_focus(c))
160 {
161 ob_debug_type(OB_DEBUG_FOCUS, "found a desktop window\n");
162 return c;
163 }
164 }
165
166 return NULL;
167 }
168
169 ObClient* focus_fallback(gboolean allow_refocus)
170 {
171 ObClient *new;
172
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. */
176 focus_nothing();
177
178 new = focus_fallback_target(allow_refocus);
179
180 return new;
181 }
182
183 void focus_nothing()
184 {
185 /* Install our own colormap */
186 if (focus_client != NULL) {
187 screen_install_colormap(focus_client, FALSE);
188 screen_install_colormap(NULL, TRUE);
189 }
190
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.
195 focus_client = NULL;
196 */
197
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
200 and ignore them !
201
202 actions should not rely on being able to move focus during an
203 interactive grab.
204 */
205 if (keyboard_interactively_grabbed())
206 keyboard_interactive_cancel();
207
208 /* when nothing will be focused, send focus to the backup target */
209 XSetInputFocus(ob_display, screen_support_win, RevertToPointerRoot,
210 event_curtime);
211 }
212
213 void focus_order_remove(ObClient *c)
214 {
215 focus_order = g_list_remove(focus_order, c);
216 }
217
218 void focus_order_to_top(ObClient *c)
219 {
220 focus_order = g_list_remove(focus_order, c);
221 if (!c->iconic) {
222 focus_order = g_list_prepend(focus_order, c);
223 } else {
224 GList *it;
225
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);
230 }
231 }
232
233 void focus_order_to_bottom(ObClient *c)
234 {
235 focus_order = g_list_remove(focus_order, c);
236 if (c->iconic) {
237 focus_order = g_list_append(focus_order, c);
238 } else {
239 GList *it;
240
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);
245 }
246 }
247
248 ObClient *focus_order_find_first(guint desktop)
249 {
250 GList *it;
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)
254 return c;
255 }
256 return NULL;
257 }
This page took 0.041609 seconds and 3 git commands to generate.