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
))
193 /* try for group relations */
197 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
198 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
199 if (sit
->data
== it
->data
)
200 if (sit
->data
!= old
&& client_normal(sit
->data
))
201 if (client_can_focus(sit
->data
)) {
202 gboolean r
= client_focus(sit
->data
);
209 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
210 if (type
!= OB_FOCUS_FALLBACK_UNFOCUSING
|| it
->data
!= old
)
211 if (client_normal(it
->data
) &&
212 /* dont fall back to 'anonymous' fullscreen windows. theres no
213 checks for this is in transient/group fallbacks, so they can
214 be fallback targets there. */
215 !((ObClient
*)it
->data
)->fullscreen
&&
216 client_can_focus(it
->data
)) {
217 gboolean r
= client_focus(it
->data
);
222 /* nothing to focus, and already set it to none above */
225 static void popup_cycle(ObClient
*c
, gboolean show
)
228 popup_hide(focus_cycle_popup
);
234 a
= screen_physical_area_monitor(0);
235 popup_position(focus_cycle_popup
, CenterGravity
,
236 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
237 /* popup_size(focus_cycle_popup, a->height/2, a->height/16);
238 popup_show(focus_cycle_popup, c->title,
239 client_icon(c, a->height/16, a->height/16));
241 /* XXX the size and the font extents need to be related on some level
243 popup_size(focus_cycle_popup
, POPUP_WIDTH
, POPUP_HEIGHT
);
245 /* use the transient's parent's title/icon */
246 while (p
->transient_for
&& p
->transient_for
!= OB_TRAN_GROUP
)
247 p
= p
->transient_for
;
252 title
= g_strconcat((c
->iconic
? c
->icon_title
: c
->title
),
254 (p
->iconic
? p
->icon_title
: p
->title
),
257 popup_show(focus_cycle_popup
,
258 (title
? title
: (c
->iconic
? c
->icon_title
: c
->title
)),
259 client_icon(p
, 48, 48));
264 ObClient
*focus_cycle(gboolean forward
, gboolean linear
, gboolean done
,
267 static ObClient
*first
= NULL
;
268 static ObClient
*t
= NULL
;
269 static GList
*order
= NULL
;
270 GList
*it
, *start
, *list
;
274 if (focus_cycle_target
)
275 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
277 frame_adjust_focus(focus_client
->frame
, TRUE
);
280 if (focus_cycle_target
)
281 client_activate(focus_cycle_target
);
285 if (!first
) first
= focus_client
;
286 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
288 if (linear
) list
= client_list
;
289 else list
= focus_order
[screen_desktop
];
291 start
= it
= g_list_find(list
, focus_cycle_target
);
292 if (!start
) /* switched desktops or something? */
293 start
= it
= forward
? g_list_last(list
) : g_list_first(list
);
294 if (!start
) goto done_cycle
;
299 if (it
== NULL
) it
= g_list_first(list
);
302 if (it
== NULL
) it
= g_list_last(list
);
304 /*ft = client_focus_target(it->data);*/
306 /* we don't use client_can_focus here, because that doesn't let you
307 focus an iconic window, but we want to be able to, so we just check
308 if the focus flags on the window allow it, and its on the current
310 if (ft
->transients
== NULL
&& client_normal(ft
) &&
311 ((ft
->can_focus
|| ft
->focus_notify
) &&
312 (ft
->desktop
== screen_desktop
|| ft
->desktop
== DESKTOP_ALL
))) {
313 if (ft
!= focus_cycle_target
) { /* prevents flicker */
314 if (focus_cycle_target
)
315 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
316 focus_cycle_target
= ft
;
317 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
319 popup_cycle(ft
, config_focus_popup
);
322 } while (it
!= start
);
327 focus_cycle_target
= NULL
;
331 popup_cycle(ft
, FALSE
);
336 void focus_order_add_new(ObClient
*c
)
341 focus_order_to_top(c
);
344 if (d
== DESKTOP_ALL
) {
345 for (i
= 0; i
< screen_num_desktops
; ++i
) {
346 if (focus_order
[i
] && ((ObClient
*)focus_order
[i
]->data
)->iconic
)
347 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 0);
349 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 1);
352 if (focus_order
[d
] && ((ObClient
*)focus_order
[d
]->data
)->iconic
)
353 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 0);
355 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 1);
359 void focus_order_remove(ObClient
*c
)
364 if (d
== DESKTOP_ALL
) {
365 for (i
= 0; i
< screen_num_desktops
; ++i
)
366 focus_order
[i
] = g_list_remove(focus_order
[i
], c
);
368 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
371 static void to_top(ObClient
*c
, guint d
)
373 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
375 focus_order
[d
] = g_list_prepend(focus_order
[d
], c
);
379 /* insert before first iconic window */
380 for (it
= focus_order
[d
];
381 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
382 g_list_insert_before(focus_order
[d
], it
, c
);
386 void focus_order_to_top(ObClient
*c
)
391 if (d
== DESKTOP_ALL
) {
392 for (i
= 0; i
< screen_num_desktops
; ++i
)
398 static void to_bottom(ObClient
*c
, guint d
)
400 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
402 focus_order
[d
] = g_list_append(focus_order
[d
], c
);
406 /* insert before first iconic window */
407 for (it
= focus_order
[d
];
408 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
409 g_list_insert_before(focus_order
[d
], it
, c
);
413 void focus_order_to_bottom(ObClient
*c
)
418 if (d
== DESKTOP_ALL
) {
419 for (i
= 0; i
< screen_num_desktops
; ++i
)