]> git.lizzy.rs Git - bspwm.git/blob - desktop.c
Neutralize obscuring windows in `pseudo_focus`
[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         put_status(SBSC_MASK_DESKTOP_FOCUS, "desktop_focus %s %s\n", m->name, d->name);
46
47         show_desktop(d);
48         hide_desktop(mon->desk);
49
50         mon->desk = d;
51
52         ewmh_update_current_desktop();
53         put_status(SBSC_MASK_REPORT);
54 }
55
56 desktop_t *closest_desktop(monitor_t *m, desktop_t *d, cycle_dir_t dir, desktop_select_t sel)
57 {
58         desktop_t *f = (dir == CYCLE_PREV ? d->prev : d->next);
59         if (f == NULL)
60                 f = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head);
61
62         while (f != d) {
63                 coordinates_t loc = {m, f, NULL};
64                 if (desktop_matches(&loc, &loc, sel))
65                         return f;
66                 f = (dir == CYCLE_PREV ? f->prev : f->next);
67                 if (f == NULL)
68                         f = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head);
69         }
70
71         return NULL;
72 }
73
74 void change_layout(monitor_t *m, desktop_t *d, layout_t l)
75 {
76         put_status(SBSC_MASK_DESKTOP_LAYOUT, "desktop_layout %s %s %s\n", m->name, d->name, l==LAYOUT_TILED?"tiled":"monocle");
77         d->layout = l;
78         arrange(m, d);
79         if (d == m->desk) {
80                 put_status(SBSC_MASK_REPORT);
81         }
82 }
83
84 void transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d)
85 {
86         if (ms == md)
87                 return;
88
89         put_status(SBSC_MASK_DESKTOP_TRANSFER, "desktop_transfer %s %s %s\n", ms->name, d->name, md->name);
90
91         desktop_t *dd = ms->desk;
92         unlink_desktop(ms, d);
93         insert_desktop(md, d);
94
95         if (d == dd) {
96                 if (ms->desk != NULL) {
97                         show_desktop(ms->desk);
98                 }
99                 if (md->desk != d) {
100                         hide_desktop(d);
101                 }
102         }
103
104         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
105                 translate_client(ms, md, n->client);
106         }
107
108         arrange(md, d);
109
110         if (d != dd && md->desk == d) {
111                 show_desktop(d);
112         }
113
114         history_transfer_desktop(md, d);
115
116         ewmh_update_wm_desktops();
117         ewmh_update_desktop_names();
118         ewmh_update_current_desktop();
119         put_status(SBSC_MASK_REPORT);
120 }
121
122 desktop_t *make_desktop(const char *name)
123 {
124         desktop_t *d = malloc(sizeof(desktop_t));
125         if (name == NULL)
126                 snprintf(d->name, sizeof(d->name), "%s%d", DEFAULT_DESK_NAME, ++desktop_uid);
127         else
128                 snprintf(d->name, sizeof(d->name), "%s", name);
129         d->prev = d->next = NULL;
130         d->root = d->focus = NULL;
131         initialize_desktop(d);
132         return d;
133 }
134
135 void rename_desktop(desktop_t *d, const char *name)
136 {
137         snprintf(d->name, sizeof(d->name), "%s", name);
138         ewmh_update_desktop_names();
139 }
140
141 void initialize_desktop(desktop_t *d)
142 {
143         d->layout = LAYOUT_TILED;
144         d->top_padding = d->right_padding = d->bottom_padding = d->left_padding = 0;
145         d->window_gap = window_gap;
146         d->border_width = border_width;
147 }
148
149 void insert_desktop(monitor_t *m, desktop_t *d)
150 {
151         if (m->desk == NULL) {
152                 m->desk = d;
153                 m->desk_head = d;
154                 m->desk_tail = d;
155         } else {
156                 m->desk_tail->next = d;
157                 d->prev = m->desk_tail;
158                 m->desk_tail = d;
159         }
160 }
161
162 void add_desktop(monitor_t *m, desktop_t *d)
163 {
164         PRINTF("add desktop %s\n", d->name);
165         put_status(SBSC_MASK_DESKTOP_ADD, "desktop_add %s %s\n", m->name, d->name);
166
167         insert_desktop(m, d);
168         num_desktops++;
169         ewmh_update_number_of_desktops();
170         ewmh_update_desktop_names();
171         ewmh_update_wm_desktops();
172         put_status(SBSC_MASK_REPORT);
173 }
174
175 void empty_desktop(desktop_t *d)
176 {
177         destroy_tree(d->root);
178         d->root = d->focus = NULL;
179 }
180
181 void unlink_desktop(monitor_t *m, desktop_t *d)
182 {
183         desktop_t *prev = d->prev;
184         desktop_t *next = d->next;
185         desktop_t *last_desk = history_get_desktop(m, d);
186         if (prev != NULL)
187                 prev->next = next;
188         if (next != NULL)
189                 next->prev = prev;
190         if (m->desk_head == d)
191                 m->desk_head = next;
192         if (m->desk_tail == d)
193                 m->desk_tail = prev;
194         if (m->desk == d)
195                 m->desk = (last_desk == NULL ? (prev == NULL ? next : prev) : last_desk);
196         d->prev = d->next = NULL;
197 }
198
199 void remove_desktop(monitor_t *m, desktop_t *d)
200 {
201         PRINTF("remove desktop %s\n", d->name);
202         put_status(SBSC_MASK_DESKTOP_REMOVE, "desktop_remove %s\n", d->name);
203
204         unlink_desktop(m, d);
205         history_remove(d, NULL);
206         empty_desktop(d);
207         free(d);
208
209         num_desktops--;
210
211         ewmh_update_current_desktop();
212         ewmh_update_number_of_desktops();
213         ewmh_update_desktop_names();
214
215         put_status(SBSC_MASK_REPORT);
216 }
217
218 void merge_desktops(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop_t *dd)
219 {
220         if (ds == NULL || dd == NULL || ds == dd)
221                 return;
222         node_t *n = first_extrema(ds->root);
223         while (n != NULL) {
224                 node_t *next = next_leaf(n, ds->root);
225                 transfer_node(ms, ds, n, md, dd, dd->focus);
226                 n = next;
227         }
228 }
229
230 void swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2)
231 {
232         if (d1 == NULL || d2 == NULL || d1 == d2)
233                 return;
234
235         PRINTF("swap desktops %s %s\n", d1->name, d2->name);
236         put_status(SBSC_MASK_DESKTOP_SWAP, "desktop_swap %s %s %s %s\n", m1->name, d1->name, m2->name, d2->name);
237
238         bool d1_focused = (m1->desk == d1);
239         bool d2_focused = (m2->desk == d2);
240
241         if (m1 != m2) {
242                 if (m1->desk == d1)
243                         m1->desk = d2;
244                 if (m1->desk_head == d1)
245                         m1->desk_head = d2;
246                 if (m1->desk_tail == d1)
247                         m1->desk_tail = d2;
248                 if (m2->desk == d2)
249                         m2->desk = d1;
250                 if (m2->desk_head == d2)
251                         m2->desk_head = d1;
252                 if (m2->desk_tail == d2)
253                         m2->desk_tail = d1;
254         } else {
255                 if (m1->desk_head == d1)
256                         m1->desk_head = d2;
257                 else if (m1->desk_head == d2)
258                         m1->desk_head = d1;
259                 if (m1->desk_tail == d1)
260                         m1->desk_tail = d2;
261                 else if (m1->desk_tail == d2)
262                         m1->desk_tail = d1;
263         }
264
265         desktop_t *p1 = d1->prev;
266         desktop_t *n1 = d1->next;
267         desktop_t *p2 = d2->prev;
268         desktop_t *n2 = d2->next;
269
270         if (p1 != NULL && p1 != d2)
271                 p1->next = d2;
272         if (n1 != NULL && n1 != d2)
273                 n1->prev = d2;
274         if (p2 != NULL && p2 != d1)
275                 p2->next = d1;
276         if (n2 != NULL && n2 != d1)
277                 n2->prev = d1;
278
279         d1->prev = p2 == d1 ? d2 : p2;
280         d1->next = n2 == d1 ? d2 : n2;
281         d2->prev = p1 == d2 ? d1 : p1;
282         d2->next = n1 == d2 ? d1 : n1;
283
284         if (m1 != m2) {
285                 for (node_t *n = first_extrema(d1->root); n != NULL; n = next_leaf(n, d1->root))
286                         translate_client(m1, m2, n->client);
287                 for (node_t *n = first_extrema(d2->root); n != NULL; n = next_leaf(n, d2->root))
288                         translate_client(m2, m1, n->client);
289                 history_swap_desktops(m1, d1, m2, d2);
290                 arrange(m1, d2);
291                 arrange(m2, d1);
292                 if (d1_focused && !d2_focused) {
293                         hide_desktop(d1);
294                         show_desktop(d2);
295                 } else if (!d1_focused && d2_focused) {
296                         show_desktop(d1);
297                         hide_desktop(d2);
298                 }
299         }
300
301         update_input_focus();
302         ewmh_update_wm_desktops();
303         ewmh_update_desktop_names();
304         ewmh_update_current_desktop();
305         put_status(SBSC_MASK_REPORT);
306 }
307
308 void show_desktop(desktop_t *d)
309 {
310         if (!visible)
311                 return;
312         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
313                 window_show(n->client->window);
314 }
315
316 void hide_desktop(desktop_t *d)
317 {
318         if (!visible)
319                 return;
320         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
321                 window_hide(n->client->window);
322 }
323
324 bool is_urgent(desktop_t *d)
325 {
326         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
327                 if (n->client->urgent)
328                         return true;
329         return false;
330 }