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