]>
Dogcows Code - chaz/openbox/blob - openbox/stacking.c
2050219db83de16556bcfc21de36036b3802ad31
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 Ben 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.
29 GList
*stacking_list
= NULL
;
31 void stacking_set_list()
33 Window
*windows
= NULL
;
37 /* on shutdown, don't update the properties, so that we can read it back
38 in on startup and re-stack the windows as they were before we shut down
40 if (ob_state() == OB_STATE_EXITING
) return;
42 /* create an array of the window ids (from bottom to top,
45 windows
= g_new(Window
, g_list_length(stacking_list
));
46 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
47 if (WINDOW_IS_CLIENT(it
->data
))
48 windows
[i
++] = WINDOW_AS_CLIENT(it
->data
)->window
;
52 PROP_SETA32(RootWindow(ob_display
, ob_screen
),
53 net_client_list_stacking
, window
, (gulong
*)windows
, i
);
58 static void do_restack(GList
*wins
, GList
*before
)
66 /* pls only restack stuff in the same layer at a time */
67 for (it
= wins
; it
; it
= next
) {
68 next
= g_list_next(it
);
70 g_assert (window_layer(it
->data
) == window_layer(next
->data
));
73 g_assert(window_layer(it
->data
) >= window_layer(before
->data
));
76 win
= g_new(Window
, g_list_length(wins
) + 1);
78 if (before
== stacking_list
)
79 win
[0] = screen_support_win
;
81 win
[0] = window_top(g_list_last(stacking_list
)->data
);
83 win
[0] = window_top(g_list_previous(before
)->data
);
85 for (i
= 1, it
= wins
; it
; ++i
, it
= g_list_next(it
)) {
86 win
[i
] = window_top(it
->data
);
87 g_assert(win
[i
] != None
); /* better not call stacking shit before
88 setting your top level window value */
89 stacking_list
= g_list_insert_before(stacking_list
, before
, it
->data
);
93 /* some debug checking of the stacking list's order */
94 for (it
= stacking_list
; ; it
= next
) {
95 next
= g_list_next(it
);
97 g_assert(window_layer(it
->data
) >= window_layer(next
->data
));
101 XRestackWindows(ob_display
, win
, i
);
107 static void do_raise(GList
*wins
)
110 GList
*layer
[OB_NUM_STACKING_LAYERS
] = {NULL
};
113 for (it
= wins
; it
; it
= g_list_next(it
)) {
116 l
= window_layer(it
->data
);
117 layer
[l
] = g_list_append(layer
[l
], it
->data
);
121 for (i
= OB_NUM_STACKING_LAYERS
- 1; i
>= 0; --i
) {
123 for (; it
; it
= g_list_next(it
)) {
124 /* look for the top of the layer */
125 if (window_layer(it
->data
) <= (ObStackingLayer
) i
)
128 do_restack(layer
[i
], it
);
129 g_list_free(layer
[i
]);
134 static void do_lower(GList
*wins
)
137 GList
*layer
[OB_NUM_STACKING_LAYERS
] = {NULL
};
140 for (it
= wins
; it
; it
= g_list_next(it
)) {
143 l
= window_layer(it
->data
);
144 layer
[l
] = g_list_append(layer
[l
], it
->data
);
148 for (i
= OB_NUM_STACKING_LAYERS
- 1; i
>= 0; --i
) {
150 for (; it
; it
= g_list_next(it
)) {
151 /* look for the top of the next layer down */
152 if (window_layer(it
->data
) < (ObStackingLayer
) i
)
155 do_restack(layer
[i
], it
);
156 g_list_free(layer
[i
]);
161 static void restack_windows(ObClient
*selected
, gboolean raise
)
163 GList
*it
, *last
, *below
, *above
, *next
;
166 GList
*group_modals
= NULL
;
167 GList
*group_trans
= NULL
;
168 GList
*modals
= NULL
;
171 if (!raise
&& selected
->transient_for
) {
172 GSList
*top
, *top_it
;
173 GSList
*top_reorder
= NULL
;
175 /* if it's a transient lowering, lower its parents so that we can lower
176 this window, or it won't move */
177 top
= client_search_all_top_parents(selected
);
179 /* go thru stacking list backwards so we can use g_slist_prepend */
180 for (it
= g_list_last(stacking_list
); it
&& top
;
181 it
= g_list_previous(it
))
182 if ((top_it
= g_slist_find(top
, it
->data
))) {
183 top_reorder
= g_slist_prepend(top_reorder
, top_it
->data
);
184 top
= g_slist_delete_link(top
, top_it
);
186 g_assert(top
== NULL
);
188 /* call restack for each of these to lower them */
189 for (top_it
= top_reorder
; top_it
; top_it
= g_slist_next(top_it
))
190 restack_windows(top_it
->data
, raise
);
194 /* remove first so we can't run into ourself */
195 it
= g_list_find(stacking_list
, selected
);
197 stacking_list
= g_list_delete_link(stacking_list
, it
);
199 /* go from the bottom of the stacking list up */
200 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
)) {
201 if (WINDOW_IS_CLIENT(it
->data
)) {
202 ObClient
*ch
= it
->data
;
204 /* only move windows in the same stacking layer */
205 if (ch
->layer
== selected
->layer
&&
206 client_search_transient(selected
, ch
))
208 if (client_is_direct_child(selected
, ch
)) {
210 modals
= g_list_prepend(modals
, ch
);
212 trans
= g_list_prepend(trans
, ch
);
216 group_modals
= g_list_prepend(group_modals
, ch
);
218 group_trans
= g_list_prepend(group_trans
, ch
);
220 stacking_list
= g_list_delete_link(stacking_list
, it
);
225 /* put transients of the selected window right above it */
226 wins
= g_list_concat(modals
, trans
);
227 wins
= g_list_append(wins
, selected
);
229 /* if selected window is transient for group then raise it above others */
230 if (selected
->transient_for
== OB_TRAN_GROUP
) {
231 /* if it's modal, raise it above those also */
232 if (selected
->modal
) {
233 wins
= g_list_concat(wins
, group_modals
);
236 wins
= g_list_concat(wins
, group_trans
);
240 /* find where to put the selected window, start from bottom of list,
241 this is the window below everything we are re-adding to the list */
243 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
))
245 if (window_layer(it
->data
) < selected
->layer
) {
249 /* if lowering, stop at the beginning of the layer */
252 /* if raising, stop at the end of the layer */
253 if (window_layer(it
->data
) > selected
->layer
)
259 /* save this position in the stacking list */
262 /* find where to put the group transients, start from the top of list */
263 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
264 /* skip past higher layers */
265 if (window_layer(it
->data
) > selected
->layer
)
267 /* if we reach the end of the layer (how?) then don't go further */
268 if (window_layer(it
->data
) < selected
->layer
)
270 /* stop when we reach the first window in the group */
271 if (WINDOW_IS_CLIENT(it
->data
)) {
272 ObClient
*c
= it
->data
;
273 if (c
->group
== selected
->group
)
276 /* if we don't hit any other group members, stop here because this
277 is where we are putting the selected window (and its children) */
282 /* save this position, this is the top of the group of windows between the
283 group transient ones we're restacking and the others up above that we're
286 we actually want to save 1 position _above_ that, for for loops to work
287 nicely, so move back one position in the list while saving it
289 above
= it
? g_list_previous(it
) : g_list_last(stacking_list
);
291 /* put the windows inside the gap to the other windows we're stacking
292 into the restacking list, go from the bottom up so that we can use
294 if (below
) it
= g_list_previous(below
);
295 else it
= g_list_last(stacking_list
);
296 for (; it
!= above
; it
= next
) {
297 next
= g_list_previous(it
);
298 wins
= g_list_prepend(wins
, it
->data
);
299 stacking_list
= g_list_delete_link(stacking_list
, it
);
302 /* group transients go above the rest of the stuff acquired to now */
303 wins
= g_list_concat(group_trans
, wins
);
304 /* group modals go on the very top */
305 wins
= g_list_concat(group_modals
, wins
);
307 do_restack(wins
, below
);
311 void stacking_raise(ObWindow
*window
)
313 if (WINDOW_IS_CLIENT(window
)) {
315 selected
= WINDOW_AS_CLIENT(window
);
316 restack_windows(selected
, TRUE
);
319 wins
= g_list_append(NULL
, window
);
320 stacking_list
= g_list_remove(stacking_list
, window
);
326 void stacking_lower(ObWindow
*window
)
328 if (WINDOW_IS_CLIENT(window
)) {
330 selected
= WINDOW_AS_CLIENT(window
);
331 restack_windows(selected
, FALSE
);
334 wins
= g_list_append(NULL
, window
);
335 stacking_list
= g_list_remove(stacking_list
, window
);
341 void stacking_below(ObWindow
*window
, ObWindow
*below
)
343 GList
*wins
, *before
;
345 if (window_layer(window
) != window_layer(below
))
348 wins
= g_list_append(NULL
, window
);
349 stacking_list
= g_list_remove(stacking_list
, window
);
350 before
= g_list_next(g_list_find(stacking_list
, below
));
351 do_restack(wins
, before
);
355 void stacking_add(ObWindow
*win
)
357 g_assert(screen_support_win
!= None
); /* make sure I dont break this in the
360 stacking_list
= g_list_append(stacking_list
, win
);
364 void stacking_add_nonintrusive(ObWindow
*win
)
367 ObClient
*parent
= NULL
;
368 GList
*it_below
= NULL
;
370 if (!WINDOW_IS_CLIENT(win
)) {
371 stacking_add(win
); /* no special rules for others */
375 client
= WINDOW_AS_CLIENT(win
);
377 /* insert above its highest parent */
378 if (client
->transient_for
) {
379 if (client
->transient_for
!= OB_TRAN_GROUP
) {
380 parent
= client
->transient_for
;
386 for (it
= stacking_list
; !parent
&& it
; it
= g_list_next(it
)) {
387 if ((sit
= g_slist_find(client
->group
->members
, it
->data
)))
388 for (sit
= client
->group
->members
; !parent
&& sit
;
389 sit
= g_slist_next(sit
))
391 ObClient
*c
= sit
->data
;
392 /* checking transient_for prevents infinate loops! */
393 if (sit
->data
== it
->data
&& !c
->transient_for
)
400 if (!(it_below
= g_list_find(stacking_list
, parent
))) {
401 /* no parent to put above, try find the focused client to go
403 if (focus_client
&& focus_client
->layer
== client
->layer
) {
404 if ((it_below
= g_list_find(stacking_list
, focus_client
)))
405 it_below
= it_below
->next
;
409 /* out of ideas, just add it normally... */
412 /* make sure it's not in the wrong layer though ! */
413 for (; it_below
; it_below
= g_list_next(it_below
))
415 /* stop when the window is not in a higher layer than the window
416 it is going above (it_below) */
417 if (client
->layer
>= window_layer(it_below
->data
))
420 for (; it_below
!= stacking_list
;
421 it_below
= g_list_previous(it_below
))
423 /* stop when the window is not in a lower layer than the
424 window it is going under (it_above) */
425 GList
*it_above
= g_list_previous(it_below
);
426 if (client
->layer
<= window_layer(it_above
->data
))
430 GList
*wins
= g_list_append(NULL
, win
);
431 do_restack(wins
, it_below
);
This page took 0.05258 seconds and 4 git commands to generate.