diff options
Diffstat (limited to 'src/parser.c')
| -rw-r--r-- | src/parser.c | 240 |
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 } |
