diff options
Diffstat (limited to 'sway/commands.c')
-rw-r--r-- | sway/commands.c | 239 |
1 files changed, 154 insertions, 85 deletions
diff --git a/sway/commands.c b/sway/commands.c index 68bdff2c..03c682d7 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -20,6 +20,40 @@ | |||
20 | #include "sway.h" | 20 | #include "sway.h" |
21 | #include "resize.h" | 21 | #include "resize.h" |
22 | 22 | ||
23 | typedef enum cmd_status sway_cmd(int argc, char **argv); | ||
24 | |||
25 | struct cmd_handler { | ||
26 | char *command; | ||
27 | sway_cmd *handle; | ||
28 | }; | ||
29 | |||
30 | static sway_cmd cmd_bindsym; | ||
31 | static sway_cmd cmd_orientation; | ||
32 | static sway_cmd cmd_exec; | ||
33 | static sway_cmd cmd_exec_always; | ||
34 | static sway_cmd cmd_exit; | ||
35 | static sway_cmd cmd_floating; | ||
36 | static sway_cmd cmd_floating_mod; | ||
37 | static sway_cmd cmd_focus; | ||
38 | static sway_cmd cmd_focus_follows_mouse; | ||
39 | static sway_cmd cmd_fullscreen; | ||
40 | static sway_cmd cmd_gaps; | ||
41 | static sway_cmd cmd_kill; | ||
42 | static sway_cmd cmd_layout; | ||
43 | static sway_cmd cmd_log_colors; | ||
44 | static sway_cmd cmd_mode; | ||
45 | static sway_cmd cmd_move; | ||
46 | static sway_cmd cmd_output; | ||
47 | static sway_cmd cmd_reload; | ||
48 | static sway_cmd cmd_resize; | ||
49 | static sway_cmd cmd_scratchpad; | ||
50 | static sway_cmd cmd_set; | ||
51 | static sway_cmd cmd_split; | ||
52 | static sway_cmd cmd_splith; | ||
53 | static sway_cmd cmd_splitv; | ||
54 | static sway_cmd cmd_workspace; | ||
55 | static sway_cmd cmd_ws_auto_back_and_forth; | ||
56 | |||
23 | swayc_t *sp_view; | 57 | swayc_t *sp_view; |
24 | int sp_index = 0; | 58 | int sp_index = 0; |
25 | 59 | ||
@@ -147,37 +181,33 @@ static enum cmd_status cmd_bindsym(int argc, char **argv) { | |||
147 | } | 181 | } |
148 | 182 | ||
149 | static enum cmd_status cmd_exec_always(int argc, char **argv) { | 183 | static enum cmd_status cmd_exec_always(int argc, char **argv) { |
184 | if (!config->active) return CMD_DEFER; | ||
150 | if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) { | 185 | if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) { |
151 | return CMD_FAILURE; | 186 | return CMD_FAILURE; |
152 | } | 187 | } |
153 | if (!config->active) { | 188 | // Put argument into cmd array |
154 | return CMD_DEFER; | 189 | char *tmp = join_args(argv, argc); |
155 | } | 190 | char cmd[4096]; |
156 | 191 | strcpy(cmd, tmp); | |
157 | pid_t pid = fork(); | 192 | free(tmp); |
158 | /* Failed to fork */ | 193 | |
159 | if (pid < 0) { | 194 | char *args[] = {"sh", "-c", cmd, 0 }; |
160 | sway_log(L_ERROR, "exec command failed, sway did not fork"); | 195 | sway_log(L_DEBUG, "Executing %s", cmd); |
196 | |||
197 | pid_t pid; | ||
198 | if ((pid = fork()) == 0) { | ||
199 | execv("/bin/sh", args); | ||
200 | _exit(-1); | ||
201 | } else if (pid < 0) { | ||
202 | sway_log(L_ERROR, "exec command failed, sway could not fork"); | ||
161 | return CMD_FAILURE; | 203 | return CMD_FAILURE; |
162 | } | 204 | } |
163 | /* Child process */ | ||
164 | if (pid == 0) { | ||
165 | char *args = join_args(argv, argc); | ||
166 | sway_log(L_DEBUG, "Executing %s", args); | ||
167 | execl("/bin/sh", "sh", "-c", args, (char *)NULL); | ||
168 | /* Execl doesnt return unless failure */ | ||
169 | sway_log(L_ERROR, "could not find /bin/sh"); | ||
170 | free(args); | ||
171 | exit(-1); | ||
172 | } | ||
173 | /* Parent */ | ||
174 | return CMD_SUCCESS; | 205 | return CMD_SUCCESS; |
175 | } | 206 | } |
176 | 207 | ||
177 | static enum cmd_status cmd_exec(int argc, char **argv) { | 208 | static enum cmd_status cmd_exec(int argc, char **argv) { |
178 | if (!config->active) { | 209 | if (!config->active) return CMD_DEFER; |
179 | return CMD_DEFER; | 210 | |
180 | } | ||
181 | if (config->reloading) { | 211 | if (config->reloading) { |
182 | char *args = join_args(argv, argc); | 212 | char *args = join_args(argv, argc); |
183 | sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); | 213 | sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); |
@@ -194,8 +224,8 @@ static void kill_views(swayc_t *container, void *data) { | |||
194 | } | 224 | } |
195 | 225 | ||
196 | static enum cmd_status cmd_exit(int argc, char **argv) { | 226 | static enum cmd_status cmd_exit(int argc, char **argv) { |
197 | if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0) | 227 | if (config->reading) return CMD_INVALID; |
198 | || config->reading || !config->active) { | 228 | if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0)) { |
199 | return CMD_FAILURE; | 229 | return CMD_FAILURE; |
200 | } | 230 | } |
201 | // Close all views | 231 | // Close all views |
@@ -205,8 +235,8 @@ static enum cmd_status cmd_exit(int argc, char **argv) { | |||
205 | } | 235 | } |
206 | 236 | ||
207 | static enum cmd_status cmd_floating(int argc, char **argv) { | 237 | static enum cmd_status cmd_floating(int argc, char **argv) { |
208 | if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1) | 238 | if (config->reading) return CMD_INVALID; |
209 | || config->reading || !config->active) { | 239 | if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1)) { |
210 | return CMD_FAILURE; | 240 | return CMD_FAILURE; |
211 | } | 241 | } |
212 | 242 | ||
@@ -267,8 +297,8 @@ static enum cmd_status cmd_floating(int argc, char **argv) { | |||
267 | } | 297 | } |
268 | 298 | ||
269 | static enum cmd_status cmd_floating_mod(int argc, char **argv) { | 299 | static enum cmd_status cmd_floating_mod(int argc, char **argv) { |
270 | if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1) | 300 | if (!config->reading) return CMD_INVALID; |
271 | || !config->reading) { | 301 | if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)) { |
272 | return CMD_FAILURE; | 302 | return CMD_FAILURE; |
273 | } | 303 | } |
274 | int i, j; | 304 | int i, j; |
@@ -292,10 +322,10 @@ static enum cmd_status cmd_floating_mod(int argc, char **argv) { | |||
292 | } | 322 | } |
293 | 323 | ||
294 | static enum cmd_status cmd_focus(int argc, char **argv) { | 324 | static enum cmd_status cmd_focus(int argc, char **argv) { |
325 | if (config->reading) return CMD_INVALID; | ||
295 | static int floating_toggled_index = 0; | 326 | static int floating_toggled_index = 0; |
296 | static int tiled_toggled_index = 0; | 327 | static int tiled_toggled_index = 0; |
297 | if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1) | 328 | if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)) { |
298 | || config->reading || !config->active) { | ||
299 | return CMD_FAILURE; | 329 | return CMD_FAILURE; |
300 | } | 330 | } |
301 | if (strcasecmp(argv[0], "left") == 0) { | 331 | if (strcasecmp(argv[0], "left") == 0) { |
@@ -350,6 +380,7 @@ static enum cmd_status cmd_focus(int argc, char **argv) { | |||
350 | } | 380 | } |
351 | 381 | ||
352 | static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) { | 382 | static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) { |
383 | if (!config->reading) return CMD_INVALID; | ||
353 | if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) { | 384 | if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) { |
354 | return CMD_FAILURE; | 385 | return CMD_FAILURE; |
355 | } | 386 | } |
@@ -359,7 +390,7 @@ static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) { | |||
359 | } | 390 | } |
360 | 391 | ||
361 | static void hide_view_in_scratchpad(swayc_t *sp_view) { | 392 | static void hide_view_in_scratchpad(swayc_t *sp_view) { |
362 | if(sp_view == NULL) { | 393 | if (sp_view == NULL) { |
363 | return; | 394 | return; |
364 | } | 395 | } |
365 | 396 | ||
@@ -375,15 +406,19 @@ static void hide_view_in_scratchpad(swayc_t *sp_view) { | |||
375 | } | 406 | } |
376 | 407 | ||
377 | static enum cmd_status cmd_mode(int argc, char **argv) { | 408 | static enum cmd_status cmd_mode(int argc, char **argv) { |
378 | if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) { | 409 | if (!checkarg(argc, "mode", EXPECTED_AT_LEAST, 1)) { |
379 | return CMD_FAILURE; | 410 | return CMD_FAILURE; |
380 | } | 411 | } |
381 | bool mode_make = !strcmp(argv[argc-1], "{"); | 412 | char *mode_name = join_args(argv, argc); |
382 | if (mode_make && !config->reading) { | 413 | int mode_len = strlen(mode_name); |
383 | return CMD_FAILURE; | 414 | bool mode_make = mode_name[mode_len-1] == '{'; |
415 | if (mode_make) { | ||
416 | if (!config->reading) return CMD_INVALID; | ||
417 | // Trim trailing spaces | ||
418 | do { | ||
419 | mode_name[--mode_len] = 0; | ||
420 | } while(isspace(mode_name[mode_len-1])); | ||
384 | } | 421 | } |
385 | |||
386 | char *mode_name = join_args(argv, argc - mode_make); | ||
387 | struct sway_mode *mode = NULL; | 422 | struct sway_mode *mode = NULL; |
388 | // Find mode | 423 | // Find mode |
389 | int i, len = config->modes->length; | 424 | int i, len = config->modes->length; |
@@ -406,16 +441,18 @@ static enum cmd_status cmd_mode(int argc, char **argv) { | |||
406 | free(mode_name); | 441 | free(mode_name); |
407 | return CMD_FAILURE; | 442 | return CMD_FAILURE; |
408 | } | 443 | } |
409 | sway_log(L_DEBUG, "Switching to mode `%s'",mode->name); | 444 | if ((config->reading && mode_make) || (!config->reading && !mode_make)) { |
445 | sway_log(L_DEBUG, "Switching to mode `%s'",mode->name); | ||
446 | } | ||
410 | free(mode_name); | 447 | free(mode_name); |
411 | // Set current mode | 448 | // Set current mode |
412 | config->current_mode = mode; | 449 | config->current_mode = mode; |
413 | return CMD_SUCCESS; | 450 | return mode_make ? CMD_BLOCK_MODE : CMD_SUCCESS; |
414 | } | 451 | } |
415 | 452 | ||
416 | static enum cmd_status cmd_move(int argc, char **argv) { | 453 | static enum cmd_status cmd_move(int argc, char **argv) { |
417 | if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1) | 454 | if (config->reading) return CMD_FAILURE; |
418 | || config->reading || !config->active) { | 455 | if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) { |
419 | return CMD_FAILURE; | 456 | return CMD_FAILURE; |
420 | } | 457 | } |
421 | 458 | ||
@@ -485,10 +522,11 @@ static enum cmd_status cmd_move(int argc, char **argv) { | |||
485 | } | 522 | } |
486 | 523 | ||
487 | static enum cmd_status cmd_orientation(int argc, char **argv) { | 524 | static enum cmd_status cmd_orientation(int argc, char **argv) { |
488 | if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1) | 525 | if (!config->reading) return CMD_FAILURE; |
489 | || !config->reading) { | 526 | if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1)) { |
490 | return CMD_FAILURE; | 527 | return CMD_FAILURE; |
491 | } | 528 | } |
529 | |||
492 | if (strcasecmp(argv[0], "horizontal") == 0) { | 530 | if (strcasecmp(argv[0], "horizontal") == 0) { |
493 | config->default_orientation = L_HORIZ; | 531 | config->default_orientation = L_HORIZ; |
494 | } else if (strcasecmp(argv[0], "vertical") == 0) { | 532 | } else if (strcasecmp(argv[0], "vertical") == 0) { |
@@ -502,6 +540,7 @@ static enum cmd_status cmd_orientation(int argc, char **argv) { | |||
502 | } | 540 | } |
503 | 541 | ||
504 | static enum cmd_status cmd_output(int argc, char **argv) { | 542 | static enum cmd_status cmd_output(int argc, char **argv) { |
543 | if (!config->reading) return CMD_FAILURE; | ||
505 | if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) { | 544 | if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) { |
506 | return CMD_FAILURE; | 545 | return CMD_FAILURE; |
507 | } | 546 | } |
@@ -512,7 +551,6 @@ static enum cmd_status cmd_output(int argc, char **argv) { | |||
512 | output->enabled = true; | 551 | output->enabled = true; |
513 | 552 | ||
514 | // TODO: atoi doesn't handle invalid numbers | 553 | // TODO: atoi doesn't handle invalid numbers |
515 | |||
516 | if (strcasecmp(argv[1], "disable") == 0) { | 554 | if (strcasecmp(argv[1], "disable") == 0) { |
517 | output->enabled = false; | 555 | output->enabled = false; |
518 | } | 556 | } |
@@ -953,7 +991,7 @@ static enum cmd_status cmd_log_colors(int argc, char **argv) { | |||
953 | } | 991 | } |
954 | if (strcasecmp(argv[0], "no") == 0) { | 992 | if (strcasecmp(argv[0], "no") == 0) { |
955 | sway_log_colors(0); | 993 | sway_log_colors(0); |
956 | } else if(strcasecmp(argv[0], "yes") == 0) { | 994 | } else if (strcasecmp(argv[0], "yes") == 0) { |
957 | sway_log_colors(1); | 995 | sway_log_colors(1); |
958 | } else { | 996 | } else { |
959 | sway_log(L_ERROR, "Invalid log_colors command (expected `yes` or `no`, got '%s')", argv[0]); | 997 | sway_log(L_ERROR, "Invalid log_colors command (expected `yes` or `no`, got '%s')", argv[0]); |
@@ -1089,57 +1127,88 @@ static struct cmd_handler *find_handler(char *line) { | |||
1089 | return res; | 1127 | return res; |
1090 | } | 1128 | } |
1091 | 1129 | ||
1092 | enum cmd_status handle_command(char *exec) { | 1130 | enum cmd_status handle_command(char *_exec) { |
1093 | sway_log(L_INFO, "Handling command '%s'", exec); | 1131 | enum cmd_status status = CMD_SUCCESS; |
1094 | int argc; | 1132 | char *exec = strdup(_exec); |
1095 | char **argv = split_args(exec, &argc); | 1133 | char *head = exec; |
1096 | enum cmd_status status = CMD_FAILURE; | 1134 | char *cmdlist; |
1097 | struct cmd_handler *handler; | 1135 | char *cmd; |
1098 | if (!argc) { | 1136 | char *criteria __attribute__((unused)); |
1099 | return status; | 1137 | |
1100 | } | 1138 | head = exec; |
1101 | if ((handler = find_handler(argv[0])) == NULL | 1139 | do { |
1102 | || (status = handler->handle(argc - 1, argv + 1)) != CMD_SUCCESS) { | 1140 | // Handle criteria |
1103 | sway_log(L_ERROR, "Command failed: %s", argv[0]); | 1141 | if (*head == '[') { |
1104 | } | 1142 | criteria = argsep(&head, "]"); |
1105 | free_argv(argc, argv); | 1143 | if (head) { |
1144 | ++head; | ||
1145 | // TODO handle criteria | ||
1146 | } else { | ||
1147 | sway_log(L_ERROR, "Unmatched ["); | ||
1148 | status = CMD_INVALID; | ||
1149 | } | ||
1150 | // Skip leading whitespace | ||
1151 | head += strspn(head, whitespace); | ||
1152 | } | ||
1153 | // Split command list | ||
1154 | cmdlist = argsep(&head, ";"); | ||
1155 | cmdlist += strspn(cmdlist, whitespace); | ||
1156 | do { | ||
1157 | // Split commands | ||
1158 | cmd = argsep(&cmdlist, ","); | ||
1159 | cmd += strspn(cmd, whitespace); | ||
1160 | sway_log(L_INFO, "Handling command '%s'", cmd); | ||
1161 | //TODO better handling of argv | ||
1162 | int argc; | ||
1163 | char **argv = split_args(cmd, &argc); | ||
1164 | if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { | ||
1165 | strip_quotes(argv[1]); | ||
1166 | } | ||
1167 | struct cmd_handler *handler = find_handler(argv[0]); | ||
1168 | enum cmd_status res = CMD_INVALID; | ||
1169 | if (!handler | ||
1170 | || (res = handler->handle(argc-1, argv+1)) != CMD_SUCCESS) { | ||
1171 | sway_log(L_ERROR, "Command '%s' failed", cmd); | ||
1172 | free_argv(argc, argv); | ||
1173 | status = res; | ||
1174 | goto cleanup; | ||
1175 | } | ||
1176 | free_argv(argc, argv); | ||
1177 | } while(cmdlist); | ||
1178 | } while(head); | ||
1179 | cleanup: | ||
1180 | free(exec); | ||
1106 | return status; | 1181 | return status; |
1107 | } | 1182 | } |
1108 | 1183 | ||
1109 | enum cmd_status config_command(char *exec) { | 1184 | enum cmd_status config_command(char *exec) { |
1110 | sway_log(L_INFO, "handling config command '%s'", exec); | 1185 | enum cmd_status status = CMD_SUCCESS; |
1111 | int argc; | 1186 | int argc; |
1112 | char **argv = split_args(exec, &argc); | 1187 | char **argv = split_args(exec, &argc); |
1113 | enum cmd_status status = CMD_FAILURE; | 1188 | if (!argc) goto cleanup; |
1114 | struct cmd_handler *handler; | 1189 | |
1115 | if (!argc) { | 1190 | sway_log(L_INFO, "handling config command '%s'", exec); |
1116 | status = CMD_SUCCESS; | 1191 | // Endblock |
1192 | if (**argv == '}') { | ||
1193 | status = CMD_BLOCK_END; | ||
1117 | goto cleanup; | 1194 | goto cleanup; |
1118 | } | 1195 | } |
1119 | // TODO better block handling | 1196 | struct cmd_handler *handler = find_handler(argv[0]); |
1120 | if (strncmp(argv[0], "}", 1) == 0) { | 1197 | if (!handler) { |
1121 | config->current_mode = config->modes->items[0]; | 1198 | status = CMD_INVALID; |
1122 | status = CMD_SUCCESS; | ||
1123 | goto cleanup; | 1199 | goto cleanup; |
1124 | } | 1200 | } |
1125 | if ((handler = find_handler(argv[0]))) { | 1201 | int i; |
1126 | // Dont replace first argument in cmd_set | 1202 | // Var replacement, for all but first argument of set |
1127 | int i = handler->handle == cmd_set ? 2 : 1; | 1203 | for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { |
1128 | int e = argc; | 1204 | argv[i] = do_var_replacement(argv[i]); |
1129 | for (; i < e; ++i) { | 1205 | } |
1130 | argv[i] = do_var_replacement(argv[i]); | 1206 | /* Strip quotes for first argument. |
1131 | } | 1207 | * TODO This part needs to be handled much better */ |
1132 | status = handler->handle(argc - 1, argv + 1); | 1208 | if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { |
1133 | if (status == CMD_FAILURE) { | 1209 | strip_quotes(argv[1]); |
1134 | sway_log(L_ERROR, "Config load failed for line `%s'", exec); | ||
1135 | } else if (status == CMD_DEFER) { | ||
1136 | sway_log(L_DEBUG, "Defferring command `%s'", exec); | ||
1137 | list_add(config->cmd_queue, strdup(exec)); | ||
1138 | status = CMD_SUCCESS; | ||
1139 | } | ||
1140 | } else { | ||
1141 | sway_log(L_ERROR, "Unknown command `%s'", exec); | ||
1142 | } | 1210 | } |
1211 | status = handler->handle(argc-1, argv+1); | ||
1143 | cleanup: | 1212 | cleanup: |
1144 | free_argv(argc, argv); | 1213 | free_argv(argc, argv); |
1145 | return status; | 1214 | return status; |