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