summaryrefslogtreecommitdiffstats
path: root/sway/commands.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands.c')
-rw-r--r--sway/commands.c214
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
21typedef enum cmd_status sway_cmd(int argc, char **argv);
22
23struct cmd_handler {
24 char *command;
25 sway_cmd *handle;
26};
27
28static sway_cmd cmd_bindsym;
29static sway_cmd cmd_orientation;
30static sway_cmd cmd_exec;
31static sway_cmd cmd_exec_always;
32static sway_cmd cmd_exit;
33static sway_cmd cmd_floating;
34static sway_cmd cmd_floating_mod;
35static sway_cmd cmd_focus;
36static sway_cmd cmd_focus_follows_mouse;
37static sway_cmd cmd_for_window;
38static sway_cmd cmd_fullscreen;
39static sway_cmd cmd_gaps;
40static sway_cmd cmd_kill;
41static sway_cmd cmd_layout;
42static sway_cmd cmd_log_colors;
43static sway_cmd cmd_mode;
44static sway_cmd cmd_move;
45static sway_cmd cmd_output;
46static sway_cmd cmd_reload;
47static sway_cmd cmd_resize;
48static sway_cmd cmd_scratchpad;
49static sway_cmd cmd_set;
50static sway_cmd cmd_split;
51static sway_cmd cmd_splith;
52static sway_cmd cmd_splitv;
53static sway_cmd cmd_workspace;
54static 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
21swayc_t *sp_view; 60swayc_t *sp_view;
22int sp_index = 0; 61int sp_index = 0;
23 62
@@ -145,14 +184,19 @@ static enum cmd_status cmd_bindsym(int argc, char **argv) {
145} 184}
146 185
147static enum cmd_status cmd_exec_always(int argc, char **argv) { 186static 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
175static enum cmd_status cmd_exec(int argc, char **argv) { 217static 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
375static enum cmd_status cmd_mode(int argc, char **argv) { 415static 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
414static enum cmd_status cmd_move(int argc, char **argv) { 460static 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
485static enum cmd_status cmd_orientation(int argc, char **argv) { 531static 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
502static enum cmd_status cmd_output(int argc, char **argv) { 549static 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))
1011enum cmd_status cmd_for_window(int argc, char **argv) {
1012 return CMD_FAILURE;
1013}
1014
963static enum cmd_status cmd_fullscreen(int argc, char **argv) { 1015static 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
1090enum cmd_status handle_command(char *exec) { 1142enum 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
1107enum cmd_status config_command(char *exec) { 1196enum 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;