4 #include "framerender.h"
20 ObClient
*focus_client
;
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
;
30 focus_cycle_popup
= popup_new(TRUE
);
32 /* start with nothing focused */
33 focus_set_client(NULL
);
40 for (i
= 0; i
< screen_num_desktops
; ++i
)
41 g_list_free(focus_order
[i
]);
44 popup_free(focus_cycle_popup
);
46 /* reset focus to root */
47 XSetInputFocus(ob_display
, PointerRoot
, RevertToPointerRoot
,
51 static void push_to_top(ObClient
*client
)
55 desktop
= client
->desktop
;
56 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
57 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
], client
);
58 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
], client
);
61 void focus_set_client(ObClient
*client
)
67 g_message("focus_set_client 0x%lx", client
? client
->window
: 0);
70 /* uninstall the old colormap, and install the new one */
71 screen_install_colormap(focus_client
, FALSE
);
72 screen_install_colormap(client
, TRUE
);
75 /* when nothing will be focused, send focus to the backup target */
76 XSetInputFocus(ob_display
, screen_support_win
, RevertToPointerRoot
,
78 XSync(ob_display
, FALSE
);
81 /* in the middle of cycling..? kill it. */
82 if (focus_cycle_target
)
83 focus_cycle(TRUE
, TRUE
, TRUE
, TRUE
);
86 focus_client
= client
;
88 /* move to the top of the list */
92 /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
93 if (ob_state() != OB_STATE_EXITING
) {
94 active
= client
? client
->window
: None
;
95 PROP_SET32(RootWindow(ob_display
, ob_screen
),
96 net_active_window
, window
, active
);
99 if (focus_client
!= NULL
)
100 dispatch_client(Event_Client_Focus
, focus_client
, 0, 0);
102 dispatch_client(Event_Client_Unfocus
, old
, 0, 0);
105 static gboolean
focus_under_pointer()
110 if (screen_pointer_pos(&x
, &y
)) {
111 for (it
= stacking_list
; it
!= NULL
; it
= it
->next
) {
112 if (WINDOW_IS_CLIENT(it
->data
)) {
113 ObClient
*c
= WINDOW_AS_CLIENT(it
->data
);
114 if (c
->desktop
== screen_desktop
&&
115 RECT_CONTAINS(c
->frame
->area
, x
, y
))
120 g_assert(WINDOW_IS_CLIENT(it
->data
));
121 return client_normal(it
->data
) && client_focus(it
->data
);
127 /* finds the first transient that isn't 'skip' and ensure's that client_normal
129 static ObClient
*find_transient_recursive(ObClient
*c
, ObClient
*top
, ObClient
*skip
)
134 for (it
= c
->transients
; it
; it
= it
->next
) {
135 if (it
->data
== top
) return NULL
;
136 ret
= find_transient_recursive(it
->data
, top
, skip
);
137 if (ret
&& ret
!= skip
&& client_normal(ret
)) return ret
;
138 if (it
->data
!= skip
&& client_normal(it
->data
)) return it
->data
;
143 static gboolean
focus_fallback_transient(ObClient
*top
, ObClient
*old
)
145 ObClient
*target
= find_transient_recursive(top
, top
, old
);
147 /* make sure client_normal is true always */
148 if (!client_normal(top
))
150 target
= top
; /* no transient, keep the top */
152 return client_focus(target
);
155 void focus_fallback(ObFocusFallbackType type
)
158 ObClient
*old
= NULL
;
162 /* unfocus any focused clients.. they can be focused by Pointer events
163 and such, and then when I try focus them, I won't get a FocusIn event
166 focus_set_client(NULL
);
168 if (!(type
== OB_FOCUS_FALLBACK_DESKTOP
?
169 config_focus_last_on_desktop
: config_focus_last
)) {
170 if (config_focus_follow
) focus_under_pointer();
174 if (type
== OB_FOCUS_FALLBACK_UNFOCUSING
&& old
) {
175 /* try for transient relations */
176 if (old
->transient_for
) {
177 if (old
->transient_for
== OB_TRAN_GROUP
) {
178 for (it
= focus_order
[screen_desktop
]; it
; it
= it
->next
) {
181 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
182 if (sit
->data
== it
->data
)
183 if (focus_fallback_transient(sit
->data
, old
))
187 if (focus_fallback_transient(old
->transient_for
, old
))
192 /* try for group relations */
196 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
197 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
198 if (sit
->data
== it
->data
)
199 if (sit
->data
!= old
&& client_normal(sit
->data
))
200 if (client_can_focus(sit
->data
)) {
201 gboolean r
= client_focus(sit
->data
);
208 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
209 if (type
!= OB_FOCUS_FALLBACK_UNFOCUSING
|| it
->data
!= old
)
210 if (client_normal(it
->data
) &&
211 /* dont fall back to 'anonymous' fullscreen windows. theres no
212 checks for this is in transient/group fallbacks, so they can
213 be fallback targets there. */
214 !((ObClient
*)it
->data
)->fullscreen
&&
215 client_can_focus(it
->data
)) {
216 gboolean r
= client_focus(it
->data
);
221 /* nothing to focus, and already set it to none above */
224 static void popup_cycle(ObClient
*c
, gboolean show
)
227 popup_hide(focus_cycle_popup
);
233 a
= screen_physical_area_monitor(0);
234 popup_position(focus_cycle_popup
, CenterGravity
,
235 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
236 /* popup_size(focus_cycle_popup, a->height/2, a->height/16);
237 popup_show(focus_cycle_popup, c->title,
238 client_icon(c, a->height/16, a->height/16));
240 /* XXX the size and the font extents need to be related on some level
242 popup_size(focus_cycle_popup
, 320, 48);
244 /* use the transient's parent's title/icon */
245 while (p
->transient_for
&& p
->transient_for
!= OB_TRAN_GROUP
)
246 p
= p
->transient_for
;
251 title
= g_strconcat((c
->iconic
? c
->icon_title
: c
->title
),
253 (p
->iconic
? p
->icon_title
: p
->title
),
256 popup_show(focus_cycle_popup
,
257 (title
? title
: (c
->iconic
? c
->icon_title
: c
->title
)),
258 client_icon(p
, 48, 48));
263 ObClient
*focus_cycle(gboolean forward
, gboolean linear
, gboolean done
,
266 static ObClient
*first
= NULL
;
267 static ObClient
*t
= NULL
;
268 static GList
*order
= NULL
;
269 GList
*it
, *start
, *list
;
273 if (focus_cycle_target
)
274 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
276 frame_adjust_focus(focus_client
->frame
, TRUE
);
279 if (focus_cycle_target
)
280 client_activate(focus_cycle_target
);
284 grab_pointer(TRUE
, None
);
286 if (!first
) first
= focus_client
;
287 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
289 if (linear
) list
= client_list
;
290 else list
= focus_order
[screen_desktop
];
292 start
= it
= g_list_find(list
, focus_cycle_target
);
293 if (!start
) /* switched desktops or something? */
294 start
= it
= forward
? g_list_last(list
) : g_list_first(list
);
295 if (!start
) goto done_cycle
;
300 if (it
== NULL
) it
= g_list_first(list
);
303 if (it
== NULL
) it
= g_list_last(list
);
305 /*ft = client_focus_target(it->data);*/
307 /* we don't use client_can_focus here, because that doesn't let you
308 focus an iconic window, but we want to be able to, so we just check
309 if the focus flags on the window allow it, and its on the current
311 if (ft
->transients
== NULL
&& client_normal(ft
) &&
312 ((ft
->can_focus
|| ft
->focus_notify
) &&
313 (ft
->desktop
== screen_desktop
|| ft
->desktop
== DESKTOP_ALL
))) {
314 if (ft
!= focus_cycle_target
) { /* prevents flicker */
315 if (focus_cycle_target
)
316 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
317 focus_cycle_target
= ft
;
318 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
320 popup_cycle(ft
, config_focus_popup
);
323 } while (it
!= start
);
328 focus_cycle_target
= NULL
;
332 popup_cycle(ft
, FALSE
);
333 grab_pointer(FALSE
, None
);
338 void focus_order_add_new(ObClient
*c
)
343 focus_order_to_top(c
);
346 if (d
== DESKTOP_ALL
) {
347 for (i
= 0; i
< screen_num_desktops
; ++i
) {
348 if (focus_order
[i
] && ((ObClient
*)focus_order
[i
]->data
)->iconic
)
349 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 0);
351 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 1);
354 if (focus_order
[d
] && ((ObClient
*)focus_order
[d
]->data
)->iconic
)
355 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 0);
357 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 1);
361 void focus_order_remove(ObClient
*c
)
366 if (d
== DESKTOP_ALL
) {
367 for (i
= 0; i
< screen_num_desktops
; ++i
)
368 focus_order
[i
] = g_list_remove(focus_order
[i
], c
);
370 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
373 static void to_top(ObClient
*c
, guint d
)
375 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
377 focus_order
[d
] = g_list_prepend(focus_order
[d
], c
);
381 /* insert before first iconic window */
382 for (it
= focus_order
[d
];
383 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
384 g_list_insert_before(focus_order
[d
], it
, c
);
388 void focus_order_to_top(ObClient
*c
)
393 if (d
== DESKTOP_ALL
) {
394 for (i
= 0; i
< screen_num_desktops
; ++i
)
400 static void to_bottom(ObClient
*c
, guint d
)
402 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
404 focus_order
[d
] = g_list_append(focus_order
[d
], c
);
408 /* insert before first iconic window */
409 for (it
= focus_order
[d
];
410 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
411 g_list_insert_before(focus_order
[d
], it
, c
);
415 void focus_order_to_bottom(ObClient
*c
)
420 if (d
== DESKTOP_ALL
) {
421 for (i
= 0; i
< screen_num_desktops
; ++i
)