4 #include "framerender.h"
20 ObClient
*focus_client
= NULL
;
21 GList
**focus_order
= NULL
; /* these lists are created when screen_startup
22 sets the number of desktops */
24 Window focus_backup
= None
;
26 static ObClient
*focus_cycle_target
= NULL
;
27 static Popup
*focus_cycle_popup
= NULL
;
31 /* create the window which gets focus when no clients get it. Have to
32 make it override-redirect so we don't try manage it, since it is
34 XSetWindowAttributes attrib
;
38 attrib
.override_redirect
= TRUE
;
39 focus_backup
= XCreateWindow(ob_display
, ob_root
,
41 CopyFromParent
, InputOutput
, CopyFromParent
,
42 CWOverrideRedirect
, &attrib
);
43 XMapRaised(ob_display
, focus_backup
);
45 /* do this *after* focus_backup is created, since it is used for
47 focus_cycle_popup
= popup_new(TRUE
);
49 /* start with nothing focused */
50 focus_set_client(NULL
);
57 for (i
= 0; i
< screen_num_desktops
; ++i
)
58 g_list_free(focus_order
[i
]);
62 popup_free(focus_cycle_popup
);
63 focus_cycle_popup
= NULL
;
65 XDestroyWindow(ob_display
, focus_backup
);
67 /* reset focus to root */
68 XSetInputFocus(ob_display
, PointerRoot
, RevertToPointerRoot
,
72 static void push_to_top(ObClient
*client
)
76 desktop
= client
->desktop
;
77 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
78 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
], client
);
79 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
], client
);
82 void focus_set_client(ObClient
*client
)
88 g_message("focus_set_client 0x%lx", client
? client
->window
: 0);
91 /* uninstall the old colormap, and install the new one */
92 screen_install_colormap(focus_client
, FALSE
);
93 screen_install_colormap(client
, TRUE
);
96 /* when nothing will be focused, send focus to the backup target */
97 XSetInputFocus(ob_display
, focus_backup
, RevertToPointerRoot
,
99 XSync(ob_display
, FALSE
);
102 /* in the middle of cycling..? kill it. */
103 if (focus_cycle_target
)
104 focus_cycle(TRUE
, TRUE
, TRUE
, TRUE
);
107 focus_client
= client
;
109 /* move to the top of the list */
113 /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
114 if (ob_state
!= OB_STATE_EXITING
) {
115 active
= client
? client
->window
: None
;
116 PROP_SET32(ob_root
, net_active_window
, window
, active
);
119 if (focus_client
!= NULL
)
120 dispatch_client(Event_Client_Focus
, focus_client
, 0, 0);
122 dispatch_client(Event_Client_Unfocus
, old
, 0, 0);
125 static gboolean
focus_under_pointer()
130 if (ob_pointer_pos(&x
, &y
)) {
131 for (it
= stacking_list
; it
!= NULL
; it
= it
->next
) {
132 if (WINDOW_IS_CLIENT(it
->data
)) {
133 ObClient
*c
= WINDOW_AS_CLIENT(it
->data
);
134 if (c
->desktop
== screen_desktop
&&
135 RECT_CONTAINS(c
->frame
->area
, x
, y
))
140 g_assert(WINDOW_IS_CLIENT(it
->data
));
141 return client_normal(it
->data
) && client_focus(it
->data
);
147 /* finds the first transient that isn't 'skip' and ensure's that client_normal
149 static ObClient
*find_transient_recursive(ObClient
*c
, ObClient
*top
, ObClient
*skip
)
154 for (it
= c
->transients
; it
; it
= it
->next
) {
155 if (it
->data
== top
) return NULL
;
156 ret
= find_transient_recursive(it
->data
, top
, skip
);
157 if (ret
&& ret
!= skip
&& client_normal(ret
)) return ret
;
158 if (it
->data
!= skip
&& client_normal(it
->data
)) return it
->data
;
163 static gboolean
focus_fallback_transient(ObClient
*top
, ObClient
*old
)
165 ObClient
*target
= find_transient_recursive(top
, top
, old
);
167 /* make sure client_normal is true always */
168 if (!client_normal(top
))
170 target
= top
; /* no transient, keep the top */
172 return client_focus(target
);
175 void focus_fallback(FallbackType type
)
178 ObClient
*old
= NULL
;
182 /* unfocus any focused clients.. they can be focused by Pointer events
183 and such, and then when I try focus them, I won't get a FocusIn event
186 focus_set_client(NULL
);
188 if (!(type
== Fallback_Desktop
?
189 config_focus_last_on_desktop
: config_focus_last
)) {
190 if (config_focus_follow
) focus_under_pointer();
194 if (type
== Fallback_Unfocusing
&& old
) {
195 /* try for transient relations */
196 if (old
->transient_for
) {
197 if (old
->transient_for
== OB_TRAN_GROUP
) {
198 for (it
= focus_order
[screen_desktop
]; it
; it
= it
->next
) {
201 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
202 if (sit
->data
== it
->data
)
203 if (focus_fallback_transient(sit
->data
, old
))
207 if (focus_fallback_transient(old
->transient_for
, old
))
212 /* try for group relations */
216 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
217 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
218 if (sit
->data
== it
->data
)
219 if (sit
->data
!= old
&& client_normal(sit
->data
))
220 if (client_can_focus(sit
->data
)) {
221 gboolean r
= client_focus(sit
->data
);
228 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
229 if (type
!= Fallback_Unfocusing
|| it
->data
!= old
)
230 if (client_normal(it
->data
) &&
231 /* dont fall back to 'anonymous' fullscreen windows. theres no
232 checks for this is in transient/group fallbacks, so they can
233 be fallback targets there. */
234 !((ObClient
*)it
->data
)->fullscreen
&&
235 client_can_focus(it
->data
)) {
236 gboolean r
= client_focus(it
->data
);
241 /* nothing to focus, and already set it to none above */
244 static void popup_cycle(ObClient
*c
, gboolean show
)
247 popup_hide(focus_cycle_popup
);
253 a
= screen_physical_area_monitor(0);
254 popup_position(focus_cycle_popup
, CenterGravity
,
255 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
256 /* popup_size(focus_cycle_popup, a->height/2, a->height/16);
257 popup_show(focus_cycle_popup, c->title,
258 client_icon(c, a->height/16, a->height/16));
260 /* XXX the size and the font extents need to be related on some level
262 popup_size(focus_cycle_popup
, 320, 48);
264 /* use the transient's parent's title/icon */
265 while (p
->transient_for
&& p
->transient_for
!= OB_TRAN_GROUP
)
266 p
= p
->transient_for
;
271 title
= g_strconcat((c
->iconic
? c
->icon_title
: c
->title
),
273 (p
->iconic
? p
->icon_title
: p
->title
),
276 popup_show(focus_cycle_popup
,
277 (title
? title
: (c
->iconic
? c
->icon_title
: c
->title
)),
278 client_icon(p
, 48, 48));
283 ObClient
*focus_cycle(gboolean forward
, gboolean linear
, gboolean done
,
286 static ObClient
*first
= NULL
;
287 static ObClient
*t
= NULL
;
288 static GList
*order
= NULL
;
289 GList
*it
, *start
, *list
;
293 if (focus_cycle_target
)
294 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
296 frame_adjust_focus(focus_client
->frame
, TRUE
);
299 if (focus_cycle_target
)
300 client_activate(focus_cycle_target
);
304 grab_pointer(TRUE
, None
);
306 if (!first
) first
= focus_client
;
307 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
309 if (linear
) list
= client_list
;
310 else list
= focus_order
[screen_desktop
];
312 start
= it
= g_list_find(list
, focus_cycle_target
);
313 if (!start
) /* switched desktops or something? */
314 start
= it
= forward
? g_list_last(list
) : g_list_first(list
);
315 if (!start
) goto done_cycle
;
320 if (it
== NULL
) it
= g_list_first(list
);
323 if (it
== NULL
) it
= g_list_last(list
);
325 /*ft = client_focus_target(it->data);*/
327 /* we don't use client_can_focus here, because that doesn't let you
328 focus an iconic window, but we want to be able to, so we just check
329 if the focus flags on the window allow it, and its on the current
331 if (ft
->transients
== NULL
&& client_normal(ft
) &&
332 ((ft
->can_focus
|| ft
->focus_notify
) &&
333 (ft
->desktop
== screen_desktop
|| ft
->desktop
== DESKTOP_ALL
))) {
334 if (ft
!= focus_cycle_target
) { /* prevents flicker */
335 if (focus_cycle_target
)
336 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
337 focus_cycle_target
= ft
;
338 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
340 popup_cycle(ft
, config_focus_popup
);
343 } while (it
!= start
);
348 focus_cycle_target
= NULL
;
352 popup_cycle(ft
, FALSE
);
353 grab_pointer(FALSE
, None
);
358 void focus_order_add_new(ObClient
*c
)
363 focus_order_to_top(c
);
366 if (d
== DESKTOP_ALL
) {
367 for (i
= 0; i
< screen_num_desktops
; ++i
) {
368 if (focus_order
[i
] && ((ObClient
*)focus_order
[i
]->data
)->iconic
)
369 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 0);
371 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 1);
374 if (focus_order
[d
] && ((ObClient
*)focus_order
[d
]->data
)->iconic
)
375 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 0);
377 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 1);
381 void focus_order_remove(ObClient
*c
)
386 if (d
== DESKTOP_ALL
) {
387 for (i
= 0; i
< screen_num_desktops
; ++i
)
388 focus_order
[i
] = g_list_remove(focus_order
[i
], c
);
390 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
393 static void to_top(ObClient
*c
, guint d
)
395 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
397 focus_order
[d
] = g_list_prepend(focus_order
[d
], c
);
401 /* insert before first iconic window */
402 for (it
= focus_order
[d
];
403 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
404 g_list_insert_before(focus_order
[d
], it
, c
);
408 void focus_order_to_top(ObClient
*c
)
413 if (d
== DESKTOP_ALL
) {
414 for (i
= 0; i
< screen_num_desktops
; ++i
)
420 static void to_bottom(ObClient
*c
, guint d
)
422 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
424 focus_order
[d
] = g_list_append(focus_order
[d
], c
);
428 /* insert before first iconic window */
429 for (it
= focus_order
[d
];
430 it
&& !((ObClient
*)it
->data
)->iconic
; it
= it
->next
);
431 g_list_insert_before(focus_order
[d
], it
, c
);
435 void focus_order_to_bottom(ObClient
*c
)
440 if (d
== DESKTOP_ALL
) {
441 for (i
= 0; i
< screen_num_desktops
; ++i
)