]> git.lizzy.rs Git - bspwm.git/blob - query.c
Implement private windows
[bspwm.git] / query.c
1 /* * Copyright (c) 2012-2013 Bastien Dejean
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification,
5  * are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation and/or
11  * other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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 ON
20  * 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 <stdio.h>
26 #include <string.h>
27 #include "bspwm.h"
28 #include "desktop.h"
29 #include "history.h"
30 #include "messages.h"
31 #include "monitor.h"
32 #include "tree.h"
33 #include "query.h"
34
35 void query_monitors(coordinates_t loc, domain_t dom, char *rsp)
36 {
37     char line[MAXLEN];
38     for (monitor_t *m = mon_head; m != NULL; m = m->next) {
39         if (loc.monitor != NULL && m != loc.monitor)
40             continue;
41         if (dom != DOMAIN_DESKTOP) {
42             if (dom == DOMAIN_MONITOR) {
43                 snprintf(line, sizeof(line), "%s\n", m->name);
44                 strncat(rsp, line, REMLEN(rsp));
45                 continue;
46             } else {
47                 snprintf(line, sizeof(line), "%s %ux%u%+i%+i %i,%i,%i,%i", m->name, m->rectangle.width, m->rectangle.height, m->rectangle.x, m->rectangle.y, m->top_padding, m->right_padding, m->bottom_padding, m->left_padding);
48                 strncat(rsp, line, REMLEN(rsp));
49                 if (m == mon)
50                     strncat(rsp, " *", REMLEN(rsp));
51                 strncat(rsp, "\n", REMLEN(rsp));
52             }
53         }
54         query_desktops(m, dom, loc, (dom == DOMAIN_DESKTOP ? 0 : 1), rsp);
55     }
56 }
57
58 void query_desktops(monitor_t *m, domain_t dom, coordinates_t loc, unsigned int depth, char *rsp)
59 {
60     char line[MAXLEN];
61     for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
62         if (loc.desktop != NULL && d != loc.desktop)
63             continue;
64         for (unsigned int i = 0; i < depth; i++)
65             strncat(rsp, "  ", REMLEN(rsp));
66         if (dom == DOMAIN_DESKTOP) {
67             snprintf(line, sizeof(line), "%s\n", d->name);
68             strncat(rsp, line, REMLEN(rsp));
69             continue;
70         } else {
71             snprintf(line, sizeof(line), "%s %u %i %u %c", d->name, d->border_width, d->window_gap, d->tags_field, (d->layout == LAYOUT_TILED ? 'T' : 'M'));
72             strncat(rsp, line, REMLEN(rsp));
73             if (d == m->desk)
74                 strncat(rsp, " *", REMLEN(rsp));
75             strncat(rsp, "\n", REMLEN(rsp));
76         }
77         query_tree(d, d->root, rsp, depth + 1);
78     }
79 }
80
81 void query_tree(desktop_t *d, node_t *n, char *rsp, unsigned int depth)
82 {
83     if (n == NULL)
84         return;
85
86     char line[MAXLEN];
87
88     for (unsigned int i = 0; i < depth; i++)
89         strncat(rsp, "  ", REMLEN(rsp));
90
91     if (is_leaf(n)) {
92         client_t *c = n->client;
93         snprintf(line, sizeof(line), "%c %s 0x%X %u %u %ux%u%+i%+i %c %c%c%c%c%c%c%c%c%c", (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), c->class_name, c->window, c->tags_field, c->border_width, c->floating_rectangle.width, c->floating_rectangle.height, c->floating_rectangle.x, c->floating_rectangle.y, (n->split_dir == DIR_UP ? 'U' : (n->split_dir == DIR_RIGHT ? 'R' : (n->split_dir == DIR_DOWN ? 'D' : 'L'))), (c->floating ? 'f' : '-'), (c->transient ? 't' : '-'), (c->fullscreen ? 'F' : '-'), (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'), (c->sticky ? 's' : '-'), (c->frame ? 'e' : '-'), (c->private ? 'i' : '-'), (n->split_mode ? 'p' : '-'));
94     } else {
95         snprintf(line, sizeof(line), "%c %c %.2f", (n->split_type == TYPE_HORIZONTAL ? 'H' : 'V'), (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), n->split_ratio);
96     }
97
98     strncat(rsp, line, REMLEN(rsp));
99
100     if (n == d->focus)
101         strncat(rsp, " *", REMLEN(rsp));
102     strncat(rsp, "\n", REMLEN(rsp));
103
104     query_tree(d, n->first_child, rsp, depth + 1);
105     query_tree(d, n->second_child, rsp, depth + 1);
106 }
107
108 void query_history(coordinates_t loc, char *rsp)
109 {
110     char line[MAXLEN];
111     for (history_t *h = history_head; h != NULL; h = h->next) {
112         if ((loc.monitor != NULL && h->loc.monitor != loc.monitor)
113                 || (loc.desktop != NULL && h->loc.desktop != loc.desktop))
114             continue;
115         xcb_window_t win = XCB_NONE;
116         if (h->loc.node != NULL)
117             win = h->loc.node->client->window;
118         snprintf(line, sizeof(line), "%s %s 0x%X", h->loc.monitor->name, h->loc.desktop->name, win);
119         strncat(rsp, line, REMLEN(rsp));
120         strncat(rsp, "\n", REMLEN(rsp));
121     }
122 }
123
124 void query_stack(char *rsp)
125 {
126     char line[MAXLEN];
127     for (stacking_list_t *s = stack_head; s != NULL; s = s->next) {
128         snprintf(line, sizeof(line), "0x%X", s->node->client->window);
129         strncat(rsp, line, REMLEN(rsp));
130         strncat(rsp, "\n", REMLEN(rsp));
131     }
132 }
133
134 void query_windows(coordinates_t loc, char *rsp)
135 {
136     char line[MAXLEN];
137
138     for (monitor_t *m = mon_head; m != NULL; m = m->next) {
139         if (loc.monitor != NULL && m != loc.monitor)
140             continue;
141         for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
142             if (loc.desktop != NULL && d != loc.desktop)
143                 continue;
144             for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
145                 if (loc.node != NULL && n != loc.node)
146                     continue;
147                 snprintf(line, sizeof(line), "0x%X\n", n->client->window);
148                 strncat(rsp, line, REMLEN(rsp));
149             }
150         }
151     }
152 }
153
154 bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
155 {
156     client_select_t sel = {CLIENT_TYPE_ALL, CLIENT_CLASS_ALL, false, false, false};
157     char *tok;
158     while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
159         tok[0] = '\0';
160         tok++;
161         if (streq("tiled", tok)) {
162             sel.type = CLIENT_TYPE_TILED;
163         } else if (streq("floating", tok)) {
164             sel.type = CLIENT_TYPE_FLOATING;
165         } else if (streq("like", tok)) {
166             sel.class = CLIENT_CLASS_EQUAL;
167         } else if (streq("unlike", tok)) {
168             sel.class = CLIENT_CLASS_DIFFER;
169         } else if (streq("urgent", tok)) {
170             sel.urgent = true;
171         } else if (streq("manual", tok)) {
172             sel.manual = true;
173         } else if (streq("local", tok)) {
174             sel.local = true;
175         }
176     }
177
178     dst->monitor = ref->monitor;
179     dst->desktop = ref->desktop;
180     dst->node = NULL;
181
182     direction_t dir;
183     cycle_dir_t cyc;
184     history_dir_t hdi;
185     if (parse_direction(desc, &dir)) {
186         dst->node = nearest_neighbor(ref->monitor, ref->desktop, ref->node, dir, sel);
187     } else if (parse_cycle_direction(desc, &cyc)) {
188         dst->node = closest_node(ref->monitor, ref->desktop, ref->node, cyc, sel);
189     } else if (parse_history_direction(desc, &hdi)) {
190         history_find_node(hdi, ref, dst, sel);
191     } else if (streq("last", desc)) {
192         history_find_node(HISTORY_OLDER, ref, dst, sel);
193     } else if (streq("biggest", desc)) {
194         dst->node = find_biggest(ref->monitor, ref->desktop, ref->node, sel);
195     } else if (streq("focused", desc)) {
196         coordinates_t loc = {mon, mon->desk, mon->desk->focus};
197         if (node_matches(&loc, ref, sel)) {
198             dst->monitor = mon;
199             dst->desktop = mon->desk;
200             dst->node = mon->desk->focus;
201         }
202     } else {
203         long int wid;
204         if (parse_window_id(desc, &wid))
205             locate_window(wid, dst);
206     }
207
208     return (dst->node != NULL);
209 }
210
211 bool desktop_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
212 {
213     desktop_select_t sel = {DESKTOP_STATUS_ALL, false, false};
214     char *tok;
215     while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
216         tok[0] = '\0';
217         tok++;
218         if (streq("free", tok)) {
219             sel.status = DESKTOP_STATUS_FREE;
220         } else if (streq("occupied", tok)) {
221             sel.status = DESKTOP_STATUS_OCCUPIED;
222         } else if (streq("urgent", tok)) {
223             sel.urgent = true;
224         } else if (streq("local", tok)) {
225             sel.local = true;
226         }
227     }
228
229     dst->desktop = NULL;
230
231     cycle_dir_t cyc;
232     history_dir_t hdi;
233     int idx;
234     if (parse_cycle_direction(desc, &cyc)) {
235         dst->monitor = ref->monitor;
236         dst->desktop = closest_desktop(ref->monitor, ref->desktop, cyc, sel);
237     } else if (parse_history_direction(desc, &hdi)) {
238         history_find_desktop(hdi, ref, dst, sel);
239     } else if (streq("last", desc)) {
240         history_find_desktop(HISTORY_OLDER, ref, dst, sel);
241     } else if (streq("focused", desc)) {
242         coordinates_t loc = {mon, mon->desk, NULL};
243         if (desktop_matches(&loc, ref, sel)) {
244             dst->monitor = mon;
245             dst->desktop = mon->desk;
246         }
247     } else if (parse_index(desc, &idx)) {
248         desktop_from_index(idx, dst);
249     } else {
250         locate_desktop(desc, dst);
251     }
252
253     return (dst->desktop != NULL);
254 }
255
256 bool monitor_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
257 {
258     desktop_select_t sel = {DESKTOP_STATUS_ALL, false, false};
259     char *tok;
260     while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
261         tok[0] = '\0';
262         tok++;
263         if (streq("free", tok)) {
264             sel.status = DESKTOP_STATUS_FREE;
265         } else if (streq("occupied", tok)) {
266             sel.status = DESKTOP_STATUS_OCCUPIED;
267         }
268     }
269
270     dst->monitor = NULL;
271
272     direction_t dir;
273     cycle_dir_t cyc;
274     history_dir_t hdi;
275     int idx;
276     if (parse_direction(desc, &dir)) {
277         dst->monitor = nearest_monitor(ref->monitor, dir, sel);
278     } else if (parse_cycle_direction(desc, &cyc)) {
279         dst->monitor = closest_monitor(ref->monitor, cyc, sel);
280     } else if (parse_history_direction(desc, &hdi)) {
281         history_find_monitor(hdi, ref, dst, sel);
282     } else if (streq("last", desc)) {
283         history_find_monitor(HISTORY_OLDER, ref, dst, sel);
284     } else if (streq("primary", desc)) {
285         coordinates_t loc = {pri_mon, pri_mon->desk, NULL};
286         if (pri_mon != NULL && desktop_matches(&loc, ref, sel))
287             dst->monitor = pri_mon;
288     } else if (streq("focused", desc)) {
289         coordinates_t loc = {mon, mon->desk, NULL};
290         if (desktop_matches(&loc, ref, sel))
291             dst->monitor = mon;
292     } else if (parse_index(desc, &idx)) {
293         monitor_from_index(idx, dst);
294     } else {
295         locate_monitor(desc, dst);
296     }
297
298     return (dst->monitor != NULL);
299 }
300
301 bool locate_window(xcb_window_t win, coordinates_t *loc)
302 {
303     for (monitor_t *m = mon_head; m != NULL; m = m->next)
304         for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
305             for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
306                 if (n->client->window == win) {
307                     loc->monitor = m;
308                     loc->desktop = d;
309                     loc->node = n;
310                     return true;
311                 }
312     return false;
313 }
314
315 bool locate_desktop(char *name, coordinates_t *loc)
316 {
317     for (monitor_t *m = mon_head; m != NULL; m = m->next)
318         for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
319             if (streq(d->name, name)) {
320                 loc->monitor = m;
321                 loc->desktop = d;
322                 return true;
323             }
324     return false;
325 }
326
327 bool locate_monitor(char *name, coordinates_t *loc)
328 {
329     for (monitor_t *m = mon_head; m != NULL; m = m->next)
330         if (streq(m->name, name)) {
331             loc->monitor = m;
332             return true;
333         }
334     return false;
335 }
336
337 bool desktop_from_index(int i, coordinates_t *loc)
338 {
339     for (monitor_t *m = mon_head; m != NULL; m = m->next)
340         for (desktop_t *d = m->desk_head; d != NULL; d = d->next, i--)
341             if (i == 1) {
342                 loc->monitor = m;
343                 loc->desktop = d;
344                 loc->node = NULL;
345                 return true;
346             }
347     return false;
348 }
349
350 bool monitor_from_index(int i, coordinates_t *loc)
351 {
352     for (monitor_t *m = mon_head; m != NULL; m = m->next, i--)
353         if (i == 1) {
354             loc->monitor = m;
355             loc->desktop = NULL;
356             loc->node = NULL;
357             return true;
358         }
359     return false;
360 }
361
362 bool node_matches(coordinates_t *loc, coordinates_t *ref, client_select_t sel)
363 {
364     if (sel.type != CLIENT_TYPE_ALL &&
365             is_tiled(loc->node->client)
366             ? sel.type == CLIENT_TYPE_FLOATING
367             : sel.type == CLIENT_TYPE_TILED)
368         return false;
369
370     if (sel.class != CLIENT_CLASS_ALL &&
371             streq(loc->node->client->class_name, ref->node->client->class_name)
372             ? sel.class == CLIENT_CLASS_DIFFER
373             : sel.class == CLIENT_CLASS_EQUAL)
374         return false;
375
376     if (sel.manual && loc->node->split_mode != MODE_MANUAL)
377         return false;
378
379     if (sel.local && loc->desktop != ref->desktop)
380         return false;
381
382     if (sel.urgent && !loc->node->client->urgent)
383         return false;
384
385     return true;
386 }
387
388 bool desktop_matches(coordinates_t *loc, coordinates_t *ref, desktop_select_t sel)
389 {
390     if (sel.status != DESKTOP_STATUS_ALL &&
391             loc->desktop->root == NULL
392             ? sel.status == DESKTOP_STATUS_OCCUPIED
393             : sel.status == DESKTOP_STATUS_FREE)
394         return false;
395
396     if (sel.urgent && !is_urgent(loc->desktop))
397         return false;
398
399     if (sel.local && ref->monitor != loc->monitor)
400         return false;
401
402     return true;
403 }