4 #include "framerender.h"
20 Client
*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 Client
*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
;
37 focus_cycle_popup
= popup_new(TRUE
);
39 attrib
.override_redirect
= TRUE
;
40 focus_backup
= XCreateWindow(ob_display
, ob_root
,
42 CopyFromParent
, InputOutput
, CopyFromParent
,
43 CWOverrideRedirect
, &attrib
);
44 XMapRaised(ob_display
, focus_backup
);
46 /* start with nothing focused */
47 focus_set_client(NULL
);
54 for (i
= 0; i
< screen_num_desktops
; ++i
)
55 g_list_free(focus_order
[i
]);
59 popup_free(focus_cycle_popup
);
60 focus_cycle_popup
= NULL
;
62 XDestroyWindow(ob_display
, focus_backup
);
64 /* reset focus to root */
65 XSetInputFocus(ob_display
, PointerRoot
, RevertToPointerRoot
,
69 static void push_to_top(Client
*client
)
73 desktop
= client
->desktop
;
74 if (desktop
== DESKTOP_ALL
) desktop
= screen_desktop
;
75 focus_order
[desktop
] = g_list_remove(focus_order
[desktop
], client
);
76 focus_order
[desktop
] = g_list_prepend(focus_order
[desktop
], client
);
79 void focus_set_client(Client
*client
)
85 g_message("focus_set_client 0x%lx", client
? client
->window
: 0);
88 /* uninstall the old colormap, and install the new one */
89 screen_install_colormap(focus_client
, FALSE
);
90 screen_install_colormap(client
, TRUE
);
93 /* when nothing will be focused, send focus to the backup target */
94 XSetInputFocus(ob_display
, focus_backup
, RevertToPointerRoot
,
96 XSync(ob_display
, FALSE
);
99 /* in the middle of cycling..? kill it. */
100 if (focus_cycle_target
)
101 focus_cycle(TRUE
, TRUE
, TRUE
, TRUE
);
104 focus_client
= client
;
106 /* move to the top of the list */
110 /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
111 if (ob_state
!= State_Exiting
) {
112 active
= client
? client
->window
: None
;
113 PROP_SET32(ob_root
, net_active_window
, window
, active
);
116 if (focus_client
!= NULL
)
117 dispatch_client(Event_Client_Focus
, focus_client
, 0, 0);
119 dispatch_client(Event_Client_Unfocus
, old
, 0, 0);
122 static gboolean
focus_under_pointer()
127 if (ob_pointer_pos(&x
, &y
)) {
128 for (it
= stacking_list
; it
!= NULL
; it
= it
->next
) {
129 if (WINDOW_IS_CLIENT(it
->data
)) {
130 Client
*c
= WINDOW_AS_CLIENT(it
->data
);
131 if (c
->desktop
== screen_desktop
&&
132 RECT_CONTAINS(c
->frame
->area
, x
, y
))
137 g_assert(WINDOW_IS_CLIENT(it
->data
));
138 return client_normal(it
->data
) && client_focus(it
->data
);
144 /* finds the first transient that isn't 'skip' and ensure's that client_normal
146 static Client
*find_transient_recursive(Client
*c
, Client
*top
, Client
*skip
)
151 for (it
= c
->transients
; it
; it
= it
->next
) {
152 if (it
->data
== top
) return NULL
;
153 ret
= find_transient_recursive(it
->data
, top
, skip
);
154 if (ret
&& ret
!= skip
&& client_normal(ret
)) return ret
;
155 if (it
->data
!= skip
&& client_normal(it
->data
)) return it
->data
;
160 static gboolean
focus_fallback_transient(Client
*top
, Client
*old
)
162 Client
*target
= find_transient_recursive(top
, top
, old
);
164 /* make sure client_normal is true always */
165 if (!client_normal(top
))
167 target
= top
; /* no transient, keep the top */
169 return client_focus(target
);
172 void focus_fallback(FallbackType type
)
179 /* unfocus any focused clients.. they can be focused by Pointer events
180 and such, and then when I try focus them, I won't get a FocusIn event
183 focus_set_client(NULL
);
185 if (!(type
== Fallback_Desktop
?
186 config_focus_last_on_desktop
: config_focus_last
)) {
187 if (config_focus_follow
) focus_under_pointer();
191 if (type
== Fallback_Unfocusing
&& old
) {
192 /* try for transient relations */
193 if (old
->transient_for
) {
194 if (old
->transient_for
== TRAN_GROUP
) {
195 for (it
= focus_order
[screen_desktop
]; it
; it
= it
->next
) {
198 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
199 if (sit
->data
== it
->data
)
200 if (focus_fallback_transient(sit
->data
, old
))
204 if (focus_fallback_transient(old
->transient_for
, old
))
209 /* try for group relations */
213 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
214 for (sit
= old
->group
->members
; sit
; sit
= sit
->next
)
215 if (sit
->data
== it
->data
)
216 if (sit
->data
!= old
&& client_normal(sit
->data
))
217 if (client_can_focus(sit
->data
)) {
218 gboolean r
= client_focus(sit
->data
);
225 for (it
= focus_order
[screen_desktop
]; it
!= NULL
; it
= it
->next
)
226 if (type
!= Fallback_Unfocusing
|| it
->data
!= old
)
227 if (client_normal(it
->data
) &&
228 /* dont fall back to 'anonymous' fullscreen windows. theres no
229 checks for this is in transient/group fallbacks, so they can
230 be fallback targets there. */
231 !((Client
*)it
->data
)->fullscreen
&&
232 client_can_focus(it
->data
)) {
233 gboolean r
= client_focus(it
->data
);
238 /* nothing to focus */
239 focus_set_client(NULL
);
242 static void popup_cycle(Client
*c
, gboolean show
)
245 popup_hide(focus_cycle_popup
);
251 a
= screen_area(c
->desktop
);
252 popup_position(focus_cycle_popup
, CenterGravity
,
253 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
254 /* popup_size(focus_cycle_popup, a->height/2, a->height/16);
255 popup_show(focus_cycle_popup, c->title,
256 client_icon(c, a->height/16, a->height/16));
258 /* XXX the size and the font extents need to be related on some level
260 popup_size(focus_cycle_popup
, 320, 48);
262 /* use the transient's parent's title/icon */
263 while (p
->transient_for
&& p
->transient_for
!= TRAN_GROUP
)
264 p
= p
->transient_for
;
269 title
= g_strconcat((p
->iconic
? p
->icon_title
: p
->title
),
271 (c
->iconic
? c
->icon_title
: c
->title
),
274 popup_show(focus_cycle_popup
,
275 (title
? title
: (c
->iconic
? c
->icon_title
: c
->title
)),
276 client_icon(p
, 48, 48));
281 Client
*focus_cycle(gboolean forward
, gboolean linear
, gboolean done
,
284 static Client
*first
= NULL
;
285 static Client
*t
= NULL
;
286 static GList
*order
= NULL
;
287 GList
*it
, *start
, *list
;
291 if (focus_cycle_target
)
292 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
294 frame_adjust_focus(focus_client
->frame
, TRUE
);
297 if (focus_cycle_target
)
298 client_activate(focus_cycle_target
);
302 grab_pointer(TRUE
, None
);
304 if (!first
) first
= focus_client
;
305 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
307 if (linear
) list
= client_list
;
308 else list
= focus_order
[screen_desktop
];
310 start
= it
= g_list_find(list
, focus_cycle_target
);
311 if (!start
) /* switched desktops or something? */
312 start
= it
= forward
? g_list_last(list
) : g_list_first(list
);
313 if (!start
) goto done_cycle
;
318 if (it
== NULL
) it
= g_list_first(list
);
321 if (it
== NULL
) it
= g_list_last(list
);
323 /*ft = client_focus_target(it->data);*/
325 /* we don't use client_can_focus here, because that doesn't let you
326 focus an iconic window, but we want to be able to, so we just check
327 if the focus flags on the window allow it, and its on the current
329 if (ft
->transients
== NULL
&& client_normal(ft
) &&
330 ((ft
->can_focus
|| ft
->focus_notify
) &&
331 (ft
->desktop
== screen_desktop
|| ft
->desktop
== DESKTOP_ALL
))) {
332 if (ft
!= focus_cycle_target
) { /* prevents flicker */
333 if (focus_cycle_target
)
334 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
335 focus_cycle_target
= ft
;
336 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
338 popup_cycle(ft
, config_focus_popup
);
341 } while (it
!= start
);
346 focus_cycle_target
= NULL
;
350 popup_cycle(ft
, FALSE
);
351 grab_pointer(FALSE
, None
);
356 void focus_order_add_new(Client
*c
)
361 focus_order_to_top(c
);
364 if (d
== DESKTOP_ALL
) {
365 for (i
= 0; i
< screen_num_desktops
; ++i
) {
366 if (focus_order
[i
] && ((Client
*)focus_order
[i
]->data
)->iconic
)
367 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 0);
369 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 1);
372 if (focus_order
[d
] && ((Client
*)focus_order
[d
]->data
)->iconic
)
373 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 0);
375 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 1);
379 void focus_order_remove(Client
*c
)
384 if (d
== DESKTOP_ALL
) {
385 for (i
= 0; i
< screen_num_desktops
; ++i
)
386 focus_order
[i
] = g_list_remove(focus_order
[i
], c
);
388 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
391 static void to_top(Client
*c
, guint d
)
393 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
395 focus_order
[d
] = g_list_prepend(focus_order
[d
], c
);
399 /* insert before first iconic window */
400 for (it
= focus_order
[d
];
401 it
&& !((Client
*)it
->data
)->iconic
; it
= it
->next
);
402 g_list_insert_before(focus_order
[d
], it
, c
);
406 void focus_order_to_top(Client
*c
)
411 if (d
== DESKTOP_ALL
) {
412 for (i
= 0; i
< screen_num_desktops
; ++i
)
418 static void to_bottom(Client
*c
, guint d
)
420 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
422 focus_order
[d
] = g_list_append(focus_order
[d
], c
);
426 /* insert before first iconic window */
427 for (it
= focus_order
[d
];
428 it
&& !((Client
*)it
->data
)->iconic
; it
= it
->next
);
429 g_list_insert_before(focus_order
[d
], it
, c
);
433 void focus_order_to_bottom(Client
*c
)
438 if (d
== DESKTOP_ALL
) {
439 for (i
= 0; i
< screen_num_desktops
; ++i
)