5 #include "framerender.h"
21 ObClient
*focus_client
;
22 GList
**focus_order
= NULL
; /* these lists are created when screen_startup
23 sets the number of desktops */
25 static ObClient
*focus_cycle_target
= NULL
;
26 static Popup
*focus_cycle_popup
= NULL
;
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
, 320, 48);
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 grab_pointer(TRUE
, None
);
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
) &&
314 (ft
->desktop
== screen_desktop
|| ft
->desktop
== DESKTOP_ALL
))) {
315 if (ft
!= focus_cycle_target
) { /* prevents flicker */
316 if (focus_cycle_target
)
317 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
318 focus_cycle_target
= ft
;
319 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
321 popup_cycle(ft
, config_focus_popup
);
324 } while (it
!= start
);
329 focus_cycle_target
= NULL
;
333 popup_cycle(ft
, FALSE
);
334 grab_pointer(FALSE
, None
);
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
)