]>
Dogcows Code - chaz/openbox/blob - openbox/stacking.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 stacking.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
30 GList
*stacking_list
= NULL
;
32 void stacking_set_list()
34 Window
*windows
= NULL
;
38 /* on shutdown, don't update the properties, so that we can read it back
39 in on startup and re-stack the windows as they were before we shut down
41 if (ob_state() == OB_STATE_EXITING
) return;
43 /* create an array of the window ids (from bottom to top,
46 windows
= g_new(Window
, g_list_length(stacking_list
));
47 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
48 if (WINDOW_IS_CLIENT(it
->data
))
49 windows
[i
++] = WINDOW_AS_CLIENT(it
->data
)->window
;
53 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
54 net_client_list_stacking
, window
, (gulong
*)windows
, i
);
59 static void do_restack(GList
*wins
, GList
*before
)
67 /* pls only restack stuff in the same layer at a time */
68 for (it
= wins
; it
; it
= next
) {
69 next
= g_list_next(it
);
71 g_assert (window_layer(it
->data
) == window_layer(next
->data
));
74 g_assert(window_layer(it
->data
) >= window_layer(before
->data
));
77 win
= g_new(Window
, g_list_length(wins
) + 1);
79 if (before
== stacking_list
)
80 win
[0] = screen_support_win
;
82 win
[0] = window_top(g_list_last(stacking_list
)->data
);
84 win
[0] = window_top(g_list_previous(before
)->data
);
86 for (i
= 1, it
= wins
; it
; ++i
, it
= g_list_next(it
)) {
87 win
[i
] = window_top(it
->data
);
88 g_assert(win
[i
] != None
); /* better not call stacking shit before
89 setting your top level window value */
90 stacking_list
= g_list_insert_before(stacking_list
, before
, it
->data
);
94 /* some debug checking of the stacking list's order */
95 for (it
= stacking_list
; ; it
= next
) {
96 next
= g_list_next(it
);
98 g_assert(window_layer(it
->data
) >= window_layer(next
->data
));
102 XRestackWindows(ob_display
, win
, i
);
108 static void do_raise(GList
*wins
)
111 GList
*layer
[OB_NUM_STACKING_LAYERS
] = {NULL
};
114 for (it
= wins
; it
; it
= g_list_next(it
)) {
117 l
= window_layer(it
->data
);
118 layer
[l
] = g_list_append(layer
[l
], it
->data
);
122 for (i
= OB_NUM_STACKING_LAYERS
- 1; i
>= 0; --i
) {
124 for (; it
; it
= g_list_next(it
)) {
125 /* look for the top of the layer */
126 if (window_layer(it
->data
) <= (ObStackingLayer
) i
)
129 do_restack(layer
[i
], it
);
130 g_list_free(layer
[i
]);
135 static void do_lower(GList
*wins
)
138 GList
*layer
[OB_NUM_STACKING_LAYERS
] = {NULL
};
141 for (it
= wins
; it
; it
= g_list_next(it
)) {
144 l
= window_layer(it
->data
);
145 layer
[l
] = g_list_append(layer
[l
], it
->data
);
149 for (i
= OB_NUM_STACKING_LAYERS
- 1; i
>= 0; --i
) {
151 for (; it
; it
= g_list_next(it
)) {
152 /* look for the top of the next layer down */
153 if (window_layer(it
->data
) < (ObStackingLayer
) i
)
156 do_restack(layer
[i
], it
);
157 g_list_free(layer
[i
]);
162 static void restack_windows(ObClient
*selected
, gboolean raise
)
164 GList
*it
, *last
, *below
, *above
, *next
;
167 GList
*group_modals
= NULL
;
168 GList
*group_trans
= NULL
;
169 GList
*modals
= NULL
;
172 /* remove first so we can't run into ourself */
173 it
= g_list_find(stacking_list
, selected
);
175 stacking_list
= g_list_delete_link(stacking_list
, it
);
177 /* go from the bottom of the stacking list up. don't move any other windows
178 when lowering, we call this for each window independently */
180 for (it
= g_list_last(stacking_list
); it
; it
= next
) {
181 next
= g_list_previous(it
);
183 if (WINDOW_IS_CLIENT(it
->data
)) {
184 ObClient
*ch
= it
->data
;
186 /* only move windows in the same stacking layer */
187 if (ch
->layer
== selected
->layer
&&
188 client_search_transient(selected
, ch
))
190 if (client_is_direct_child(selected
, ch
)) {
192 modals
= g_list_prepend(modals
, ch
);
194 trans
= g_list_prepend(trans
, ch
);
198 group_modals
= g_list_prepend(group_modals
, ch
);
200 group_trans
= g_list_prepend(group_trans
, ch
);
202 stacking_list
= g_list_delete_link(stacking_list
, it
);
208 /* put transients of the selected window right above it */
209 wins
= g_list_concat(modals
, trans
);
210 wins
= g_list_append(wins
, selected
);
212 /* if selected window is transient for group then raise it above others */
213 if (selected
->transient_for_group
) {
214 /* if it's modal, raise it above those also */
215 if (selected
->modal
) {
216 wins
= g_list_concat(wins
, group_modals
);
219 wins
= g_list_concat(wins
, group_trans
);
223 /* find where to put the selected window, start from bottom of list,
224 this is the window below everything we are re-adding to the list */
226 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
))
228 if (window_layer(it
->data
) < selected
->layer
) {
232 /* if lowering, stop at the beginning of the layer */
235 /* if raising, stop at the end of the layer */
236 if (window_layer(it
->data
) > selected
->layer
)
242 /* save this position in the stacking list */
245 /* find where to put the group transients, start from the top of list */
246 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
247 /* skip past higher layers */
248 if (window_layer(it
->data
) > selected
->layer
)
250 /* if we reach the end of the layer (how?) then don't go further */
251 if (window_layer(it
->data
) < selected
->layer
)
253 /* stop when we reach the first window in the group */
254 if (WINDOW_IS_CLIENT(it
->data
)) {
255 ObClient
*c
= it
->data
;
256 if (c
->group
== selected
->group
)
259 /* if we don't hit any other group members, stop here because this
260 is where we are putting the selected window (and its children) */
265 /* save this position, this is the top of the group of windows between the
266 group transient ones we're restacking and the others up above that we're
269 we actually want to save 1 position _above_ that, for for loops to work
270 nicely, so move back one position in the list while saving it
272 above
= it
? g_list_previous(it
) : g_list_last(stacking_list
);
274 /* put the windows inside the gap to the other windows we're stacking
275 into the restacking list, go from the bottom up so that we can use
277 if (below
) it
= g_list_previous(below
);
278 else it
= g_list_last(stacking_list
);
279 for (; it
!= above
; it
= next
) {
280 next
= g_list_previous(it
);
281 wins
= g_list_prepend(wins
, it
->data
);
282 stacking_list
= g_list_delete_link(stacking_list
, it
);
285 /* group transients go above the rest of the stuff acquired to now */
286 wins
= g_list_concat(group_trans
, wins
);
287 /* group modals go on the very top */
288 wins
= g_list_concat(group_modals
, wins
);
290 do_restack(wins
, below
);
293 /* lower our parents after us, so they go below us */
294 if (!raise
&& selected
->parents
) {
295 GSList
*parents_copy
, *sit
;
296 GSList
*reorder
= NULL
;
298 parents_copy
= g_slist_copy(selected
->parents
);
300 /* go thru stacking list backwards so we can use g_slist_prepend */
301 for (it
= g_list_last(stacking_list
); it
&& parents_copy
;
302 it
= g_list_previous(it
))
303 if ((sit
= g_slist_find(parents_copy
, it
->data
))) {
304 reorder
= g_slist_prepend(reorder
, sit
->data
);
305 parents_copy
= g_slist_delete_link(parents_copy
, sit
);
307 g_assert(parents_copy
== NULL
);
309 /* call restack for each of these to lower them */
310 for (sit
= reorder
; sit
; sit
= g_slist_next(sit
))
311 restack_windows(sit
->data
, raise
);
315 void stacking_raise(ObWindow
*window
)
317 if (WINDOW_IS_CLIENT(window
)) {
319 selected
= WINDOW_AS_CLIENT(window
);
320 restack_windows(selected
, TRUE
);
323 wins
= g_list_append(NULL
, window
);
324 stacking_list
= g_list_remove(stacking_list
, window
);
330 void stacking_lower(ObWindow
*window
)
332 if (WINDOW_IS_CLIENT(window
)) {
334 selected
= WINDOW_AS_CLIENT(window
);
335 restack_windows(selected
, FALSE
);
338 wins
= g_list_append(NULL
, window
);
339 stacking_list
= g_list_remove(stacking_list
, window
);
345 void stacking_below(ObWindow
*window
, ObWindow
*below
)
347 GList
*wins
, *before
;
349 if (window_layer(window
) != window_layer(below
))
352 wins
= g_list_append(NULL
, window
);
353 stacking_list
= g_list_remove(stacking_list
, window
);
354 before
= g_list_next(g_list_find(stacking_list
, below
));
355 do_restack(wins
, before
);
359 void stacking_add(ObWindow
*win
)
361 g_assert(screen_support_win
!= None
); /* make sure I dont break this in the
364 stacking_list
= g_list_append(stacking_list
, win
);
368 static GList
*find_highest_relative(ObClient
*client
)
372 if (client
->parents
) {
376 /* get all top level relatives of this client */
377 top
= client_search_all_top_parents_layer(client
);
379 /* go from the top of the stacking order down */
380 for (it
= stacking_list
; !ret
&& it
; it
= g_list_next(it
)) {
381 if (WINDOW_IS_CLIENT(it
->data
)) {
382 ObClient
*c
= it
->data
;
383 /* only look at windows in the same layer and that are
385 if (c
->layer
== client
->layer
&&
387 (c
->desktop
== client
->desktop
||
388 c
->desktop
== DESKTOP_ALL
||
389 client
->desktop
== DESKTOP_ALL
))
393 /* go through each top level parent and see it this window
394 is related to them */
395 for (sit
= top
; !ret
&& sit
; sit
= g_slist_next(sit
)) {
396 ObClient
*topc
= sit
->data
;
398 /* are they related ? */
399 if (topc
== c
|| client_search_transient(topc
, c
))
409 void stacking_add_nonintrusive(ObWindow
*win
)
412 GList
*it_below
= NULL
; /* this client will be below us */
415 if (!WINDOW_IS_CLIENT(win
)) {
416 stacking_add(win
); /* no special rules for others */
420 client
= WINDOW_AS_CLIENT(win
);
422 /* insert above its highest parent (or its highest child !) */
423 it_below
= find_highest_relative(client
);
426 /* nothing to put it directly above, so try find the focused client
427 to put it underneath it */
428 if (focus_client
&& client
!= focus_client
&&
429 focus_client
->layer
== client
->layer
)
431 it_below
= g_list_find(stacking_list
, focus_client
);
432 /* this can give NULL, but it means the focused window is on the
433 bottom of the stacking order, so go to the bottom in that case,
435 it_below
= g_list_next(it_below
);
438 /* There is no window to put this directly above, so put it at the
439 top, so you know it is there.
441 It used to do this only if the window was focused and lower
444 We also put it at the top not the bottom to fix a bug with
445 fullscreen windows. When focusLast is off and followsMouse is
446 on, when you switch desktops, the fullscreen window loses
447 focus and goes into its lower layer. If this puts it at the
448 bottom then when you come back to the desktop, the window is
449 at the bottom and won't get focus back.
451 it_below
= stacking_list
;
455 /* make sure it's not in the wrong layer though ! */
456 for (; it_below
; it_below
= g_list_next(it_below
)) {
457 /* stop when the window is not in a higher layer than the window
458 it is going above (it_below) */
459 if (client
->layer
>= window_layer(it_below
->data
))
462 for (; it_below
!= stacking_list
; it_below
= it_above
) {
463 /* stop when the window is not in a lower layer than the
464 window it is going under (it_above) */
465 it_above
= it_below
?
466 g_list_previous(it_below
) : g_list_last(stacking_list
);
467 if (client
->layer
<= window_layer(it_above
->data
))
471 GList
*wins
= g_list_append(NULL
, win
);
472 do_restack(wins
, it_below
);
476 /*! Returns TRUE if client is occluded by the sibling. If sibling is NULL it
477 tries against all other clients.
479 static gboolean
stacking_occluded(ObClient
*client
, ObClient
*sibling
)
482 gboolean occluded
= FALSE
;
483 gboolean found
= FALSE
;
485 /* no need for any looping in this case */
486 if (sibling
&& client
->layer
!= sibling
->layer
)
489 for (it
= stacking_list
; it
;
490 it
= (found
? g_list_previous(it
) :g_list_next(it
)))
491 if (WINDOW_IS_CLIENT(it
->data
)) {
492 ObClient
*c
= it
->data
;
493 if (found
&& !c
->iconic
&&
494 (c
->desktop
== DESKTOP_ALL
|| client
->desktop
== DESKTOP_ALL
||
495 c
->desktop
== client
->desktop
) &&
496 !client_search_transient(client
, c
))
498 if (RECT_INTERSECTS_RECT(c
->frame
->area
, client
->frame
->area
))
500 if (sibling
!= NULL
) {
506 else if (c
->layer
== client
->layer
) {
510 else if (c
->layer
> client
->layer
)
511 break; /* we past its layer */
514 else if (c
== client
)
520 /*! Returns TRUE if client occludes the sibling. If sibling is NULL it tries
521 against all other clients.
523 static gboolean
stacking_occludes(ObClient
*client
, ObClient
*sibling
)
526 gboolean occludes
= FALSE
;
527 gboolean found
= FALSE
;
529 /* no need for any looping in this case */
530 if (sibling
&& client
->layer
!= sibling
->layer
)
533 for (it
= stacking_list
; it
; it
= g_list_next(it
))
534 if (WINDOW_IS_CLIENT(it
->data
)) {
535 ObClient
*c
= it
->data
;
536 if (found
&& !c
->iconic
&&
537 (c
->desktop
== DESKTOP_ALL
|| client
->desktop
== DESKTOP_ALL
||
538 c
->desktop
== client
->desktop
) &&
539 !client_search_transient(c
, client
))
541 if (RECT_INTERSECTS_RECT(c
->frame
->area
, client
->frame
->area
))
543 if (sibling
!= NULL
) {
549 else if (c
->layer
== client
->layer
) {
553 else if (c
->layer
< client
->layer
)
554 break; /* we past its layer */
557 else if (c
== client
)
563 gboolean
stacking_restack_request(ObClient
*client
, ObClient
*sibling
,
566 gboolean ret
= FALSE
;
568 if (sibling
&& ((client
->desktop
!= sibling
->desktop
&&
569 client
->desktop
!= DESKTOP_ALL
&&
570 sibling
->desktop
!= DESKTOP_ALL
) ||
573 ob_debug("Setting restack sibling to NULL, they are not on the same "
574 "desktop or it is iconified\n");
580 ob_debug("Restack request Below for client %s sibling %s\n",
581 client
->title
, sibling
? sibling
->title
: "(all)");
583 stacking_lower(CLIENT_AS_WINDOW(client
));
587 ob_debug("Restack request BottomIf for client %s sibling "
589 client
->title
, sibling
? sibling
->title
: "(all)");
590 /* if this client occludes sibling (or anything if NULL), then
591 lower it to the bottom */
592 if (stacking_occludes(client
, sibling
)) {
593 stacking_lower(CLIENT_AS_WINDOW(client
));
598 ob_debug("Restack request Above for client %s sibling %s\n",
599 client
->title
, sibling
? sibling
->title
: "(all)");
600 stacking_raise(CLIENT_AS_WINDOW(client
));
604 ob_debug("Restack request TopIf for client %s sibling %s\n",
605 client
->title
, sibling
? sibling
->title
: "(all)");
606 if (stacking_occluded(client
, sibling
)) {
607 stacking_raise(CLIENT_AS_WINDOW(client
));
612 ob_debug("Restack request Opposite for client %s sibling "
614 client
->title
, sibling
? sibling
->title
: "(all)");
615 if (stacking_occluded(client
, sibling
)) {
616 stacking_raise(CLIENT_AS_WINDOW(client
));
619 else if (stacking_occludes(client
, sibling
)) {
620 stacking_lower(CLIENT_AS_WINDOW(client
));
This page took 0.069131 seconds and 4 git commands to generate.