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, and already set it to none above */
241 static void popup_cycle(Client
*c
, gboolean show
)
244 popup_hide(focus_cycle_popup
);
250 a
= screen_physical_area_xinerama(0);
251 popup_position(focus_cycle_popup
, CenterGravity
,
252 a
->x
+ a
->width
/ 2, a
->y
+ a
->height
/ 2);
253 /* popup_size(focus_cycle_popup, a->height/2, a->height/16);
254 popup_show(focus_cycle_popup, c->title,
255 client_icon(c, a->height/16, a->height/16));
257 /* XXX the size and the font extents need to be related on some level
259 popup_size(focus_cycle_popup
, 320, 48);
261 /* use the transient's parent's title/icon */
262 while (p
->transient_for
&& p
->transient_for
!= TRAN_GROUP
)
263 p
= p
->transient_for
;
268 title
= g_strconcat((p
->iconic
? p
->icon_title
: p
->title
),
270 (c
->iconic
? c
->icon_title
: c
->title
),
273 popup_show(focus_cycle_popup
,
274 (title
? title
: (c
->iconic
? c
->icon_title
: c
->title
)),
275 client_icon(p
, 48, 48));
280 Client
*focus_cycle(gboolean forward
, gboolean linear
, gboolean done
,
283 static Client
*first
= NULL
;
284 static Client
*t
= NULL
;
285 static GList
*order
= NULL
;
286 GList
*it
, *start
, *list
;
290 if (focus_cycle_target
)
291 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
293 frame_adjust_focus(focus_client
->frame
, TRUE
);
296 if (focus_cycle_target
)
297 client_activate(focus_cycle_target
);
301 grab_pointer(TRUE
, None
);
303 if (!first
) first
= focus_client
;
304 if (!focus_cycle_target
) focus_cycle_target
= focus_client
;
306 if (linear
) list
= client_list
;
307 else list
= focus_order
[screen_desktop
];
309 start
= it
= g_list_find(list
, focus_cycle_target
);
310 if (!start
) /* switched desktops or something? */
311 start
= it
= forward
? g_list_last(list
) : g_list_first(list
);
312 if (!start
) goto done_cycle
;
317 if (it
== NULL
) it
= g_list_first(list
);
320 if (it
== NULL
) it
= g_list_last(list
);
322 /*ft = client_focus_target(it->data);*/
324 /* we don't use client_can_focus here, because that doesn't let you
325 focus an iconic window, but we want to be able to, so we just check
326 if the focus flags on the window allow it, and its on the current
328 if (ft
->transients
== NULL
&& client_normal(ft
) &&
329 ((ft
->can_focus
|| ft
->focus_notify
) &&
330 (ft
->desktop
== screen_desktop
|| ft
->desktop
== DESKTOP_ALL
))) {
331 if (ft
!= focus_cycle_target
) { /* prevents flicker */
332 if (focus_cycle_target
)
333 frame_adjust_focus(focus_cycle_target
->frame
, FALSE
);
334 focus_cycle_target
= ft
;
335 frame_adjust_focus(focus_cycle_target
->frame
, TRUE
);
337 popup_cycle(ft
, config_focus_popup
);
340 } while (it
!= start
);
345 focus_cycle_target
= NULL
;
349 popup_cycle(ft
, FALSE
);
350 grab_pointer(FALSE
, None
);
355 void focus_order_add_new(Client
*c
)
360 focus_order_to_top(c
);
363 if (d
== DESKTOP_ALL
) {
364 for (i
= 0; i
< screen_num_desktops
; ++i
) {
365 if (focus_order
[i
] && ((Client
*)focus_order
[i
]->data
)->iconic
)
366 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 0);
368 focus_order
[i
] = g_list_insert(focus_order
[i
], c
, 1);
371 if (focus_order
[d
] && ((Client
*)focus_order
[d
]->data
)->iconic
)
372 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 0);
374 focus_order
[d
] = g_list_insert(focus_order
[d
], c
, 1);
378 void focus_order_remove(Client
*c
)
383 if (d
== DESKTOP_ALL
) {
384 for (i
= 0; i
< screen_num_desktops
; ++i
)
385 focus_order
[i
] = g_list_remove(focus_order
[i
], c
);
387 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
390 static void to_top(Client
*c
, guint d
)
392 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
394 focus_order
[d
] = g_list_prepend(focus_order
[d
], c
);
398 /* insert before first iconic window */
399 for (it
= focus_order
[d
];
400 it
&& !((Client
*)it
->data
)->iconic
; it
= it
->next
);
401 g_list_insert_before(focus_order
[d
], it
, c
);
405 void focus_order_to_top(Client
*c
)
410 if (d
== DESKTOP_ALL
) {
411 for (i
= 0; i
< screen_num_desktops
; ++i
)
417 static void to_bottom(Client
*c
, guint d
)
419 focus_order
[d
] = g_list_remove(focus_order
[d
], c
);
421 focus_order
[d
] = g_list_append(focus_order
[d
], c
);
425 /* insert before first iconic window */
426 for (it
= focus_order
[d
];
427 it
&& !((Client
*)it
->data
)->iconic
; it
= it
->next
);
428 g_list_insert_before(focus_order
[d
], it
, c
);
432 void focus_order_to_bottom(Client
*c
)
437 if (d
== DESKTOP_ALL
) {
438 for (i
= 0; i
< screen_num_desktops
; ++i
)