merge the C branch into HEAD
[dana/openbox.git] / openbox / stacking.c
1 #include "openbox.h"
2 #include "prop.h"
3 #include "focus.h"
4 #include "client.h"
5 #include "frame.h"
6 #include <glib.h>
7
8 GList  *stacking_list = NULL;
9
10 void stacking_set_list()
11 {
12     Window *windows, *win_it;
13     GList *it;
14     guint size = g_list_length(stacking_list);
15
16     /* create an array of the window ids (from bottom to top,
17        reverse order!) */
18     if (size > 0) {
19         windows = g_new(Window, size);
20         win_it = windows;
21         for (it = g_list_last(stacking_list); it; it = it->prev, ++win_it)
22             *win_it = ((Client*)it->data)->window;
23     } else
24         windows = NULL;
25
26     PROP_SET32A(ob_root, net_client_list_stacking, window, windows, size);
27
28     if (windows)
29         g_free(windows);
30 }
31
32 void stacking_raise(Client *client)
33 {
34     Window wins[2];  /* only ever restack 2 windows. */
35     GList *it;
36     Client *m;
37
38     g_assert(stacking_list != NULL); /* this would be bad */
39
40     m = client_find_modal_child(client);
41     /* if we have a modal child, raise it instead, we'll go along tho later */
42     if (m) stacking_raise(m);
43   
44     /* remove the client before looking so we can't run into ourselves */
45     stacking_list = g_list_remove(stacking_list, client);
46   
47     /* the stacking list is from highest to lowest */
48     it = stacking_list;
49     while (it) {
50         Client *c = it->data;
51         if (client->layer >= c->layer && m != c)
52             break;
53         it = it->next;
54     }
55
56     /*
57       if our new position is the top, we want to stack under the focus_backup.
58       otherwise, we want to stack under the previous window in the stack.
59     */
60     if (it == stacking_list)
61         wins[0] = focus_backup;
62     else if (it != NULL)
63         wins[0] = ((Client*)it->prev->data)->frame->window;
64     else
65         wins[0] = ((Client*)g_list_last(stacking_list)->data)->frame->window;
66     wins[1] = client->frame->window;
67
68     stacking_list = g_list_insert_before(stacking_list, it, client);
69
70     XRestackWindows(ob_display, wins, 2);
71
72     stacking_set_list();
73 }
74
75 void stacking_lower(Client *client)
76 {
77     Window wins[2];  /* only ever restack 2 windows. */
78     GList *it;
79
80     g_assert(stacking_list != NULL); /* this would be bad */
81
82     it = g_list_last(stacking_list);
83
84     if (client->modal && client->transient_for) {
85         /* don't let a modal window lower below its transient_for */
86         it = g_list_find(stacking_list, client->transient_for);
87         g_assert(it != NULL);
88
89         wins[0] = (it == stacking_list ? focus_backup :
90                    ((Client*)it->prev->data)->frame->window);
91         wins[1] = client->frame->window;
92         if (wins[0] == wins[1]) return; /* already right above the window */
93
94         stacking_list = g_list_remove(stacking_list, client);
95         stacking_list = g_list_insert_before(stacking_list, it, client);
96     } else {
97         while (it != stacking_list) {
98             Client *c = it->data;
99             if (client->layer >= c->layer)
100                 break;
101             it = it->prev;
102         }
103         if (it->data == client) return; /* already the bottom, return */
104
105         wins[0] = ((Client*)it->data)->frame->window;
106         wins[1] = client->frame->window;
107
108         stacking_list = g_list_remove(stacking_list, client);
109         stacking_list = g_list_insert_before(stacking_list,
110                                              it->next, client);
111     }
112
113     XRestackWindows(ob_display, wins, 2);
114     stacking_set_list();
115 }
116