]> git.lizzy.rs Git - bspwm.git/blob - query.c
Mention the default reference
[bspwm.git] / query.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 <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "bspwm.h"
29 #include "desktop.h"
30 #include "history.h"
31 #include "parse.h"
32 #include "monitor.h"
33 #include "window.h"
34 #include "tree.h"
35 #include "query.h"
36
37 void query_tree(FILE *rsp)
38 {
39         fprintf(rsp, "{");
40         fprintf(rsp, "\"focusedMonitorId\":%u,", mon->id);
41         if (pri_mon != NULL) {
42                 fprintf(rsp, "\"primaryMonitorId\":%u,", pri_mon->id);
43         }
44         fprintf(rsp, "\"clientsCount\":%i,", clients_count);
45         fprintf(rsp, "\"monitors\":");
46         fprintf(rsp, "[");
47         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
48                 query_monitor(m, rsp);
49                 if (m->next != NULL) {
50                         fprintf(rsp, ",");
51                 }
52         }
53         fprintf(rsp, "]");
54         fprintf(rsp,",");
55         fprintf(rsp, "\"focusHistory\":");
56         query_history(rsp);
57         fprintf(rsp,",");
58         fprintf(rsp, "\"stackingList\":");
59         query_stack(rsp);
60         fprintf(rsp, "}");
61
62 }
63
64 void query_monitor(monitor_t *m, FILE *rsp)
65 {
66         fprintf(rsp, "{");
67         fprintf(rsp, "\"name\":\"%s\",", m->name);
68         fprintf(rsp, "\"id\":%u,", m->id);
69         fprintf(rsp, "\"randrId\":%u,", m->randr_id);
70         fprintf(rsp, "\"wired\":%s,", BOOL_STR(m->wired));
71         fprintf(rsp, "\"stickyCount\":%i,", m->sticky_count);
72         fprintf(rsp, "\"windowGap\":%i,", m->window_gap);
73         fprintf(rsp, "\"borderWidth\":%u,", m->border_width);
74         fprintf(rsp, "\"focusedDesktopId\":%u,", m->desk->id);
75         fprintf(rsp, "\"padding\":");
76         query_padding(m->padding, rsp);
77         fprintf(rsp,",");
78         fprintf(rsp, "\"rectangle\":");
79         query_rectangle(m->rectangle, rsp);
80         fprintf(rsp,",");
81         fprintf(rsp, "\"desktops\":");
82         fprintf(rsp, "[");
83         for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
84                 query_desktop(d, rsp);
85                 if (d->next != NULL) {
86                         fprintf(rsp,",");
87                 }
88         }
89         fprintf(rsp, "]");
90         fprintf(rsp, "}");
91 }
92
93 void query_desktop(desktop_t *d, FILE *rsp)
94 {
95         fprintf(rsp, "{");
96         fprintf(rsp, "\"name\":\"%s\",", d->name);
97         fprintf(rsp, "\"id\":%u,", d->id);
98         fprintf(rsp, "\"layout\":\"%s\",", LAYOUT_STR(d->layout));
99         fprintf(rsp, "\"windowGap\":%i,", d->window_gap);
100         fprintf(rsp, "\"borderWidth\":%u,", d->border_width);
101         fprintf(rsp, "\"focusedNodeId\":%u,", d->focus != NULL ? d->focus->id : 0);
102         fprintf(rsp, "\"padding\":");
103         query_padding(d->padding, rsp);
104         fprintf(rsp,",");
105         fprintf(rsp, "\"root\":");
106         query_node(d->root, rsp);
107         fprintf(rsp, "}");
108 }
109
110 void query_node(node_t *n, FILE *rsp)
111 {
112         if (n == NULL) {
113                 fprintf(rsp, "null");
114         } else {
115                 fprintf(rsp, "{");
116                 fprintf(rsp, "\"id\":%u,", n->id);
117                 fprintf(rsp, "\"splitType\":\"%s\",", SPLIT_TYPE_STR(n->split_type));
118                 fprintf(rsp, "\"splitRatio\":%lf,", n->split_ratio);
119                 fprintf(rsp, "\"birthRotation\":%i,", n->birth_rotation);
120                 fprintf(rsp, "\"vacant\":%s,", BOOL_STR(n->vacant));
121                 fprintf(rsp, "\"hidden\":%s,", BOOL_STR(n->hidden));
122                 fprintf(rsp, "\"sticky\":%s,", BOOL_STR(n->sticky));
123                 fprintf(rsp, "\"private\":%s,", BOOL_STR(n->private));
124                 fprintf(rsp, "\"locked\":%s,", BOOL_STR(n->locked));
125                 fprintf(rsp, "\"presel\":");
126                 query_presel(n->presel, rsp);
127                 fprintf(rsp,",");
128                 fprintf(rsp, "\"rectangle\":");
129                 query_rectangle(n->rectangle, rsp);
130                 fprintf(rsp,",");
131                 fprintf(rsp, "\"firstChild\":");
132                 query_node(n->first_child, rsp);
133                 fprintf(rsp,",");
134                 fprintf(rsp, "\"secondChild\":");
135                 query_node(n->second_child, rsp);
136                 fprintf(rsp,",");
137                 fprintf(rsp, "\"client\":");
138                 query_client(n->client, rsp);
139                 fprintf(rsp, "}");
140         }
141 }
142
143 void query_presel(presel_t *p, FILE *rsp)
144 {
145         if (p == NULL) {
146                 fprintf(rsp, "null");
147         } else {
148                 fprintf(rsp, "{\"splitDir\":\"%s\",\"splitRatio\":%lf}", SPLIT_DIR_STR(p->split_dir), p->split_ratio);
149         }
150 }
151
152 void query_client(client_t *c, FILE *rsp)
153 {
154         if (c == NULL) {
155                 fprintf(rsp, "null");
156         } else {
157                 fprintf(rsp, "{");
158                 fprintf(rsp, "\"className\":\"%s\",", c->class_name);
159                 fprintf(rsp, "\"instanceName\":\"%s\",", c->instance_name);
160                 fprintf(rsp, "\"borderWidth\":%u,", c->border_width);
161                 fprintf(rsp, "\"state\":\"%s\",", STATE_STR(c->state));
162                 fprintf(rsp, "\"lastState\":\"%s\",", STATE_STR(c->last_state));
163                 fprintf(rsp, "\"layer\":\"%s\",", LAYER_STR(c->layer));
164                 fprintf(rsp, "\"lastLayer\":\"%s\",", LAYER_STR(c->last_layer));
165                 fprintf(rsp, "\"urgent\":%s,", BOOL_STR(c->urgent));
166                 fprintf(rsp, "\"shown\":%s,", BOOL_STR(c->shown));
167                 fprintf(rsp, "\"tiledRectangle\":");
168                 query_rectangle(c->tiled_rectangle, rsp);
169                 fprintf(rsp,",");
170                 fprintf(rsp, "\"floatingRectangle\":");
171                 query_rectangle(c->floating_rectangle, rsp);
172                 fprintf(rsp, "}");
173         }
174 }
175
176 void query_rectangle(xcb_rectangle_t r, FILE *rsp)
177 {
178         fprintf(rsp, "{\"x\":%i,\"y\":%i,\"width\":%u,\"height\":%u}", r.x, r.y, r.width, r.height);
179 }
180
181 void query_padding(padding_t p, FILE *rsp)
182 {
183         fprintf(rsp, "{\"top\":%i,\"right\":%i,\"bottom\":%i,\"left\":%i}", p.top, p.right, p.bottom, p.left);
184 }
185
186 void query_history(FILE *rsp)
187 {
188         fprintf(rsp, "[");
189         for (history_t *h = history_head; h != NULL; h = h->next) {
190                 query_coordinates(&h->loc, rsp);
191                 if (h->next != NULL) {
192                         fprintf(rsp, ",");
193                 }
194         }
195         fprintf(rsp, "]");
196 }
197
198 void query_coordinates(coordinates_t *loc, FILE *rsp)
199 {
200         fprintf(rsp, "{\"monitorId\":%u,\"desktopId\":%u,\"nodeId\":%u}", loc->monitor->id, loc->desktop->id, loc->node!=NULL?loc->node->id:0);
201 }
202
203 void query_stack(FILE *rsp)
204 {
205         fprintf(rsp, "[");
206         for (stacking_list_t *s = stack_head; s != NULL; s = s->next) {
207                 fprintf(rsp, "%u", s->node->id);
208                 if (s->next != NULL) {
209                         fprintf(rsp, ",");
210                 }
211         }
212         fprintf(rsp, "]");
213 }
214
215 int query_node_ids(coordinates_t loc, node_select_t *sel, FILE *rsp)
216 {
217         int count = 0;
218         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
219                 if (loc.monitor != NULL && m != loc.monitor) {
220                         continue;
221                 }
222                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
223                         if (loc.desktop != NULL && d != loc.desktop) {
224                                 continue;
225                         }
226                         count += query_node_ids_in(d->root, d, m, loc, sel, rsp);
227                 }
228         }
229         return count;
230 }
231
232 int query_node_ids_in(node_t *n, desktop_t *d, monitor_t *m, coordinates_t loc, node_select_t *sel, FILE *rsp)
233 {
234         int count = 0;
235         if (n == NULL) {
236                 return 0;
237         } else {
238                 coordinates_t ref = {mon, mon->desk, mon->desk->focus};
239                 coordinates_t trg = {m, d, n};
240                 if ((loc.node == NULL || n == loc.node) &&
241                     (sel == NULL || node_matches(&trg, &ref, *sel))) {
242                         fprintf(rsp, "0x%08X\n", n->id);
243                         count++;
244                 }
245                 count += query_node_ids_in(n->first_child, d, m, loc, sel, rsp);
246                 count += query_node_ids_in(n->second_child, d, m, loc, sel, rsp);
247         }
248         return count;
249 }
250
251 int query_desktop_ids(coordinates_t loc, desktop_select_t *sel, FILE *rsp)
252 {
253         int count = 0;
254         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
255                 if (loc.monitor != NULL && m != loc.monitor) {
256                         continue;
257                 }
258                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
259                         coordinates_t ref = {mon, mon->desk, NULL};
260                         coordinates_t trg = {m, d, NULL};
261                         if ((loc.desktop != NULL && d != loc.desktop) ||
262                             (sel != NULL && !desktop_matches(&trg, &ref, *sel))) {
263                                 continue;
264                         }
265                         fprintf(rsp, "0x%08X\n", d->id);
266                         count++;
267                 }
268         }
269         return count;
270 }
271
272 int query_monitor_ids(coordinates_t loc, monitor_select_t *sel, FILE *rsp)
273 {
274         int count = 0;
275         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
276                 coordinates_t ref = {mon, NULL, NULL};
277                 coordinates_t trg = {m, NULL, NULL};
278                 if ((loc.monitor != NULL && m != loc.monitor) ||
279                         (sel != NULL && !monitor_matches(&trg, &ref, *sel))) {
280                         continue;
281                 }
282                 fprintf(rsp, "0x%08X\n", m->id);
283                 count++;
284         }
285         return count;
286 }
287
288 void print_modifier_mask(uint16_t m, FILE *rsp)
289 {
290         switch (m) {
291                 case XCB_MOD_MASK_SHIFT:
292                         fprintf(rsp, "shift");
293                         break;
294                 case XCB_MOD_MASK_CONTROL:
295                         fprintf(rsp, "control");
296                         break;
297                 case XCB_MOD_MASK_LOCK:
298                         fprintf(rsp, "lock");
299                         break;
300                 case XCB_MOD_MASK_1:
301                         fprintf(rsp, "mod1");
302                         break;
303                 case XCB_MOD_MASK_2:
304                         fprintf(rsp, "mod2");
305                         break;
306                 case XCB_MOD_MASK_3:
307                         fprintf(rsp, "mod3");
308                         break;
309                 case XCB_MOD_MASK_4:
310                         fprintf(rsp, "mod4");
311                         break;
312                 case XCB_MOD_MASK_5:
313                         fprintf(rsp, "mod5");
314                         break;
315         }
316 }
317
318 void print_pointer_action(pointer_action_t a, FILE *rsp)
319 {
320         switch (a) {
321                 case ACTION_FOCUS:
322                         fprintf(rsp, "focus");
323                         break;
324                 case ACTION_MOVE:
325                         fprintf(rsp, "move");
326                         break;
327                 case ACTION_RESIZE_SIDE:
328                         fprintf(rsp, "resize_side");
329                         break;
330                 case ACTION_RESIZE_CORNER:
331                         fprintf(rsp, "resize_corner");
332                         break;
333         }
334 }
335
336 node_select_t make_node_select(void)
337 {
338         node_select_t sel = {
339                 .automatic = OPTION_NONE,
340                 .focused = OPTION_NONE,
341                 .local = OPTION_NONE,
342                 .leaf = OPTION_NONE,
343                 .window = OPTION_NONE,
344                 .tiled = OPTION_NONE,
345                 .pseudo_tiled = OPTION_NONE,
346                 .floating = OPTION_NONE,
347                 .fullscreen = OPTION_NONE,
348                 .hidden = OPTION_NONE,
349                 .sticky = OPTION_NONE,
350                 .private = OPTION_NONE,
351                 .locked = OPTION_NONE,
352                 .urgent = OPTION_NONE,
353                 .same_class = OPTION_NONE,
354                 .below = OPTION_NONE,
355                 .normal = OPTION_NONE,
356                 .above = OPTION_NONE
357         };
358         return sel;
359 }
360
361 desktop_select_t make_desktop_select(void)
362 {
363         desktop_select_t sel = {
364                 .occupied = OPTION_NONE,
365                 .focused = OPTION_NONE,
366                 .urgent = OPTION_NONE,
367                 .local = OPTION_NONE
368         };
369         return sel;
370 }
371
372 monitor_select_t make_monitor_select(void)
373 {
374         monitor_select_t sel = {
375                 .occupied = OPTION_NONE,
376                 .focused = OPTION_NONE
377         };
378         return sel;
379 }
380
381 int node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
382 {
383         char *desc_copy = copy_string(desc, strlen(desc));
384         desc = desc_copy;
385         node_select_t sel = make_node_select();
386         char *colon = strrchr(desc, ':');
387
388         if (!parse_node_modifiers(colon != NULL ? colon : desc, &sel)) {
389                 free(desc_copy);
390                 return SELECTOR_BAD_MODIFIERS;
391         }
392
393         dst->monitor = ref->monitor;
394         dst->desktop = ref->desktop;
395         dst->node = NULL;
396
397         direction_t dir;
398         cycle_dir_t cyc;
399         history_dir_t hdi;
400         if (parse_direction(desc, &dir)) {
401                 find_nearest_neighbor(ref, dst, dir, sel);
402         } else if (parse_cycle_direction(desc, &cyc)) {
403                 find_closest_node(ref, dst, cyc, sel);
404         } else if (parse_history_direction(desc, &hdi)) {
405                 history_find_node(hdi, ref, dst, sel);
406         } else if (streq("last", desc)) {
407                 history_find_node(HISTORY_OLDER, ref, dst, sel);
408         } else if (streq("biggest", desc)) {
409                 dst->node = find_biggest(ref->monitor, ref->desktop, ref->node, sel);
410         } else if (streq("pointed", desc)) {
411                 xcb_window_t win;
412                 query_pointer(&win, NULL);
413                 if (locate_window(win, dst) && node_matches(dst, ref, sel)) {
414                         return SELECTOR_OK;
415                 } else {
416                         return SELECTOR_INVALID;
417                 }
418         } else if (streq("focused", desc)) {
419                 coordinates_t loc = {mon, mon->desk, mon->desk->focus};
420                 if (node_matches(&loc, ref, sel)) {
421                         dst->monitor = mon;
422                         dst->desktop = mon->desk;
423                         dst->node = mon->desk->focus;
424                 }
425         } else if (*desc == '@') {
426                 desc++;
427                 if (colon != NULL) {
428                         *colon = '\0';
429                         int ret;
430                         if ((ret = desktop_from_desc(desc, ref, dst)) == SELECTOR_OK) {
431                                 desc = colon + 1;
432                         } else {
433                                 free(desc_copy);
434                                 return ret;
435                         }
436                 }
437                 dst->node = (*desc == '/' ? dst->desktop->root : dst->desktop->focus);
438                 char *move = strtok(desc, PTH_TOK);
439                 while (move != NULL && dst->node != NULL) {
440                         if (streq("first", move) || streq("1", move)) {
441                                 dst->node = dst->node->first_child;
442                         } else if (streq("second", move) || streq("2", move)) {
443                                 dst->node = dst->node->second_child;
444                         } else if (streq("parent", move)) {
445                                 dst->node = dst->node->parent;
446                         } else if (streq("brother", move)) {
447                                 dst->node = brother_tree(dst->node);
448                         } else {
449                                 direction_t dir;
450                                 if (parse_direction(move, &dir)) {
451                                         dst->node = find_fence(dst->node, dir);
452                                 } else {
453                                         free(desc_copy);
454                                         return SELECTOR_BAD_DESCRIPTOR;
455                                 }
456                         }
457                         move = strtok(NULL, PTH_TOK);
458                 }
459                 free(desc_copy);
460                 if (dst->node != NULL) {
461                         if (node_matches(dst, ref, sel)) {
462                                 return SELECTOR_OK;
463                         } else {
464                                 return SELECTOR_INVALID;
465                         }
466                 }
467                 return SELECTOR_OK;
468         } else {
469                 uint32_t id;
470                 if (parse_id(desc, &id)) {
471                         free(desc_copy);
472                         if (find_by_id(id, dst) && node_matches(dst, ref, sel)) {
473                                 return SELECTOR_OK;
474                         } else {
475                                 return SELECTOR_INVALID;
476                         }
477                 } else {
478                         free(desc_copy);
479                         return SELECTOR_BAD_DESCRIPTOR;
480                 }
481         }
482
483         free(desc_copy);
484
485         if (dst->node == NULL) {
486                 return SELECTOR_INVALID;
487         }
488
489         return SELECTOR_OK;
490 }
491
492 int desktop_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
493 {
494         char *desc_copy = copy_string(desc, strlen(desc));
495         desc = desc_copy;
496         desktop_select_t sel = make_desktop_select();
497         char *colon = strrchr(desc, ':');
498
499         if (!parse_desktop_modifiers(colon != NULL ? colon : desc, &sel)) {
500                 free(desc_copy);
501                 return SELECTOR_BAD_MODIFIERS;
502         }
503
504         dst->desktop = NULL;
505
506         cycle_dir_t cyc;
507         history_dir_t hdi;
508         uint16_t idx;
509         uint32_t id;
510         if (parse_cycle_direction(desc, &cyc)) {
511                 find_closest_desktop(ref, dst, cyc, sel);
512         } else if (parse_history_direction(desc, &hdi)) {
513                 history_find_desktop(hdi, ref, dst, sel);
514         } else if (streq("last", desc)) {
515                 history_find_desktop(HISTORY_OLDER, ref, dst, sel);
516         } else if (streq("focused", desc)) {
517                 coordinates_t loc = {mon, mon->desk, NULL};
518                 if (desktop_matches(&loc, ref, sel)) {
519                         *dst = loc;
520                 }
521         } else if (colon != NULL) {
522                 *colon = '\0';
523                 int ret;
524                 if ((ret = monitor_from_desc(desc, ref, dst)) == SELECTOR_OK) {
525                         if (streq("focused", colon + 1)) {
526                                 coordinates_t loc = {dst->monitor, dst->monitor->desk, NULL};
527                                 if (desktop_matches(&loc, ref, sel)) {
528                                         *dst = loc;
529                                 }
530                         } else if (parse_index(colon + 1, &idx)) {
531                                 free(desc_copy);
532                                 if (desktop_from_index(idx, dst, dst->monitor) && desktop_matches(dst, ref, sel)) {
533                                         return SELECTOR_OK;
534                                 } else {
535                                         return SELECTOR_INVALID;
536                                 }
537                         } else {
538                                 free(desc_copy);
539                                 return SELECTOR_BAD_DESCRIPTOR;
540                         }
541                 } else {
542                         free(desc_copy);
543                         return ret;
544                 }
545         } else if (parse_index(desc, &idx) && desktop_from_index(idx, dst, NULL)) {
546                 free(desc_copy);
547                 if (desktop_matches(dst, ref, sel)) {
548                         return SELECTOR_OK;
549                 } else {
550                         return SELECTOR_INVALID;
551                 }
552         } else if (parse_id(desc, &id) && desktop_from_id(id, dst, NULL)) {
553                 free(desc_copy);
554                 if (desktop_matches(dst, ref, sel)) {
555                         return SELECTOR_OK;
556                 } else {
557                         return SELECTOR_INVALID;
558                 }
559         } else {
560                 if (locate_desktop(desc, dst)) {
561                         free(desc_copy);
562                         if (desktop_matches(dst, ref, sel)) {
563                                 return SELECTOR_OK;
564                         } else {
565                                 return SELECTOR_INVALID;
566                         }
567                 } else {
568                         free(desc_copy);
569                         return SELECTOR_BAD_DESCRIPTOR;
570                 }
571         }
572
573         free(desc_copy);
574
575         if (dst->desktop == NULL) {
576                 return SELECTOR_INVALID;
577         }
578
579         return SELECTOR_OK;
580 }
581
582 int monitor_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
583 {
584         char *desc_copy = copy_string(desc, strlen(desc));
585         desc = desc_copy;
586         monitor_select_t sel = make_monitor_select();
587
588         if (!parse_monitor_modifiers(desc, &sel)) {
589                 free(desc_copy);
590                 return SELECTOR_BAD_MODIFIERS;
591         }
592
593         dst->monitor = NULL;
594
595         direction_t dir;
596         cycle_dir_t cyc;
597         history_dir_t hdi;
598         uint16_t idx;
599         uint32_t id;
600         if (parse_direction(desc, &dir)) {
601                 dst->monitor = nearest_monitor(ref->monitor, dir, sel);
602         } else if (parse_cycle_direction(desc, &cyc)) {
603                 dst->monitor = closest_monitor(ref->monitor, cyc, sel);
604         } else if (parse_history_direction(desc, &hdi)) {
605                 history_find_monitor(hdi, ref, dst, sel);
606         } else if (streq("last", desc)) {
607                 history_find_monitor(HISTORY_OLDER, ref, dst, sel);
608         } else if (streq("primary", desc)) {
609                 if (pri_mon != NULL) {
610                         coordinates_t loc = {pri_mon, NULL, NULL};
611                         if (monitor_matches(&loc, ref, sel)) {
612                                 dst->monitor = pri_mon;
613                         }
614                 }
615         } else if (streq("focused", desc)) {
616                 coordinates_t loc = {mon, NULL, NULL};
617                 if (monitor_matches(&loc, ref, sel)) {
618                         dst->monitor = mon;
619                 }
620         } else if (parse_index(desc, &idx) && monitor_from_index(idx, dst)) {
621                 free(desc_copy);
622                 if (monitor_matches(dst, ref, sel)) {
623                         return SELECTOR_OK;
624                 } else {
625                         return SELECTOR_INVALID;
626                 }
627         } else if (parse_id(desc, &id) && monitor_from_id(id, dst)) {
628                 free(desc_copy);
629                 if (monitor_matches(dst, ref, sel)) {
630                         return SELECTOR_OK;
631                 } else {
632                         return SELECTOR_INVALID;
633                 }
634         } else {
635                 if (locate_monitor(desc, dst)) {
636                         free(desc_copy);
637                         if (monitor_matches(dst, ref, sel)) {
638                                 return SELECTOR_OK;
639                         } else {
640                                 return SELECTOR_INVALID;
641                         }
642                 } else {
643                         free(desc_copy);
644                         return SELECTOR_BAD_DESCRIPTOR;
645                 }
646         }
647
648         free(desc_copy);
649
650         if (dst->monitor == NULL) {
651                 return SELECTOR_INVALID;
652         }
653
654         return SELECTOR_OK;
655 }
656
657 bool locate_window(xcb_window_t win, coordinates_t *loc)
658 {
659         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
660                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
661                         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
662                                 if (n->client == NULL) {
663                                         continue;
664                                 }
665                                 if (n->id == win) {
666                                         loc->monitor = m;
667                                         loc->desktop = d;
668                                         loc->node = n;
669                                         return true;
670                                 }
671                         }
672                 }
673         }
674         return false;
675 }
676
677 bool locate_desktop(char *name, coordinates_t *loc)
678 {
679         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
680                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
681                         if (streq(d->name, name)) {
682                                 loc->monitor = m;
683                                 loc->desktop = d;
684                                 return true;
685                         }
686                 }
687         }
688         return false;
689 }
690
691 bool locate_monitor(char *name, coordinates_t *loc)
692 {
693         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
694                 if (streq(m->name, name)) {
695                         loc->monitor = m;
696                         return true;
697                 }
698         }
699         return false;
700 }
701
702 bool desktop_from_id(uint32_t id, coordinates_t *loc, monitor_t *mm)
703 {
704         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
705                 if (mm != NULL && m != mm) {
706                         continue;
707                 }
708                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
709                         if (d->id == id) {
710                                 loc->monitor = m;
711                                 loc->desktop = d;
712                                 loc->node = NULL;
713                                 return true;
714                         }
715                 }
716         }
717         return false;
718 }
719
720 bool desktop_from_index(uint16_t idx, coordinates_t *loc, monitor_t *mm)
721 {
722         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
723                 if (mm != NULL && m != mm) {
724                         continue;
725                 }
726                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next, idx--) {
727                         if (idx == 1) {
728                                 loc->monitor = m;
729                                 loc->desktop = d;
730                                 loc->node = NULL;
731                                 return true;
732                         }
733                 }
734         }
735         return false;
736 }
737
738 bool monitor_from_id(uint32_t id, coordinates_t *loc)
739 {
740         for (monitor_t *m = mon_head; m != NULL; m = m->next) {
741                 if (m->id == id) {
742                         loc->monitor = m;
743                         loc->desktop = NULL;
744                         loc->node = NULL;
745                         return true;
746                 }
747         }
748         return false;
749 }
750
751 bool monitor_from_index(int idx, coordinates_t *loc)
752 {
753         for (monitor_t *m = mon_head; m != NULL; m = m->next, idx--) {
754                 if (idx == 1) {
755                         loc->monitor = m;
756                         loc->desktop = NULL;
757                         loc->node = NULL;
758                         return true;
759                 }
760         }
761         return false;
762 }
763
764 bool node_matches(coordinates_t *loc, coordinates_t *ref, node_select_t sel)
765 {
766         if (loc->node == NULL) {
767                 return false;
768         }
769
770         if (sel.focused != OPTION_NONE &&
771             loc->node != mon->desk->focus
772             ? sel.focused == OPTION_TRUE
773             : sel.focused == OPTION_FALSE) {
774                 return false;
775         }
776
777         if (sel.automatic != OPTION_NONE &&
778             loc->node->presel != NULL
779             ? sel.automatic == OPTION_TRUE
780             : sel.automatic == OPTION_FALSE) {
781                 return false;
782         }
783
784         if (sel.local != OPTION_NONE &&
785             loc->desktop != ref->desktop
786             ? sel.local == OPTION_TRUE
787             : sel.local == OPTION_FALSE) {
788                 return false;
789         }
790
791         if (sel.leaf != OPTION_NONE &&
792             !is_leaf(loc->node)
793             ? sel.leaf == OPTION_TRUE
794             : sel.leaf == OPTION_FALSE) {
795                 return false;
796         }
797
798         if (sel.window != OPTION_NONE &&
799             loc->node->client == NULL
800             ? sel.window == OPTION_TRUE
801             : sel.window == OPTION_FALSE) {
802                 return false;
803         }
804
805 #define NFLAG(p) \
806         if (sel.p != OPTION_NONE && \
807             !loc->node->p \
808             ? sel.p == OPTION_TRUE \
809             : sel.p == OPTION_FALSE) { \
810                 return false; \
811         }
812         NFLAG(hidden)
813         NFLAG(sticky)
814         NFLAG(private)
815         NFLAG(locked)
816 #undef WFLAG
817
818         if (loc->node->client == NULL &&
819                 (sel.same_class != OPTION_NONE ||
820                  sel.tiled != OPTION_NONE ||
821                  sel.pseudo_tiled != OPTION_NONE ||
822                  sel.floating != OPTION_NONE ||
823                  sel.fullscreen != OPTION_NONE ||
824                  sel.below != OPTION_NONE ||
825                  sel.normal != OPTION_NONE ||
826                  sel.above != OPTION_NONE ||
827                  sel.urgent != OPTION_NONE)) {
828                 return false;
829         }
830
831         if (ref->node != NULL && ref->node->client != NULL &&
832             sel.same_class != OPTION_NONE &&
833             streq(loc->node->client->class_name, ref->node->client->class_name)
834             ? sel.same_class == OPTION_FALSE
835             : sel.same_class == OPTION_TRUE) {
836                 return false;
837         }
838
839 #define WSTATE(p, e) \
840         if (sel.p != OPTION_NONE && \
841             loc->node->client->state != e \
842             ? sel.p == OPTION_TRUE \
843             : sel.p == OPTION_FALSE) { \
844                 return false; \
845         }
846         WSTATE(tiled, STATE_TILED)
847         WSTATE(pseudo_tiled, STATE_PSEUDO_TILED)
848         WSTATE(floating, STATE_FLOATING)
849         WSTATE(fullscreen, STATE_FULLSCREEN)
850 #undef WSTATE
851
852 #define WLAYER(p, e) \
853         if (sel.p != OPTION_NONE && \
854             loc->node->client->layer != e \
855             ? sel.p == OPTION_TRUE \
856             : sel.p == OPTION_FALSE) { \
857                 return false; \
858         }
859         WLAYER(below, LAYER_BELOW)
860         WLAYER(normal, LAYER_NORMAL)
861         WLAYER(above, LAYER_ABOVE)
862 #undef WLAYER
863
864 #define WFLAG(p) \
865         if (sel.p != OPTION_NONE && \
866             !loc->node->client->p \
867             ? sel.p == OPTION_TRUE \
868             : sel.p == OPTION_FALSE) { \
869                 return false; \
870         }
871         WFLAG(urgent)
872 #undef WFLAG
873
874         return true;
875 }
876
877 bool desktop_matches(coordinates_t *loc, coordinates_t *ref, desktop_select_t sel)
878 {
879         if (sel.occupied != OPTION_NONE &&
880             loc->desktop->root == NULL
881             ? sel.occupied == OPTION_TRUE
882             : sel.occupied == OPTION_FALSE) {
883                 return false;
884         }
885
886         if (sel.focused != OPTION_NONE &&
887             mon->desk != loc->desktop
888             ? sel.focused == OPTION_TRUE
889             : sel.focused == OPTION_FALSE) {
890                 return false;
891         }
892
893         if (sel.urgent != OPTION_NONE &&
894             !is_urgent(loc->desktop)
895             ? sel.urgent == OPTION_TRUE
896             : sel.urgent == OPTION_FALSE) {
897                 return false;
898         }
899
900         if (sel.local != OPTION_NONE &&
901             ref->monitor != loc->monitor
902             ? sel.local == OPTION_TRUE
903             : sel.local == OPTION_FALSE) {
904                 return false;
905         }
906
907         return true;
908 }
909
910 bool monitor_matches(coordinates_t *loc, __attribute__((unused)) coordinates_t *ref, monitor_select_t sel)
911 {
912         if (sel.occupied != OPTION_NONE &&
913             loc->monitor->desk->root == NULL
914             ? sel.occupied == OPTION_TRUE
915             : sel.occupied == OPTION_FALSE) {
916                 return false;
917         }
918
919         if (sel.focused != OPTION_NONE &&
920             mon != loc->monitor
921             ? sel.focused == OPTION_TRUE
922             : sel.focused == OPTION_FALSE) {
923                 return false;
924         }
925
926         return true;
927 }