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 void 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
);
274 focus_cycle_target
= NULL
;
276 } else if (done
&& dialog
) {
280 if (!first
) first
= focus_client
;
281 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
283 if (linear
) list
= client_list
;
284 else list
= focus_order
[screen_desktop
];
286 start
= it
= g_list_find(list
, focus_cycle_target
);
287 if (!start
) /* switched desktops or something? */
288 start
= it
= forward
? g_list_last(list
) : g_list_first(list
);
289 if (!start
) goto done_cycle
;
294 if (it
== NULL
) it
= g_list_first(list
);
297 if (it
== NULL
) it
= g_list_last(list
);
299 /*ft = client_focus_target(it->data);*/
301 /* we don't use client_can_focus here, because that doesn't let you
302 focus an iconic window, but we want to be able to, so we just check
303 if the focus flags on the window allow it, and its on the current
305 if (ft
->transients
== NULL
&& client_normal(ft
) &&
306 ((ft
->can_focus
|| ft
->focus_notify
) &&
308 (ft
->desktop
== screen_desktop
|| ft
->desktop
== DESKTOP_ALL
))) {
309 if (ft
!= focus_cycle_target
) { /* prevents flicker */
310 if (focus_cycle_target
)
311 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
312 focus_cycle_target
= ft
;
313 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
315 popup_cycle(ft
, dialog
);
318 } while (it
!= start
);
321 if (done
&& focus_cycle_target
)
322 client_activate(focus_cycle_target
, FALSE
);
326 focus_cycle_target
= NULL
;
330 popup_cycle(ft
, FALSE
);
335 void focus_directional_cycle(ObDirection dir
,
336 gboolean dialog
, gboolean done
, gboolean cancel
)
338 static ObClient
*first
= NULL
;
342 if (focus_cycle_target
)
343 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
345 frame_adjust_focus(focus_client
->frame
, TRUE
);
346 focus_cycle_target
= NULL
;
348 } else if (done
&& dialog
) {
352 if (!first
) first
= focus_client
;
353 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
355 if ((ft
= client_find_directional(focus_cycle_target
, dir
))) {
356 if (ft
!= focus_cycle_target
) {/* prevents flicker */
357 if (focus_cycle_target
)
358 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
359 focus_cycle_target
= ft
;
360 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
362 popup_cycle(ft
, dialog
);
368 if (done
&& focus_cycle_target
)
369 client_activate(focus_cycle_target
, FALSE
);
372 focus_cycle_target
= NULL
;
374 popup_cycle(ft
, FALSE
);
379 void focus_order_add_new(ObClient
*c
)
384 focus_order_to_top(c
);
387 if (d
== DESKTOP_ALL
) {
388 for (i
= 0; i
< screen_num_desktops
; ++i
) {
389 if (focus_order
[i
] && ((ObClient
*)focus_order
[i
]->data
)->iconic
)
390 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 0);
392 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 1);
395 if (focus_order
[d
] && ((ObClient
*)focus_order
[d
]->data
)->iconic
)
396 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 0);
398 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 1);
402 void focus_order_remove(ObClient
*c
)
407 if (d
== DESKTOP_ALL
) {
408 for (i
= 0; i
< screen_num_desktops
; ++i
)
409 focus_order
[i
] = g_list_remove(focus_order
[i
], c
);
411 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
414 static void to_top(ObClient
*c
, guint d
)
416 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
418 focus_order
[d
] = g_list_prepend(focus_order
[d
], c
);
422 /* insert before first iconic window */
423 for (it
= focus_order
[d
];
424 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
425 g_list_insert_before(focus_order
[d
], it
, c
);
429 void focus_order_to_top(ObClient
*c
)
434 if (d
== DESKTOP_ALL
) {
435 for (i
= 0; i
< screen_num_desktops
; ++i
)
441 static void to_bottom(ObClient
*c
, guint d
)
443 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
445 focus_order
[d
] = g_list_append(focus_order
[d
], c
);
449 /* insert before first iconic window */
450 for (it
= focus_order
[d
];
451 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
452 g_list_insert_before(focus_order
[d
], it
, c
);
456 void focus_order_to_bottom(ObClient
*c
)
461 if (d
== DESKTOP_ALL
) {
462 for (i
= 0; i
< screen_num_desktops
; ++i
)