summaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c240
1 files changed, 227 insertions, 13 deletions
diff --git a/src/parser.c b/src/parser.c
index cb01d78..713a298 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1,14 +1,16 @@
#define _POSIX_C_SOURCE 200809L
#include <ctype.h>
-#include <limits.h>
+#include <linux/limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#ifdef __linux__
#include <wordexp.h>
+#endif
#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
#include <X11/Xlib.h>
-
#include "parser.h"
#include "defs.h"
@@ -19,9 +21,13 @@ static const struct {
{"decrease_gaps", dec_gaps},
{"focus_next", focus_next},
{"focus_prev", focus_prev},
+ {"focus_next_mon", focus_next_mon},
+ {"focus_prev_mon", focus_prev_mon},
{"increase_gaps", inc_gaps},
{"master_next", move_master_next},
{"master_previous", move_master_prev},
+ {"move_next_mon", move_next_mon},
+ {"move_prev_mon", move_prev_mon},
{"quit", quit},
{"reload_config", reload_config},
{"master_increase", resize_master_add},
@@ -31,6 +37,7 @@ static const struct {
{"toggle_floating", toggle_floating},
{"global_floating", toggle_floating_global},
{"fullscreen", toggle_fullscreen},
+ {"centre_window", centre_window},
{NULL, NULL}};
static void remap_and_dedupe_binds(Config *cfg)
@@ -100,9 +107,6 @@ static unsigned parse_combo(const char *combo, Config *cfg, KeySym *out_ks)
}
buf[sizeof buf - 1] = '\0';
for (char *tok = strtok(buf, "+"); tok; tok = strtok(NULL, "+")) {
- for (char *q = tok; *q; q++) {
- *q = tolower((unsigned char)*q);
- }
if (!strcmp(tok, "mod")) {
m |= cfg->modkey;
}
@@ -119,6 +123,7 @@ static unsigned parse_combo(const char *combo, Config *cfg, KeySym *out_ks)
m |= Mod4Mask;
}
else {
+ ks = XStringToKeysym(tok);
ks = parse_keysym(tok);
}
}
@@ -178,11 +183,9 @@ found:
/* Initialize should_float matrix */
for (int j = 0; j < 256; j++) {
- cfg->should_float[j] = calloc(1, sizeof(char *));
+ cfg->should_float[j] = calloc(2, sizeof(char *));
if (!cfg->should_float[j]) {
- fprintf(stderr, "calloc failed\n");
- fclose(f);
- return -1;
+ goto cleanup_file;
}
}
@@ -364,17 +367,58 @@ found:
int n;
if (sscanf(act, "move %d", &n) == 1 && n >= 1 && n <= NUM_WORKSPACES) {
- b->type = TYPE_CWKSP;
+ b->type = TYPE_WS_CHANGE;
b->action.ws = n - 1;
}
else if (sscanf(act, "swap %d", &n) == 1 && n >= 1 && n <= NUM_WORKSPACES) {
- b->type = TYPE_MWKSP;
+ b->type = TYPE_WS_MOVE;
b->action.ws = n - 1;
}
else {
fprintf(stderr, "sxwmrc:%d: invalid workspace action '%s'\n", lineno, act);
}
}
+ else if (!strcmp(key, "scratchpad")) {
+ char *mid = strchr(rest, ':');
+ if (!mid) {
+ fprintf(stderr, "sxwmrc:%d: scratchpad missing action\n", lineno);
+ continue;
+ }
+ *mid = '\0';
+ char *combo = strip(rest);
+ char *act = strip(mid + 1);
+
+ KeySym ks;
+ unsigned mods = parse_combo(combo, cfg, &ks);
+ if (ks == NoSymbol) {
+ fprintf(stderr, "sxwmrc:%d: bad key in '%s'\n", lineno, combo);
+ continue;
+ }
+
+ Binding *b = alloc_bind(cfg, mods, ks);
+ if (!b) {
+ fputs("sxwm: too many binds\n", stderr);
+ goto cleanup_file;
+ }
+
+ int padnum = -1;
+
+ if (sscanf(act, "create %d", &padnum) == 1 && padnum >= 1 && padnum <= MAX_SCRATCHPADS) {
+ b->type = TYPE_SP_CREATE;
+ b->action.sp = padnum - 1;
+ }
+ else if (sscanf(act, "toggle %d", &padnum) == 1 && padnum >= 1 && padnum <= MAX_SCRATCHPADS) {
+ b->type = TYPE_SP_TOGGLE;
+ b->action.sp = padnum - 1;
+ }
+ else if (sscanf(act, "remove %d", &padnum) == 1 && padnum >= 1 && padnum <= MAX_SCRATCHPADS) {
+ b->type = TYPE_SP_REMOVE;
+ b->action.sp = padnum - 1;
+ }
+ else {
+ fprintf(stderr, "sxwmrc:%d: invalid scratchpad action '%s'\n", lineno, act);
+ }
+ }
else if (!strcmp(key, "exec")) {
if (torun >= 256) {
fprintf(stderr, "sxwmrc:%d: too many exec commands\n", lineno);
@@ -401,6 +445,81 @@ found:
}
torun++;
}
+ else if (!strcmp(key, "can_swallow")) {
+ char *token = strtok(rest, ",");
+ int i = 0;
+ while (token && i < 256) {
+ char *item = strip_quotes(strip(token));
+ if (*item) {
+ cfg->can_swallow[i] = malloc(2 * sizeof(char *));
+ if (!cfg->can_swallow[i]) {
+ fprintf(stderr, "sxwmrc:%d: malloc failed\n", lineno);
+ break;
+ }
+ cfg->can_swallow[i][0] = strdup(item);
+ cfg->can_swallow[i][1] = NULL;
+ i++;
+ }
+ token = strtok(NULL, ",");
+ }
+ }
+ else if (!strcmp(key, "can_be_swallowed")) {
+ char *token = strtok(rest, ",");
+ int i = 0;
+ while (token && i < 256) {
+ char *item = strip_quotes(strip(token));
+ if (*item) {
+ cfg->can_be_swallowed[i] = malloc(2 * sizeof(char *));
+ if (!cfg->can_be_swallowed[i]) {
+ break;
+ }
+ cfg->can_be_swallowed[i][0] = strdup(item);
+ cfg->can_be_swallowed[i][1] = NULL;
+ i++;
+ }
+ token = strtok(NULL, ",");
+ }
+ }
+ else if (!strcmp(key, "new_win_master")) {
+ cfg->new_win_master = !strcmp(rest, "true") ? True : False;
+ }
+ else if (!strcmp(key, "open_in_workspace")) {
+ char *mid = strchr(rest, ':');
+ if (!mid) {
+ fprintf(stderr, "sxwmrc:%d: open_in_workspace missing workspace number\n", lineno);
+ continue;
+ }
+ *mid = '\0';
+ char *class_name = strip(rest);
+ char *ws_str = strip(mid + 1);
+
+ class_name = strip_quotes(class_name);
+
+ int ws = atoi(ws_str);
+ if (ws < 1 || ws > NUM_WORKSPACES) {
+ fprintf(stderr, "sxwmrc:%d: invalid workspace number %d\n", lineno, ws);
+ continue;
+ }
+
+ /* find free slot in open_in_workspace */
+ int slot = -1;
+ for (int i = 0; i < 256; i++) {
+ if (!cfg->open_in_workspace[i]) {
+ slot = i;
+ break;
+ }
+ }
+
+ if (slot >= 0) {
+ cfg->open_in_workspace[slot] = malloc(2 * sizeof(char *));
+ if (cfg->open_in_workspace[slot]) {
+ cfg->open_in_workspace[slot][0] = strdup(class_name); /* class name */
+ char ws_buf[16];
+ snprintf(ws_buf, sizeof(ws_buf), "%d", ws - 1); /* 0-indexed workspace */
+ cfg->open_in_workspace[slot][1] = strdup(ws_buf); /* workspace number */
+ }
+ }
+ }
else {
fprintf(stderr, "sxwmrc:%d: unknown option '%s'\n", lineno, key);
}
@@ -419,6 +538,19 @@ cleanup_file:
free(cfg->should_float[j][0]);
free(cfg->should_float[j]);
}
+ if (cfg->can_swallow[j]) {
+ free(cfg->can_swallow[j][0]);
+ free(cfg->can_swallow[j]);
+ }
+ if (cfg->can_be_swallowed[j]) {
+ free(cfg->can_be_swallowed[j][0]);
+ free(cfg->can_be_swallowed[j]);
+ }
+ if (cfg->open_in_workspace[j]) {
+ free(cfg->open_in_workspace[j][0]);
+ free(cfg->open_in_workspace[j][1]);
+ free(cfg->open_in_workspace[j]);
+ }
}
for (int i = 0; i < torun; i++) {
free(cfg->torun[i]);
@@ -468,15 +600,75 @@ KeySym parse_keysym(const char *key)
return NoSymbol;
}
+#ifndef __linux__
+static char **split_cmd(const char *cmd, int *out_argc)
+{
+ enum { NORMAL, IN_QUOTE } state = NORMAL;
+ const char *p = cmd;
+ size_t cap = 8, argc = 0, toklen = 0;
+ char *token = malloc(strlen(cmd) + 1);
+ char **argv = malloc(cap * sizeof *argv);
+ if (!token || !argv) {
+ goto err;
+ }
+
+ while (*p) {
+ if (state == NORMAL && isspace((unsigned char)*p)) {
+ if (toklen) {
+ token[toklen] = '\0';
+ if (argc + 1 >= cap) {
+ cap *= 2;
+ argv = realloc(argv, cap * sizeof *argv);
+ if (!argv) {
+ goto err;
+ }
+ }
+ argv[argc++] = strdup(token);
+ toklen = 0;
+ }
+ }
+ else if (*p == '"') {
+ state = (state == NORMAL) ? IN_QUOTE : NORMAL;
+ }
+ else {
+ token[toklen++] = *p;
+ }
+ p++;
+ }
+
+ if (toklen) {
+ token[toklen] = '\0';
+ argv[argc++] = strdup(token);
+ }
+ argv[argc] = NULL;
+ *out_argc = argc;
+ free(token);
+ return argv;
+
+err:
+ if (token) {
+ free(token);
+ }
+ if (argv) {
+ for (size_t i = 0; i < argc; i++) {
+ free(argv[i]);
+ }
+ free(argv);
+ }
+ return NULL;
+}
+#endif
+
const char **build_argv(const char *cmd)
{
+#ifdef __linux__
wordexp_t p;
if (wordexp(cmd, &p, 0) != 0 || p.we_wordc == 0) {
fprintf(stderr, "sxwm: wordexp failed for cmd: '%s'\n", cmd);
return NULL;
}
- const char **argv = malloc((p.we_wordc + 1) * sizeof(char *));
+ const char **argv = malloc((p.we_wordc + 1) * sizeof *argv);
if (!argv) {
wordfree(&p);
return NULL;
@@ -486,7 +678,29 @@ const char **build_argv(const char *cmd)
argv[i] = strdup(p.we_wordv[i]);
}
argv[p.we_wordc] = NULL;
-
wordfree(&p);
return argv;
+#else
+ int argc = 0;
+ char **tmp = split_cmd(cmd, &argc);
+ if (!tmp) {
+ return NULL;
+ }
+
+ const char **argv = malloc((argc + 1) * sizeof *argv);
+ if (!argv) {
+ for (int i = 0; i < argc; i++) {
+ free(tmp[i]);
+ }
+ free(tmp);
+ return NULL;
+ }
+
+ for (int i = 0; i < argc; i++) {
+ argv[i] = tmp[i];
+ }
+ argv[argc] = NULL;
+ free(tmp);
+ return argv;
+#endif
}