]> git.lizzy.rs Git - bspwm.git/blob - messages.c
Implement sticky windows
[bspwm.git] / messages.c
1 #include <errno.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "bspwm.h"
6 #include "desktop.h"
7 #include "ewmh.h"
8 #include "history.h"
9 #include "monitor.h"
10 #include "pointer.h"
11 #include "query.h"
12 #include "restore.h"
13 #include "rule.h"
14 #include "settings.h"
15 #include "tree.h"
16 #include "window.h"
17 #include "messages.h"
18
19 bool handle_message(char *msg, int msg_len, char *rsp)
20 {
21     int cap = INIT_CAP;
22     int num = 0;
23     char **args = malloc(cap * sizeof(char *));
24     if (args == NULL)
25         return false;
26
27     for (int i = 0, j = 0; i < msg_len; i++) {
28         if (msg[i] == 0) {
29             args[num++] = msg + j;
30             j = i + 1;
31         }
32         if (num >= cap) {
33             cap *= 2;
34             char **new = realloc(args, cap * sizeof(char *));
35             if (new == NULL) {
36                 free(args);
37                 return false;
38             } else {
39                 args = new;
40             }
41         }
42     }
43
44     if (num < 1) {
45         free(args);
46         return false;
47     }
48
49     char **args_orig = args;
50     bool ret = process_message(args, num, rsp);
51     free(args_orig);
52     return ret;
53 }
54
55 bool process_message(char **args, int num, char *rsp)
56 {
57     if (streq("window", *args)) {
58         return cmd_window(++args, --num);
59     } else if (streq("desktop", *args)) {
60         return cmd_desktop(++args, --num);
61     } else if (streq("monitor", *args)) {
62         return cmd_monitor(++args, --num);
63     } else if (streq("query", *args)) {
64         return cmd_query(++args, --num, rsp);
65     } else if (streq("restore", *args)) {
66         return cmd_restore(++args, --num);
67     } else if (streq("control", *args)) {
68         return cmd_control(++args, --num);
69     } else if (streq("rule", *args)) {
70         return cmd_rule(++args, --num, rsp);
71     } else if (streq("pointer", *args)) {
72         return cmd_pointer(++args, --num);
73     } else if (streq("config", *args)) {
74         return cmd_config(++args, --num, rsp);
75     } else if (streq("quit", *args)) {
76         return cmd_quit(++args, --num);
77     }
78
79     return false;
80 }
81
82 bool cmd_window(char **args, int num)
83 {
84     if (num < 1)
85         return false;
86
87     coordinates_t ref = {mon, mon->desk, mon->desk->focus};
88     coordinates_t trg = ref;
89
90     if (*args[0] != OPT_CHR) {
91         if (node_from_desc(*args, &ref, &trg))
92             num--, args++;
93         else
94             return false;
95     }
96
97     if (trg.node == NULL)
98         return false;
99
100     bool dirty = false;
101
102     while (num > 0) {
103         if (streq("-f", *args) || streq("--focus", *args)) {
104             coordinates_t dst = trg;
105             if (num > 1 && *(args + 1)[0] != OPT_CHR) {
106                 num--, args++;
107                 if (!node_from_desc(*args, &trg, &dst))
108                     return false;
109             }
110             focus_node(dst.monitor, dst.desktop, dst.node);
111         } else if (streq("-d", *args) || streq("--to-desktop", *args)) {
112             num--, args++;
113             coordinates_t dst;
114             if (desktop_from_desc(*args, &trg, &dst)) {
115                 transfer_node(trg.monitor, trg.desktop, trg.node, dst.monitor, dst.desktop, dst.desktop->focus);
116                 trg.monitor = dst.monitor;
117                 trg.desktop = dst.desktop;
118             } else {
119                 return false;
120             }
121         } else if (streq("-m", *args) || streq("--to-monitor", *args)) {
122             num--, args++;
123             if (num < 1)
124                 return false;
125             coordinates_t dst;
126             if (monitor_from_desc(*args, &trg, &dst)) {
127                 transfer_node(trg.monitor, trg.desktop, trg.node, dst.monitor, dst.monitor->desk, dst.monitor->desk->focus);
128                 trg.monitor = dst.monitor;
129                 trg.desktop = dst.monitor->desk;
130             } else {
131                 return false;
132             }
133         } else if (streq("-w", *args) || streq("--to-window", *args)) {
134             num--, args++;
135             if (num < 1)
136                 return false;
137             coordinates_t dst;
138             if (node_from_desc(*args, &trg, &dst))
139                 transfer_node(trg.monitor, trg.desktop, trg.node, dst.monitor, dst.desktop, dst.node);
140             else
141                 return false;
142             dirty = true;
143         } else if (streq("-s", *args) || streq("--swap", *args)) {
144             num--, args++;
145             if (num < 1)
146                 return false;
147             coordinates_t dst;
148             if (node_from_desc(*args, &trg, &dst))
149                 swap_nodes(trg.monitor, trg.desktop, trg.node, dst.monitor, dst.desktop, dst.node);
150             else
151                 return false;
152             if (trg.desktop != dst.desktop)
153                 arrange(dst.monitor, dst.desktop);
154             dirty = true;
155         } else if (streq("-t", *args) || streq("--toggle", *args)) {
156             num--, args++;
157             if (num < 1)
158                 return false;
159             char *key = strtok(*args, EQL_TOK);
160             char *val = strtok(NULL, EQL_TOK);
161             state_alter_t a = ALTER_NONE;
162             bool b;
163             if (val == NULL) {
164                 a = ALTER_TOGGLE;
165             } else {
166                 if (parse_bool(val, &b))
167                     a = ALTER_SET;
168                 else
169                     return false;
170             }
171             if (streq("fullscreen", key)) {
172                 set_fullscreen(trg.node, (a == ALTER_SET ? b : !trg.node->client->fullscreen));
173                 dirty = true;
174             } else if (streq("floating", key)) {
175                 set_floating(trg.node, (a == ALTER_SET ? b : !trg.node->client->floating));
176                 dirty = true;
177             } else if (streq("locked", key)) {
178                 set_locked(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->locked));
179             } else if (streq("sticky", key)) {
180                 set_sticky(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->sticky));
181             }
182         } else if (streq("-p", *args) || streq("--presel", *args)) {
183             num--, args++;
184             if (num < 1 || !is_tiled(trg.node->client)
185                     || trg.desktop->layout != LAYOUT_TILED)
186                 return false;
187             if (streq("cancel", *args)) {
188                 reset_mode(&trg);
189             } else {
190                 direction_t dir;
191                 if (parse_direction(*args, &dir)) {
192                     double rat = trg.node->split_ratio;
193                     if (num > 1 && *(args + 1)[0] != OPT_CHR) {
194                         num--, args++;
195                         if (sscanf(*args, "%lf", &rat) != 1 || rat <= 0 || rat >= 1)
196                             return false;
197                     }
198                     if (auto_cancel && trg.node->split_mode == MODE_MANUAL
199                             && dir == trg.node->split_dir
200                             && rat == trg.node->split_ratio) {
201                         reset_mode(&trg);
202                     } else {
203                         trg.node->split_mode = MODE_MANUAL;
204                         trg.node->split_dir = dir;
205                         trg.node->split_ratio = rat;
206                     }
207                     window_draw_border(trg.node, trg.desktop->focus == trg.node, mon == trg.monitor);
208                 } else {
209                     return false;
210                 }
211             }
212         } else if (streq("-e", *args) || streq("--edge", *args)) {
213             num--, args++;
214             if (num < 2)
215                 return false;
216             direction_t dir;
217             if (!parse_direction(*args, &dir))
218                 return false;
219             node_t *n = find_fence(trg.node, dir);
220             if (n == NULL)
221                 return false;
222             num--, args++;
223             fence_move_t fmo;
224             if (parse_fence_move(*args, &fmo)) {
225                 move_fence(n, dir, fmo);
226             } else {
227                 double rat;
228                 if (sscanf(*args, "%lf", &rat) == 1 && rat > 0 && rat < 1)
229                     n->split_ratio = rat;
230                 else
231                     return false;
232             }
233             dirty = true;
234         } else if (streq("-r", *args) || streq("--ratio", *args)) {
235             num--, args++;
236             if (num < 1)
237                 return false;
238             double rat;
239             if (sscanf(*args, "%lf", &rat) == 1 && rat > 0 && rat < 1) {
240                 trg.node->split_ratio = rat;
241                 window_draw_border(trg.node, trg.desktop->focus == trg.node, mon == trg.monitor);
242             } else {
243                 return false;
244             }
245         } else if (streq("-R", *args) || streq("--rotate", *args)) {
246             num--, args++;
247             if (num < 2)
248                 return false;
249             direction_t dir;
250             if (!parse_direction(*args, &dir))
251                 return false;
252             node_t *n = find_fence(trg.node, dir);
253             if (n == NULL)
254                 return false;
255             num--, args++;
256             int deg;
257             if (parse_degree(*args, &deg)) {
258                 rotate_tree(n, deg);
259                 dirty = true;
260             } else {
261                 return false;
262             }
263         } else if (streq("-c", *args) || streq("--close", *args)) {
264             if (num > 1)
265                 return false;
266             window_close(trg.node);
267         } else if (streq("-k", *args) || streq("--kill", *args)) {
268             if (num > 1)
269                 return false;
270             window_kill(trg.desktop, trg.node);
271             dirty = true;
272         } else {
273             return false;
274         }
275         num--, args++;
276     }
277
278     if (dirty)
279         arrange(trg.monitor, trg.desktop);
280
281     return true;
282 }
283
284 bool cmd_desktop(char **args, int num)
285 {
286     if (num < 1)
287         return false;
288
289     coordinates_t ref = {mon, mon->desk, NULL};
290     coordinates_t trg = ref;
291
292     if (*args[0] != OPT_CHR) {
293         if (desktop_from_desc(*args, &ref, &trg))
294             num--, args++;
295         else
296             return false;
297     }
298
299     bool dirty = false;
300
301     while (num > 0) {
302         if (streq("-f", *args) || streq("--focus", *args)) {
303             coordinates_t dst = trg;
304             if (num > 1 && *(args + 1)[0] != OPT_CHR) {
305                 num--, args++;
306                 if (!desktop_from_desc(*args, &trg, &dst))
307                     return false;
308             }
309             if (auto_alternate && dst.desktop == dst.monitor->desk) {
310                 desktop_select_t sel;
311                 sel.status = DESKTOP_STATUS_ALL;
312                 sel.urgency = DESKTOP_URGENCY_ALL;
313                 history_last_desktop(dst.desktop, sel, &dst);
314             }
315             focus_node(dst.monitor, dst.desktop, dst.desktop->focus);
316         } else if (streq("-m", *args) || streq("--to-monitor", *args)) {
317             num--, args++;
318             if (num < 1 || trg.monitor->desk_head == trg.monitor->desk_tail)
319                 return false;
320             coordinates_t dst;
321             if (monitor_from_desc(*args, &trg, &dst)) {
322                 transfer_desktop(trg.monitor, dst.monitor, trg.desktop);
323                 trg.monitor = dst.monitor;
324                 update_current();
325             } else {
326                 return false;
327             }
328         } else if (streq("-s", *args) || streq("--swap", *args)) {
329             num--, args++;
330             if (num < 1)
331                 return false;
332             coordinates_t dst;
333             if (desktop_from_desc(*args, &trg, &dst) && trg.monitor == dst.monitor)
334                 swap_desktops(trg.monitor, trg.desktop, dst.monitor, dst.desktop);
335             else
336                 return false;
337         } else if (streq("-l", *args) || streq("--layout", *args)) {
338             num--, args++;
339             if (num < 1)
340                 return false;
341             layout_t lyt;
342             cycle_dir_t cyc;
343             if (parse_cycle_direction(*args, &cyc))
344                 change_layout(trg.monitor, trg.desktop, (trg.desktop->layout + 1) % 2);
345             else if (parse_layout(*args, &lyt))
346                 change_layout(trg.monitor, trg.desktop, lyt);
347             else
348                 return false;
349         } else if (streq("-n", *args) || streq("--rename", *args)) {
350             num--, args++;
351             if (num < 1)
352                 return false;
353             snprintf(trg.desktop->name, sizeof(trg.desktop->name), "%s", *args);
354             ewmh_update_desktop_names();
355             put_status();
356         } else if (streq("-r", *args) || streq("--remove", *args)) {
357             if (trg.desktop->root == NULL
358                     && trg.monitor->desk_head != trg.monitor->desk_tail) {
359                 remove_desktop(trg.monitor, trg.desktop);
360                 show_desktop(trg.monitor->desk);
361                 update_current();
362                 return true;
363             } else {
364                 return false;
365             }
366         } else if (streq("-c", *args) || streq("--cancel-presel", *args)) {
367             reset_mode(&trg);
368         } else if (streq("-F", *args) || streq("--flip", *args)) {
369             num--, args++;
370             if (num < 1)
371                 return false;
372             flip_t flp;
373             if (parse_flip(*args, &flp)) {
374                 flip_tree(trg.desktop->root, flp);
375                 dirty = true;
376             } else {
377                 return false;
378             }
379         } else if (streq("-R", *args) || streq("--rotate", *args)) {
380             num--, args++;
381             if (num < 1)
382                 return false;
383             int deg;
384             if (parse_degree(*args, &deg)) {
385                 rotate_tree(trg.desktop->root, deg);
386                 dirty = true;
387             } else {
388                 return false;
389             }
390         } else if (streq("-B", *args) || streq("--balance", *args)) {
391             balance_tree(trg.desktop->root);
392             dirty = true;
393         } else if (streq("-C", *args) || streq("--circulate", *args)) {
394             num--, args++;
395             if (num < 1)
396                 return false;
397             circulate_dir_t cir;
398             if (parse_circulate_direction(*args, &cir)) {
399                 circulate_leaves(trg.monitor, trg.desktop, cir);
400                 dirty = true;
401             } else {
402                 return false;
403             }
404         } else {
405             return false;
406         }
407         num--, args++;
408     }
409
410     if (dirty)
411         arrange(trg.monitor, trg.desktop);
412
413     return true;
414 }
415
416 bool cmd_monitor(char **args, int num)
417 {
418     if (num < 1)
419         return false;
420
421     coordinates_t ref = {mon, NULL, NULL};
422     coordinates_t trg = ref;
423
424     if (*args[0] != OPT_CHR) {
425         if (monitor_from_desc(*args, &ref, &trg))
426             num--, args++;
427         else
428             return false;
429     }
430
431     while (num > 0) {
432         if (streq("-f", *args) || streq("--focus", *args)) {
433             coordinates_t dst = trg;
434             if (num > 1 && *(args + 1)[0] != OPT_CHR) {
435                 num--, args++;
436                 if (!monitor_from_desc(*args, &trg, &dst))
437                     return false;
438             }
439             if (auto_alternate && dst.monitor == mon) {
440                 desktop_select_t sel;
441                 sel.status = DESKTOP_STATUS_ALL;
442                 sel.urgency = DESKTOP_URGENCY_ALL;
443                 history_last_monitor(dst.monitor, sel, &dst);
444             }
445             focus_node(dst.monitor, dst.monitor->desk, dst.monitor->desk->focus);
446         } else if (streq("-a", *args) || streq("--add-desktops", *args)) {
447             num--, args++;
448             if (num < 1)
449                 return false;
450             while (num > 0) {
451                 add_desktop(trg.monitor, make_desktop(*args));
452                 num--, args++;
453             }
454         } else if (streq("-r", *args) || streq("--remove-desktops", *args)) {
455             num--, args++;
456             if (num < 1)
457                 return false;
458             while (num > 0) {
459                 coordinates_t dst;
460                 if (locate_desktop(*args, &dst) && dst.monitor->desk_head != dst.monitor->desk_tail && dst.desktop->root == NULL) {
461                     remove_desktop(dst.monitor, dst.desktop);
462                     show_desktop(dst.monitor->desk);
463                 }
464                 num--, args++;
465             }
466         } else if (streq("-n", *args) || streq("--rename", *args)) {
467             num--, args++;
468             if (num < 1)
469                 return false;
470             snprintf(trg.monitor->name, sizeof(trg.monitor->name), "%s", *args);
471             put_status();
472         } else if (streq("-s", *args) || streq("--swap", *args)) {
473             num--, args++;
474             if (num < 1)
475                 return false;
476             coordinates_t dst;
477             if (monitor_from_desc(*args, &trg, &dst))
478                 swap_monitors(trg.monitor, dst.monitor);
479             else
480                 return false;
481         } else {
482             return false;
483         }
484         num--, args++;
485     }
486
487     return true;
488 }
489
490 bool cmd_query(char **args, int num, char *rsp) {
491     coordinates_t ref = {mon, mon->desk, mon->desk->focus};
492     coordinates_t trg = {NULL, NULL, NULL};
493     domain_t dom = DOMAIN_TREE;
494     int d = 0, t = 0;
495
496     while (num > 0) {
497         if (streq("-T", *args) || streq("--tree", *args)) {
498             dom = DOMAIN_TREE, d++;
499         } else if (streq("-M", *args) || streq("--monitors", *args)) {
500             dom = DOMAIN_MONITOR, d++;
501         } else if (streq("-D", *args) || streq("--desktops", *args)) {
502             dom = DOMAIN_DESKTOP, d++;
503         } else if (streq("-W", *args) || streq("--windows", *args)) {
504             dom = DOMAIN_WINDOW, d++;
505         } else if (streq("-H", *args) || streq("--history", *args)) {
506             dom = DOMAIN_HISTORY, d++;
507         } else if (streq("-S", *args) || streq("--stack", *args)) {
508             dom = DOMAIN_STACK, d++;
509         } else if (streq("-m", *args) || streq("--monitor", *args)) {
510             trg.monitor = ref.monitor;
511             if (num > 1 && *(args + 1)[0] != OPT_CHR) {
512                 num--, args++;
513                 if (!monitor_from_desc(*args, &ref, &trg))
514                     return false;
515             }
516             t++;
517         } else if (streq("-d", *args) || streq("--desktop", *args)) {
518             trg.monitor = ref.monitor;
519             trg.desktop = ref.desktop;
520             if (num > 1 && *(args + 1)[0] != OPT_CHR) {
521                 num--, args++;
522                 if (!desktop_from_desc(*args, &ref, &trg))
523                     return false;
524             }
525             t++;
526         } else if (streq("-w", *args) || streq("--window", *args)) {
527             trg = ref;
528             if (num > 1 && *(args + 1)[0] != OPT_CHR) {
529                 num--, args++;
530                 if (!node_from_desc(*args, &ref, &trg))
531                     return false;
532             }
533             t++;
534         } else {
535             return false;
536         }
537         num--, args++;
538     }
539
540     if (d != 1 || t > 1)
541         return false;
542
543     if (dom == DOMAIN_HISTORY)
544         query_history(trg, rsp);
545     else if (dom == DOMAIN_STACK)
546         query_stack(rsp);
547     else if (dom == DOMAIN_WINDOW)
548         query_windows(trg, rsp);
549     else
550         query_monitors(trg, dom, rsp);
551
552     return true;
553 }
554
555 bool cmd_rule(char **args, int num, char *rsp) {
556     if (num < 1)
557         return false;
558     while (num > 0) {
559         if (streq("-a", *args) || streq("--add", *args)) {
560             num--, args++;
561             if (num < 2)
562                 return false;
563             rule_t *rule = make_rule();
564             snprintf(rule->cause.name, sizeof(rule->cause.name), "%s", *args);
565             num--, args++;
566             while (num > 0) {
567                 if (streq("--floating", *args)) {
568                     rule->effect.floating = true;
569                 } else if (streq("--fullscreen", *args)) {
570                     rule->effect.fullscreen = true;
571                 } else if (streq("--locked", *args)) {
572                     rule->effect.locked = true;
573                 } else if (streq("--sticky", *args)) {
574                     rule->effect.sticky = true;
575                 } else if (streq("--follow", *args)) {
576                     rule->effect.follow = true;
577                 } else if (streq("--focus", *args)) {
578                     rule->effect.focus = true;
579                 } else if (streq("--unmanage", *args)) {
580                     rule->effect.unmanage = true;
581                 } else if (streq("--one-shot", *args)) {
582                     rule->one_shot = true;
583                 } else if (streq("-d", *args) || streq("--desktop", *args)) {
584                     num--, args++;
585                     if (num < 1) {
586                         free(rule);
587                         rule_uid--;
588                         return false;
589                     }
590                     snprintf(rule->effect.desc, sizeof(rule->effect.desc), "%s", *args);
591                 } else {
592                     free(rule);
593                     rule_uid--;
594                     return false;
595                 }
596                 num--, args++;
597             }
598             add_rule(rule);
599         } else if (streq("-r", *args) || streq("--remove", *args)) {
600             num--, args++;
601             if (num < 1)
602                 return false;
603             unsigned int uid;
604             while (num > 0) {
605                 if (sscanf(*args, "%X", &uid) == 1)
606                     remove_rule_by_uid(uid);
607                 else if (streq("tail", *args))
608                     remove_rule(rule_tail);
609                 else if (streq("head", *args))
610                     remove_rule(rule_head);
611                 else
612                     return false;
613                 num--, args++;
614             }
615         } else if (streq("-l", *args) || streq("--list", *args)) {
616             num--, args++;
617             list_rules(num > 0 ? *args : NULL, rsp);
618         } else {
619             return false;
620         }
621         num--, args++;
622     }
623
624     return true;
625 }
626
627 bool cmd_pointer(char **args, int num) {
628     if (num < 1)
629         return false;
630     while (num > 0) {
631         if (streq("-t", *args) || streq("--track", *args)) {
632             num--, args++;
633             if (num < 2)
634                 return false;
635             int x, y;
636             if (sscanf(*args, "%i", &x) == 1 && sscanf(*(args + 1), "%i", &y) == 1)
637                 track_pointer(x, y);
638             else
639                 return false;
640         } else if (streq("-g", *args) || streq("--grab", *args)) {
641             num--, args++;
642             if (num < 1)
643                 return false;
644             pointer_action_t pac;
645             if (parse_pointer_action(*args, &pac))
646                 grab_pointer(pac);
647             else
648                 return false;
649         } else {
650             return false;
651         }
652         num--, args++;
653     }
654
655     return true;
656 }
657
658 bool cmd_restore(char **args, int num) {
659     if (num < 1)
660         return false;
661     while (num > 0) {
662         if (streq("-T", *args) || streq("--tree", *args)) {
663             num--, args++;
664             if (num < 1)
665                 return false;
666             restore_tree(*args);
667         } else if (streq("-H", *args) || streq("--history", *args)) {
668             num--, args++;
669             if (num < 1)
670                 return false;
671             restore_history(*args);
672         } else if (streq("-S", *args) || streq("--stack", *args)) {
673             num--, args++;
674             if (num < 1)
675                 return false;
676             restore_stack(*args);
677         } else {
678             return false;
679         }
680         num--, args++;
681     }
682
683     return true;
684 }
685
686 bool cmd_control(char **args, int num) {
687     if (num < 1)
688         return false;
689     while (num > 0) {
690         if (streq("--adopt-orphans", *args)) {
691             adopt_orphans();
692         } else if (streq("--put-status", *args)) {
693             put_status();
694         } else if (streq("--toggle-visibility", *args)) {
695             toggle_visibility();
696         } else {
697             return false;
698         }
699         num--, args++;
700     }
701
702     return true;
703 }
704
705 bool cmd_config(char **args, int num, char *rsp) {
706     if (num < 1)
707         return false;
708     coordinates_t ref = {mon, mon->desk, mon->desk->focus};
709     coordinates_t trg = {NULL, NULL, NULL};
710     if (*args[0] == OPT_CHR) {
711         if (streq("-d", *args) || streq("--desktop", *args)) {
712             num--, args++;
713             if (num < 1)
714                 return false;
715             if (!desktop_from_desc(*args, &ref, &trg))
716                 return false;
717         } else if (streq("-m", *args) || streq("--monitor", *args)) {
718             num--, args++;
719             if (num < 1)
720                 return false;
721             if (!monitor_from_desc(*args, &ref, &trg))
722                 return false;
723         } else {
724             return false;
725         }
726         num--, args++;
727     }
728     if (num == 2)
729         return set_setting(trg, *args, *(args + 1));
730     else if (num == 1)
731         return get_setting(trg, *args, rsp);
732     else
733         return false;
734 }
735
736 bool cmd_quit(char **args, int num) {
737     if (num > 0 && sscanf(*args, "%i", &exit_status) != 1)
738         return false;
739     quit();
740     return true;
741 }
742
743 bool set_setting(coordinates_t loc, char *name, char *value)
744 {
745 #define DESKSET(k, v) \
746         if (loc.desktop != NULL) \
747             loc.desktop->k = v; \
748         else if (loc.monitor != NULL) \
749             for (desktop_t *d = loc.monitor->desk_head; d != NULL; d = d->next) \
750                 d->k = v; \
751         else \
752             for (monitor_t *m = mon_head; m != NULL; m = m->next) \
753                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next) \
754                     d->k = v;
755     if (streq("border_width", name)) {
756         unsigned int bw;
757         if (sscanf(value, "%u", &bw) != 1)
758             return false;
759         DESKSET(border_width, bw)
760     } else if (streq("window_gap", name)) {
761         int wg;
762         if (sscanf(value, "%i", &wg) != 1)
763             return false;
764         DESKSET(window_gap, wg)
765 #undef DESKSET
766 #define MONSET(k) \
767     } else if (streq(#k, name)) { \
768         int v; \
769         if (sscanf(value, "%i", &v) != 1) \
770             return false; \
771         if (loc.monitor != NULL) \
772             loc.monitor->k = v; \
773         else \
774             for (monitor_t *m = mon_head; m!= NULL; m = m->next) \
775                 m->k = v;
776     MONSET(top_padding)
777     MONSET(right_padding)
778     MONSET(bottom_padding)
779     MONSET(left_padding)
780 #undef MONSET
781     } else if (streq("split_ratio", name)) {
782         double r;
783         if (sscanf(value, "%lf", &r) == 1 && r > 0 && r < 1)
784             split_ratio = r;
785         else
786             return false;
787         return true;
788     } else if (streq("growth_factor", name)) {
789         double g;
790         if (sscanf(value, "%lf", &g) == 1 && g > 1)
791             growth_factor = g;
792         else
793             return false;
794         return true;
795 #define SETCOLOR(s) \
796     } else if (streq(#s, name)) { \
797         snprintf(s, sizeof(s), "%s", value);
798     SETCOLOR(focused_border_color)
799     SETCOLOR(active_border_color)
800     SETCOLOR(normal_border_color)
801     SETCOLOR(presel_border_color)
802     SETCOLOR(focused_locked_border_color)
803     SETCOLOR(active_locked_border_color)
804     SETCOLOR(normal_locked_border_color)
805     SETCOLOR(focused_sticky_border_color)
806     SETCOLOR(normal_sticky_border_color)
807     SETCOLOR(urgent_border_color)
808 #undef SETCOLOR
809     } else if (streq("focus_follows_pointer", name)) {
810         bool b;
811         if (parse_bool(value, &b) && b != focus_follows_pointer) {
812             uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK : CLIENT_EVENT_MASK_FFP)};
813             for (monitor_t *m = mon_head; m != NULL; m = m->next)
814                 for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
815                     for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
816                         xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
817             if (focus_follows_pointer) {
818                 for (monitor_t *m = mon_head; m != NULL; m = m->next)
819                     window_hide(m->root);
820                 disable_motion_recorder();
821             } else {
822                 for (monitor_t *m = mon_head; m != NULL; m = m->next)
823                     window_show(m->root);
824                 enable_motion_recorder();
825             }
826             focus_follows_pointer = b;
827             return true;
828         } else {
829             return false;
830         }
831 #define SETBOOL(s) \
832     } else if (streq(#s, name)) { \
833         if (!parse_bool(value, &s)) \
834             return false;
835         SETBOOL(borderless_monocle)
836         SETBOOL(gapless_monocle)
837         SETBOOL(pointer_follows_monitor)
838         SETBOOL(apply_floating_atom)
839         SETBOOL(auto_alternate)
840         SETBOOL(auto_cancel)
841         SETBOOL(history_aware_focus)
842         SETBOOL(honor_ewmh_focus)
843 #undef SETBOOL
844     } else {
845         return false;
846     }
847
848     for (monitor_t *m = mon_head; m != NULL; m = m->next)
849         for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
850             arrange(m, d);
851
852     return true;
853 }
854
855 bool get_setting(coordinates_t loc, char *name, char* rsp)
856 {
857     if (streq("split_ratio", name))
858         snprintf(rsp, BUFSIZ, "%lf", split_ratio);
859     else if (streq("growth_factor", name))
860         snprintf(rsp, BUFSIZ, "%lf", growth_factor);
861     else if (streq("window_gap", name))
862         if (loc.desktop == NULL)
863             return false;
864         else
865             snprintf(rsp, BUFSIZ, "%i", loc.desktop->window_gap);
866     else if (streq("border_width", name))
867         if (loc.desktop == NULL)
868             return false;
869         else
870             snprintf(rsp, BUFSIZ, "%u", loc.desktop->border_width);
871 #define MONGET(k) \
872     else if (streq(#k, name)) \
873         if (loc.monitor == NULL) \
874             return false; \
875         else \
876             snprintf(rsp, BUFSIZ, "%i", loc.monitor->k);
877     MONGET(top_padding)
878     MONGET(right_padding)
879     MONGET(bottom_padding)
880     MONGET(left_padding)
881 #undef MONGET
882 #define GETCOLOR(s) \
883     else if (streq(#s, name)) \
884         snprintf(rsp, BUFSIZ, "%s", s);
885     GETCOLOR(focused_border_color)
886     GETCOLOR(active_border_color)
887     GETCOLOR(normal_border_color)
888     GETCOLOR(presel_border_color)
889     GETCOLOR(focused_locked_border_color)
890     GETCOLOR(active_locked_border_color)
891     GETCOLOR(normal_locked_border_color)
892     GETCOLOR(focused_sticky_border_color)
893     GETCOLOR(normal_sticky_border_color)
894     GETCOLOR(urgent_border_color)
895 #undef GETCOLOR
896 #define GETBOOL(s) \
897     else if (streq(#s, name)) \
898         snprintf(rsp, BUFSIZ, "%s", BOOLSTR(s));
899     GETBOOL(borderless_monocle)
900     GETBOOL(gapless_monocle)
901     GETBOOL(focus_follows_pointer)
902     GETBOOL(pointer_follows_monitor)
903     GETBOOL(apply_floating_atom)
904     GETBOOL(auto_alternate)
905     GETBOOL(auto_cancel)
906     GETBOOL(history_aware_focus)
907     GETBOOL(honor_ewmh_focus)
908 #undef GETBOOL
909     else
910         return false;
911     return true;
912 }
913
914 bool parse_bool(char *value, bool *b)
915 {
916     if (streq("true", value) || streq("on", value)) {
917         *b = true;
918         return true;
919     } else if (streq("false", value) || streq("off", value)) {
920         *b = false;
921         return true;
922     }
923     return false;
924 }
925
926 bool parse_layout(char *s, layout_t *l)
927 {
928     if (streq("monocle", s)) {
929         *l = LAYOUT_MONOCLE;
930         return true;
931     } else if (streq("tiled", s)) {
932         *l = LAYOUT_TILED;
933         return true;
934     }
935     return false;
936 }
937
938 bool parse_direction(char *s, direction_t *d)
939 {
940     if (streq("right", s)) {
941         *d = DIR_RIGHT;
942         return true;
943     } else if (streq("down", s)) {
944         *d = DIR_DOWN;
945         return true;
946     } else if (streq("left", s)) {
947         *d = DIR_LEFT;
948         return true;
949     } else if (streq("up", s)) {
950         *d = DIR_UP;
951         return true;
952     }
953     return false;
954 }
955
956 bool parse_cycle_direction(char *s, cycle_dir_t *d)
957 {
958     if (streq("next", s)) {
959         *d = CYCLE_NEXT;
960         return true;
961     } else if (streq("prev", s)) {
962         *d = CYCLE_PREV;
963         return true;
964     }
965     return false;
966 }
967
968 bool parse_circulate_direction(char *s, circulate_dir_t *d)
969 {
970     if (streq("forward", s)) {
971         *d = CIRCULATE_FORWARD;
972         return true;
973     } else if (streq("backward", s)) {
974         *d = CIRCULATE_BACKWARD;
975         return true;
976     }
977     return false;
978 }
979
980 bool parse_flip(char *s, flip_t *f)
981 {
982     if (streq("horizontal", s)) {
983         *f = FLIP_HORIZONTAL;
984         return true;
985     } else if (streq("vertical", s)) {
986         *f = FLIP_VERTICAL;
987         return true;
988     }
989     return false;
990 }
991
992 bool parse_fence_move(char *s, fence_move_t *m)
993 {
994     if (streq("push", s)) {
995         *m = MOVE_PUSH;
996         return true;
997     } else if (streq("pull", s)) {
998         *m = MOVE_PULL;
999         return true;
1000     }
1001     return false;
1002 }
1003
1004 bool parse_pointer_action(char *s, pointer_action_t *a)
1005 {
1006     if (streq("move", s)) {
1007         *a = ACTION_MOVE;
1008         return true;
1009     } else if (streq("resize_corner", s)) {
1010         *a = ACTION_RESIZE_CORNER;
1011         return true;
1012     } else if (streq("resize_side", s)) {
1013         *a = ACTION_RESIZE_SIDE;
1014         return true;
1015     } else if (streq("focus", s)) {
1016         *a = ACTION_FOCUS;
1017         return true;
1018     }
1019     return false;
1020 }
1021
1022 bool parse_degree(char *s, int *d)
1023 {
1024     int i = atoi(s);
1025     while (i < 0)
1026         i += 360;
1027     while (i > 359)
1028         i -= 360;
1029     if ((i % 90) != 0) {
1030         return false;
1031     } else {
1032         *d = i;
1033         return true;
1034     }
1035 }
1036
1037 bool parse_window_id(char *s, long int *i)
1038 {
1039     char *end;
1040     errno = 0;
1041     long int ret = strtol(s, &end, 0);
1042     if (errno != 0 || *end != '\0')
1043         return false;
1044     else
1045         *i = ret;
1046     return true;
1047 }
1048
1049 bool parse_index(char *s, int *i)
1050 {
1051     return sscanf(s, "^%i", i) == 1;
1052 }