diff options
author | taiyu <taiyu.len@gmail.com> | 2015-09-14 19:59:25 -0700 |
---|---|---|
committer | taiyu <taiyu.len@gmail.com> | 2015-09-14 19:59:25 -0700 |
commit | 0bea2e2122bd573d1f9dc68b5a990c8f2ad3f3f0 (patch) | |
tree | ae6c559e756b68a6b6091914a7d33d212e374ef3 /sway/commands.c | |
parent | Revert "new_workspace null behavior + testmap functions + regex" (diff) | |
download | sway-0bea2e2122bd573d1f9dc68b5a990c8f2ad3f3f0.tar.gz sway-0bea2e2122bd573d1f9dc68b5a990c8f2ad3f3f0.tar.zst sway-0bea2e2122bd573d1f9dc68b5a990c8f2ad3f3f0.zip |
multi command keybinds
Diffstat (limited to 'sway/commands.c')
-rw-r--r-- | sway/commands.c | 214 |
1 files changed, 149 insertions, 65 deletions
diff --git a/sway/commands.c b/sway/commands.c index e79746ae..c426928e 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -18,6 +18,45 @@ | |||
18 | #include "sway.h" | 18 | #include "sway.h" |
19 | #include "resize.h" | 19 | #include "resize.h" |
20 | 20 | ||
21 | typedef enum cmd_status sway_cmd(int argc, char **argv); | ||
22 | |||
23 | struct cmd_handler { | ||
24 | char *command; | ||
25 | sway_cmd *handle; | ||
26 | }; | ||
27 | |||
28 | static sway_cmd cmd_bindsym; | ||
29 | static sway_cmd cmd_orientation; | ||
30 | static sway_cmd cmd_exec; | ||
31 | static sway_cmd cmd_exec_always; | ||
32 | static sway_cmd cmd_exit; | ||
33 | static sway_cmd cmd_floating; | ||
34 | static sway_cmd cmd_floating_mod; | ||
35 | static sway_cmd cmd_focus; | ||
36 | static sway_cmd cmd_focus_follows_mouse; | ||
37 | static sway_cmd cmd_for_window; | ||
38 | static sway_cmd cmd_fullscreen; | ||
39 | static sway_cmd cmd_gaps; | ||
40 | static sway_cmd cmd_kill; | ||
41 | static sway_cmd cmd_layout; | ||
42 | static sway_cmd cmd_log_colors; | ||
43 | static sway_cmd cmd_mode; | ||
44 | static sway_cmd cmd_move; | ||
45 | static sway_cmd cmd_output; | ||
46 | static sway_cmd cmd_reload; | ||
47 | static sway_cmd cmd_resize; | ||
48 | static sway_cmd cmd_scratchpad; | ||
49 | static sway_cmd cmd_set; | ||
50 | static sway_cmd cmd_split; | ||
51 | static sway_cmd cmd_splith; | ||
52 | static sway_cmd cmd_splitv; | ||
53 | static sway_cmd cmd_workspace; | ||
54 | static sway_cmd cmd_ws_auto_back_and_forth; | ||
55 | |||
56 | #define NO_BIND() if (!config->reading) return CMD_FAILURE; | ||
57 | #define NO_CONF() if (config->reading) return CMD_FAILURE; | ||
58 | #define DEFER() if (!config->active) return CMD_DEFER; | ||
59 | |||
21 | swayc_t *sp_view; | 60 | swayc_t *sp_view; |
22 | int sp_index = 0; | 61 | int sp_index = 0; |
23 | 62 | ||
@@ -145,14 +184,19 @@ static enum cmd_status cmd_bindsym(int argc, char **argv) { | |||
145 | } | 184 | } |
146 | 185 | ||
147 | static enum cmd_status cmd_exec_always(int argc, char **argv) { | 186 | static enum cmd_status cmd_exec_always(int argc, char **argv) { |
187 | DEFER(); | ||
148 | if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) { | 188 | if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) { |
149 | return CMD_FAILURE; | 189 | return CMD_FAILURE; |
150 | } | 190 | } |
151 | if (!config->active) { | 191 | // Put argument into cmd array |
152 | return CMD_DEFER; | 192 | char *tmp = join_args(argv, argc); |
153 | } | 193 | char cmd[4096]; |
194 | strcpy(cmd, tmp); | ||
195 | free(tmp); | ||
196 | |||
197 | char *args[] = {"sh", "-c", cmd, 0 }; | ||
154 | 198 | ||
155 | pid_t pid = fork(); | 199 | pid_t pid = vfork(); |
156 | /* Failed to fork */ | 200 | /* Failed to fork */ |
157 | if (pid < 0) { | 201 | if (pid < 0) { |
158 | sway_log(L_ERROR, "exec command failed, sway did not fork"); | 202 | sway_log(L_ERROR, "exec command failed, sway did not fork"); |
@@ -160,22 +204,18 @@ static enum cmd_status cmd_exec_always(int argc, char **argv) { | |||
160 | } | 204 | } |
161 | /* Child process */ | 205 | /* Child process */ |
162 | if (pid == 0) { | 206 | if (pid == 0) { |
163 | char *args = join_args(argv, argc); | 207 | sway_log(L_DEBUG, "Executing %s", cmd); |
164 | sway_log(L_DEBUG, "Executing %s", args); | 208 | execv("/bin/sh", args); |
165 | execl("/bin/sh", "sh", "-c", args, (char *)NULL); | 209 | /* Execv doesnt return unless failure */ |
166 | /* Execl doesnt return unless failure */ | 210 | sway_log(L_ERROR, "execv failde to return"); |
167 | sway_log(L_ERROR, "could not find /bin/sh"); | 211 | _exit(-1); |
168 | free(args); | ||
169 | exit(-1); | ||
170 | } | 212 | } |
171 | /* Parent */ | 213 | /* Parent */ |
172 | return CMD_SUCCESS; | 214 | return CMD_SUCCESS; |
173 | } | 215 | } |
174 | 216 | ||
175 | static enum cmd_status cmd_exec(int argc, char **argv) { | 217 | static enum cmd_status cmd_exec(int argc, char **argv) { |
176 | if (!config->active) { | 218 | DEFER(); |
177 | return CMD_DEFER; | ||
178 | } | ||
179 | if (config->reloading) { | 219 | if (config->reloading) { |
180 | char *args = join_args(argv, argc); | 220 | char *args = join_args(argv, argc); |
181 | sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); | 221 | sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); |
@@ -373,15 +413,19 @@ static void hide_view_in_scratchpad(swayc_t *sp_view) { | |||
373 | } | 413 | } |
374 | 414 | ||
375 | static enum cmd_status cmd_mode(int argc, char **argv) { | 415 | static enum cmd_status cmd_mode(int argc, char **argv) { |
376 | if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) { | 416 | if (!checkarg(argc, "mode", EXPECTED_AT_LEAST, 1)) { |
377 | return CMD_FAILURE; | 417 | return CMD_FAILURE; |
378 | } | 418 | } |
379 | bool mode_make = !strcmp(argv[argc-1], "{"); | 419 | char *mode_name = join_args(argv, argc); |
380 | if (mode_make && !config->reading) { | 420 | int mode_len = strlen(mode_name); |
381 | return CMD_FAILURE; | 421 | bool mode_make = mode_name[mode_len-1] == '{'; |
422 | if (mode_make) { | ||
423 | NO_BIND(); | ||
424 | // Trim trailing spaces | ||
425 | do { | ||
426 | mode_name[--mode_len] = 0; | ||
427 | } while(isspace(mode_name[mode_len-1])); | ||
382 | } | 428 | } |
383 | |||
384 | char *mode_name = join_args(argv, argc - mode_make); | ||
385 | struct sway_mode *mode = NULL; | 429 | struct sway_mode *mode = NULL; |
386 | // Find mode | 430 | // Find mode |
387 | int i, len = config->modes->length; | 431 | int i, len = config->modes->length; |
@@ -404,16 +448,18 @@ static enum cmd_status cmd_mode(int argc, char **argv) { | |||
404 | free(mode_name); | 448 | free(mode_name); |
405 | return CMD_FAILURE; | 449 | return CMD_FAILURE; |
406 | } | 450 | } |
407 | sway_log(L_DEBUG, "Switching to mode `%s'",mode->name); | 451 | if ((config->reading && mode_make) || (!config->reading && !mode_make)) { |
452 | sway_log(L_DEBUG, "Switching to mode `%s'",mode->name); | ||
453 | } | ||
408 | free(mode_name); | 454 | free(mode_name); |
409 | // Set current mode | 455 | // Set current mode |
410 | config->current_mode = mode; | 456 | config->current_mode = mode; |
411 | return CMD_SUCCESS; | 457 | return mode_make ? CMD_BLOCK_MODE : CMD_SUCCESS; |
412 | } | 458 | } |
413 | 459 | ||
414 | static enum cmd_status cmd_move(int argc, char **argv) { | 460 | static enum cmd_status cmd_move(int argc, char **argv) { |
415 | if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1) | 461 | NO_CONF(); |
416 | || config->reading || !config->active) { | 462 | if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) { |
417 | return CMD_FAILURE; | 463 | return CMD_FAILURE; |
418 | } | 464 | } |
419 | 465 | ||
@@ -483,10 +529,11 @@ static enum cmd_status cmd_move(int argc, char **argv) { | |||
483 | } | 529 | } |
484 | 530 | ||
485 | static enum cmd_status cmd_orientation(int argc, char **argv) { | 531 | static enum cmd_status cmd_orientation(int argc, char **argv) { |
486 | if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1) | 532 | NO_BIND(); |
487 | || !config->reading) { | 533 | if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1)) { |
488 | return CMD_FAILURE; | 534 | return CMD_FAILURE; |
489 | } | 535 | } |
536 | |||
490 | if (strcasecmp(argv[0], "horizontal") == 0) { | 537 | if (strcasecmp(argv[0], "horizontal") == 0) { |
491 | config->default_orientation = L_HORIZ; | 538 | config->default_orientation = L_HORIZ; |
492 | } else if (strcasecmp(argv[0], "vertical") == 0) { | 539 | } else if (strcasecmp(argv[0], "vertical") == 0) { |
@@ -500,6 +547,7 @@ static enum cmd_status cmd_orientation(int argc, char **argv) { | |||
500 | } | 547 | } |
501 | 548 | ||
502 | static enum cmd_status cmd_output(int argc, char **argv) { | 549 | static enum cmd_status cmd_output(int argc, char **argv) { |
550 | NO_BIND(); | ||
503 | if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) { | 551 | if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) { |
504 | return CMD_FAILURE; | 552 | return CMD_FAILURE; |
505 | } | 553 | } |
@@ -510,7 +558,6 @@ static enum cmd_status cmd_output(int argc, char **argv) { | |||
510 | output->enabled = true; | 558 | output->enabled = true; |
511 | 559 | ||
512 | // TODO: atoi doesn't handle invalid numbers | 560 | // TODO: atoi doesn't handle invalid numbers |
513 | |||
514 | if (strcasecmp(argv[1], "disable") == 0) { | 561 | if (strcasecmp(argv[1], "disable") == 0) { |
515 | output->enabled = false; | 562 | output->enabled = false; |
516 | } | 563 | } |
@@ -960,6 +1007,11 @@ static enum cmd_status cmd_log_colors(int argc, char **argv) { | |||
960 | return CMD_SUCCESS; | 1007 | return CMD_SUCCESS; |
961 | } | 1008 | } |
962 | 1009 | ||
1010 | __attribute__((unused)) | ||
1011 | enum cmd_status cmd_for_window(int argc, char **argv) { | ||
1012 | return CMD_FAILURE; | ||
1013 | } | ||
1014 | |||
963 | static enum cmd_status cmd_fullscreen(int argc, char **argv) { | 1015 | static enum cmd_status cmd_fullscreen(int argc, char **argv) { |
964 | if (!checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0) | 1016 | if (!checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0) |
965 | || config->reading || !config->active) { | 1017 | || config->reading || !config->active) { |
@@ -1087,57 +1139,89 @@ static struct cmd_handler *find_handler(char *line) { | |||
1087 | return res; | 1139 | return res; |
1088 | } | 1140 | } |
1089 | 1141 | ||
1090 | enum cmd_status handle_command(char *exec) { | 1142 | enum cmd_status handle_command(char *_exec) { |
1091 | sway_log(L_INFO, "Handling command '%s'", exec); | 1143 | enum cmd_status status = CMD_SUCCESS; |
1092 | int argc; | 1144 | char *exec = strdup(_exec); |
1093 | char **argv = split_args(exec, &argc); | 1145 | char *head = exec; |
1094 | enum cmd_status status = CMD_FAILURE; | 1146 | char *cmdlist; |
1095 | struct cmd_handler *handler; | 1147 | char *cmd; |
1096 | if (!argc) { | 1148 | char *criteria __attribute__((unused)); |
1097 | return status; | 1149 | |
1098 | } | 1150 | head = exec; |
1099 | if ((handler = find_handler(argv[0])) == NULL | 1151 | do { |
1100 | || (status = handler->handle(argc - 1, argv + 1)) != CMD_SUCCESS) { | 1152 | // Handle criteria |
1101 | sway_log(L_ERROR, "Command failed: %s", argv[0]); | 1153 | if (*head == '[') { |
1102 | } | 1154 | criteria = argsep(&head, "]"); |
1103 | free_argv(argc, argv); | 1155 | if (head) { |
1156 | ++head; | ||
1157 | // TODO handle criteria | ||
1158 | } else { | ||
1159 | sway_log(L_ERROR, "Unmatched ["); | ||
1160 | status = CMD_INVALID; | ||
1161 | } | ||
1162 | // Skip leading whitespace | ||
1163 | head += strspn(head, whitespace); | ||
1164 | } | ||
1165 | // Split command list | ||
1166 | cmdlist = argsep(&head, ";"); | ||
1167 | cmdlist += strspn(cmdlist, whitespace); | ||
1168 | do { | ||
1169 | // Split commands | ||
1170 | cmd = argsep(&cmdlist, ","); | ||
1171 | cmd += strspn(cmd, whitespace); | ||
1172 | sway_log(L_INFO, "Handling command '%s'", cmd); | ||
1173 | //TODO better handling of argv | ||
1174 | int argc; | ||
1175 | char **argv = split_args(cmd, &argc); | ||
1176 | if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { | ||
1177 | strip_quotes(argv[1]); | ||
1178 | } | ||
1179 | struct cmd_handler *handler = find_handler(argv[0]); | ||
1180 | enum cmd_status res = CMD_INVALID; | ||
1181 | if (!handler | ||
1182 | || (res = handler->handle(argc-1, argv+1)) != CMD_SUCCESS) { | ||
1183 | sway_log(L_ERROR, "Command '%s' failed", cmd); | ||
1184 | free_argv(argc, argv); | ||
1185 | status = res; | ||
1186 | goto cleanup; | ||
1187 | } | ||
1188 | free_argv(argc, argv); | ||
1189 | } while(cmdlist); | ||
1190 | } while(head); | ||
1191 | cleanup: | ||
1192 | free(exec); | ||
1104 | return status; | 1193 | return status; |
1105 | } | 1194 | } |
1106 | 1195 | ||
1107 | enum cmd_status config_command(char *exec) { | 1196 | enum cmd_status config_command(char *exec) { |
1108 | sway_log(L_INFO, "handling config command '%s'", exec); | 1197 | sway_log(L_INFO, "handling config command '%s'", exec); |
1198 | enum cmd_status status = CMD_SUCCESS; | ||
1109 | int argc; | 1199 | int argc; |
1110 | char **argv = split_args(exec, &argc); | 1200 | char **argv = split_args(exec, &argc); |
1111 | enum cmd_status status = CMD_FAILURE; | ||
1112 | struct cmd_handler *handler; | ||
1113 | if (!argc) { | 1201 | if (!argc) { |
1114 | status = CMD_SUCCESS; | ||
1115 | goto cleanup; | 1202 | goto cleanup; |
1116 | } | 1203 | } |
1117 | // TODO better block handling | 1204 | // Endblock |
1118 | if (strncmp(argv[0], "}", 1) == 0) { | 1205 | if (**argv == '}') { |
1119 | config->current_mode = config->modes->items[0]; | 1206 | status = CMD_BLOCK_END; |
1120 | status = CMD_SUCCESS; | ||
1121 | goto cleanup; | 1207 | goto cleanup; |
1122 | } | 1208 | } |
1123 | if ((handler = find_handler(argv[0]))) { | 1209 | struct cmd_handler *handler = find_handler(argv[0]); |
1124 | // Dont replace first argument in cmd_set | 1210 | if (!handler) { |
1125 | int i = handler->handle == cmd_set ? 2 : 1; | 1211 | status = CMD_INVALID; |
1126 | int e = argc; | 1212 | goto cleanup; |
1127 | for (; i < e; ++i) { | 1213 | } |
1128 | argv[i] = do_var_replacement(argv[i]); | 1214 | int i; |
1129 | } | 1215 | // Var replacement, for all but first argument of set |
1130 | status = handler->handle(argc - 1, argv + 1); | 1216 | for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { |
1131 | if (status == CMD_FAILURE) { | 1217 | argv[i] = do_var_replacement(argv[i]); |
1132 | sway_log(L_ERROR, "Config load failed for line `%s'", exec); | 1218 | } |
1133 | } else if (status == CMD_DEFER) { | 1219 | /* Strip quotes for first argument. |
1134 | sway_log(L_DEBUG, "Defferring command `%s'", exec); | 1220 | * TODO This part needs to be handled much better */ |
1135 | list_add(config->cmd_queue, strdup(exec)); | 1221 | if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { |
1136 | status = CMD_SUCCESS; | 1222 | strip_quotes(argv[1]); |
1137 | } | ||
1138 | } else { | ||
1139 | sway_log(L_ERROR, "Unknown command `%s'", exec); | ||
1140 | } | 1223 | } |
1224 | status = handler->handle(argc-1, argv+1); | ||
1141 | cleanup: | 1225 | cleanup: |
1142 | free_argv(argc, argv); | 1226 | free_argv(argc, argv); |
1143 | return status; | 1227 | return status; |