5 #include "framerender.h"
20 ObClient
*focus_client
;
21 GList
**focus_order
; /* these lists are created when screen_startup
22 sets the number of desktops */
24 static ObClient
*focus_cycle_target
;
25 static Popup
*focus_cycle_popup
;
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 ob_debug("focus_set_client 0x%lx\n", 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
, 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
);
100 static gboolean
focus_under_pointer()
105 if (screen_pointer_pos(&x
, &y
)) {
106 for (it
= stacking_list
; it
!= NULL
; it
= it
->next
) {
107 if (WINDOW_IS_CLIENT(it
->data
)) {
108 ObClient
*c
= WINDOW_AS_CLIENT(it
->data
);
109 if (c
->desktop
== screen_desktop
&&
110 RECT_CONTAINS(c
->frame
->area
, x
, y
))
115 g_assert(WINDOW_IS_CLIENT(it
->data
));
116 return client_normal(it
->data
) && client_focus(it
->data
);
122 /* finds the first transient that isn't 'skip' and ensure's that client_normal
124 static ObClient
*find_transient_recursive(ObClient
*c
, ObClient
*top
, ObClient
*skip
)
129 for (it
= c
->transients
; it
; it
= it
->next
) {
130 if (it
->data
== top
) return NULL
;
131 ret
= find_transient_recursive(it
->data
, top
, skip
);
132 if (ret
&& ret
!= skip
&& client_normal(ret
)) return ret
;
133 if (it
->data
!= skip
&& client_normal(it
->data
)) return it
->data
;
138 static gboolean
focus_fallback_transient(ObClient
*top
, ObClient
*old
)
140 ObClient
*target
= find_transient_recursive(top
, top
, old
);
142 /* make sure client_normal is true always */
143 if (!client_normal(top
))
145 target
= top
; /* no transient, keep the top */
147 return client_focus(target
);
150 void focus_fallback(ObFocusFallbackType type
)
153 ObClient
*old
= NULL
;
157 /* unfocus any focused clients.. they can be focused by Pointer events
158 and such, and then when I try focus them, I won't get a FocusIn event
161 focus_set_client(NULL
);
163 if (!(type
== OB_FOCUS_FALLBACK_DESKTOP
?
164 config_focus_last_on_desktop
: config_focus_last
)) {
165 if (config_focus_follow
) focus_under_pointer();
169 if (type
== OB_FOCUS_FALLBACK_UNFOCUSING
&& old
) {
170 /* try for transient relations */
171 if (old
->transient_for
) {
172 if (old
->transient_for
== OB_TRAN_GROUP
) {
173 for (it
= focus_order
[screen_desktop
]; it
; it
= it
->next
) {
176 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
177 if (sit
->data
== it
->data
)
178 if (focus_fallback_transient(sit
->data
, old
))
182 if (focus_fallback_transient(old
->transient_for
, old
))
188 /* try for group relations */
192 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
193 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
194 if (sit
->data
== it
->data
)
195 if (sit
->data
!= old
&& client_normal(sit
->data
))
196 if (client_can_focus(sit
->data
)) {
197 gboolean r
= client_focus(sit
->data
);
205 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
206 if (type
!= OB_FOCUS_FALLBACK_UNFOCUSING
|| it
->data
!= old
)
207 if (client_normal(it
->data
) &&
208 /* dont fall back to 'anonymous' fullscreen windows. theres no
209 checks for this is in transient/group fallbacks, so they can
210 be fallback targets there. */
211 !((ObClient
*)it
->data
)->fullscreen
&&
212 client_can_focus(it
->data
)) {
213 gboolean r
= client_focus(it
->data
);
218 /* nothing to focus, and already set it to none above */
221 static void popup_cycle(ObClient
*c
, gboolean show
)
224 popup_hide(focus_cycle_popup
);
230 a
= screen_physical_area_monitor(0);
231 popup_position(focus_cycle_popup
, CenterGravity
,
232 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
233 /* popup_size(focus_cycle_popup, a->height/2, a->height/16);
234 popup_show(focus_cycle_popup, c->title,
235 client_icon(c, a->height/16, a->height/16));
237 /* XXX the size and the font extents need to be related on some level
239 popup_size(focus_cycle_popup
, POPUP_WIDTH
, POPUP_HEIGHT
);
241 /* use the transient's parent's title/icon */
242 while (p
->transient_for
&& p
->transient_for
!= OB_TRAN_GROUP
)
243 p
= p
->transient_for
;
248 title
= g_strconcat((c
->iconic
? c
->icon_title
: c
->title
),
250 (p
->iconic
? p
->icon_title
: p
->title
),
253 popup_show(focus_cycle_popup
,
254 (title
? title
: (c
->iconic
? c
->icon_title
: c
->title
)),
255 client_icon(p
, 48, 48));
260 ObClient
*focus_cycle(gboolean forward
, gboolean linear
,
261 gboolean dialog
, gboolean done
, gboolean cancel
)
263 static ObClient
*first
= NULL
;
264 static ObClient
*t
= NULL
;
265 static GList
*order
= NULL
;
266 GList
*it
, *start
, *list
;
270 if (focus_cycle_target
)
271 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
273 frame_adjust_focus(focus_client
->frame
, TRUE
);
276 if (focus_cycle_target
)
277 client_activate(focus_cycle_target
, FALSE
);
281 if (!first
) first
= focus_client
;
282 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
284 if (linear
) list
= client_list
;
285 else list
= focus_order
[screen_desktop
];
287 start
= it
= g_list_find(list
, focus_cycle_target
);
288 if (!start
) /* switched desktops or something? */
289 start
= it
= forward
? g_list_last(list
) : g_list_first(list
);
290 if (!start
) goto done_cycle
;
295 if (it
== NULL
) it
= g_list_first(list
);
298 if (it
== NULL
) it
= g_list_last(list
);
300 /*ft = client_focus_target(it->data);*/
302 /* we don't use client_can_focus here, because that doesn't let you
303 focus an iconic window, but we want to be able to, so we just check
304 if the focus flags on the window allow it, and its on the current
306 if (ft
->transients
== NULL
&& client_normal(ft
) &&
307 ((ft
->can_focus
|| ft
->focus_notify
) &&
309 (ft
->desktop
== screen_desktop
|| ft
->desktop
== DESKTOP_ALL
))) {
310 if (ft
!= focus_cycle_target
) { /* prevents flicker */
311 if (focus_cycle_target
)
312 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
313 focus_cycle_target
= ft
;
314 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
316 popup_cycle(ft
, dialog
);
319 } while (it
!= start
);
324 focus_cycle_target
= NULL
;
328 popup_cycle(ft
, FALSE
);
333 void focus_order_add_new(ObClient
*c
)
338 focus_order_to_top(c
);
341 if (d
== DESKTOP_ALL
) {
342 for (i
= 0; i
< screen_num_desktops
; ++i
) {
343 if (focus_order
[i
] && ((ObClient
*)focus_order
[i
]->data
)->iconic
)
344 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 0);
346 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 1);
349 if (focus_order
[d
] && ((ObClient
*)focus_order
[d
]->data
)->iconic
)
350 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 0);
352 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 1);
356 void focus_order_remove(ObClient
*c
)
361 if (d
== DESKTOP_ALL
) {
362 for (i
= 0; i
< screen_num_desktops
; ++i
)
363 focus_order
[i
] = g_list_remove(focus_order
[i
], c
);
365 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
368 static void to_top(ObClient
*c
, guint d
)
370 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
372 focus_order
[d
] = g_list_prepend(focus_order
[d
], c
);
376 /* insert before first iconic window */
377 for (it
= focus_order
[d
];
378 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
379 g_list_insert_before(focus_order
[d
], it
, c
);
383 void focus_order_to_top(ObClient
*c
)
388 if (d
== DESKTOP_ALL
) {
389 for (i
= 0; i
< screen_num_desktops
; ++i
)
395 static void to_bottom(ObClient
*c
, guint d
)
397 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
399 focus_order
[d
] = g_list_append(focus_order
[d
], c
);
403 /* insert before first iconic window */
404 for (it
= focus_order
[d
];
405 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
406 g_list_insert_before(focus_order
[d
], it
, c
);
410 void focus_order_to_bottom(ObClient
*c
)
415 if (d
== DESKTOP_ALL
) {
416 for (i
= 0; i
< screen_num_desktops
; ++i
)