]> git.lizzy.rs Git - bspwm.git/blob - desktop.c
Allow subscribers to choose what they listen to
[bspwm.git] / desktop.c
1 /* Copyright (c) 2012, Bastien Dejean
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this
8  *    list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include <stdlib.h>
26 #include "bspwm.h"
27 #include "ewmh.h"
28 #include "history.h"
29 #include "monitor.h"
30 #include "query.h"
31 #include "tree.h"
32 #include "window.h"
33 #include "desktop.h"
34 #include "subscribe.h"
35 #include "settings.h"
36
37 void focus_desktop(monitor_t *m, desktop_t *d)
38 {
39         focus_monitor(m);
40
41         if (d == mon->desk)
42                 return;
43
44         PRINTF("focus desktop %s\n", d->name);
45
46         show_desktop(d);
47         hide_desktop(mon->desk);
48
49         mon->desk = d;
50
51         ewmh_update_current_desktop();
52         put_status(SBSC_MASK_REPORT);
53 }
54
55 desktop_t *closest_desktop(monitor_t *m, desktop_t *d, cycle_dir_t dir, desktop_select_t sel)
56 {
57         desktop_t *f = (dir == CYCLE_PREV ? d->prev : d->next);
58         if (f == NULL)
59                 f = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head);
60
61         while (f != d) {
62                 coordinates_t loc = {m, f, NULL};
63                 if (desktop_matches(&loc, &loc, sel))
64                         return f;
65                 f = (dir == CYCLE_PREV ? f->prev : f->next);
66                 if (f == NULL)
67                         f = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head);
68         }
69
70         return NULL;
71 }
72
73 void change_layout(monitor_t *m, desktop_t *d, layout_t l)
74 {
75         d->layout = l;
76         arrange(m, d);
77         if (d == m->desk)
78                 put_status(SBSC_MASK_REPORT);
79 }
80
81 void transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d)
82 {
83         if (ms == md)
84                 return;
85
86         desktop_t *dd = ms->desk;
87         unlink_desktop(ms, d);
88         insert_desktop(md, d);
89
90         if (d == dd) {
91                 if (ms->desk != NULL)
92                         show_desktop(ms->desk);
93                 if (md->desk != d)
94                         hide_desktop(d);
95         }
96
97         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
98                 translate_client(ms, md, n->client);
99
100         arrange(md, d);
101
102         if (d != dd && md->desk == d)
103                 show_desktop(d);
104
105         history_transfer_desktop(md, d);
106
107         ewmh_update_wm_desktops();
108         ewmh_update_desktop_names();
109         ewmh_update_current_desktop();
110         put_status(SBSC_MASK_REPORT);
111 }
112
113 desktop_t *make_desktop(const char *name)
114 {
115         desktop_t *d = malloc(sizeof(desktop_t));
116         if (name == NULL)
117                 snprintf(d->name, sizeof(d->name), "%s%d", DEFAULT_DESK_NAME, ++desktop_uid);
118         else
119                 snprintf(d->name, sizeof(d->name), "%s", name);
120         d->prev = d->next = NULL;
121         d->root = d->focus = NULL;
122         initialize_desktop(d);
123         return d;
124 }
125
126 void initialize_desktop(desktop_t *d)
127 {
128         d->layout = LAYOUT_TILED;
129         d->top_padding = d->right_padding = d->bottom_padding = d->left_padding = 0;
130         d->window_gap = window_gap;
131         d->border_width = border_width;
132         d->floating = false;
133 }
134
135 void insert_desktop(monitor_t *m, desktop_t *d)
136 {
137         if (m->desk == NULL) {
138                 m->desk = d;
139                 m->desk_head = d;
140                 m->desk_tail = d;
141         } else {
142                 m->desk_tail->next = d;
143                 d->prev = m->desk_tail;
144                 m->desk_tail = d;
145         }
146 }
147
148 void add_desktop(monitor_t *m, desktop_t *d)
149 {
150         PRINTF("add desktop %s\n", d->name);
151         put_status(SBSC_MASK_DESKTOP_ADD, "desktop_add %s\n", d->name);
152
153         insert_desktop(m, d);
154         num_desktops++;
155         ewmh_update_number_of_desktops();
156         ewmh_update_desktop_names();
157         put_status(SBSC_MASK_REPORT);
158 }
159
160 void empty_desktop(desktop_t *d)
161 {
162         destroy_tree(d->root);
163         d->root = d->focus = NULL;
164 }
165
166 void unlink_desktop(monitor_t *m, desktop_t *d)
167 {
168         desktop_t *prev = d->prev;
169         desktop_t *next = d->next;
170         desktop_t *last_desk = history_get_desktop(m, d);
171         if (prev != NULL)
172                 prev->next = next;
173         if (next != NULL)
174                 next->prev = prev;
175         if (m->desk_head == d)
176                 m->desk_head = next;
177         if (m->desk_tail == d)
178                 m->desk_tail = prev;
179         if (m->desk == d)
180                 m->desk = (last_desk == NULL ? (prev == NULL ? next : prev) : last_desk);
181         d->prev = d->next = NULL;
182 }
183
184 void remove_desktop(monitor_t *m, desktop_t *d)
185 {
186         PRINTF("remove desktop %s\n", d->name);
187         put_status(SBSC_MASK_DESKTOP_REMOVE, "desktop_remove %s\n", d->name);
188
189         unlink_desktop(m, d);
190         history_remove(d, NULL);
191         empty_desktop(d);
192         free(d);
193
194         num_desktops--;
195
196         ewmh_update_current_desktop();
197         ewmh_update_number_of_desktops();
198         ewmh_update_desktop_names();
199
200         put_status(SBSC_MASK_REPORT);
201 }
202
203 void merge_desktops(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop_t *dd)
204 {
205         if (ds == NULL || dd == NULL || ds == dd)
206                 return;
207         node_t *n = first_extrema(ds->root);
208         while (n != NULL) {
209                 node_t *next = next_leaf(n, ds->root);
210                 transfer_node(ms, ds, n, md, dd, dd->focus);
211                 n = next;
212         }
213 }
214
215 void swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2)
216 {
217         if (d1 == NULL || d2 == NULL || d1 == d2)
218                 return;
219
220         PRINTF("swap desktops %s %s\n", d1->name, d2->name);
221
222         bool d1_focused = (m1->desk == d1);
223         bool d2_focused = (m2->desk == d2);
224
225         if (m1 != m2) {
226                 if (m1->desk == d1)
227                         m1->desk = d2;
228                 if (m1->desk_head == d1)
229                         m1->desk_head = d2;
230                 if (m1->desk_tail == d1)
231                         m1->desk_tail = d2;
232                 if (m2->desk == d2)
233                         m2->desk = d1;
234                 if (m2->desk_head == d2)
235                         m2->desk_head = d1;
236                 if (m2->desk_tail == d2)
237                         m2->desk_tail = d1;
238         } else {
239                 if (m1->desk_head == d1)
240                         m1->desk_head = d2;
241                 else if (m1->desk_head == d2)
242                         m1->desk_head = d1;
243                 if (m1->desk_tail == d1)
244                         m1->desk_tail = d2;
245                 else if (m1->desk_tail == d2)
246                         m1->desk_tail = d1;
247         }
248
249         desktop_t *p1 = d1->prev;
250         desktop_t *n1 = d1->next;
251         desktop_t *p2 = d2->prev;
252         desktop_t *n2 = d2->next;
253
254         if (p1 != NULL && p1 != d2)
255                 p1->next = d2;
256         if (n1 != NULL && n1 != d2)
257                 n1->prev = d2;
258         if (p2 != NULL && p2 != d1)
259                 p2->next = d1;
260         if (n2 != NULL && n2 != d1)
261                 n2->prev = d1;
262
263         d1->prev = p2 == d1 ? d2 : p2;
264         d1->next = n2 == d1 ? d2 : n2;
265         d2->prev = p1 == d2 ? d1 : p1;
266         d2->next = n1 == d2 ? d1 : n1;
267
268         if (m1 != m2) {
269                 for (node_t *n = first_extrema(d1->root); n != NULL; n = next_leaf(n, d1->root))
270                         translate_client(m1, m2, n->client);
271                 for (node_t *n = first_extrema(d2->root); n != NULL; n = next_leaf(n, d2->root))
272                         translate_client(m2, m1, n->client);
273                 history_swap_desktops(m1, d1, m2, d2);
274                 arrange(m1, d2);
275                 arrange(m2, d1);
276                 if (d1_focused && !d2_focused) {
277                         hide_desktop(d1);
278                         show_desktop(d2);
279                 } else if (!d1_focused && d2_focused) {
280                         show_desktop(d1);
281                         hide_desktop(d2);
282                 }
283         }
284
285         update_input_focus();
286         ewmh_update_wm_desktops();
287         ewmh_update_desktop_names();
288         ewmh_update_current_desktop();
289         put_status(SBSC_MASK_REPORT);
290 }
291
292 void show_desktop(desktop_t *d)
293 {
294         if (!visible)
295                 return;
296         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
297                 window_show(n->client->window);
298 }
299
300 void hide_desktop(desktop_t *d)
301 {
302         if (!visible)
303                 return;
304         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
305                 window_hide(n->client->window);
306 }
307
308 bool is_urgent(desktop_t *d)
309 {
310         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
311                 if (n->client->urgent)
312                         return true;
313         return false;
314 }