]>
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 if (!raise
&& selected
->transient_for
) {
173 GSList
*top
, *top_it
;
174 GSList
*top_reorder
= NULL
;
176 /* if it's a transient lowering, lower its parents so that we can lower
177 this window, or it won't move */
178 top
= client_search_all_top_parents_layer(selected
);
180 /* that is, if it has any parents */
181 if (!(top
->data
== selected
&& top
->next
== NULL
)) {
182 /* go thru stacking list backwards so we can use g_slist_prepend */
183 for (it
= g_list_last(stacking_list
); it
&& top
;
184 it
= g_list_previous(it
))
185 if ((top_it
= g_slist_find(top
, it
->data
))) {
186 top_reorder
= g_slist_prepend(top_reorder
, top_it
->data
);
187 top
= g_slist_delete_link(top
, top_it
);
189 g_assert(top
== NULL
);
191 /* call restack for each of these to lower them */
192 for (top_it
= top_reorder
; top_it
; top_it
= g_slist_next(top_it
))
193 restack_windows(top_it
->data
, raise
);
198 /* remove first so we can't run into ourself */
199 it
= g_list_find(stacking_list
, selected
);
201 stacking_list
= g_list_delete_link(stacking_list
, it
);
203 /* go from the bottom of the stacking list up */
204 for (it
= g_list_last(stacking_list
); it
; it
= next
) {
205 next
= g_list_previous(it
);
207 if (WINDOW_IS_CLIENT(it
->data
)) {
208 ObClient
*ch
= it
->data
;
210 /* only move windows in the same stacking layer */
211 if (ch
->layer
== selected
->layer
&&
212 client_search_transient(selected
, ch
))
214 if (client_is_direct_child(selected
, ch
)) {
216 modals
= g_list_prepend(modals
, ch
);
218 trans
= g_list_prepend(trans
, ch
);
222 group_modals
= g_list_prepend(group_modals
, ch
);
224 group_trans
= g_list_prepend(group_trans
, ch
);
226 stacking_list
= g_list_delete_link(stacking_list
, it
);
231 /* put transients of the selected window right above it */
232 wins
= g_list_concat(modals
, trans
);
233 wins
= g_list_append(wins
, selected
);
235 /* if selected window is transient for group then raise it above others */
236 if (selected
->transient_for
== OB_TRAN_GROUP
) {
237 /* if it's modal, raise it above those also */
238 if (selected
->modal
) {
239 wins
= g_list_concat(wins
, group_modals
);
242 wins
= g_list_concat(wins
, group_trans
);
246 /* find where to put the selected window, start from bottom of list,
247 this is the window below everything we are re-adding to the list */
249 for (it
= g_list_last(stacking_list
); it
; it
= g_list_previous(it
))
251 if (window_layer(it
->data
) < selected
->layer
) {
255 /* if lowering, stop at the beginning of the layer */
258 /* if raising, stop at the end of the layer */
259 if (window_layer(it
->data
) > selected
->layer
)
265 /* save this position in the stacking list */
268 /* find where to put the group transients, start from the top of list */
269 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
270 /* skip past higher layers */
271 if (window_layer(it
->data
) > selected
->layer
)
273 /* if we reach the end of the layer (how?) then don't go further */
274 if (window_layer(it
->data
) < selected
->layer
)
276 /* stop when we reach the first window in the group */
277 if (WINDOW_IS_CLIENT(it
->data
)) {
278 ObClient
*c
= it
->data
;
279 if (c
->group
== selected
->group
)
282 /* if we don't hit any other group members, stop here because this
283 is where we are putting the selected window (and its children) */
288 /* save this position, this is the top of the group of windows between the
289 group transient ones we're restacking and the others up above that we're
292 we actually want to save 1 position _above_ that, for for loops to work
293 nicely, so move back one position in the list while saving it
295 above
= it
? g_list_previous(it
) : g_list_last(stacking_list
);
297 /* put the windows inside the gap to the other windows we're stacking
298 into the restacking list, go from the bottom up so that we can use
300 if (below
) it
= g_list_previous(below
);
301 else it
= g_list_last(stacking_list
);
302 for (; it
!= above
; it
= next
) {
303 next
= g_list_previous(it
);
304 wins
= g_list_prepend(wins
, it
->data
);
305 stacking_list
= g_list_delete_link(stacking_list
, it
);
308 /* group transients go above the rest of the stuff acquired to now */
309 wins
= g_list_concat(group_trans
, wins
);
310 /* group modals go on the very top */
311 wins
= g_list_concat(group_modals
, wins
);
313 do_restack(wins
, below
);
317 void stacking_raise(ObWindow
*window
)
319 if (WINDOW_IS_CLIENT(window
)) {
321 selected
= WINDOW_AS_CLIENT(window
);
322 restack_windows(selected
, TRUE
);
325 wins
= g_list_append(NULL
, window
);
326 stacking_list
= g_list_remove(stacking_list
, window
);
332 void stacking_lower(ObWindow
*window
)
334 if (WINDOW_IS_CLIENT(window
)) {
336 selected
= WINDOW_AS_CLIENT(window
);
337 restack_windows(selected
, FALSE
);
340 wins
= g_list_append(NULL
, window
);
341 stacking_list
= g_list_remove(stacking_list
, window
);
347 void stacking_below(ObWindow
*window
, ObWindow
*below
)
349 GList
*wins
, *before
;
351 if (window_layer(window
) != window_layer(below
))
354 wins
= g_list_append(NULL
, window
);
355 stacking_list
= g_list_remove(stacking_list
, window
);
356 before
= g_list_next(g_list_find(stacking_list
, below
));
357 do_restack(wins
, before
);
361 void stacking_add(ObWindow
*win
)
363 g_assert(screen_support_win
!= None
); /* make sure I dont break this in the
366 stacking_list
= g_list_append(stacking_list
, win
);
370 static GList
*find_highest_relative(ObClient
*client
)
374 if (client
->transient_for
) {
378 /* get all top level relatives of this client */
379 top
= client_search_all_top_parents_layer(client
);
381 /* go from the top of the stacking order down */
382 for (it
= stacking_list
; !ret
&& it
; it
= g_list_next(it
)) {
383 if (WINDOW_IS_CLIENT(it
->data
)) {
384 ObClient
*c
= it
->data
;
385 /* only look at windows in the same layer */
386 if (c
->layer
== client
->layer
) {
389 /* go through each top level parent and see it this window
390 is related to them */
391 for (sit
= top
; !ret
&& sit
; sit
= g_slist_next(sit
)) {
392 ObClient
*topc
= sit
->data
;
394 /* are they related ? */
395 if (topc
== c
|| client_search_transient(topc
, c
))
405 void stacking_add_nonintrusive(ObWindow
*win
)
408 GList
*it_below
= NULL
;
410 if (!WINDOW_IS_CLIENT(win
)) {
411 stacking_add(win
); /* no special rules for others */
415 client
= WINDOW_AS_CLIENT(win
);
417 /* insert above its highest parent (or its highest child !) */
418 it_below
= find_highest_relative(client
);
420 if (!it_below
&& client
!= focus_client
) {
421 /* nothing to put it directly above, so try find the focused client to
422 put it underneath it */
423 if (focus_client
&& focus_client
->layer
== client
->layer
) {
424 if ((it_below
= g_list_find(stacking_list
, focus_client
)))
425 it_below
= it_below
->next
;
429 /* There is no window to put this directly above, so put it at the
430 top, so you know it is there.
432 It used to do this only if the window was focused and lower
435 We also put it at the top not the bottom to fix a bug with
436 fullscreen windows. When focusLast is off and followsMouse is
437 on, when you switch desktops, the fullscreen window loses
438 focus and goes into its lower layer. If this puts it at the
439 bottom then when you come back to the desktop, the window is
440 at the bottom and won't get focus back.
442 stacking_list
= g_list_append(stacking_list
, win
);
445 /* make sure it's not in the wrong layer though ! */
446 for (; it_below
; it_below
= g_list_next(it_below
))
448 /* stop when the window is not in a higher layer than the window
449 it is going above (it_below) */
450 if (client
->layer
>= window_layer(it_below
->data
))
453 for (; it_below
!= stacking_list
;
454 it_below
= g_list_previous(it_below
))
456 /* stop when the window is not in a lower layer than the
457 window it is going under (it_above) */
458 GList
*it_above
= g_list_previous(it_below
);
459 if (client
->layer
<= window_layer(it_above
->data
))
463 GList
*wins
= g_list_append(NULL
, win
);
464 do_restack(wins
, it_below
);
469 /*! Returns TRUE if client is occluded by the sibling. If sibling is NULL it
470 tries against all other clients.
472 static gboolean
stacking_occluded(ObClient
*client
, ObClient
*sibling
)
475 gboolean occluded
= FALSE
;
476 gboolean found
= FALSE
;
478 /* no need for any looping in this case */
479 if (sibling
&& client
->layer
!= sibling
->layer
)
482 for (it
= stacking_list
; it
;
483 it
= (found
? g_list_previous(it
) :g_list_next(it
)))
484 if (WINDOW_IS_CLIENT(it
->data
)) {
485 ObClient
*c
= it
->data
;
487 if (RECT_INTERSECTS_RECT(c
->frame
->area
, client
->frame
->area
))
489 if (sibling
!= NULL
) {
495 else if (c
->layer
== client
->layer
) {
499 else if (c
->layer
> client
->layer
)
500 break; /* we past its layer */
503 else if (c
== client
)
509 /*! Returns TRUE if client is occludes the sibling. If sibling is NULL it tries
510 against all other clients.
512 static gboolean
stacking_occludes(ObClient
*client
, ObClient
*sibling
)
515 gboolean occludes
= FALSE
;
516 gboolean found
= FALSE
;
518 /* no need for any looping in this case */
519 if (sibling
&& client
->layer
!= sibling
->layer
)
522 for (it
= stacking_list
; it
; it
= g_list_next(it
))
523 if (WINDOW_IS_CLIENT(it
->data
)) {
524 ObClient
*c
= it
->data
;
526 if (RECT_INTERSECTS_RECT(c
->frame
->area
, client
->frame
->area
))
528 if (sibling
!= NULL
) {
534 else if (c
->layer
== client
->layer
) {
538 else if (c
->layer
< client
->layer
)
539 break; /* we past its layer */
542 else if (c
== client
)
548 void stacking_restack_request(ObClient
*client
, ObClient
*sibling
,
549 gint detail
, gboolean activate
)
553 ob_debug("Restack request Below for client %s sibling %s\n",
554 client
->title
, sibling
? sibling
->title
: "(all)");
556 stacking_lower(CLIENT_AS_WINDOW(client
));
559 ob_debug("Restack request BottomIf for client %s sibling "
561 client
->title
, sibling
? sibling
->title
: "(all)");
562 /* if this client occludes sibling (or anything if NULL), then
563 lower it to the bottom */
564 if (stacking_occludes(client
, sibling
))
565 stacking_lower(CLIENT_AS_WINDOW(client
));
568 ob_debug("Restack request Above for client %s sibling %s\n",
569 client
->title
, sibling
? sibling
->title
: "(all)");
570 if (activate
&& !client
->iconic
)
571 /* use user=TRUE because it is impossible to get a timestamp
573 client_activate(client
, FALSE
, TRUE
);
575 stacking_raise(CLIENT_AS_WINDOW(client
));
578 ob_debug("Restack request TopIf for client %s sibling %s\n",
579 client
->title
, sibling
? sibling
->title
: "(all)");
580 if (stacking_occluded(client
, sibling
)) {
581 if (activate
&& !client
->iconic
)
582 /* use user=TRUE because it is impossible to get a timestamp
584 client_activate(client
, FALSE
, TRUE
);
586 stacking_raise(CLIENT_AS_WINDOW(client
));
590 ob_debug("Restack request Opposite for client %s sibling "
592 client
->title
, sibling
? sibling
->title
: "(all)");
593 if (stacking_occluded(client
, sibling
)) {
594 if (activate
&& !client
->iconic
)
595 /* use user=TRUE because it is impossible to get a timestamp
597 client_activate(client
, FALSE
, TRUE
);
599 stacking_raise(CLIENT_AS_WINDOW(client
));
601 else if (stacking_occludes(client
, sibling
))
602 stacking_lower(CLIENT_AS_WINDOW(client
));
This page took 0.065968 seconds and 4 git commands to generate.