4 #include "framerender.h"
20 ObClient *focus_client = NULL;
21 GList **focus_order = NULL; /* these lists are created when screen_startup
22 sets the number of desktops */
24 static ObClient *focus_cycle_target = NULL;
25 static Popup *focus_cycle_popup = NULL;
32 focus_cycle_popup = popup_new(TRUE);
34 /* start with nothing focused */
35 focus_set_client(NULL);
42 for (i = 0; i < screen_num_desktops; ++i)
43 g_list_free(focus_order[i]);
47 popup_free(focus_cycle_popup);
48 focus_cycle_popup = NULL;
50 /* reset focus to root */
51 XSetInputFocus(ob_display, PointerRoot, RevertToPointerRoot,
55 static void push_to_top(ObClient *client)
59 desktop = client->desktop;
60 if (desktop == DESKTOP_ALL) desktop = screen_desktop;
61 focus_order[desktop] = g_list_remove(focus_order[desktop], client);
62 focus_order[desktop] = g_list_prepend(focus_order[desktop], client);
65 void focus_set_client(ObClient *client)
71 g_message("focus_set_client 0x%lx", client ? client->window : 0);
74 /* uninstall the old colormap, and install the new one */
75 screen_install_colormap(focus_client, FALSE);
76 screen_install_colormap(client, TRUE);
79 /* when nothing will be focused, send focus to the backup target */
80 XSetInputFocus(ob_display, screen_support_win, RevertToPointerRoot,
82 XSync(ob_display, FALSE);
85 /* in the middle of cycling..? kill it. */
86 if (focus_cycle_target)
87 focus_cycle(TRUE, TRUE, TRUE, TRUE);
90 focus_client = client;
92 /* move to the top of the list */
96 /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
97 if (ob_state != OB_STATE_EXITING) {
98 active = client ? client->window : None;
99 PROP_SET32(ob_root, net_active_window, window, active);
102 if (focus_client != NULL)
103 dispatch_client(Event_Client_Focus, focus_client, 0, 0);
105 dispatch_client(Event_Client_Unfocus, old, 0, 0);
108 static gboolean focus_under_pointer()
113 if (ob_pointer_pos(&x, &y)) {
114 for (it = stacking_list; it != NULL; it = it->next) {
115 if (WINDOW_IS_CLIENT(it->data)) {
116 ObClient *c = WINDOW_AS_CLIENT(it->data);
117 if (c->desktop == screen_desktop &&
118 RECT_CONTAINS(c->frame->area, x, y))
123 g_assert(WINDOW_IS_CLIENT(it->data));
124 return client_normal(it->data) && client_focus(it->data);
130 /* finds the first transient that isn't 'skip' and ensure's that client_normal
132 static ObClient *find_transient_recursive(ObClient *c, ObClient *top, ObClient *skip)
137 for (it = c->transients; it; it = it->next) {
138 if (it->data == top) return NULL;
139 ret = find_transient_recursive(it->data, top, skip);
140 if (ret && ret != skip && client_normal(ret)) return ret;
141 if (it->data != skip && client_normal(it->data)) return it->data;
146 static gboolean focus_fallback_transient(ObClient *top, ObClient *old)
148 ObClient *target = find_transient_recursive(top, top, old);
150 /* make sure client_normal is true always */
151 if (!client_normal(top))
153 target = top; /* no transient, keep the top */
155 return client_focus(target);
158 void focus_fallback(ObFocusFallbackType type)
161 ObClient *old = NULL;
165 /* unfocus any focused clients.. they can be focused by Pointer events
166 and such, and then when I try focus them, I won't get a FocusIn event
169 focus_set_client(NULL);
171 if (!(type == OB_FOCUS_FALLBACK_DESKTOP ?
172 config_focus_last_on_desktop : config_focus_last)) {
173 if (config_focus_follow) focus_under_pointer();
177 if (type == OB_FOCUS_FALLBACK_UNFOCUSING && old) {
178 /* try for transient relations */
179 if (old->transient_for) {
180 if (old->transient_for == OB_TRAN_GROUP) {
181 for (it = focus_order[screen_desktop]; it; it = it->next) {
184 for (sit = old->group->members; sit; sit = sit->next)
185 if (sit->data == it->data)
186 if (focus_fallback_transient(sit->data, old))
190 if (focus_fallback_transient(old->transient_for, old))
195 /* try for group relations */
199 for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
200 for (sit = old->group->members; sit; sit = sit->next)
201 if (sit->data == it->data)
202 if (sit->data != old && client_normal(sit->data))
203 if (client_can_focus(sit->data)) {
204 gboolean r = client_focus(sit->data);
211 for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
212 if (type != OB_FOCUS_FALLBACK_UNFOCUSING || it->data != old)
213 if (client_normal(it->data) &&
214 /* dont fall back to 'anonymous' fullscreen windows. theres no
215 checks for this is in transient/group fallbacks, so they can
216 be fallback targets there. */
217 !((ObClient*)it->data)->fullscreen &&
218 client_can_focus(it->data)) {
219 gboolean r = client_focus(it->data);
224 /* nothing to focus, and already set it to none above */
227 static void popup_cycle(ObClient *c, gboolean show)
230 popup_hide(focus_cycle_popup);
236 a = screen_physical_area_monitor(0);
237 popup_position(focus_cycle_popup, CenterGravity,
238 a->x + a->width / 2, a->y + a->height / 2);
239 /* popup_size(focus_cycle_popup, a->height/2, a->height/16);
240 popup_show(focus_cycle_popup, c->title,
241 client_icon(c, a->height/16, a->height/16));
243 /* XXX the size and the font extents need to be related on some level
245 popup_size(focus_cycle_popup, 320, 48);
247 /* use the transient's parent's title/icon */
248 while (p->transient_for && p->transient_for != OB_TRAN_GROUP)
249 p = p->transient_for;
254 title = g_strconcat((c->iconic ? c->icon_title : c->title),
256 (p->iconic ? p->icon_title : p->title),
259 popup_show(focus_cycle_popup,
260 (title ? title : (c->iconic ? c->icon_title : c->title)),
261 client_icon(p, 48, 48));
266 ObClient *focus_cycle(gboolean forward, gboolean linear, gboolean done,
269 static ObClient *first = NULL;
270 static ObClient *t = NULL;
271 static GList *order = NULL;
272 GList *it, *start, *list;
276 if (focus_cycle_target)
277 frame_adjust_focus(focus_cycle_target->frame, FALSE);
279 frame_adjust_focus(focus_client->frame, TRUE);
282 if (focus_cycle_target)
283 client_activate(focus_cycle_target);
287 grab_pointer(TRUE, None);
289 if (!first) first = focus_client;
290 if (!focus_cycle_target) focus_cycle_target = focus_client;
292 if (linear) list = client_list;
293 else list = focus_order[screen_desktop];
295 start = it = g_list_find(list, focus_cycle_target);
296 if (!start) /* switched desktops or something? */
297 start = it = forward ? g_list_last(list) : g_list_first(list);
298 if (!start) goto done_cycle;
303 if (it == NULL) it = g_list_first(list);
306 if (it == NULL) it = g_list_last(list);
308 /*ft = client_focus_target(it->data);*/
310 /* we don't use client_can_focus here, because that doesn't let you
311 focus an iconic window, but we want to be able to, so we just check
312 if the focus flags on the window allow it, and its on the current
314 if (ft->transients == NULL && client_normal(ft) &&
315 ((ft->can_focus || ft->focus_notify) &&
316 (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL))) {
317 if (ft != focus_cycle_target) { /* prevents flicker */
318 if (focus_cycle_target)
319 frame_adjust_focus(focus_cycle_target->frame, FALSE);
320 focus_cycle_target = ft;
321 frame_adjust_focus(focus_cycle_target->frame, TRUE);
323 popup_cycle(ft, config_focus_popup);
326 } while (it != start);
331 focus_cycle_target = NULL;
335 popup_cycle(ft, FALSE);
336 grab_pointer(FALSE, None);
341 void focus_order_add_new(ObClient *c)
346 focus_order_to_top(c);
349 if (d == DESKTOP_ALL) {
350 for (i = 0; i < screen_num_desktops; ++i) {
351 if (focus_order[i] && ((ObClient*)focus_order[i]->data)->iconic)
352 focus_order[i] = g_list_insert(focus_order[i], c, 0);
354 focus_order[i] = g_list_insert(focus_order[i], c, 1);
357 if (focus_order[d] && ((ObClient*)focus_order[d]->data)->iconic)
358 focus_order[d] = g_list_insert(focus_order[d], c, 0);
360 focus_order[d] = g_list_insert(focus_order[d], c, 1);
364 void focus_order_remove(ObClient *c)
369 if (d == DESKTOP_ALL) {
370 for (i = 0; i < screen_num_desktops; ++i)
371 focus_order[i] = g_list_remove(focus_order[i], c);
373 focus_order[d] = g_list_remove(focus_order[d], c);
376 static void to_top(ObClient *c, guint d)
378 focus_order[d] = g_list_remove(focus_order[d], c);
380 focus_order[d] = g_list_prepend(focus_order[d], c);
384 /* insert before first iconic window */
385 for (it = focus_order[d];
386 it && !((ObClient*)it->data)->iconic; it = it->next);
387 g_list_insert_before(focus_order[d], it, c);
391 void focus_order_to_top(ObClient *c)
396 if (d == DESKTOP_ALL) {
397 for (i = 0; i < screen_num_desktops; ++i)
403 static void to_bottom(ObClient *c, guint d)
405 focus_order[d] = g_list_remove(focus_order[d], c);
407 focus_order[d] = g_list_append(focus_order[d], c);
411 /* insert before first iconic window */
412 for (it = focus_order[d];
413 it && !((ObClient*)it->data)->iconic; it = it->next);
414 g_list_insert_before(focus_order[d], it, c);
418 void focus_order_to_bottom(ObClient *c)
423 if (d == DESKTOP_ALL) {
424 for (i = 0; i < screen_num_desktops; ++i)