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
;
91 /* focus state can affect the stacking layer */
92 client_calc_layer(old
);
95 /* focus state can affect the stacking layer */
96 client_calc_layer(client
);
98 /* move to the top of the list */
102 /* set the NET_ACTIVE_WINDOW hint */
103 active
= client
? client
->window
: None
;
104 PROP_SET32(RootWindow(ob_display
, ob_screen
),
105 net_active_window
, window
, active
);
108 static gboolean
focus_under_pointer()
113 if (screen_pointer_pos(&x
, &y
)) {
114 for (it
= stacking_list
; it
!= NULL
; it
= it
->next
) {
115 if (WINDOW_IS_CLIENT(it
->data
)) {
116 ObClient
*c
= WINDOW_AS_CLIENT(it
->data
);
117 if (c
->desktop
== screen_desktop
&&
118 RECT_CONTAINS(c
->frame
->area
, x
, y
))
123 g_assert(WINDOW_IS_CLIENT(it
->data
));
124 return client_normal(it
->data
) && client_focus(it
->data
);
130 /* finds the first transient that isn't 'skip' and ensure's that client_normal
132 static ObClient
*find_transient_recursive(ObClient
*c
, ObClient
*top
, ObClient
*skip
)
137 for (it
= c
->transients
; it
; it
= it
->next
) {
138 if (it
->data
== top
) return NULL
;
139 ret
= find_transient_recursive(it
->data
, top
, skip
);
140 if (ret
&& ret
!= skip
&& client_normal(ret
)) return ret
;
141 if (it
->data
!= skip
&& client_normal(it
->data
)) return it
->data
;
146 static gboolean
focus_fallback_transient(ObClient
*top
, ObClient
*old
)
148 ObClient
*target
= find_transient_recursive(top
, top
, old
);
150 /* make sure client_normal is true always */
151 if (!client_normal(top
))
153 target
= top
; /* no transient, keep the top */
155 return client_focus(target
);
158 void focus_fallback(ObFocusFallbackType type
)
161 ObClient
*old
= NULL
;
165 /* unfocus any focused clients.. they can be focused by Pointer events
166 and such, and then when I try focus them, I won't get a FocusIn event
169 focus_set_client(NULL
);
171 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
))
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
);
210 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
211 if (type
!= OB_FOCUS_FALLBACK_UNFOCUSING
|| it
->data
!= old
)
212 if (client_normal(it
->data
) &&
213 /* dont fall back to 'anonymous' fullscreen windows. theres no
214 checks for this is in transient/group fallbacks, so they can
215 be fallback targets there. */
216 !((ObClient
*)it
->data
)->fullscreen
&&
217 client_can_focus(it
->data
)) {
218 gboolean r
= client_focus(it
->data
);
223 /* nothing to focus, and already set it to none above */
226 static void popup_cycle(ObClient
*c
, gboolean show
)
229 icon_popup_hide(focus_cycle_popup
);
235 a
= screen_physical_area_monitor(0);
236 icon_popup_position(focus_cycle_popup
, CenterGravity
,
237 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
238 /* icon_popup_size(focus_cycle_popup, a->height/2, a->height/16);
239 icon_popup_show(focus_cycle_popup, c->title,
240 client_icon(c, a->height/16, a->height/16));
242 /* XXX the size and the font extents need to be related on some level
244 icon_popup_size(focus_cycle_popup
, POPUP_WIDTH
, POPUP_HEIGHT
);
246 /* use the transient's parent's title/icon */
247 while (p
->transient_for
&& p
->transient_for
!= OB_TRAN_GROUP
)
248 p
= p
->transient_for
;
253 title
= g_strconcat((c
->iconic
? c
->icon_title
: c
->title
),
255 (p
->iconic
? p
->icon_title
: p
->title
),
258 icon_popup_show(focus_cycle_popup
,
260 (c
->iconic
? c
->icon_title
: c
->title
)),
261 client_icon(p
, 48, 48));
266 static gboolean
valid_focus_target(ObClient
*ft
)
268 /* we don't use client_can_focus here, because that doesn't let you
269 focus an iconic window, but we want to be able to, so we just check
270 if the focus flags on the window allow it, and its on the current
272 return (ft
->transients
== NULL
&& client_normal(ft
) &&
273 ((ft
->can_focus
|| ft
->focus_notify
) &&
275 (ft
->desktop
== screen_desktop
|| ft
->desktop
== DESKTOP_ALL
)));
278 void focus_cycle(gboolean forward
, gboolean linear
,
279 gboolean dialog
, gboolean done
, gboolean cancel
)
281 static ObClient
*first
= NULL
;
282 static ObClient
*t
= NULL
;
283 static GList
*order
= NULL
;
284 GList
*it
, *start
, *list
;
288 if (focus_cycle_target
)
289 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
291 frame_adjust_focus(focus_client
->frame
, TRUE
);
292 focus_cycle_target
= NULL
;
294 } else if (done
&& dialog
) {
298 if (!focus_order
[screen_desktop
])
301 if (!first
) first
= focus_client
;
302 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
304 if (linear
) list
= client_list
;
305 else list
= focus_order
[screen_desktop
];
307 start
= it
= g_list_find(list
, focus_cycle_target
);
308 if (!start
) /* switched desktops or something? */
309 start
= it
= forward
? g_list_last(list
) : g_list_first(list
);
310 if (!start
) goto done_cycle
;
315 if (it
== NULL
) it
= g_list_first(list
);
318 if (it
== NULL
) it
= g_list_last(list
);
320 /*ft = client_focus_target(it->data);*/
322 if (valid_focus_target(ft
)) {
323 if (ft
!= focus_cycle_target
) { /* prevents flicker */
324 if (focus_cycle_target
)
325 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
326 focus_cycle_target
= ft
;
327 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
329 popup_cycle(ft
, dialog
);
332 } while (it
!= start
);
335 if (done
&& focus_cycle_target
)
336 client_activate(focus_cycle_target
, FALSE
);
340 focus_cycle_target
= NULL
;
344 popup_cycle(ft
, FALSE
);
349 void focus_directional_cycle(ObDirection dir
,
350 gboolean dialog
, gboolean done
, gboolean cancel
)
352 static ObClient
*first
= NULL
;
356 if (focus_cycle_target
)
357 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
359 frame_adjust_focus(focus_client
->frame
, TRUE
);
360 focus_cycle_target
= NULL
;
362 } else if (done
&& dialog
) {
366 if (!focus_order
[screen_desktop
])
369 if (!first
) first
= focus_client
;
370 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
372 if (focus_cycle_target
)
373 ft
= client_find_directional(focus_cycle_target
, dir
);
377 for (it
= focus_order
[screen_desktop
]; it
; it
= g_list_next(it
))
378 if (valid_focus_target(it
->data
))
383 if (ft
!= focus_cycle_target
) {/* prevents flicker */
384 if (focus_cycle_target
)
385 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
386 focus_cycle_target
= ft
;
387 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
389 popup_cycle(ft
, dialog
);
395 if (done
&& focus_cycle_target
)
396 client_activate(focus_cycle_target
, FALSE
);
399 focus_cycle_target
= NULL
;
401 popup_cycle(ft
, FALSE
);
406 void focus_order_add_new(ObClient
*c
)
411 focus_order_to_top(c
);
414 if (d
== DESKTOP_ALL
) {
415 for (i
= 0; i
< screen_num_desktops
; ++i
) {
416 if (focus_order
[i
] && ((ObClient
*)focus_order
[i
]->data
)->iconic
)
417 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 0);
419 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 1);
422 if (focus_order
[d
] && ((ObClient
*)focus_order
[d
]->data
)->iconic
)
423 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 0);
425 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 1);
429 void focus_order_remove(ObClient
*c
)
434 if (d
== DESKTOP_ALL
) {
435 for (i
= 0; i
< screen_num_desktops
; ++i
)
436 focus_order
[i
] = g_list_remove(focus_order
[i
], c
);
438 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
441 static void to_top(ObClient
*c
, guint d
)
443 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
445 focus_order
[d
] = g_list_prepend(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 focus_order
[d
] = g_list_insert_before(focus_order
[d
], it
, c
);
456 void focus_order_to_top(ObClient
*c
)
461 if (d
== DESKTOP_ALL
) {
462 for (i
= 0; i
< screen_num_desktops
; ++i
)
468 static void to_bottom(ObClient
*c
, guint d
)
470 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
472 focus_order
[d
] = g_list_append(focus_order
[d
], c
);
476 /* insert before first iconic window */
477 for (it
= focus_order
[d
];
478 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
479 g_list_insert_before(focus_order
[d
], it
, c
);
483 void focus_order_to_bottom(ObClient
*c
)
488 if (d
== DESKTOP_ALL
) {
489 for (i
= 0; i
< screen_num_desktops
; ++i
)