multi command keybinds

This commit is contained in:
taiyu 2015-09-14 19:59:25 -07:00
parent e505abfe75
commit 0bea2e2122
6 changed files with 280 additions and 109 deletions

View file

@ -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;