diff options
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 @@ #include "sway.h" #include "resize.h" +typedef enum cmd_status sway_cmd(int argc, char **argv); + +struct cmd_handler { + char *command; + sway_cmd *handle; +}; + +static sway_cmd cmd_bindsym; +static sway_cmd cmd_orientation; +static sway_cmd cmd_exec; +static sway_cmd cmd_exec_always; +static sway_cmd cmd_exit; +static sway_cmd cmd_floating; +static sway_cmd cmd_floating_mod; +static sway_cmd cmd_focus; +static sway_cmd cmd_focus_follows_mouse; +static sway_cmd cmd_for_window; +static sway_cmd cmd_fullscreen; +static sway_cmd cmd_gaps; +static sway_cmd cmd_kill; +static sway_cmd cmd_layout; +static sway_cmd cmd_log_colors; +static sway_cmd cmd_mode; +static sway_cmd cmd_move; +static sway_cmd cmd_output; +static sway_cmd cmd_reload; +static sway_cmd cmd_resize; +static sway_cmd cmd_scratchpad; +static sway_cmd cmd_set; +static sway_cmd cmd_split; +static sway_cmd cmd_splith; +static sway_cmd cmd_splitv; +static sway_cmd cmd_workspace; +static sway_cmd cmd_ws_auto_back_and_forth; + +#define NO_BIND() if (!config->reading) return CMD_FAILURE; +#define NO_CONF() if (config->reading) return CMD_FAILURE; +#define DEFER() if (!config->active) return CMD_DEFER; + swayc_t *sp_view; int sp_index = 0; @@ -145,14 +184,19 @@ static enum cmd_status cmd_bindsym(int argc, char **argv) { } static enum cmd_status cmd_exec_always(int argc, char **argv) { + DEFER(); if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) { return CMD_FAILURE; } - if (!config->active) { - return CMD_DEFER; - } + // Put argument into cmd array + char *tmp = join_args(argv, argc); + char cmd[4096]; + strcpy(cmd, tmp); + free(tmp); + + char *args[] = {"sh", "-c", cmd, 0 }; - pid_t pid = fork(); + pid_t pid = vfork(); /* Failed to fork */ if (pid < 0) { 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) { } /* Child process */ if (pid == 0) { - char *args = join_args(argv, argc); - sway_log(L_DEBUG, "Executing %s", args); - execl("/bin/sh", "sh", "-c", args, (char *)NULL); - /* Execl doesnt return unless failure */ - sway_log(L_ERROR, "could not find /bin/sh"); - free(args); - exit(-1); + sway_log(L_DEBUG, "Executing %s", cmd); + execv("/bin/sh", args); + /* Execv doesnt return unless failure */ + sway_log(L_ERROR, "execv failde to return"); + _exit(-1); } /* Parent */ return CMD_SUCCESS; } static enum cmd_status cmd_exec(int argc, char **argv) { - if (!config->active) { - return CMD_DEFER; - } + DEFER(); if (config->reloading) { char *args = join_args(argv, argc); 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) { } static enum cmd_status cmd_mode(int argc, char **argv) { - if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) { + if (!checkarg(argc, "mode", EXPECTED_AT_LEAST, 1)) { return CMD_FAILURE; } - bool mode_make = !strcmp(argv[argc-1], "{"); - if (mode_make && !config->reading) { - return CMD_FAILURE; + char *mode_name = join_args(argv, argc); + int mode_len = strlen(mode_name); + bool mode_make = mode_name[mode_len-1] == '{'; + if (mode_make) { + NO_BIND(); + // Trim trailing spaces + do { + mode_name[--mode_len] = 0; + } while(isspace(mode_name[mode_len-1])); } - - char *mode_name = join_args(argv, argc - mode_make); struct sway_mode *mode = NULL; // Find mode int i, len = config->modes->length; @@ -404,16 +448,18 @@ static enum cmd_status cmd_mode(int argc, char **argv) { free(mode_name); return CMD_FAILURE; } - sway_log(L_DEBUG, "Switching to mode `%s'",mode->name); + if ((config->reading && mode_make) || (!config->reading && !mode_make)) { + sway_log(L_DEBUG, "Switching to mode `%s'",mode->name); + } free(mode_name); // Set current mode config->current_mode = mode; - return CMD_SUCCESS; + return mode_make ? CMD_BLOCK_MODE : CMD_SUCCESS; } static enum cmd_status cmd_move(int argc, char **argv) { - if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1) - || config->reading || !config->active) { + NO_CONF(); + if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) { return CMD_FAILURE; } @@ -483,10 +529,11 @@ static enum cmd_status cmd_move(int argc, char **argv) { } static enum cmd_status cmd_orientation(int argc, char **argv) { - if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1) - || !config->reading) { + NO_BIND(); + if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1)) { return CMD_FAILURE; } + if (strcasecmp(argv[0], "horizontal") == 0) { config->default_orientation = L_HORIZ; } else if (strcasecmp(argv[0], "vertical") == 0) { @@ -500,6 +547,7 @@ static enum cmd_status cmd_orientation(int argc, char **argv) { } static enum cmd_status cmd_output(int argc, char **argv) { + NO_BIND(); if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) { return CMD_FAILURE; } @@ -510,7 +558,6 @@ static enum cmd_status cmd_output(int argc, char **argv) { output->enabled = true; // TODO: atoi doesn't handle invalid numbers - if (strcasecmp(argv[1], "disable") == 0) { output->enabled = false; } @@ -960,6 +1007,11 @@ static enum cmd_status cmd_log_colors(int argc, char **argv) { return CMD_SUCCESS; } +__attribute__((unused)) +enum cmd_status cmd_for_window(int argc, char **argv) { + return CMD_FAILURE; +} + static enum cmd_status cmd_fullscreen(int argc, char **argv) { if (!checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0) || config->reading || !config->active) { @@ -1087,57 +1139,89 @@ static struct cmd_handler *find_handler(char *line) { return res; } -enum cmd_status handle_command(char *exec) { - sway_log(L_INFO, "Handling command '%s'", exec); - int argc; - char **argv = split_args(exec, &argc); - enum cmd_status status = CMD_FAILURE; - struct cmd_handler *handler; - if (!argc) { - return status; - } - if ((handler = find_handler(argv[0])) == NULL - || (status = handler->handle(argc - 1, argv + 1)) != CMD_SUCCESS) { - sway_log(L_ERROR, "Command failed: %s", argv[0]); - } - free_argv(argc, argv); +enum cmd_status handle_command(char *_exec) { + enum cmd_status status = CMD_SUCCESS; + char *exec = strdup(_exec); + char *head = exec; + char *cmdlist; + char *cmd; + char *criteria __attribute__((unused)); + + head = exec; + do { + // Handle criteria + if (*head == '[') { + criteria = argsep(&head, "]"); + if (head) { + ++head; + // TODO handle criteria + } else { + sway_log(L_ERROR, "Unmatched ["); + status = CMD_INVALID; + } + // Skip leading whitespace + head += strspn(head, whitespace); + } + // Split command list + cmdlist = argsep(&head, ";"); + cmdlist += strspn(cmdlist, whitespace); + do { + // Split commands + cmd = argsep(&cmdlist, ","); + cmd += strspn(cmd, whitespace); + sway_log(L_INFO, "Handling command '%s'", cmd); + //TODO better handling of argv + int argc; + char **argv = split_args(cmd, &argc); + if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { + strip_quotes(argv[1]); + } + struct cmd_handler *handler = find_handler(argv[0]); + enum cmd_status res = CMD_INVALID; + if (!handler + || (res = handler->handle(argc-1, argv+1)) != CMD_SUCCESS) { + sway_log(L_ERROR, "Command '%s' failed", cmd); + free_argv(argc, argv); + status = res; + goto cleanup; + } + free_argv(argc, argv); + } while(cmdlist); + } while(head); + cleanup: + free(exec); return status; } enum cmd_status config_command(char *exec) { sway_log(L_INFO, "handling config command '%s'", exec); + enum cmd_status status = CMD_SUCCESS; int argc; char **argv = split_args(exec, &argc); - enum cmd_status status = CMD_FAILURE; - struct cmd_handler *handler; if (!argc) { - status = CMD_SUCCESS; goto cleanup; } - // TODO better block handling - if (strncmp(argv[0], "}", 1) == 0) { - config->current_mode = config->modes->items[0]; - status = CMD_SUCCESS; + // Endblock + if (**argv == '}') { + status = CMD_BLOCK_END; goto cleanup; } - if ((handler = find_handler(argv[0]))) { - // Dont replace first argument in cmd_set - int i = handler->handle == cmd_set ? 2 : 1; - int e = argc; - for (; i < e; ++i) { - argv[i] = do_var_replacement(argv[i]); - } - status = handler->handle(argc - 1, argv + 1); - if (status == CMD_FAILURE) { - sway_log(L_ERROR, "Config load failed for line `%s'", exec); - } else if (status == CMD_DEFER) { - sway_log(L_DEBUG, "Defferring command `%s'", exec); - list_add(config->cmd_queue, strdup(exec)); - status = CMD_SUCCESS; - } - } else { - sway_log(L_ERROR, "Unknown command `%s'", exec); + struct cmd_handler *handler = find_handler(argv[0]); + if (!handler) { + status = CMD_INVALID; + goto cleanup; + } + int i; + // Var replacement, for all but first argument of set + for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { + argv[i] = do_var_replacement(argv[i]); + } + /* Strip quotes for first argument. + * TODO This part needs to be handled much better */ + if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { + strip_quotes(argv[1]); } + status = handler->handle(argc-1, argv+1); cleanup: free_argv(argc, argv); return status; |