5 #include "framerender.h"
21 ObClient
*focus_client
;
22 GList
**focus_order
; /* these lists are created when screen_startup
23 sets the number of desktops */
25 static ObClient
*focus_cycle_target
;
26 static Popup
*focus_cycle_popup
;
31 focus_cycle_popup
= popup_new(TRUE
);
33 /* start with nothing focused */
34 focus_set_client(NULL
);
41 for (i
= 0; i
< screen_num_desktops
; ++i
)
42 g_list_free(focus_order
[i
]);
45 popup_free(focus_cycle_popup
);
47 /* reset focus to root */
48 XSetInputFocus(ob_display
, PointerRoot
, RevertToPointerRoot
,
52 static void push_to_top(ObClient
*client
)
56 desktop
= client
->desktop
;
57 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
58 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
], client
);
59 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
], client
);
62 void focus_set_client(ObClient
*client
)
68 ob_debug("focus_set_client 0x%lx\n", client
? client
->window
: 0);
71 /* uninstall the old colormap, and install the new one */
72 screen_install_colormap(focus_client
, FALSE
);
73 screen_install_colormap(client
, TRUE
);
76 /* when nothing will be focused, send focus to the backup target */
77 XSetInputFocus(ob_display
, screen_support_win
, RevertToPointerRoot
,
79 XSync(ob_display
, FALSE
);
82 /* in the middle of cycling..? kill it. */
83 if (focus_cycle_target
)
84 focus_cycle(TRUE
, TRUE
, TRUE
, TRUE
);
87 focus_client
= client
;
89 /* move to the top of the list */
93 /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
94 if (ob_state() != OB_STATE_EXITING
) {
95 active
= client
? client
->window
: None
;
96 PROP_SET32(RootWindow(ob_display
, ob_screen
),
97 net_active_window
, window
, active
);
100 if (focus_client
!= NULL
)
101 dispatch_client(Event_Client_Focus
, focus_client
, 0, 0);
103 dispatch_client(Event_Client_Unfocus
, old
, 0, 0);
106 static gboolean
focus_under_pointer()
111 if (screen_pointer_pos(&x
, &y
)) {
112 for (it
= stacking_list
; it
!= NULL
; it
= it
->next
) {
113 if (WINDOW_IS_CLIENT(it
->data
)) {
114 ObClient
*c
= WINDOW_AS_CLIENT(it
->data
);
115 if (c
->desktop
== screen_desktop
&&
116 RECT_CONTAINS(c
->frame
->area
, x
, y
))
121 g_assert(WINDOW_IS_CLIENT(it
->data
));
122 return client_normal(it
->data
) && client_focus(it
->data
);
128 /* finds the first transient that isn't 'skip' and ensure's that client_normal
130 static ObClient
*find_transient_recursive(ObClient
*c
, ObClient
*top
, ObClient
*skip
)
135 for (it
= c
->transients
; it
; it
= it
->next
) {
136 if (it
->data
== top
) return NULL
;
137 ret
= find_transient_recursive(it
->data
, top
, skip
);
138 if (ret
&& ret
!= skip
&& client_normal(ret
)) return ret
;
139 if (it
->data
!= skip
&& client_normal(it
->data
)) return it
->data
;
144 static gboolean
focus_fallback_transient(ObClient
*top
, ObClient
*old
)
146 ObClient
*target
= find_transient_recursive(top
, top
, old
);
148 /* make sure client_normal is true always */
149 if (!client_normal(top
))
151 target
= top
; /* no transient, keep the top */
153 return client_focus(target
);
156 void focus_fallback(ObFocusFallbackType type
)
159 ObClient
*old
= NULL
;
163 /* unfocus any focused clients.. they can be focused by Pointer events
164 and such, and then when I try focus them, I won't get a FocusIn event
167 focus_set_client(NULL
);
169 if (!(type
== OB_FOCUS_FALLBACK_DESKTOP
?
170 config_focus_last_on_desktop
: config_focus_last
)) {
171 if (config_focus_follow
) focus_under_pointer();
175 if (type
== OB_FOCUS_FALLBACK_UNFOCUSING
&& old
) {
176 /* try for transient relations */
177 if (old
->transient_for
) {
178 if (old
->transient_for
== OB_TRAN_GROUP
) {
179 for (it
= focus_order
[screen_desktop
]; it
; it
= it
->next
) {
182 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
183 if (sit
->data
== it
->data
)
184 if (focus_fallback_transient(sit
->data
, old
))
188 if (focus_fallback_transient(old
->transient_for
, old
))
194 /* try for group relations */
198 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
199 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
200 if (sit
->data
== it
->data
)
201 if (sit
->data
!= old
&& client_normal(sit
->data
))
202 if (client_can_focus(sit
->data
)) {
203 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
, POPUP_WIDTH
, POPUP_HEIGHT
);
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
, FALSE
);
287 if (!first
) first
= focus_client
;
288 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
290 if (linear
) list
= client_list
;
291 else list
= focus_order
[screen_desktop
];
293 start
= it
= g_list_find(list
, focus_cycle_target
);
294 if (!start
) /* switched desktops or something? */
295 start
= it
= forward
? g_list_last(list
) : g_list_first(list
);
296 if (!start
) goto done_cycle
;
301 if (it
== NULL
) it
= g_list_first(list
);
304 if (it
== NULL
) it
= g_list_last(list
);
306 /*ft = client_focus_target(it->data);*/
308 /* we don't use client_can_focus here, because that doesn't let you
309 focus an iconic window, but we want to be able to, so we just check
310 if the focus flags on the window allow it, and its on the current
312 if (ft
->transients
== NULL
&& client_normal(ft
) &&
313 ((ft
->can_focus
|| ft
->focus_notify
) &&
315 (ft
->desktop
== screen_desktop
|| ft
->desktop
== DESKTOP_ALL
))) {
316 if (ft
!= focus_cycle_target
) { /* prevents flicker */
317 if (focus_cycle_target
)
318 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
319 focus_cycle_target
= ft
;
320 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
322 popup_cycle(ft
, config_focus_popup
);
325 } while (it
!= start
);
330 focus_cycle_target
= NULL
;
334 popup_cycle(ft
, FALSE
);
339 void focus_order_add_new(ObClient
*c
)
344 focus_order_to_top(c
);
347 if (d
== DESKTOP_ALL
) {
348 for (i
= 0; i
< screen_num_desktops
; ++i
) {
349 if (focus_order
[i
] && ((ObClient
*)focus_order
[i
]->data
)->iconic
)
350 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 0);
352 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 1);
355 if (focus_order
[d
] && ((ObClient
*)focus_order
[d
]->data
)->iconic
)
356 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 0);
358 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 1);
362 void focus_order_remove(ObClient
*c
)
367 if (d
== DESKTOP_ALL
) {
368 for (i
= 0; i
< screen_num_desktops
; ++i
)
369 focus_order
[i
] = g_list_remove(focus_order
[i
], c
);
371 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
374 static void to_top(ObClient
*c
, guint d
)
376 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
378 focus_order
[d
] = g_list_prepend(focus_order
[d
], c
);
382 /* insert before first iconic window */
383 for (it
= focus_order
[d
];
384 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
385 g_list_insert_before(focus_order
[d
], it
, c
);
389 void focus_order_to_top(ObClient
*c
)
394 if (d
== DESKTOP_ALL
) {
395 for (i
= 0; i
< screen_num_desktops
; ++i
)
401 static void to_bottom(ObClient
*c
, guint d
)
403 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
405 focus_order
[d
] = g_list_append(focus_order
[d
], c
);
409 /* insert before first iconic window */
410 for (it
= focus_order
[d
];
411 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
412 g_list_insert_before(focus_order
[d
], it
, c
);
416 void focus_order_to_bottom(ObClient
*c
)
421 if (d
== DESKTOP_ALL
) {
422 for (i
= 0; i
< screen_num_desktops
; ++i
)