aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c236
-rw-r--r--sway/config.c34
-rw-r--r--sway/container.c2
-rw-r--r--sway/handlers.c2
-rw-r--r--sway/log.c8
-rw-r--r--sway/stringop.c118
6 files changed, 277 insertions, 123 deletions
diff --git a/sway/commands.c b/sway/commands.c
index 68bdff2c..80770e87 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -20,6 +20,40 @@
#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_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;
+
swayc_t *sp_view;
int sp_index = 0;
@@ -147,37 +181,33 @@ static enum cmd_status cmd_bindsym(int argc, char **argv) {
}
static enum cmd_status cmd_exec_always(int argc, char **argv) {
+ if (!config->active) return CMD_DEFER;
if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) {
return CMD_FAILURE;
}
- if (!config->active) {
- return CMD_DEFER;
- }
-
- pid_t pid = fork();
- /* Failed to fork */
- if (pid < 0) {
- sway_log(L_ERROR, "exec command failed, sway did not fork");
+ // 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 };
+ sway_log(L_DEBUG, "Executing %s", cmd);
+
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ execv("/bin/sh", args);
+ _exit(-1);
+ } else if (pid < 0) {
+ sway_log(L_ERROR, "exec command failed, sway could not fork");
return CMD_FAILURE;
}
- /* 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);
- }
- /* Parent */
return CMD_SUCCESS;
}
static enum cmd_status cmd_exec(int argc, char **argv) {
- if (!config->active) {
- return CMD_DEFER;
- }
+ if (!config->active) return CMD_DEFER;
+
if (config->reloading) {
char *args = join_args(argv, argc);
sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args);
@@ -194,8 +224,8 @@ static void kill_views(swayc_t *container, void *data) {
}
static enum cmd_status cmd_exit(int argc, char **argv) {
- if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0)
- || config->reading || !config->active) {
+ if (config->reading) return CMD_INVALID;
+ if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0)) {
return CMD_FAILURE;
}
// Close all views
@@ -205,8 +235,8 @@ static enum cmd_status cmd_exit(int argc, char **argv) {
}
static enum cmd_status cmd_floating(int argc, char **argv) {
- if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1)
- || config->reading || !config->active) {
+ if (config->reading) return CMD_INVALID;
+ if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1)) {
return CMD_FAILURE;
}
@@ -267,8 +297,8 @@ static enum cmd_status cmd_floating(int argc, char **argv) {
}
static enum cmd_status cmd_floating_mod(int argc, char **argv) {
- if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)
- || !config->reading) {
+ if (!config->reading) return CMD_INVALID;
+ if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)) {
return CMD_FAILURE;
}
int i, j;
@@ -292,10 +322,10 @@ static enum cmd_status cmd_floating_mod(int argc, char **argv) {
}
static enum cmd_status cmd_focus(int argc, char **argv) {
+ if (config->reading) return CMD_INVALID;
static int floating_toggled_index = 0;
static int tiled_toggled_index = 0;
- if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)
- || config->reading || !config->active) {
+ if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)) {
return CMD_FAILURE;
}
if (strcasecmp(argv[0], "left") == 0) {
@@ -350,6 +380,7 @@ static enum cmd_status cmd_focus(int argc, char **argv) {
}
static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) {
+ if (!config->reading) return CMD_INVALID;
if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) {
return CMD_FAILURE;
}
@@ -359,7 +390,7 @@ static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) {
}
static void hide_view_in_scratchpad(swayc_t *sp_view) {
- if(sp_view == NULL) {
+ if (sp_view == NULL) {
return;
}
@@ -375,15 +406,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) {
+ if (!config->reading) return CMD_INVALID;
+ // 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;
@@ -406,16 +441,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) {
+ if (config->reading) return CMD_FAILURE;
+ if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) {
return CMD_FAILURE;
}
@@ -485,10 +522,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) {
+ if (!config->reading) return CMD_FAILURE;
+ 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) {
@@ -502,6 +540,7 @@ static enum cmd_status cmd_orientation(int argc, char **argv) {
}
static enum cmd_status cmd_output(int argc, char **argv) {
+ if (!config->reading) return CMD_FAILURE;
if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) {
return CMD_FAILURE;
}
@@ -512,7 +551,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;
}
@@ -953,7 +991,7 @@ static enum cmd_status cmd_log_colors(int argc, char **argv) {
}
if (strcasecmp(argv[0], "no") == 0) {
sway_log_colors(0);
- } else if(strcasecmp(argv[0], "yes") == 0) {
+ } else if (strcasecmp(argv[0], "yes") == 0) {
sway_log_colors(1);
} else {
sway_log(L_ERROR, "Invalid log_colors command (expected `yes` or `no`, got '%s')", argv[0]);
@@ -1089,57 +1127,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;
diff --git a/sway/config.c b/sway/config.c
index 23d6ac0d..0026e0af 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -225,14 +225,46 @@ bool read_config(FILE *file, bool is_active) {
config->active = true;
}
bool success = true;
+ enum cmd_status block = CMD_BLOCK_END;
char *line;
while (!feof(file)) {
line = read_line(file);
line = strip_comments(line);
- if (config_command(line) == CMD_FAILURE) {
+ switch(config_command(line)) {
+ case CMD_FAILURE:
+ case CMD_INVALID:
sway_log(L_ERROR, "Error on line '%s'", line);
success = false;
+ break;
+
+ case CMD_DEFER:
+ sway_log(L_DEBUG, "Defferring command `%s'", line);
+ list_add(config->cmd_queue, strdup(line));
+ break;
+
+ case CMD_BLOCK_MODE:
+ if (block == CMD_BLOCK_END) {
+ block = CMD_BLOCK_MODE;
+ } else {
+ sway_log(L_ERROR, "Invalid block '%s'", line);
+ }
+ break;
+
+ case CMD_BLOCK_END:
+ switch(block) {
+ case CMD_BLOCK_MODE:
+ sway_log(L_DEBUG, "End of mode block");
+ config->current_mode = config->modes->items[0];
+ break;
+
+ case CMD_BLOCK_END:
+ sway_log(L_ERROR, "Unmatched }");
+ break;
+
+ default:;
+ }
+ default:;
}
free(line);
}
diff --git a/sway/container.c b/sway/container.c
index 85b169a1..4c523827 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -405,7 +405,7 @@ swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *dat
}
static bool test_name(swayc_t *view, void *data) {
- if (!view && !view->name) {
+ if (!view || !view->name) {
return false;
}
return strcmp(view->name, data) == 0;
diff --git a/sway/handlers.c b/sway/handlers.c
index 096df53c..15fa6521 100644
--- a/sway/handlers.c
+++ b/sway/handlers.c
@@ -331,7 +331,7 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
struct sway_binding *binding = mode->bindings->items[i];
if ((modifiers->mods ^ binding->modifiers) == 0) {
- bool match;
+ bool match = false;
int j;
for (j = 0; j < binding->keys->length; ++j) {
xkb_keysym_t *key = binding->keys->items[j];
diff --git a/sway/log.c b/sway/log.c
index a6582172..a206d971 100644
--- a/sway/log.c
+++ b/sway/log.c
@@ -14,10 +14,10 @@ int colored = 1;
log_importance_t v = L_SILENT;
static const char *verbosity_colors[] = {
- "", // L_SILENT
- "\x1B[1;31m", // L_ERROR
- "\x1B[1;34m", // L_INFO
- "\x1B[1;30m", // L_DEBUG
+ [L_SILENT] = "",
+ [L_ERROR ] = "\x1B[1;31m",
+ [L_INFO ] = "\x1B[1;34m",
+ [L_DEBUG ] = "\x1B[1;30m",
};
void init_log(log_importance_t verbosity) {
diff --git a/sway/stringop.c b/sway/stringop.c
index 7a2c8317..31a036c3 100644
--- a/sway/stringop.c
+++ b/sway/stringop.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <strings.h>
#include <ctype.h>
#include "stringop.h"
@@ -7,7 +8,7 @@
#include "string.h"
#include "list.h"
-const char *whitespace = " \f\n\r\t\v";
+const char whitespace[] = " \f\n\r\t\v";
/* Note: This returns 8 characters for trimmed_start per tab character. */
char *strip_whitespace(char *_str) {
@@ -105,40 +106,40 @@ char **split_args(const char *start, int *argc) {
bool in_char = false;
bool escaped = false;
const char *end = start;
- while (*start) {
- if (!in_token) {
- start = (end += strspn(end, whitespace));
- in_token = true;
- }
- if (*end == '"' && !in_char && !escaped) {
- in_string = !in_string;
- } else if (*end == '\'' && !in_string && !escaped) {
- in_char = !in_char;
- } else if (*end == '\\') {
- escaped = !escaped;
- } else if (*end == '\0' || (!in_string && !in_char && !escaped
- && strchr(whitespace, *end))) {
- goto add_part;
- }
- if (*end != '\\') {
- escaped = false;
- }
- ++end;
- continue;
- add_part:
- if (end - start > 0) {
- char *token = malloc(end - start + 1);
- strncpy(token, start, end - start + 1);
- token[end - start] = '\0';
- strip_quotes(token);
- unescape_string(token);
- argv[*argc] = token;
- if (++*argc + 1 == alloc) {
- argv = realloc(argv, (alloc *= 2) * sizeof(char *));
+ if (start) {
+ while (*start) {
+ if (!in_token) {
+ start = (end += strspn(end, whitespace));
+ in_token = true;
+ }
+ if (*end == '"' && !in_char && !escaped) {
+ in_string = !in_string;
+ } else if (*end == '\'' && !in_string && !escaped) {
+ in_char = !in_char;
+ } else if (*end == '\\') {
+ escaped = !escaped;
+ } else if (*end == '\0' || (!in_string && !in_char && !escaped
+ && strchr(whitespace, *end))) {
+ goto add_token;
+ }
+ if (*end != '\\') {
+ escaped = false;
+ }
+ ++end;
+ continue;
+ add_token:
+ if (end - start > 0) {
+ char *token = malloc(end - start + 1);
+ strncpy(token, start, end - start + 1);
+ token[end - start] = '\0';
+ argv[*argc] = token;
+ if (++*argc + 1 == alloc) {
+ argv = realloc(argv, (alloc *= 2) * sizeof(char *));
+ }
}
+ in_token = false;
+ escaped = false;
}
- in_token = false;
- escaped = false;
}
argv[*argc] = NULL;
return argv;
@@ -312,6 +313,56 @@ char *join_list(list_t *list, char *separator) {
return res;
}
+char *cmdsep(char **stringp, const char *delim) {
+ // skip over leading delims
+ char *head = *stringp + strspn(*stringp, delim);
+ // Find end token
+ char *tail = *stringp += strcspn(*stringp, delim);
+ // Set stringp to begining of next token
+ *stringp += strspn(*stringp, delim);
+ // Set stringp to null if last token
+ if (!**stringp) *stringp = NULL;
+ // Nullify end of first token
+ *tail = 0;
+ return head;
+}
+
+char *argsep(char **stringp, const char *delim) {
+ char *start = *stringp;
+ char *end = start;
+ bool in_string = false;
+ bool in_char = false;
+ bool escaped = false;
+ while (1) {
+ if (*end == '"' && !in_char && !escaped) {
+ in_string = !in_string;
+ } else if (*end == '\'' && !in_string && !escaped) {
+ in_char = !in_char;
+ } else if (*end == '\\') {
+ escaped = !escaped;
+ } else if (*end == '\0') {
+ *stringp = NULL;
+ goto found;
+ } else if (!in_string && !in_char && !escaped && strchr(delim, *end)) {
+ if (end - start) {
+ *(end++) = 0;
+ *stringp = end + strspn(end, delim);;
+ if (!**stringp) *stringp = NULL;
+ goto found;
+ } else {
+ ++start;
+ end = start;
+ }
+ }
+ if (*end != '\\') {
+ escaped = false;
+ }
+ ++end;
+ }
+ found:
+ return start;
+}
+
char *strdup(const char *str) {
char *dup = malloc(strlen(str) + 1);
if (dup) {
@@ -319,3 +370,4 @@ char *strdup(const char *str) {
}
return dup;
}
+