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 */
23 ObClient
*focus_cycle_target
;
25 static ObIconPopup
*focus_cycle_popup
;
27 void focus_startup(gboolean reconfig
)
29 focus_cycle_popup
= icon_popup_new(TRUE
);
32 /* start with nothing focused */
33 focus_set_client(NULL
);
36 void focus_shutdown(gboolean reconfig
)
40 icon_popup_free(focus_cycle_popup
);
43 for (i
= 0; i
< screen_num_desktops
; ++i
)
44 g_list_free(focus_order
[i
]);
47 /* reset focus to root */
48 XSetInputFocus(ob_display
, PointerRoot
, RevertToPointerRoot
,
53 static void push_to_top(ObClient
*client
)
57 desktop
= client
->desktop
;
58 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
59 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
], client
);
60 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
], client
);
63 void focus_set_client(ObClient
*client
)
69 ob_debug("focus_set_client 0x%lx\n", client
? client
->window
: 0);
72 /* uninstall the old colormap, and install the new one */
73 screen_install_colormap(focus_client
, FALSE
);
74 screen_install_colormap(client
, TRUE
);
77 /* when nothing will be focused, send focus to the backup target */
78 XSetInputFocus(ob_display
, screen_support_win
, RevertToPointerRoot
,
80 XSync(ob_display
, FALSE
);
83 /* in the middle of cycling..? kill it. */
84 if (focus_cycle_target
)
85 focus_cycle(TRUE
, TRUE
, TRUE
, TRUE
, TRUE
);
88 focus_client
= client
;
90 /* move to the top of the list */
94 /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
95 if (ob_state() != OB_STATE_EXITING
) {
96 active
= client
? client
->window
: None
;
97 PROP_SET32(RootWindow(ob_display
, ob_screen
),
98 net_active_window
, window
, active
);
102 static gboolean
focus_under_pointer()
107 if (screen_pointer_pos(&x
, &y
)) {
108 for (it
= stacking_list
; it
!= NULL
; it
= it
->next
) {
109 if (WINDOW_IS_CLIENT(it
->data
)) {
110 ObClient
*c
= WINDOW_AS_CLIENT(it
->data
);
111 if (c
->desktop
== screen_desktop
&&
112 RECT_CONTAINS(c
->frame
->area
, x
, y
))
117 g_assert(WINDOW_IS_CLIENT(it
->data
));
118 return client_normal(it
->data
) && client_focus(it
->data
);
124 /* finds the first transient that isn't 'skip' and ensure's that client_normal
126 static ObClient
*find_transient_recursive(ObClient
*c
, ObClient
*top
, ObClient
*skip
)
131 for (it
= c
->transients
; it
; it
= it
->next
) {
132 if (it
->data
== top
) return NULL
;
133 ret
= find_transient_recursive(it
->data
, top
, skip
);
134 if (ret
&& ret
!= skip
&& client_normal(ret
)) return ret
;
135 if (it
->data
!= skip
&& client_normal(it
->data
)) return it
->data
;
140 static gboolean
focus_fallback_transient(ObClient
*top
, ObClient
*old
)
142 ObClient
*target
= find_transient_recursive(top
, top
, old
);
144 /* make sure client_normal is true always */
145 if (!client_normal(top
))
147 target
= top
; /* no transient, keep the top */
149 return client_focus(target
);
152 void focus_fallback(ObFocusFallbackType type
)
155 ObClient
*old
= NULL
;
159 /* unfocus any focused clients.. they can be focused by Pointer events
160 and such, and then when I try focus them, I won't get a FocusIn event
163 focus_set_client(NULL
);
165 if (config_focus_follow
&& focus_under_pointer())
168 if (type
== OB_FOCUS_FALLBACK_UNFOCUSING
&& old
) {
169 /* try for transient relations */
170 if (old
->transient_for
) {
171 if (old
->transient_for
== OB_TRAN_GROUP
) {
172 for (it
= focus_order
[screen_desktop
]; it
; it
= it
->next
) {
175 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
176 if (sit
->data
== it
->data
)
177 if (focus_fallback_transient(sit
->data
, old
))
181 if (focus_fallback_transient(old
->transient_for
, old
))
187 /* try for group relations */
191 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
192 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
193 if (sit
->data
== it
->data
)
194 if (sit
->data
!= old
&& client_normal(sit
->data
))
195 if (client_can_focus(sit
->data
)) {
196 gboolean r
= client_focus(sit
->data
);
204 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
205 if (type
!= OB_FOCUS_FALLBACK_UNFOCUSING
|| it
->data
!= old
)
206 if (client_normal(it
->data
) &&
207 /* dont fall back to 'anonymous' fullscreen windows. theres no
208 checks for this is in transient/group fallbacks, so they can
209 be fallback targets there. */
210 !((ObClient
*)it
->data
)->fullscreen
&&
211 client_can_focus(it
->data
)) {
212 gboolean r
= client_focus(it
->data
);
217 /* nothing to focus, and already set it to none above */
220 static void popup_cycle(ObClient
*c
, gboolean show
)
223 icon_popup_hide(focus_cycle_popup
);
229 a
= screen_physical_area_monitor(0);
230 icon_popup_position(focus_cycle_popup
, CenterGravity
,
231 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
232 /* icon_popup_size(focus_cycle_popup, a->height/2, a->height/16);
233 icon_popup_show(focus_cycle_popup, c->title,
234 client_icon(c, a->height/16, a->height/16));
236 /* XXX the size and the font extents need to be related on some level
238 icon_popup_size(focus_cycle_popup
, POPUP_WIDTH
, POPUP_HEIGHT
);
240 /* use the transient's parent's title/icon */
241 while (p
->transient_for
&& p
->transient_for
!= OB_TRAN_GROUP
)
242 p
= p
->transient_for
;
247 title
= g_strconcat((c
->iconic
? c
->icon_title
: c
->title
),
249 (p
->iconic
? p
->icon_title
: p
->title
),
252 icon_popup_show(focus_cycle_popup
,
254 (c
->iconic
? c
->icon_title
: c
->title
)),
255 client_icon(p
, 48, 48));
260 static gboolean
valid_focus_target(ObClient
*ft
)
262 /* we don't use client_can_focus here, because that doesn't let you
263 focus an iconic window, but we want to be able to, so we just check
264 if the focus flags on the window allow it, and its on the current
266 return (ft
->transients
== NULL
&& client_normal(ft
) &&
267 ((ft
->can_focus
|| ft
->focus_notify
) &&
269 (ft
->desktop
== screen_desktop
|| ft
->desktop
== DESKTOP_ALL
)));
272 void focus_cycle(gboolean forward
, gboolean linear
,
273 gboolean dialog
, gboolean done
, gboolean cancel
)
275 static ObClient
*first
= NULL
;
276 static ObClient
*t
= NULL
;
277 static GList
*order
= NULL
;
278 GList
*it
, *start
, *list
;
282 if (focus_cycle_target
)
283 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
285 frame_adjust_focus(focus_client
->frame
, TRUE
);
286 focus_cycle_target
= NULL
;
288 } else if (done
&& dialog
) {
292 if (!focus_order
[screen_desktop
])
295 if (!first
) first
= focus_client
;
296 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
298 if (linear
) list
= client_list
;
299 else list
= focus_order
[screen_desktop
];
301 start
= it
= g_list_find(list
, focus_cycle_target
);
302 if (!start
) /* switched desktops or something? */
303 start
= it
= forward
? g_list_last(list
) : g_list_first(list
);
304 if (!start
) goto done_cycle
;
309 if (it
== NULL
) it
= g_list_first(list
);
312 if (it
== NULL
) it
= g_list_last(list
);
314 /*ft = client_focus_target(it->data);*/
316 if (valid_focus_target(ft
)) {
317 if (ft
!= focus_cycle_target
) { /* prevents flicker */
318 if (focus_cycle_target
)
319 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
320 focus_cycle_target
= ft
;
321 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
323 popup_cycle(ft
, dialog
);
326 } while (it
!= start
);
329 if (done
&& focus_cycle_target
)
330 client_activate(focus_cycle_target
, FALSE
);
334 focus_cycle_target
= NULL
;
338 popup_cycle(ft
, FALSE
);
343 void focus_directional_cycle(ObDirection dir
,
344 gboolean dialog
, gboolean done
, gboolean cancel
)
346 static ObClient
*first
= NULL
;
350 if (focus_cycle_target
)
351 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
353 frame_adjust_focus(focus_client
->frame
, TRUE
);
354 focus_cycle_target
= NULL
;
356 } else if (done
&& dialog
) {
360 if (!focus_order
[screen_desktop
])
363 if (!first
) first
= focus_client
;
364 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
366 if (focus_cycle_target
)
367 ft
= client_find_directional(focus_cycle_target
, dir
);
371 for (it
= focus_order
[screen_desktop
]; it
; it
= g_list_next(it
))
372 if (valid_focus_target(it
->data
))
377 if (ft
!= focus_cycle_target
) {/* prevents flicker */
378 if (focus_cycle_target
)
379 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
380 focus_cycle_target
= ft
;
381 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
383 popup_cycle(ft
, dialog
);
389 if (done
&& focus_cycle_target
)
390 client_activate(focus_cycle_target
, FALSE
);
393 focus_cycle_target
= NULL
;
395 popup_cycle(ft
, FALSE
);
400 void focus_order_add_new(ObClient
*c
)
405 focus_order_to_top(c
);
408 if (d
== DESKTOP_ALL
) {
409 for (i
= 0; i
< screen_num_desktops
; ++i
) {
410 if (focus_order
[i
] && ((ObClient
*)focus_order
[i
]->data
)->iconic
)
411 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 0);
413 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 1);
416 if (focus_order
[d
] && ((ObClient
*)focus_order
[d
]->data
)->iconic
)
417 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 0);
419 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 1);
423 void focus_order_remove(ObClient
*c
)
428 if (d
== DESKTOP_ALL
) {
429 for (i
= 0; i
< screen_num_desktops
; ++i
)
430 focus_order
[i
] = g_list_remove(focus_order
[i
], c
);
432 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
435 static void to_top(ObClient
*c
, guint d
)
437 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
439 focus_order
[d
] = g_list_prepend(focus_order
[d
], c
);
443 /* insert before first iconic window */
444 for (it
= focus_order
[d
];
445 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
446 focus_order
[d
] = g_list_insert_before(focus_order
[d
], it
, c
);
450 void focus_order_to_top(ObClient
*c
)
455 if (d
== DESKTOP_ALL
) {
456 for (i
= 0; i
< screen_num_desktops
; ++i
)
462 static void to_bottom(ObClient
*c
, guint d
)
464 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
466 focus_order
[d
] = g_list_append(focus_order
[d
], c
);
470 /* insert before first iconic window */
471 for (it
= focus_order
[d
];
472 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
473 g_list_insert_before(focus_order
[d
], it
, c
);
477 void focus_order_to_bottom(ObClient
*c
)
482 if (d
== DESKTOP_ALL
) {
483 for (i
= 0; i
< screen_num_desktops
; ++i
)