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. */
78 focus_cycle_stop(focus_client
);
79 focus_cycle_stop(client
);
81 focus_client
= client
;
84 /* move to the top of the list */
86 /* remove hiliting from the window when it gets focused */
87 client_hilite(client
, FALSE
);
90 /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
91 if (ob_state() != OB_STATE_EXITING
) {
92 active
= client
? client
->window
: None
;
93 PROP_SET32(RootWindow(ob_display
, ob_screen
),
94 net_active_window
, window
, active
);
98 static ObClient
* focus_fallback_target(gboolean allow_refocus
,
99 gboolean allow_pointer
,
100 gboolean allow_omnipresent
,
106 ob_debug_type(OB_DEBUG_FOCUS
, "trying pointer stuff\n");
107 if (allow_pointer
&& config_focus_follow
)
108 if ((c
= client_under_pointer()) &&
109 (allow_refocus
|| client_focus_target(c
) != old
) &&
113 ob_debug_type(OB_DEBUG_FOCUS
, "found in pointer stuff\n");
117 ob_debug_type(OB_DEBUG_FOCUS
, "trying the focus order\n");
118 for (it
= focus_order
; it
; it
= g_list_next(it
)) {
120 /* fallback focus to a window if:
121 1. it is on the current desktop. this ignores omnipresent
122 windows, which are problematic in their own rite, unless they are
124 2. it is a normal type window, don't fall back onto a dock or
125 a splashscreen or a desktop window (save the desktop as a
126 backup fallback though)
128 if ((allow_omnipresent
|| c
->desktop
== screen_desktop
) &&
130 (allow_refocus
|| client_focus_target(c
) != old
) &&
133 ob_debug_type(OB_DEBUG_FOCUS
, "found in focus order\n");
138 ob_debug_type(OB_DEBUG_FOCUS
, "trying a desktop window\n");
139 for (it
= focus_order
; it
; it
= g_list_next(it
)) {
141 /* fallback focus to a window if:
142 1. it is on the current desktop. this ignores omnipresent
143 windows, which are problematic in their own rite.
144 2. it is a normal type window, don't fall back onto a dock or
145 a splashscreen or a desktop window (save the desktop as a
146 backup fallback though)
148 if (c
->type
== OB_CLIENT_TYPE_DESKTOP
&&
149 (allow_refocus
|| client_focus_target(c
) != old
) &&
152 ob_debug_type(OB_DEBUG_FOCUS
, "found a desktop window\n");
160 ObClient
* focus_fallback(gboolean allow_refocus
, gboolean allow_pointer
,
161 gboolean allow_omnipresent
)
164 ObClient
*old
= focus_client
;
166 /* unfocus any focused clients.. they can be focused by Pointer events
167 and such, and then when we try focus them, we won't get a FocusIn
168 event at all for them. */
171 new = focus_fallback_target(allow_refocus
, allow_pointer
,
172 allow_omnipresent
, old
);
173 /* get what was really focused */
174 if (new) new = client_focus_target(new);
181 /* Install our own colormap */
182 if (focus_client
!= NULL
) {
183 screen_install_colormap(focus_client
, FALSE
);
184 screen_install_colormap(NULL
, TRUE
);
187 /* nothing is focused, update the colormap and _the root property_ */
188 focus_set_client(NULL
);
190 /* if there is a grab going on, then we need to cancel it. if we move
191 focus during the grab, applications will get NotifyWhileGrabbed events
194 actions should not rely on being able to move focus during an
197 event_cancel_all_key_grabs();
199 /* when nothing will be focused, send focus to the backup target */
200 XSetInputFocus(ob_display
, screen_support_win
, RevertToPointerRoot
,
204 void focus_order_add_new(ObClient
*c
)
207 focus_order_to_top(c
);
209 g_assert(!g_list_find(focus_order
, c
));
210 /* if there are any iconic windows, put this above them in the order,
211 but if there are not, then put it under the currently focused one */
212 if (focus_order
&& ((ObClient
*)focus_order
->data
)->iconic
)
213 focus_order
= g_list_insert(focus_order
, c
, 0);
215 focus_order
= g_list_insert(focus_order
, c
, 1);
218 /* in the middle of cycling..? kill it. */
222 void focus_order_remove(ObClient
*c
)
224 focus_order
= g_list_remove(focus_order
, c
);
226 /* in the middle of cycling..? kill it. */
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
)