18 bool handle_message(char *msg, int msg_len, char *rsp)
22 char **args = malloc(cap * sizeof(char *));
26 for (int i = 0, j = 0; i < msg_len; i++) {
28 args[num++] = msg + j;
33 char **new = realloc(args, cap * sizeof(char *));
48 char **args_orig = args;
49 bool ret = process_message(args, num, rsp);
54 bool process_message(char **args, int num, char *rsp)
56 if (streq("window", *args)) {
57 return cmd_window(++args, --num);
58 } else if (streq("desktop", *args)) {
59 return cmd_desktop(++args, --num);
60 } else if (streq("monitor", *args)) {
61 return cmd_monitor(++args, --num);
62 } else if (streq("query", *args)) {
63 return cmd_query(++args, --num, rsp);
64 } else if (streq("restore", *args)) {
65 return cmd_restore(++args, --num);
66 } else if (streq("control", *args)) {
67 return cmd_control(++args, --num);
68 } else if (streq("rule", *args)) {
69 return cmd_rule(++args, --num, rsp);
70 } else if (streq("pointer", *args)) {
71 return cmd_pointer(++args, --num);
72 } else if (streq("config", *args)) {
73 return cmd_config(++args, --num, rsp);
74 } else if (streq("quit", *args)) {
75 return cmd_quit(++args, --num);
81 bool cmd_window(char **args, int num)
86 coordinates_t ref = {mon, mon->desk, mon->desk->focus};
87 coordinates_t trg = ref;
89 if (*args[0] != OPT_CHR) {
90 if (node_from_desc(*args, &ref, &trg))
102 if (streq("-f", *args) || streq("--focus", *args)) {
103 coordinates_t dst = trg;
104 if (num > 1 && *(args + 1)[0] != OPT_CHR) {
106 if (!node_from_desc(*args, &trg, &dst))
109 focus_node(dst.monitor, dst.desktop, dst.node);
110 } else if (streq("-d", *args) || streq("--to-desktop", *args)) {
113 if (desktop_from_desc(*args, &trg, &dst)) {
114 transfer_node(trg.monitor, trg.desktop, dst.monitor, dst.desktop, trg.node);
115 trg.monitor = dst.monitor;
116 trg.desktop = dst.desktop;
120 } else if (streq("-m", *args) || streq("--to-monitor", *args)) {
125 if (monitor_from_desc(*args, &trg, &dst)) {
126 transfer_node(trg.monitor, trg.desktop, dst.monitor, dst.monitor->desk, trg.node);
127 trg.monitor = dst.monitor;
128 trg.desktop = dst.monitor->desk;
132 } else if (streq("-w", *args) || streq("--to-window", *args)) {
137 if (node_from_desc(*args, &trg, &dst))
138 transplant_node(trg.monitor, trg.desktop, trg.node, dst.node);
142 } else if (streq("-s", *args) || streq("--swap", *args)) {
147 if (node_from_desc(*args, &trg, &dst))
148 swap_nodes(trg.node, dst.node);
152 } else if (streq("-t", *args) || streq("--toggle", *args)) {
156 char *key = strtok(*args, EQL_TOK);
157 char *val = strtok(NULL, EQL_TOK);
158 state_alter_t a = ALTER_NONE;
163 if (parse_bool(val, &b))
168 if (streq("fullscreen", key)) {
169 set_fullscreen(trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->fullscreen));
171 } else if (streq("floating", key)) {
172 set_floating(trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->floating));
174 } else if (streq("locked", key)) {
175 set_locked(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->locked));
177 } else if (streq("-p", *args) || streq("--presel", *args)) {
179 if (num < 1 || !is_tiled(trg.node->client)
180 || trg.desktop->layout != LAYOUT_TILED)
182 if (streq("cancel", *args)) {
186 if (parse_direction(*args, &dir)) {
187 double rat = trg.node->split_ratio;
188 if (num > 1 && *(args + 1)[0] != OPT_CHR) {
190 if (sscanf(*args, "%lf", &rat) != 1 || rat <= 0 || rat >= 1)
193 if (auto_cancel && trg.node->split_mode == MODE_MANUAL
194 && dir == trg.node->split_dir
195 && rat == trg.node->split_ratio) {
198 trg.node->split_mode = MODE_MANUAL;
199 trg.node->split_dir = dir;
200 trg.node->split_ratio = rat;
202 window_draw_border(trg.node, trg.desktop->focus == trg.node, mon == trg.monitor);
207 } else if (streq("-e", *args) || streq("--edge", *args)) {
212 if (!parse_direction(*args, &dir))
214 node_t *n = find_fence(trg.node, dir);
219 if (parse_fence_move(*args, &fmo)) {
220 move_fence(n, dir, fmo);
223 if (sscanf(*args, "%lf", &rat) == 1 && rat > 0 && rat < 1)
224 n->split_ratio = rat;
229 } else if (streq("-r", *args) || streq("--ratio", *args)) {
234 if (sscanf(*args, "%lf", &rat) == 1 && rat > 0 && rat < 1) {
235 trg.node->split_ratio = rat;
236 window_draw_border(trg.node, trg.desktop->focus == trg.node, mon == trg.monitor);
240 } else if (streq("-R", *args) || streq("--rotate", *args)) {
245 if (!parse_direction(*args, &dir))
247 node_t *n = find_fence(trg.node, dir);
252 if (parse_degree(*args, °)) {
258 } else if (streq("-c", *args) || streq("--close", *args)) {
261 window_close(trg.node);
262 } else if (streq("-k", *args) || streq("--kill", *args)) {
265 window_kill(trg.desktop, trg.node);
274 arrange(trg.monitor, trg.desktop);
279 bool cmd_desktop(char **args, int num)
284 coordinates_t ref = {mon, mon->desk, NULL};
285 coordinates_t trg = ref;
287 if (*args[0] != OPT_CHR) {
288 if (desktop_from_desc(*args, &ref, &trg))
297 if (streq("-f", *args) || streq("--focus", *args)) {
298 coordinates_t dst = trg;
299 if (num > 1 && *(args + 1)[0] != OPT_CHR) {
301 if (!desktop_from_desc(*args, &trg, &dst))
304 if (auto_alternate && dst.desktop == dst.monitor->desk && dst.monitor->last_desk != NULL)
305 dst.desktop = dst.monitor->last_desk;
306 focus_node(dst.monitor, dst.desktop, dst.desktop->focus);
307 } else if (streq("-m", *args) || streq("--to-monitor", *args)) {
309 if (num < 1 || trg.monitor->desk_head == trg.monitor->desk_tail)
312 if (monitor_from_desc(*args, &trg, &dst)) {
313 transfer_desktop(trg.monitor, dst.monitor, trg.desktop);
314 trg.monitor = dst.monitor;
319 } else if (streq("-s", *args) || streq("--swap", *args)) {
324 if (desktop_from_desc(*args, &trg, &dst) && trg.monitor == dst.monitor)
325 swap_desktops(dst.monitor, trg.desktop, dst.desktop);
328 } else if (streq("-l", *args) || streq("--layout", *args)) {
334 if (parse_cycle_direction(*args, &cyc))
335 change_layout(trg.monitor, trg.desktop, (trg.desktop->layout + 1) % 2);
336 else if (parse_layout(*args, &lyt))
337 change_layout(trg.monitor, trg.desktop, lyt);
340 } else if (streq("-n", *args) || streq("--rename", *args)) {
344 snprintf(trg.desktop->name, sizeof(trg.desktop->name), "%s", *args);
345 ewmh_update_desktop_names();
347 } else if (streq("-r", *args) || streq("--remove", *args)) {
348 if (trg.desktop->root == NULL
349 && trg.monitor->desk_head != trg.monitor->desk_tail) {
350 remove_desktop(trg.monitor, trg.desktop);
351 show_desktop(trg.monitor->desk);
357 } else if (streq("-c", *args) || streq("--cancel-presel", *args)) {
359 } else if (streq("-F", *args) || streq("--flip", *args)) {
364 if (parse_flip(*args, &flp)) {
365 flip_tree(trg.desktop->root, flp);
370 } else if (streq("-R", *args) || streq("--rotate", *args)) {
375 if (parse_degree(*args, °)) {
376 rotate_tree(trg.desktop->root, deg);
381 } else if (streq("-B", *args) || streq("--balance", *args)) {
382 balance_tree(trg.desktop->root);
384 } else if (streq("-C", *args) || streq("--circulate", *args)) {
389 if (parse_circulate_direction(*args, &cir)) {
390 circulate_leaves(trg.monitor, trg.desktop, cir);
402 arrange(trg.monitor, trg.desktop);
407 bool cmd_monitor(char **args, int num)
412 coordinates_t ref = {mon, NULL, NULL};
413 coordinates_t trg = ref;
415 if (*args[0] != OPT_CHR) {
416 if (monitor_from_desc(*args, &ref, &trg))
423 if (streq("-f", *args) || streq("--focus", *args)) {
424 coordinates_t dst = trg;
425 if (num > 1 && *(args + 1)[0] != OPT_CHR) {
427 if (!monitor_from_desc(*args, &trg, &dst))
430 if (auto_alternate && dst.monitor == mon && last_mon != NULL)
431 dst.monitor = last_mon;
432 focus_node(dst.monitor, dst.monitor->desk, dst.monitor->desk->focus);
433 } else if (streq("-a", *args) || streq("--add-desktops", *args)) {
438 add_desktop(trg.monitor, make_desktop(*args));
441 } else if (streq("-r", *args) || streq("--remove-desktops", *args)) {
447 if (locate_desktop(*args, &dst) && dst.monitor->desk_head != dst.monitor->desk_tail && dst.desktop->root == NULL) {
448 remove_desktop(dst.monitor, dst.desktop);
449 show_desktop(dst.monitor->desk);
453 } else if (streq("-n", *args) || streq("--rename", *args)) {
457 snprintf(trg.monitor->name, sizeof(trg.monitor->name), "%s", *args);
459 } else if (streq("-s", *args) || streq("--swap", *args)) {
464 if (monitor_from_desc(*args, &trg, &dst))
465 swap_monitors(trg.monitor, dst.monitor);
477 bool cmd_query(char **args, int num, char *rsp) {
478 coordinates_t ref = {mon, mon->desk, mon->desk->focus};
479 coordinates_t trg = {NULL, NULL, NULL};
480 domain_t dom = DOMAIN_TREE;
484 if (streq("-T", *args) || streq("--tree", *args)) {
485 dom = DOMAIN_TREE, d++;
486 } else if (streq("-M", *args) || streq("--monitors", *args)) {
487 dom = DOMAIN_MONITOR, d++;
488 } else if (streq("-D", *args) || streq("--desktops", *args)) {
489 dom = DOMAIN_DESKTOP, d++;
490 } else if (streq("-W", *args) || streq("--windows", *args)) {
491 dom = DOMAIN_WINDOW, d++;
492 } else if (streq("-H", *args) || streq("--history", *args)) {
493 dom = DOMAIN_HISTORY, d++;
494 } else if (streq("-m", *args) || streq("--monitor", *args)) {
495 trg.monitor = ref.monitor;
496 if (num > 1 && *(args + 1)[0] != OPT_CHR) {
498 if (!monitor_from_desc(*args, &ref, &trg))
502 } else if (streq("-d", *args) || streq("--desktop", *args)) {
503 trg.monitor = ref.monitor;
504 trg.desktop = ref.desktop;
505 if (num > 1 && *(args + 1)[0] != OPT_CHR) {
507 if (!desktop_from_desc(*args, &ref, &trg))
511 } else if (streq("-w", *args) || streq("--window", *args)) {
513 if (num > 1 && *(args + 1)[0] != OPT_CHR) {
515 if (!node_from_desc(*args, &ref, &trg))
528 if (dom == DOMAIN_HISTORY)
529 query_history(trg, rsp);
530 else if (dom == DOMAIN_WINDOW)
531 query_windows(trg, rsp);
533 query_monitors(trg, dom, rsp);
538 bool cmd_rule(char **args, int num, char *rsp) {
542 if (streq("-a", *args) || streq("--add", *args)) {
546 rule_t *rule = make_rule();
547 snprintf(rule->cause.name, sizeof(rule->cause.name), "%s", *args);
550 if (streq("--floating", *args)) {
551 rule->effect.floating = true;
552 } else if (streq("--fullscreen", *args)) {
553 rule->effect.fullscreen = true;
554 } else if (streq("--locked", *args)) {
555 rule->effect.locked = true;
556 } else if (streq("--follow", *args)) {
557 rule->effect.follow = true;
558 } else if (streq("--focus", *args)) {
559 rule->effect.focus = true;
560 } else if (streq("--unmanage", *args)) {
561 rule->effect.unmanage = true;
562 } else if (streq("--one-shot", *args)) {
563 rule->one_shot = true;
564 } else if (streq("-d", *args) || streq("--desktop", *args)) {
571 snprintf(rule->effect.desc, sizeof(rule->effect.desc), "%s", *args);
580 } else if (streq("-r", *args) || streq("--remove", *args)) {
586 if (sscanf(*args, "%X", &uid) == 1)
587 remove_rule_by_uid(uid);
588 else if (streq("tail", *args))
589 remove_rule(rule_tail);
590 else if (streq("head", *args))
591 remove_rule(rule_head);
596 } else if (streq("-l", *args) || streq("--list", *args)) {
598 list_rules(num > 0 ? *args : NULL, rsp);
608 bool cmd_pointer(char **args, int num) {
612 if (streq("-t", *args) || streq("--track", *args)) {
617 if (sscanf(*args, "%i", &x) == 1 && sscanf(*(args + 1), "%i", &y) == 1)
621 } else if (streq("-g", *args) || streq("--grab", *args)) {
625 pointer_action_t pac;
626 if (parse_pointer_action(*args, &pac))
639 bool cmd_restore(char **args, int num) {
643 if (streq("-T", *args) || streq("--tree", *args)) {
648 } else if (streq("-H", *args) || streq("--history", *args)) {
652 restore_history(*args);
662 bool cmd_control(char **args, int num) {
666 if (streq("--adopt-orphans", *args)) {
668 } else if (streq("--put-status", *args)) {
670 } else if (streq("--toggle-visibility", *args)) {
681 bool cmd_config(char **args, int num, char *rsp) {
684 coordinates_t ref = {mon, mon->desk, mon->desk->focus};
685 coordinates_t trg = {NULL, NULL, NULL};
686 if (*args[0] == OPT_CHR) {
687 if (streq("-d", *args) || streq("--desktop", *args)) {
691 if (!desktop_from_desc(*args, &ref, &trg))
693 } else if (streq("-m", *args) || streq("--monitor", *args)) {
697 if (!monitor_from_desc(*args, &ref, &trg))
705 return set_setting(trg, *args, *(args + 1));
707 return get_setting(trg, *args, rsp);
712 bool cmd_quit(char **args, int num) {
713 if (num > 0 && sscanf(*args, "%i", &exit_status) != 1)
719 bool set_setting(coordinates_t loc, char *name, char *value)
721 if (streq("border_width", name)) {
722 if (sscanf(value, "%u", &border_width) != 1)
724 } else if (streq("window_gap", name)) {
726 if (sscanf(value, "%i", &wg) != 1)
728 if (loc.desktop != NULL)
729 loc.desktop->window_gap = wg;
730 else if (loc.monitor != NULL)
731 for (desktop_t *d = loc.monitor->desk_head; d != NULL; d = d->next)
734 for (monitor_t *m = mon_head; m != NULL; m = m->next)
735 for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
738 } else if (streq(#k, name)) { \
740 if (sscanf(value, "%i", &v) != 1) \
742 if (loc.monitor != NULL) \
743 loc.monitor->k = v; \
745 for (monitor_t *m = mon_head; m!= NULL; m = m->next) \
748 MONSET(right_padding)
749 MONSET(bottom_padding)
752 } else if (streq("split_ratio", name)) {
754 if (sscanf(value, "%lf", &r) == 1 && r > 0 && r < 1)
759 } else if (streq("growth_factor", name)) {
761 if (sscanf(value, "%lf", &g) == 1 && g > 1)
766 #define SETCOLOR(s) \
767 } else if (streq(#s, name)) { \
768 snprintf(s, sizeof(s), "%s", value);
769 SETCOLOR(focused_border_color)
770 SETCOLOR(active_border_color)
771 SETCOLOR(normal_border_color)
772 SETCOLOR(presel_border_color)
773 SETCOLOR(focused_locked_border_color)
774 SETCOLOR(active_locked_border_color)
775 SETCOLOR(normal_locked_border_color)
776 SETCOLOR(urgent_border_color)
778 } else if (streq("focus_follows_pointer", name)) {
780 if (parse_bool(value, &b) && b != focus_follows_pointer) {
781 uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK : CLIENT_EVENT_MASK_FFP)};
782 for (monitor_t *m = mon_head; m != NULL; m = m->next)
783 for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
784 for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
785 xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
786 if (focus_follows_pointer) {
787 for (monitor_t *m = mon_head; m != NULL; m = m->next)
788 window_hide(m->root);
789 disable_motion_recorder();
791 for (monitor_t *m = mon_head; m != NULL; m = m->next)
792 window_show(m->root);
793 enable_motion_recorder();
795 focus_follows_pointer = b;
801 } else if (streq(#s, name)) { \
802 if (!parse_bool(value, &s)) \
804 SETBOOL(borderless_monocle)
805 SETBOOL(gapless_monocle)
806 SETBOOL(pointer_follows_monitor)
807 SETBOOL(apply_floating_atom)
808 SETBOOL(auto_alternate)
810 SETBOOL(history_aware_focus)
811 SETBOOL(honor_ewmh_focus)
817 for (monitor_t *m = mon_head; m != NULL; m = m->next)
818 for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
824 bool get_setting(coordinates_t loc, char *name, char* rsp)
826 if (streq("border_width", name))
827 snprintf(rsp, BUFSIZ, "%u", border_width);
828 else if (streq("split_ratio", name))
829 snprintf(rsp, BUFSIZ, "%lf", split_ratio);
830 else if (streq("growth_factor", name))
831 snprintf(rsp, BUFSIZ, "%lf", growth_factor);
832 else if (streq("window_gap", name))
833 if (loc.desktop == NULL)
836 snprintf(rsp, BUFSIZ, "%i", loc.desktop->window_gap);
838 else if (streq(#k, name)) \
839 if (loc.monitor == NULL) \
842 snprintf(rsp, BUFSIZ, "%i", loc.monitor->k);
844 MONGET(right_padding)
845 MONGET(bottom_padding)
848 #define GETCOLOR(s) \
849 else if (streq(#s, name)) \
850 snprintf(rsp, BUFSIZ, "%s", s);
851 GETCOLOR(focused_border_color)
852 GETCOLOR(active_border_color)
853 GETCOLOR(normal_border_color)
854 GETCOLOR(presel_border_color)
855 GETCOLOR(focused_locked_border_color)
856 GETCOLOR(active_locked_border_color)
857 GETCOLOR(normal_locked_border_color)
858 GETCOLOR(urgent_border_color)
861 else if (streq(#s, name)) \
862 snprintf(rsp, BUFSIZ, "%s", BOOLSTR(s));
863 GETBOOL(borderless_monocle)
864 GETBOOL(gapless_monocle)
865 GETBOOL(focus_follows_pointer)
866 GETBOOL(pointer_follows_monitor)
867 GETBOOL(apply_floating_atom)
868 GETBOOL(auto_alternate)
870 GETBOOL(history_aware_focus)
871 GETBOOL(honor_ewmh_focus)
878 bool parse_bool(char *value, bool *b)
880 if (streq("true", value) || streq("on", value)) {
883 } else if (streq("false", value) || streq("off", value)) {
890 bool parse_layout(char *s, layout_t *l)
892 if (streq("monocle", s)) {
895 } else if (streq("tiled", s)) {
902 bool parse_direction(char *s, direction_t *d)
904 if (streq("right", s)) {
907 } else if (streq("down", s)) {
910 } else if (streq("left", s)) {
913 } else if (streq("up", s)) {
920 bool parse_cycle_direction(char *s, cycle_dir_t *d)
922 if (streq("next", s)) {
925 } else if (streq("prev", s)) {
932 bool parse_circulate_direction(char *s, circulate_dir_t *d)
934 if (streq("forward", s)) {
935 *d = CIRCULATE_FORWARD;
937 } else if (streq("backward", s)) {
938 *d = CIRCULATE_BACKWARD;
944 bool parse_flip(char *s, flip_t *f)
946 if (streq("horizontal", s)) {
947 *f = FLIP_HORIZONTAL;
949 } else if (streq("vertical", s)) {
956 bool parse_fence_move(char *s, fence_move_t *m)
958 if (streq("push", s)) {
961 } else if (streq("pull", s)) {
968 bool parse_pointer_action(char *s, pointer_action_t *a)
970 if (streq("move", s)) {
973 } else if (streq("resize_corner", s)) {
974 *a = ACTION_RESIZE_CORNER;
976 } else if (streq("resize_side", s)) {
977 *a = ACTION_RESIZE_SIDE;
979 } else if (streq("focus", s)) {
986 bool parse_degree(char *s, int *d)
1001 bool parse_window_id(char *s, long int *i)
1005 long int ret = strtol(s, &end, 0);
1006 if (errno != 0 || *end != '\0')
1013 bool parse_index(char *s, int *i)
1015 return sscanf(s, "^%i", i) == 1;