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(RootWindow(ob_display, ob_screen),
100 net_active_window, window, active);
103 if (focus_client != NULL)
104 dispatch_client(Event_Client_Focus, focus_client, 0, 0);
106 dispatch_client(Event_Client_Unfocus, old, 0, 0);
109 static gboolean focus_under_pointer()
114 if (ob_pointer_pos(&x, &y)) {
115 for (it = stacking_list; it != NULL; it = it->next) {
116 if (WINDOW_IS_CLIENT(it->data)) {
117 ObClient *c = WINDOW_AS_CLIENT(it->data);
118 if (c->desktop == screen_desktop &&
119 RECT_CONTAINS(c->frame->area, x, y))
124 g_assert(WINDOW_IS_CLIENT(it->data));
125 return client_normal(it->data) && client_focus(it->data);
131 /* finds the first transient that isn't 'skip' and ensure's that client_normal
133 static ObClient *find_transient_recursive(ObClient *c, ObClient *top, ObClient *skip)
138 for (it = c->transients; it; it = it->next) {
139 if (it->data == top) return NULL;
140 ret = find_transient_recursive(it->data, top, skip);
141 if (ret && ret != skip && client_normal(ret)) return ret;
142 if (it->data != skip && client_normal(it->data)) return it->data;
147 static gboolean focus_fallback_transient(ObClient *top, ObClient *old)
149 ObClient *target = find_transient_recursive(top, top, old);
151 /* make sure client_normal is true always */
152 if (!client_normal(top))
154 target = top; /* no transient, keep the top */
156 return client_focus(target);
159 void focus_fallback(ObFocusFallbackType type)
162 ObClient *old = NULL;
166 /* unfocus any focused clients.. they can be focused by Pointer events
167 and such, and then when I try focus them, I won't get a FocusIn event
170 focus_set_client(NULL);
172 if (!(type == OB_FOCUS_FALLBACK_DESKTOP ?
173 config_focus_last_on_desktop : config_focus_last)) {
174 if (config_focus_follow) focus_under_pointer();
178 if (type == OB_FOCUS_FALLBACK_UNFOCUSING && old) {
179 /* try for transient relations */
180 if (old->transient_for) {
181 if (old->transient_for == OB_TRAN_GROUP) {
182 for (it = focus_order[screen_desktop]; it; it = it->next) {
185 for (sit = old->group->members; sit; sit = sit->next)
186 if (sit->data == it->data)
187 if (focus_fallback_transient(sit->data, old))
191 if (focus_fallback_transient(old->transient_for, old))
196 /* try for group relations */
200 for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
201 for (sit = old->group->members; sit; sit = sit->next)
202 if (sit->data == it->data)
203 if (sit->data != old && client_normal(sit->data))
204 if (client_can_focus(sit->data)) {
205 gboolean r = client_focus(sit->data);
212 for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
213 if (type != OB_FOCUS_FALLBACK_UNFOCUSING || it->data != old)
214 if (client_normal(it->data) &&
215 /* dont fall back to 'anonymous' fullscreen windows. theres no
216 checks for this is in transient/group fallbacks, so they can
217 be fallback targets there. */
218 !((ObClient*)it->data)->fullscreen &&
219 client_can_focus(it->data)) {
220 gboolean r = client_focus(it->data);
225 /* nothing to focus, and already set it to none above */
228 static void popup_cycle(ObClient *c, gboolean show)
231 popup_hide(focus_cycle_popup);
237 a = screen_physical_area_monitor(0);
238 popup_position(focus_cycle_popup, CenterGravity,
239 a->x + a->width / 2, a->y + a->height / 2);
240 /* popup_size(focus_cycle_popup, a->height/2, a->height/16);
241 popup_show(focus_cycle_popup, c->title,
242 client_icon(c, a->height/16, a->height/16));
244 /* XXX the size and the font extents need to be related on some level
246 popup_size(focus_cycle_popup, 320, 48);
248 /* use the transient's parent's title/icon */
249 while (p->transient_for && p->transient_for != OB_TRAN_GROUP)
250 p = p->transient_for;
255 title = g_strconcat((c->iconic ? c->icon_title : c->title),
257 (p->iconic ? p->icon_title : p->title),
260 popup_show(focus_cycle_popup,
261 (title ? title : (c->iconic ? c->icon_title : c->title)),
262 client_icon(p, 48, 48));
267 ObClient *focus_cycle(gboolean forward, gboolean linear, gboolean done,
270 static ObClient *first = NULL;
271 static ObClient *t = NULL;
272 static GList *order = NULL;
273 GList *it, *start, *list;
277 if (focus_cycle_target)
278 frame_adjust_focus(focus_cycle_target->frame, FALSE);
280 frame_adjust_focus(focus_client->frame, TRUE);
283 if (focus_cycle_target)
284 client_activate(focus_cycle_target);
288 grab_pointer(TRUE, None);
290 if (!first) first = focus_client;
291 if (!focus_cycle_target) focus_cycle_target = focus_client;
293 if (linear) list = client_list;
294 else list = focus_order[screen_desktop];
296 start = it = g_list_find(list, focus_cycle_target);
297 if (!start) /* switched desktops or something? */
298 start = it = forward ? g_list_last(list) : g_list_first(list);
299 if (!start) goto done_cycle;
304 if (it == NULL) it = g_list_first(list);
307 if (it == NULL) it = g_list_last(list);
309 /*ft = client_focus_target(it->data);*/
311 /* we don't use client_can_focus here, because that doesn't let you
312 focus an iconic window, but we want to be able to, so we just check
313 if the focus flags on the window allow it, and its on the current
315 if (ft->transients == NULL && client_normal(ft) &&
316 ((ft->can_focus || ft->focus_notify) &&
317 (ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL))) {
318 if (ft != focus_cycle_target) { /* prevents flicker */
319 if (focus_cycle_target)
320 frame_adjust_focus(focus_cycle_target->frame, FALSE);
321 focus_cycle_target = ft;
322 frame_adjust_focus(focus_cycle_target->frame, TRUE);
324 popup_cycle(ft, config_focus_popup);
327 } while (it != start);
332 focus_cycle_target = NULL;
336 popup_cycle(ft, FALSE);
337 grab_pointer(FALSE, None);
342 void focus_order_add_new(ObClient *c)
347 focus_order_to_top(c);
350 if (d == DESKTOP_ALL) {
351 for (i = 0; i < screen_num_desktops; ++i) {
352 if (focus_order[i] && ((ObClient*)focus_order[i]->data)->iconic)
353 focus_order[i] = g_list_insert(focus_order[i], c, 0);
355 focus_order[i] = g_list_insert(focus_order[i], c, 1);
358 if (focus_order[d] && ((ObClient*)focus_order[d]->data)->iconic)
359 focus_order[d] = g_list_insert(focus_order[d], c, 0);
361 focus_order[d] = g_list_insert(focus_order[d], c, 1);
365 void focus_order_remove(ObClient *c)
370 if (d == DESKTOP_ALL) {
371 for (i = 0; i < screen_num_desktops; ++i)
372 focus_order[i] = g_list_remove(focus_order[i], c);
374 focus_order[d] = g_list_remove(focus_order[d], c);
377 static void to_top(ObClient *c, guint d)
379 focus_order[d] = g_list_remove(focus_order[d], c);
381 focus_order[d] = g_list_prepend(focus_order[d], c);
385 /* insert before first iconic window */
386 for (it = focus_order[d];
387 it && !((ObClient*)it->data)->iconic; it = it->next);
388 g_list_insert_before(focus_order[d], it, c);
392 void focus_order_to_top(ObClient *c)
397 if (d == DESKTOP_ALL) {
398 for (i = 0; i < screen_num_desktops; ++i)
404 static void to_bottom(ObClient *c, guint d)
406 focus_order[d] = g_list_remove(focus_order[d], c);
408 focus_order[d] = g_list_append(focus_order[d], c);
412 /* insert before first iconic window */
413 for (it = focus_order[d];
414 it && !((ObClient*)it->data)->iconic; it = it->next);
415 g_list_insert_before(focus_order[d], it, c);
419 void focus_order_to_bottom(ObClient *c)
424 if (d == DESKTOP_ALL) {
425 for (i = 0; i < screen_num_desktops; ++i)