all repos — openbox @ 59c3cce4f49f04ed2c2937e7de24255dd53df487

openbox fork - make it a bit more like ryudo

openbox/stacking.c (raw)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include "openbox.h"
#include "prop.h"
#include "focus.h"
#include "client.h"
#include "group.h"
#include "frame.h"
#include <glib.h>

GList  *stacking_list = NULL;

void stacking_set_list()
{
    Window *windows, *win_it;
    GList *it;
    guint size = g_list_length(stacking_list);

    /* on shutdown, don't update the properties, so that we can read it back
       in on startup and re-stack the windows as they were before we shut down
    */
    if (ob_state == State_Exiting) return;

    /* create an array of the window ids (from bottom to top,
       reverse order!) */
    if (size > 0) {
	windows = g_new(Window, size);
	win_it = windows;
	for (it = g_list_last(stacking_list); it != NULL;
             it = it->prev, ++win_it)
	    *win_it = ((Client*)it->data)->window;
    } else
	windows = NULL;

    PROP_SETA32(ob_root, net_client_list_stacking, window, windows, size);

    if (windows)
	g_free(windows);
}

static GList *find_lowest_transient(Client *c)
{
    GList *it;
    GSList *sit;

    for (it = g_list_last(stacking_list); it; it = it->prev)
        for (sit = c->transients; sit; sit = sit->next)
            if (it->data == sit->data) /* found a transient */
                return it;
    return NULL;
}

static void raise_recursive(Client *client)
{
    Window wins[2];  /* only ever restack 2 windows. */
    GList *it;
    GSList *sit;

    g_assert(stacking_list != NULL); /* this would be bad */

    /* remove the client before looking so we can't run into ourselves and our
       transients can't either. */
    stacking_list = g_list_remove(stacking_list, client);

    /* raise transients first */
    for (sit = client->transients; sit; sit = sit->next)
        raise_recursive(sit->data);

    /* find 'it' where it is the positiion in the stacking order where
       'client' will be inserted *before* */

    it = find_lowest_transient(client);
    if (it)
        it = it->next;
    else {
        /* the stacking list is from highest to lowest */
        for (it = stacking_list; it; it = it->next) {
            if (client->layer >= ((Client*)it->data)->layer)
                break;
        }
    }

    /*
      if our new position is the top, we want to stack under the focus_backup.
      otherwise, we want to stack under the previous window in the stack.
    */
    if (it == stacking_list)
	wins[0] = focus_backup;
    else if (it != NULL)
	wins[0] = ((Client*)it->prev->data)->frame->window;
    else
	wins[0] = ((Client*)g_list_last(stacking_list)->data)->frame->window;
    wins[1] = client->frame->window;

    stacking_list = g_list_insert_before(stacking_list, it, client);

    XRestackWindows(ob_display, wins, 2);
}

void stacking_raise(Client *client)
{
    g_assert(stacking_list != NULL); /* this would be bad */

    /* move up the transient chain as far as possible first */
    while (client->transient_for) {
        if (client->transient_for != TRAN_GROUP) {
            client = client->transient_for;
        } else {
            GSList *it;

            /* the check for TRAN_GROUP is to prevent an infinate loop with
               2 transients of the same group at the head of the group's
               members list */
            for (it = client->group->members; it; it = it->next) {
                Client *c = it->data;

                if (c != client && c->transient_for != TRAN_GROUP) {
                    client = it->data;
                    break;
                }
            }
            if (it == NULL) break;
        }
    }

    raise_recursive(client);

    stacking_set_list();
}

static void lower_recursive(Client *client, Client *above)
{
    Window wins[2];  /* only ever restack 2 windows. */
    GList *it;
    GSList *sit;

    /* find 'it' where 'it' is the position in the stacking_list where the
       'client' will be placed *after* */

    for (it = g_list_last(stacking_list); it != stacking_list; it = it->prev)
        if (client->layer <= ((Client*)it->data)->layer && it->data != above)
            break;

    if (it->data != client) { /* not already the bottom */
        wins[0] = ((Client*)it->data)->frame->window;
        wins[1] = client->frame->window;

        stacking_list = g_list_remove(stacking_list, client);
        stacking_list = g_list_insert_before(stacking_list, it->next, client);
        XRestackWindows(ob_display, wins, 2);
    }

    for (sit = client->transients; sit; sit = sit->next)
        lower_recursive(sit->data, client);
}

void stacking_lower(Client *client)
{
    g_assert(stacking_list != NULL); /* this would be bad */

    /* move up the transient chain as far as possible first */
    while (client->transient_for) {
        if (client->transient_for != TRAN_GROUP) {
            client = client->transient_for;
        } else {
            GSList *it;

            /* the check for TRAN_GROUP is to prevent an infinate loop with
               2 transients of the same group at the head of the group's
               members list */
            for (it = client->group->members; it; it = it->next) {
                Client *c = it->data;

                if (c != client && c->transient_for != TRAN_GROUP) {
                    client = it->data;
                    break;
                }
            }
            if (it == NULL) break;
        }
    }

    lower_recursive(client, NULL);

    stacking_set_list();
}