From 1743a7c340ee17fb8d3e41fa2a777bcadcb1a867 Mon Sep 17 00:00:00 2001 From: uint23 Date: Sat, 3 May 2025 09:09:09 +0100 Subject: update parser so binds will not overlap from pervious binds + parser is more simple --- Makefile | 2 +- build/parser.o | Bin 0 -> 39960 bytes build/sxwm.o | Bin 0 -> 141224 bytes default_sxrc | 70 ++++---- src/config.h | 260 ++++++----------------------- src/defs.h | 58 ++----- src/parser.c | 508 ++++++++++++++++++++++++++++++++------------------------- src/parser.h | 7 +- src/sxwm.c | 146 +++++++++++------ sxwm | Bin 0 -> 135960 bytes 10 files changed, 484 insertions(+), 567 deletions(-) create mode 100644 build/parser.o create mode 100644 build/sxwm.o create mode 100755 sxwm diff --git a/Makefile b/Makefile index 7c69201..2b2e550 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC ?= gcc -CFLAGS ?= -std=c99 -Wall -Wextra -O3 -Isrc +CFLAGS ?= -std=c99 -Wall -Wextra -O3 -Isrc -g LDFLAGS ?= -lX11 -lXinerama -lXcursor PREFIX ?= /usr/local diff --git a/build/parser.o b/build/parser.o new file mode 100644 index 0000000..e471159 Binary files /dev/null and b/build/parser.o differ diff --git a/build/sxwm.o b/build/sxwm.o new file mode 100644 index 0000000..d762c27 Binary files /dev/null and b/build/sxwm.o differ diff --git a/default_sxrc b/default_sxrc index f973f08..c6f96e8 100644 --- a/default_sxrc +++ b/default_sxrc @@ -18,54 +18,54 @@ motion_throttle : 60 # Set to screen refresh rate for smoothest motions mod_key : super # Application Launchers: -bind : [mod + Return] : "st" -bind : [mod + b] : "firefox" -bind : [mod + p] : "dmenu_run" +bind : mod + Return : "st" +bind : mod + b : "firefox" +bind : mod + p : "dmenu_run" # Window Management: -bind : [mod + shift + q] : close_window -bind : [mod + shift + e] : quit +call : mod + shift + q : close_window +call : mod + shift + e : quit # Focus Movement: -bind : [mod + j] : focus_next -bind : [mod + k] : focus_prev +call : mod + j : focus_next +call : mod + k : focus_prev # Master/Stack Movement -bind : [mod + shift + j] : master_next -bind : [mod + shift + k] : master_previous +call : mod + shift + j : master_next +call : mod + shift + k : master_previous # Master Area Resize -bind : [mod + l] : master_increase -bind : [mod + h] : master_decrease +call : mod + l : master_increase +call : mod + h : master_decrease # Gaps -bind : [mod + equal] : increase_gaps -bind : [mod + minus] : decrease_gaps +call : mod + equal : increase_gaps +call : mod + minus : decrease_gaps # Floating/Fullscreen -bind : [mod + space] : toggle_floating -bind : [mod + shift + space] : global_floating -bind : [mod + shift + f] : fullscreen +call : mod + space : toggle_floating +call : mod + shift + space : global_floating +call : mod + shift + f : fullscreen # Reload Config -bind : [mod + r] : reload_config +call : mod + r : reload_config # Workspaces (1-9) -bind : [mod + 1] : change_ws1 -bind : [mod + shift + 1] : moveto_ws1 -bind : [mod + 2] : change_ws2 -bind : [mod + shift + 2] : moveto_ws2 -bind : [mod + 3] : change_ws3 -bind : [mod + shift + 3] : moveto_ws3 -bind : [mod + 4] : change_ws4 -bind : [mod + shift + 4] : moveto_ws4 -bind : [mod + 5] : change_ws5 -bind : [mod + shift + 5] : moveto_ws5 -bind : [mod + 6] : change_ws6 -bind : [mod + shift + 6] : moveto_ws6 -bind : [mod + 7] : change_ws7 -bind : [mod + shift + 7] : moveto_ws7 -bind : [mod + 8] : change_ws8 -bind : [mod + shift + 8] : moveto_ws8 -bind : [mod + 9] : change_ws9 -bind : [mod + shift + 9] : moveto_ws9 \ No newline at end of file +workspace : [mod + 1] : move 1 +workspace : [mod + shift + 1] : swap 1 +workspace : [mod + 2] : move 2 +workspace : [mod + shift + 2] : swap 2 +workspace : [mod + 3] : move 3 +workspace : [mod + shift + 3] : swap 3 +workspace : [mod + 4] : move 4 +workspace : [mod + shift + 4] : swap 4 +workspace : [mod + 5] : move 5 +workspace : [mod + shift + 5] : swap 5 +workspace : [mod + 6] : move 6 +workspace : [mod + shift + 6] : swap 6 +workspace : [mod + 7] : move 7 +workspace : [mod + shift + 7] : swap 7 +workspace : [mod + 8] : move 8 +workspace : [mod + shift + 8] : swap 8 +workspace : [mod + 9] : move 9 +workspace : [mod + shift + 9] : swap 9 \ No newline at end of file diff --git a/src/config.h b/src/config.h index 64e664b..ccc28ea 100644 --- a/src/config.h +++ b/src/config.h @@ -1,211 +1,53 @@ /* See LICENSE for more information on use */ - -/* - * ——————————————< Appearance >—————————————— * - * - * In this section you can configure the - * settings for sxwm. You can ignore the - * #define as it is C specific syntax - * - * GAPS (px): - * How many pixels between windows and - * screen edges (including bar) - * BORDER_WIDTH (px): - * How thick your border is - * - * BORDER_FOC_COL (hex): - * The colour of your border when the - * window is focused - * - * BORDER_UFOC_COL (hex): - * The colour of your border when the - * window is unfocused - * - * MASTER_WIDTH (int): - * % of the screen the master window - * should take - * - * RESIZE_MASTER_AMT (%): - * % of the master width you want to - * increment by - * - * MOTION_THROTTLE (int): - * Usually you should set this to your - * screen refreshrate. This is set so - * there is no exessive number of - * requests being sent to the X server - * - * SNAP_DISTANCE (px): - * How many pixels away from the screen - * until the window *snaps* to the edge - * - * NUM_WORKSPACES (int): - * This is how many workspaces you want in - * this window manager. Best to leave it - * default (9). - * - * WORKSPACE_NAMES (char[]): - * This is just the label that will appear - * on your status bar. Doesn't have to be - * a number, it can be anything. Ignore - * the "\0", this is just a NULL that says - * to start again, otherwise it would be - * all of them concatenated together. - * - * ———————————————————————————————————————————* -*/ - -#define NUM_WORKSPACES 9 -#define WORKSPACE_NAMES \ - "1" "\0"\ - "2" "\0"\ - "3" "\0"\ - "4" "\0"\ - "5" "\0"\ - "6" "\0"\ - "7" "\0"\ - "8" "\0"\ - "9" "\0"\ - -/* - * ————————————< Keys & Bindins >—————————————* - * - * This is where you set your keybinds to - * execute apps. You can use the CMD macro - * to make new variables. - * - * How do you make a command to run an app - * It's simple! Just do this: - * - * CALL(appcallname, "app", "arg2", ...); - * - * What is appcallname? This is just the - * variable name given to this string of - * commands given to execvp, the function - * that executes these programs. - * - * ———————————————————————————————————————————* - * -*/ - -CMD(terminal, "st"); -CMD(browser, "firefox"); - -/* - * ———————————————< Bindings >————————————————* - * - * This is where you assign keybinds to - * perform some actions. - * - * How do you bind keys? In sxwm, there is - * three ways to bind keys to perform - * tasks: - * - * BIND, CALL or WORKSPACE. - * CALL, calls a function, - * BIND, executes a specified - * program. - * WORKSPACE, sets the bind to move - * and item to said workspace or to - * change to that workspace. - * - * USEAGE: - * BIND(MODIFIERS, KEY, FUNCTION) - * - * MODIFIERS: - * The mod keys you want held down - * for the task to execute. I have - * also defined SHIFT as a substitute - * for ShiftMask. - * - * KEY: - * The key to press in combination - * with the MODIFERS to run the task. - * - * FUNCTION: - * The task to execute. Depending on - * whether you're calling CALL or - * BIND, this will execute a program - * or call a function. - * - * If you're - * calling a function, just put the - * name of the funtion. - * - * Otherwise, put the program you - * either defined with the CMD above - * or you can skip that step and just - * do something like this to create a - * "string" in the bindings array: - * - * { "program", "arg1", NULL } - * - * End the line with a comma, as this is - * an array. - * - * ———————————————————————————————————————————* -*/ - -/*< This is your modifier key (ALT/SUPER) >*/ +#include #include -const Binding binds[] = -{ -/*————< Mod4MaskIFIER(S) >< KEY >—————< FUNCTION >——*/ - -/*———————< Here are your functions calls >————— — */ - - CALL(Mod4Mask|SHIFT, e, quit), - CALL(Mod4Mask|SHIFT, q, close_focused), - - CALL(Mod4Mask, j, focus_next), - CALL(Mod4Mask, k, focus_prev), - - CALL(Mod4Mask|SHIFT, j, move_master_next), - CALL(Mod4Mask|SHIFT, k, move_master_prev), - - CALL(Mod4Mask, l, resize_master_add), - CALL(Mod4Mask, h, resize_master_sub), - - CALL(Mod4Mask, equal, inc_gaps), - CALL(Mod4Mask, minus, dec_gaps), - - CALL(Mod4Mask, space, toggle_floating), - CALL(Mod4Mask|SHIFT, space, toggle_floating_global), - - CALL(Mod4Mask|SHIFT, f, toggle_fullscreen), - -/*—————< Here are your executable functions >—————*/ - - BIND(Mod4Mask, Return, terminal), - BIND(Mod4Mask, b, browser), - -/*—————< This is for workspaces >—————————————————*/ - - CALL(Mod4Mask, 1, change_ws1), - CALL(Mod4Mask|SHIFT, 1, moveto_ws1), - - CALL(Mod4Mask, 2, change_ws2), - CALL(Mod4Mask|SHIFT, 2, moveto_ws2), - - CALL(Mod4Mask, 3, change_ws3), - CALL(Mod4Mask|SHIFT, 3, moveto_ws3), - - CALL(Mod4Mask, 4, change_ws4), - CALL(Mod4Mask|SHIFT, 4, moveto_ws4), - - CALL(Mod4Mask, 5, change_ws5), - CALL(Mod4Mask|SHIFT, 5, moveto_ws5), - - CALL(Mod4Mask, 6, change_ws6), - CALL(Mod4Mask|SHIFT, 6, moveto_ws6), - - CALL(Mod4Mask, 7, change_ws7), - CALL(Mod4Mask|SHIFT, 7, moveto_ws7), - - CALL(Mod4Mask, 8, change_ws8), - CALL(Mod4Mask|SHIFT, 8, moveto_ws8), - - CALL(Mod4Mask, 9, change_ws9), - CALL(Mod4Mask|SHIFT, 9, moveto_ws9), - -}; +#include "defs.h" + +CMD(terminal, "st"); +CMD(browser, "firefox"); + +const Binding binds[] = { + {Mod4Mask | ShiftMask, XK_e, {.fn = quit}, TYPE_FUNC}, + {Mod4Mask | ShiftMask, XK_q, {.fn = close_focused}, TYPE_FUNC}, + + {Mod4Mask, XK_j, {.fn = focus_next}, TYPE_FUNC}, + {Mod4Mask, XK_k, {.fn = focus_prev}, TYPE_FUNC}, + + {Mod4Mask | ShiftMask, XK_j, {.fn = move_master_next}, TYPE_FUNC}, + {Mod4Mask | ShiftMask, XK_k, {.fn = move_master_prev}, TYPE_FUNC}, + + {Mod4Mask, XK_l, {.fn = resize_master_add}, TYPE_FUNC}, + {Mod4Mask, XK_h, {.fn = resize_master_sub}, TYPE_FUNC}, + + {Mod4Mask, XK_equal, {.fn = inc_gaps}, TYPE_FUNC}, + {Mod4Mask, XK_minus, {.fn = dec_gaps}, TYPE_FUNC}, + + {Mod4Mask, XK_space, {.fn = toggle_floating}, TYPE_FUNC}, + {Mod4Mask | ShiftMask, XK_space, {.fn = toggle_floating_global}, TYPE_FUNC}, + {Mod4Mask | ShiftMask, XK_f, {.fn = toggle_fullscreen}, TYPE_FUNC}, + + {Mod4Mask, XK_Return, {.cmd = terminal}, TYPE_CMD}, + {Mod4Mask, XK_b, {.cmd = browser}, TYPE_CMD}, + {Mod4Mask, XK_p, {.cmd = (const char *[]){"dmenu_run", NULL}}, TYPE_CMD}, + + {Mod4Mask, XK_r, {.fn = reload_config}, TYPE_FUNC}, + + {Mod4Mask, XK_1, {.ws = 0}, TYPE_CWKSP}, + {Mod4Mask | ShiftMask, XK_1, {.ws = 0}, TYPE_MWKSP}, + {Mod4Mask, XK_2, {.ws = 1}, TYPE_CWKSP}, + {Mod4Mask | ShiftMask, XK_2, {.ws = 1}, TYPE_MWKSP}, + {Mod4Mask, XK_3, {.ws = 2}, TYPE_CWKSP}, + {Mod4Mask | ShiftMask, XK_3, {.ws = 2}, TYPE_MWKSP}, + {Mod4Mask, XK_4, {.ws = 3}, TYPE_CWKSP}, + {Mod4Mask | ShiftMask, XK_4, {.ws = 3}, TYPE_MWKSP}, + {Mod4Mask, XK_5, {.ws = 4}, TYPE_CWKSP}, + {Mod4Mask | ShiftMask, XK_5, {.ws = 4}, TYPE_MWKSP}, + {Mod4Mask, XK_6, {.ws = 5}, TYPE_CWKSP}, + {Mod4Mask | ShiftMask, XK_6, {.ws = 5}, TYPE_MWKSP}, + {Mod4Mask, XK_7, {.ws = 6}, TYPE_CWKSP}, + {Mod4Mask | ShiftMask, XK_7, {.ws = 6}, TYPE_MWKSP}, + {Mod4Mask, XK_8, {.ws = 7}, TYPE_CWKSP}, + {Mod4Mask | ShiftMask, XK_8, {.ws = 7}, TYPE_MWKSP}, + {Mod4Mask, XK_9, {.ws = 8}, TYPE_CWKSP}, + {Mod4Mask | ShiftMask, XK_9, {.ws = 8}, TYPE_MWKSP}, +}; \ No newline at end of file diff --git a/src/defs.h b/src/defs.h index 9257fbc..174ae27 100644 --- a/src/defs.h +++ b/src/defs.h @@ -1,5 +1,6 @@ /* See LICENSE for more information on use */ #pragma once +#include #define SXWM_VERSION "sxwm ver. 1.4" #define SXWM_AUTHOR "(C) Abhinav Prasai 2025" #define SXWM_LICINFO "See LICENSE for more info" @@ -22,46 +23,22 @@ #define CMD(name, ...) \ const char *name[] = { __VA_ARGS__, NULL } +#define TYPE_CWKSP 0 +#define TYPE_MWKSP 1 +#define TYPE_FUNC 2 +#define TYPE_CMD 3 -#include -#define INIT_WORKSPACE \ -void change_ws1(void);\ -void moveto_ws1(void);\ -void change_ws2(void);\ -void moveto_ws2(void);\ -void change_ws3(void);\ -void moveto_ws3(void);\ -void change_ws4(void);\ -void moveto_ws4(void);\ -void change_ws5(void);\ -void moveto_ws5(void);\ -void change_ws6(void);\ -void moveto_ws6(void);\ -void change_ws7(void);\ -void moveto_ws7(void);\ -void change_ws8(void);\ -void moveto_ws8(void);\ -void change_ws9(void);\ -void moveto_ws9(void);\ -void change_ws1(void) { change_workspace(0); update_net_client_list(); } \ -void moveto_ws1(void) { move_to_workspace(0); update_net_client_list(); }\ -void change_ws2(void) { change_workspace(1); update_net_client_list(); } \ -void moveto_ws2(void) { move_to_workspace(1); update_net_client_list(); }\ -void change_ws3(void) { change_workspace(2); update_net_client_list(); } \ -void moveto_ws3(void) { move_to_workspace(2); update_net_client_list(); }\ -void change_ws4(void) { change_workspace(3); update_net_client_list(); } \ -void moveto_ws4(void) { move_to_workspace(3); update_net_client_list(); }\ -void change_ws5(void) { change_workspace(4); update_net_client_list(); } \ -void moveto_ws5(void) { move_to_workspace(4); update_net_client_list(); }\ -void change_ws6(void) { change_workspace(5); update_net_client_list(); } \ -void moveto_ws6(void) { move_to_workspace(5); update_net_client_list(); }\ -void change_ws7(void) { change_workspace(6); update_net_client_list(); } \ -void moveto_ws7(void) { move_to_workspace(6); update_net_client_list(); }\ -void change_ws8(void) { change_workspace(7); update_net_client_list(); } \ -void moveto_ws8(void) { move_to_workspace(7); update_net_client_list(); }\ -void change_ws9(void) { change_workspace(8); update_net_client_list(); } \ -void moveto_ws9(void) { move_to_workspace(8); update_net_client_list(); }\ - +#define NUM_WORKSPACES 9 +#define WORKSPACE_NAMES \ + "1" "\0"\ + "2" "\0"\ + "3" "\0"\ + "4" "\0"\ + "5" "\0"\ + "6" "\0"\ + "7" "\0"\ + "8" "\0"\ + "9" "\0"\ typedef enum { DRAG_NONE, @@ -75,13 +52,14 @@ typedef void (*EventHandler)(XEvent *); typedef union { const char **cmd; void (*fn)(void); + int ws; } Action; typedef struct { int mods; KeySym keysym; Action action; - Bool is_func; + int type; } Binding; typedef struct Client{ diff --git a/src/parser.c b/src/parser.c index d2efba7..7cf7b18 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,267 +1,323 @@ -/* See LICENSE for more information on use */ -#define _POSIX_C_SOURCE 200809L /* for strdup */ +#define _POSIX_C_SOURCE 200809L #include -#include +#include #include #include #include - #include -#include #include "parser.h" -#define MAX_LINE 512 +#include "defs.h" -static const struct { const char *name; void (*fn)(void); } call_table[] = { - { "close_window", close_focused }, - { "decrease_gaps", dec_gaps }, - { "focus_next", focus_next }, - { "focus_previous", focus_prev }, - { "increase_gaps", inc_gaps }, - { "master_next", move_master_next }, - { "master_previous", move_master_prev }, - { "quit", quit }, - { "reload_config", reload_config }, - { "master_increase", resize_master_add }, - { "master_decrease", resize_master_sub }, - { "toggle_floating", toggle_floating }, - { "global_floating", toggle_floating_global }, - { "fullscreen", toggle_fullscreen }, - { NULL, NULL } -}; +static const struct { + const char *name; + void (*fn)(void); +} call_table[] = {{"close_window", close_focused}, + {"decrease_gaps", dec_gaps}, + {"focus_next", focus_next}, + {"focus_prev", focus_prev}, + {"increase_gaps", inc_gaps}, + {"master_next", move_master_next}, + {"master_previous", move_master_prev}, + {"quit", quit}, + {"reload_config", reload_config}, + {"master_increase", resize_master_add}, + {"master_decrease", resize_master_sub}, + {"toggle_floating", toggle_floating}, + {"global_floating", toggle_floating_global}, + {"fullscreen", toggle_fullscreen}, + {NULL, NULL}}; -/* helpers */ -static char* -strip(char *s) +static void remap_and_dedupe_binds(Config *cfg) { - while (isspace((unsigned char)*s)) s++; - if (!*s) return s; - char *end = s + strlen(s) - 1; - while (end > s && isspace((unsigned char)*end)) *end-- = '\0'; - return s; + for (int i = 0; i < cfg->bindsn; i++) { + Binding *b = &cfg->binds[i]; + if (b->mods & (Mod1Mask | Mod4Mask)) { + unsigned others = b->mods & ~(Mod1Mask | Mod4Mask); + b->mods = others | cfg->modkey; + } + } + + for (int i = 0; i < cfg->bindsn; i++) { + for (int j = i + 1; j < cfg->bindsn; j++) { + if (cfg->binds[i].mods == cfg->binds[j].mods && cfg->binds[i].keysym == cfg->binds[j].keysym) { + memmove(&cfg->binds[j], &cfg->binds[j + 1], sizeof(Binding) * (cfg->bindsn - j - 1)); + cfg->bindsn--; + j--; + } + } + } } -static char* -strip_quotes(char *s) +static char *strip(char *s) { - size_t len = strlen(s); - if (len > 0 && s[0] == '"') { - s++; - len--; - } - if (len > 0 && s[len-1] == '"') { - s[len-1] = '\0'; - } - return s; + while (*s && isspace((unsigned char)*s)) { + s++; + } + char *e = s + strlen(s) - 1; + while (e > s && isspace((unsigned char)*e)) { + *e-- = '\0'; + } + return s; } -static const char** build_argv(char *cmdline) +static char *strip_quotes(char *s) { - char **argv = calloc(MAX_ARGS + 1, sizeof(char *)); - if (!argv) return NULL; - - int argc = 0; - char *tok = strtok(cmdline, " \t"); - while (tok && argc < MAX_ARGS) { - argv[argc++] = strdup(tok); - tok = strtok(NULL, " \t"); - } - argv[argc] = NULL; - return (const char **)argv; + size_t L = strlen(s); + if (L > 0 && s[0] == '"') { + s++; + L--; + } + if (L > 0 && s[L - 1] == '"') { + s[L - 1] = '\0'; + } + return s; } -unsigned int -parse_mods(const char *mods, Config *user_config) +static Binding *alloc_bind(Config *cfg, unsigned mods, KeySym ks) { - unsigned int m = 0; - char buf[MAX_LINE]; - strncpy(buf, mods, sizeof(buf)-1); - buf[sizeof(buf)-1] = '\0'; - - for (char *tok = strtok(buf, "+"); tok; tok = strtok(NULL, "+")) { - for (char *p = tok; *p; p++) *p = tolower((unsigned char)*p); - if (strcmp(tok, "mod") == 0) m |= user_config->modkey; - else if (strcmp(tok, "shift") == 0) m |= ShiftMask; - else if (strcmp(tok, "ctrl") == 0) m |= ControlMask; - else if (strcmp(tok, "alt") == 0) m |= Mod1Mask; - else if (strcmp(tok, "super") == 0) m |= Mod4Mask; - } - return m; + for (int i = 0; i < cfg->bindsn; i++) { + if (cfg->binds[i].mods == (int)mods && cfg->binds[i].keysym == ks) { + return &cfg->binds[i]; + } + } + if (cfg->bindsn >= 256) { + return NULL; + } + Binding *b = &cfg->binds[cfg->bindsn++]; + b->mods = mods; + b->keysym = ks; + return b; } -KeySym -parse_keysym(const char *key) +static unsigned parse_combo(const char *combo, Config *cfg, KeySym *out_ks) { - char buf[64]; - size_t len = strlen(key); - if (len >= sizeof(buf)) len = sizeof(buf) - 1; - - if (len == 1) { - buf[0] = key[0]; - buf[1] = '\0'; - } else { - buf[0] = toupper((unsigned char)key[0]); - for (size_t i = 1; i < len; i++) - buf[i] = tolower((unsigned char)key[i]); - buf[len] = '\0'; - } - - KeySym ks = XStringToKeysym(buf); - if (ks == NoSymbol) { - for (size_t i = 0; i < len; i++) - buf[i] = toupper((unsigned char)key[i]); - buf[len] = '\0'; - ks = XStringToKeysym(buf); - } - if (ks == NoSymbol) - fprintf(stderr, "sxwmrc: unknown keysym '%s'\n", key); - return ks; + unsigned m = 0; + KeySym ks = NoSymbol; + char buf[256]; + strncpy(buf, combo, sizeof buf - 1); + for (char *p = buf; *p; p++) { + if (*p == '+' || isspace((unsigned char)*p)) { + *p = '+'; + } + } + 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; + } else if (!strcmp(tok, "shift")) { + m |= ShiftMask; + } else if (!strcmp(tok, "ctrl")) { + m |= ControlMask; + } else if (!strcmp(tok, "alt")) { + m |= Mod1Mask; + } else if (!strcmp(tok, "super")) { + m |= Mod4Mask; + } else { + ks = parse_keysym(tok); + } + } + *out_ks = ks; + return m; } -void -handler(char *command, char *arg, int mods, KeySym keysym, Action action, - Bool is_func, Config *user_config) +int parser(Config *cfg) { - if (strcmp(command, "bind") == 0) { - /* check if binding already exists */ - int slot = user_config->bindsn; - for (int i = 0; i < user_config->bindsn; i++) { - if (user_config->binds[i].mods == mods && - user_config->binds[i].keysym == keysym) { - slot = i; - break; - } - } + char path[PATH_MAX]; + const char *home = getenv("HOME"); + if (!home) { + fputs("sxwmrc: HOME not set\n", stderr); + return -1; + } + snprintf(path, sizeof path, "%s/.config/sxwmrc", home); + FILE *f = fopen(path, "r"); + if (!f) { + fprintf(stderr, "sxwmrc: cannot open %s\n", path); + return -1; + } - if (slot == user_config->bindsn) - user_config->bindsn++; + char line[512]; + int lineno = 0; + while (fgets(line, sizeof line, f)) { + lineno++; + char *s = strip(line); + if (!*s || *s == '#') { + continue; + } - Binding *b = &user_config->binds[slot]; - b->mods = mods; - b->keysym = keysym; - b->is_func = is_func; + char *sep = strchr(s, ':'); + if (!sep) { + fprintf(stderr, "sxwmrc:%d: missing ':'\n", lineno); + continue; + } + *sep = '\0'; + char *key = strip(s); + char *rest = strip(sep + 1); - if (is_func) { - for (size_t j = 0; call_table[j].name; j++) { - if (strcmp(arg, call_table[j].name) == 0) { - b->action.fn = call_table[j].fn; - break; - } - } - } else { - b->action.cmd = action.cmd; - } - return; - } + if (!strcmp(key, "mod_key")) { + unsigned m = parse_mods(rest, cfg); + if (m & (Mod1Mask | Mod4Mask)) { + cfg->modkey = m; + } else { + fprintf(stderr, "sxwmrc:%d: unknown mod_key '%s'\n", lineno, rest); + } + } else if (!strcmp(key, "gaps")) { + cfg->gaps = atoi(rest); + } else if (!strcmp(key, "border_width")) { + cfg->border_width = atoi(rest); + } else if (!strcmp(key, "focused_border_colour")) { + cfg->border_foc_col = parse_col(rest); + } else if (!strcmp(key, "unfocused_border_colour")) { + cfg->border_ufoc_col = parse_col(rest); + } else if (!strcmp(key, "swap_border_colour")) { + cfg->border_swap_col = parse_col(rest); + } else if (!strcmp(key, "master_width")) { + cfg->master_width = atoi(rest) / 100.0f; + } else if (!strcmp(key, "motion_throttle")) { + cfg->motion_throttle = atoi(rest); + } else if (!strcmp(key, "resize_master_amount")) { + cfg->resize_master_amt = atoi(rest); + } else if (!strcmp(key, "snap_distance")) { + cfg->snap_distance = atoi(rest); + } else if (!strcmp(key, "call") || !strcmp(key, "bind")) { + char *mid = strchr(rest, ':'); + if (!mid) { + fprintf(stderr, "sxwmrc:%d: '%s' missing action\n", lineno, key); + continue; + } + *mid = '\0'; + char *combo = strip(rest); + char *act = strip(mid + 1); - if (strcmp(command, "gaps") == 0) user_config->gaps = atoi(arg); - else if (strcmp(command, "border_width") == 0) user_config->border_width = atoi(arg); - else if (strcmp(command, "focused_border_colour") == 0) user_config->border_foc_col = parse_col(arg); - else if (strcmp(command, "unfocused_border_colour") == 0) user_config->border_ufoc_col = parse_col(arg); - else if (strcmp(command, "swap_border_colour") == 0) user_config->border_swap_col = parse_col(arg); - else if (strcmp(command, "master_width") == 0) user_config->master_width = atoi(arg) / 100.0f; - else if (strcmp(command, "motion_throttle") == 0) user_config->motion_throttle = atoi(arg); - else if (strcmp(command, "resize_master_amount") == 0) user_config->resize_master_amt = atoi(arg); - else if (strcmp(command, "snap_distance") == 0) user_config->snap_distance = atoi(arg); - else if (strcmp(command, "mod_key") == 0) user_config->modkey = parse_mods(arg, user_config); - else - fprintf(stderr, "sxwmrc: unknown setting '%s'\n", command); -} -int -parser(Config *user_config) -{ - char *home = getenv("HOME"); - if (!home) { - fputs("sxwmrc: HOME not set\n", stderr); - return -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); + break; + } - char path[PATH_MAX]; - snprintf(path, sizeof(path), "%s/.config/sxwmrc", home); - FILE *f = fopen(path, "r"); - if (!f) { - fprintf(stderr, "sxwmrc: cannot open '%s'\n", path); - return -1; - } + if (*act == '"' && !strcmp(key, "bind")) { + b->type = TYPE_CMD; + b->action.cmd = build_argv(strip_quotes(act)); + } else { + b->type = TYPE_FUNC; + Bool found = False; + for (int i = 0; call_table[i].name; i++) { + if (!strcmp(act, call_table[i].name)) { + b->action.fn = call_table[i].fn; + found = True; + break; + } + } + if (!found) { + fprintf(stderr, "sxwmrc:%d: unknown function '%s'\n", lineno, act); + } + } + } else if (!strcmp(key, "workspace")) { + char *mid = strchr(rest, ':'); + if (!mid) { + fprintf(stderr, "sxwmrc:%d: workspace missing action\n", lineno); + continue; + } + *mid = '\0'; + char *combo = strip(rest); + char *act = strip(mid + 1); - char line[MAX_LINE]; - int lineno = 0; - while (fgets(line, sizeof(line), f)) { - lineno++; - char *s = strip(line); - if (!*s || *s == '#') continue; + 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); + break; + } - /* split key : value */ - char *sep = strchr(s, ':'); - if (!sep) { - fprintf(stderr, "sxwmrc:%d: missing ':'\n", lineno); - continue; - } - *sep = '\0'; - char *key = strip(s); - char *val = strip(sep + 1); + int n; + if (sscanf(act, "move %d", &n) == 1 && n >= 1 && n <= NUM_WORKSPACES) { + b->type = TYPE_CWKSP; + b->action.ws = n - 1; + } else if (sscanf(act, "swap %d", &n) == 1 && n >= 1 && n <= NUM_WORKSPACES) { + b->type = TYPE_MWKSP; + b->action.ws = n - 1; + } else { + fprintf(stderr, "sxwmrc:%d: invalid workspace action '%s'\n", lineno, act); + } + } else { + fprintf(stderr, "sxwmrc:%d: unknown option '%s'\n", lineno, key); + } + } - if (strcmp(key, "bind") == 0) { - /* bind parsing */ - char *mid = strchr(val, ':'); - if (!mid) { - fprintf(stderr, "sxwmrc:%d: bind missing action\n", lineno); - continue; - } - *mid = '\0'; - char *combo = strip(val); - char *act = strip(mid + 1); + fclose(f); + remap_and_dedupe_binds(cfg); + return 0; +} - if (*combo == '[') { - combo++; - } - size_t L = strlen(combo); - if (L && combo[L-1] == ']') { - combo[L-1] = '\0'; - } +int parse_mods(const char *mods, Config *cfg) +{ + KeySym dummy; + return parse_combo(mods, cfg, &dummy); +} - /* parse mods & key */ - unsigned int mods = 0; - char key_part[64] = {0}; - char tokbuf[MAX_LINE]; - strncpy(tokbuf, combo, sizeof(tokbuf)-1); - tokbuf[sizeof(tokbuf)-1] = '\0'; +KeySym parse_keysym(const char *key) +{ + KeySym ks = XStringToKeysym(key); + if (ks != NoSymbol) { + return ks; + } - for (char *tok = strtok(tokbuf, "+"); tok; tok = strtok(NULL, "+")) { - char *p = strip(tok); - for (char *c = p; *c; c++) *c = tolower((unsigned char)*c); - if (strcmp(p, "mod") == 0) mods |= user_config->modkey; - else if (strcmp(p, "shift") == 0) mods |= ShiftMask; - else if (strcmp(p, "ctrl") == 0) mods |= ControlMask; - else if (strcmp(p, "alt") == 0) mods |= Mod1Mask; - else if (strcmp(p, "super") == 0) mods |= Mod4Mask; - else strncpy(key_part, p, sizeof(key_part)-1); - } + char buf[64]; + size_t n = strlen(key); + if (n >= sizeof buf) { + n = sizeof buf - 1; + } - KeySym ks = parse_keysym(key_part); - if (!ks) continue; + buf[0] = toupper((unsigned char)key[0]); + for (size_t i = 1; i < n; i++) { + buf[i] = tolower((unsigned char)key[i]); + } + buf[n] = '\0'; + ks = XStringToKeysym(buf); + if (ks != NoSymbol) { + return ks; + } - Action a = { .cmd = NULL }; - Bool is_fn = False; - if (*act == '"') { - char act_buf[MAX_LINE]; - strncpy(act_buf, strip_quotes(act), sizeof(act_buf)-1); - act_buf[sizeof(act_buf)-1] = '\0'; - a.cmd = build_argv(act_buf); - fprintf(stderr, "[DEBUG parser] Parsed bind: mods=0x%x, keysym=0x%lx, cmd='%s'\n", mods, ks, act); - } else { - is_fn = True; - fprintf(stderr, "[DEBUG parser] Parsed bind: mods=0x%x, keysym=0x%lx, func='%s'\n", mods, ks, act); - } + for (size_t i = 0; i < n; i++) { + buf[i] = toupper((unsigned char)key[i]); + } + buf[n] = '\0'; + ks = XStringToKeysym(buf); + if (ks != NoSymbol) { + return ks; + } - handler("bind", act, mods, ks, a, is_fn, user_config); + fprintf(stderr, "sxwmrc: unknown keysym '%s'\n", key); + return NoSymbol; +} - } else { - /* normal settings */ - handler(key, val, 0, 0, (Action){ .cmd = NULL }, False, user_config); - } - } +const char **build_argv(const char *cmd) +{ + char *dup = strdup(cmd); + char *saveptr, *tok; + const char **argv = malloc(MAX_ARGS * sizeof *argv); + int i = 0; - fclose(f); - return 0; -} + for (tok = strtok_r(dup, " \t", &saveptr); tok && i < MAX_ARGS - 1; tok = strtok_r(NULL, " \t", &saveptr)) { + if (*tok) { + argv[i++] = strdup(tok); + } + } + argv[i] = NULL; + free(dup); + return argv; +} \ No newline at end of file diff --git a/src/parser.h b/src/parser.h index 15f82d0..2e132fe 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,9 +1,8 @@ -/* See LICENSE for more information on use */ #pragma once #include "defs.h" #define MAX_ARGS 64 -void handler(char *command, char *arg, int mods, KeySym keysym, Action action, Bool is_func, Config *user_config); +const char **build_argv(const char *cmd); int parser(Config *user_config); -unsigned int parse_mods(const char *mods, Config *user_config); -KeySym parse_keysym(const char *key); +int parse_mods(const char *mods, Config *user_config); +KeySym parse_keysym(const char *key); \ No newline at end of file diff --git a/src/sxwm.c b/src/sxwm.c index 3f3050d..6cf6d4b 100644 --- a/src/sxwm.c +++ b/src/sxwm.c @@ -83,7 +83,6 @@ void update_net_client_list(void); void update_struts(void); int xerr(Display *dpy, XErrorEvent *ee); void xev_case(XEvent *xev); -INIT_WORKSPACE #include "config.h" Atom atom_net_current_desktop; @@ -155,7 +154,7 @@ Client *add_client(Window w, int ws) focused = c; } - ++open_windows; + open_windows++; XSelectInput(dpy, w, EnterWindowMask | LeaveWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask); @@ -176,7 +175,7 @@ Client *add_client(Window w, int ws) /* need better way to determine mon */ int cx = c->x + c->w / 2, cy = c->y + c->h / 2; c->mon = 0; - for (int i = 0; i < monsn; ++i) { + for (int i = 0; i < monsn; i++) { if (cx >= mons[i].x && cx < mons[i].x + mons[i].w && cy >= mons[i].y && cy < mons[i].y + mons[i].h) { c->mon = i; break; @@ -236,7 +235,7 @@ void close_focused(void) Atom *protos; int n; if (XGetWMProtocols(dpy, focused->win, &protos, &n) && protos) { - for (int i = 0; i < n; ++i) + for (int i = 0; i < n; i++) if (protos[i] == atom_wm_delete) { XEvent ev = {.xclient = {.type = ClientMessage, .window = focused->win, @@ -258,7 +257,7 @@ void close_focused(void) void dec_gaps(void) { if (user_config.gaps > 0) { - --user_config.gaps; + user_config.gaps--; tile(); update_borders(); } @@ -305,7 +304,7 @@ void focus_prev(void) int get_monitor_for(Client *c) { int cx = c->x + c->w / 2, cy = c->y + c->h / 2; - for (int i = 0; i < monsn; ++i) { + for (int i = 0; i < monsn; i++) { if (cx >= (int)mons[i].x && cx < mons[i].x + mons[i].w && cy >= (int)mons[i].y && cy < mons[i].y + mons[i].h) return i; } @@ -314,17 +313,29 @@ int get_monitor_for(Client *c) void grab_keys(void) { - KeyCode keycode; - int modifiers[] = {0, LockMask, Mod2Mask, LockMask | Mod2Mask}; - + const int guards[] = {0, + LockMask, + Mod2Mask, + LockMask | Mod2Mask, + Mod5Mask, + LockMask | Mod5Mask, + Mod2Mask | Mod5Mask, + LockMask | Mod2Mask | Mod5Mask}; XUngrabKey(dpy, AnyKey, AnyModifier, root); - for (int i = 0; i < user_config.bindsn; ++i) { - if ((keycode = XKeysymToKeycode(dpy, user_config.binds[i].keysym))) { - for (unsigned int j = 0; j < LENGTH(modifiers); ++j) { - XGrabKey(dpy, keycode, user_config.binds[i].mods | modifiers[j], root, True, GrabModeAsync, - GrabModeAsync); - } - } + + for (int i = 0; i < user_config.bindsn; i++) { + Binding *b = &user_config.binds[i]; + + if ((b->type == TYPE_CWKSP && b->mods != user_config.modkey) || + (b->type == TYPE_MWKSP && b->mods != (user_config.modkey | ShiftMask))) + continue; + + KeyCode kc = XKeysymToKeycode(dpy, b->keysym); + if (!kc) + continue; + + for (size_t g = 0; g < sizeof guards / sizeof *guards; g++) + XGrabKey(dpy, kc, b->mods | guards[g], root, True, GrabModeAsync, GrabModeAsync); } } @@ -440,7 +451,7 @@ void hdl_client_msg(XEvent *xev) if (xev->xclient.message_type == XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False)) { Window target = xev->xclient.data.l[0]; - for (int ws = 0; ws < NUM_WORKSPACES; ++ws) { + for (int ws = 0; ws < NUM_WORKSPACES; ws++) { for (Client *c = workspaces[ws]; c; c = c->next) { if (c->win == target) { /* do NOT move to current ws */ @@ -472,7 +483,7 @@ void hdl_config_req(XEvent *xev) XConfigureRequestEvent *e = &xev->xconfigurerequest; Client *c = NULL; - for (int ws = 0; ws < NUM_WORKSPACES && !c; ++ws) + for (int ws = 0; ws < NUM_WORKSPACES && !c; ws++) for (c = workspaces[ws]; c; c = c->next) if (c->win == e->window) { break; @@ -532,7 +543,7 @@ void hdl_destroy_ntf(XEvent *xev) free(c); update_net_client_list(); - --open_windows; + open_windows--; } tile(); @@ -561,16 +572,28 @@ void hdl_enter(XEvent *xev) void hdl_keypress(XEvent *xev) { - KeySym keysym = XLookupKeysym(&xev->xkey, 0); - unsigned int mods = clean_mask(xev->xkey.state); - - for (int i = 0; i < user_config.bindsn; ++i) { - if (keysym == user_config.binds[i].keysym && mods == (unsigned int)clean_mask(user_config.binds[i].mods)) { - if (user_config.binds[i].is_func) { - user_config.binds[i].action.fn(); - } - else { - spawn(user_config.binds[i].action.cmd); + KeySym ks = XkbKeycodeToKeysym(dpy, xev->xkey.keycode, 0, 0); + int mods = clean_mask(xev->xkey.state); + + for (int i = 0; i < user_config.bindsn; i++) { + Binding *b = &user_config.binds[i]; + if (b->keysym == ks && clean_mask(b->mods) == mods) { + switch (b->type) { + case TYPE_CMD: + spawn(b->action.cmd); + break; + case TYPE_FUNC: + if (b->action.fn) + b->action.fn(); + break; + case TYPE_CWKSP: + change_workspace(b->action.ws); + update_net_client_list(); + break; + case TYPE_MWKSP: + move_to_workspace(b->action.ws); + update_net_client_list(); + break; } return; } @@ -622,8 +645,8 @@ void hdl_map_req(XEvent *xev) XMapRequestEvent *me = &xev->xmaprequest; Window w = me->window; - /* if we already manage it, only map if it’s on the current workspace */ - for (int ws = 0; ws < NUM_WORKSPACES; ++ws) { + /* only manage if on current ws */ + for (int ws = 0; ws < NUM_WORKSPACES; ws++) { for (Client *c = workspaces[ws]; c; c = c->next) { if (c->win == w) { if (c->ws == current_ws) @@ -656,7 +679,7 @@ void hdl_map_req(XEvent *xev) Atom splash = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False); Atom popup = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False); - for (unsigned long i = 0; i < nitems; ++i) { + for (unsigned long i = 0; i < nitems; i++) { if (types[i] == dock) { XFree(types); XMapWindow(dpy, w); @@ -735,7 +758,7 @@ void hdl_motion(XEvent *xev) unsigned int mask; XQueryPointer(dpy, root, &root_ret, &child, &rx, &ry, &wx, &wy, &mask); - static Client *last_swap_target = NULL; + Client *last_swap_target = NULL; Client *new_target = NULL; for (Client *c = workspaces[current_ws]; c; c = c->next) { @@ -839,7 +862,7 @@ void update_struts(void) if (!XQueryTree(dpy, root, &root_ret, &parent_ret, &children, &nchildren)) return; - for (unsigned int i = 0; i < nchildren; ++i) { + for (unsigned int i = 0; i < nchildren; i++) { Window w = children[i]; Atom actual_type; @@ -853,7 +876,7 @@ void update_struts(void) continue; Bool is_dock = False; - for (unsigned long j = 0; j < nitems; ++j) { + for (unsigned long j = 0; j < nitems; j++) { if (types[j] == atom_net_wm_window_type_dock) { is_dock = True; break; @@ -891,7 +914,7 @@ void update_struts(void) void inc_gaps(void) { - ++user_config.gaps; + user_config.gaps++; tile(); update_borders(); } @@ -910,12 +933,12 @@ void init_defaults(void) default_config.snap_distance = 5; default_config.bindsn = 0; - for (unsigned long i = 0; i < LENGTH(binds); ++i) { + for (unsigned long i = 0; i < LENGTH(binds); i++) { default_config.binds[i].mods = binds[i].mods; default_config.binds[i].keysym = binds[i].keysym; default_config.binds[i].action.cmd = binds[i].action.cmd; - default_config.binds[i].is_func = binds[i].is_func; - ++default_config.bindsn; + default_config.binds[i].type = binds[i].type; + default_config.bindsn++; } user_config = default_config; @@ -1028,7 +1051,7 @@ long parse_col(const char *hex) void quit(void) { - for (int ws = 0; ws < NUM_WORKSPACES; ++ws) { + for (int ws = 0; ws < NUM_WORKSPACES; ws++) { for (Client *c = workspaces[ws]; c; c = c->next) { XUnmapWindow(dpy, c->win); XKillClient(dpy, c->win); @@ -1045,13 +1068,33 @@ void quit(void) void reload_config(void) { puts("sxwm: reloading config..."); - memset(user_config.binds, 0, sizeof(user_config.binds)); + memset(&user_config, 0, sizeof(user_config)); + + for (int i = 0; i < user_config.bindsn; i++) { + free(user_config.binds[i].action.cmd); + user_config.binds[i].action.cmd = NULL; + + user_config.binds[i].action.fn = NULL; + user_config.binds[i].type = -1; + user_config.binds[i].keysym = 0; + user_config.binds[i].mods = 0; + } + init_defaults(); if (parser(&user_config)) { fprintf(stderr, "sxrc: error parsing config file\n"); init_defaults(); } grab_keys(); + XUngrabButton(dpy, AnyButton, AnyModifier, root); + XGrabButton(dpy, Button1, user_config.modkey, root, True, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, None, None); + XGrabButton(dpy, Button1, user_config.modkey | ShiftMask, root, True, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None); + XGrabButton(dpy, Button3, user_config.modkey, root, True, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, None, None); + XSync(dpy, False); + tile(); update_borders(); } @@ -1090,7 +1133,7 @@ void scan_existing_windows(void) unsigned int nchildren; if (XQueryTree(dpy, root, &root_return, &parent_return, &children, &nchildren)) { - for (unsigned int i = 0; i < nchildren; ++i) { + for (unsigned int i = 0; i < nchildren; i++) { XWindowAttributes wa; if (!XGetWindowAttributes(dpy, children[i], &wa) || wa.override_redirect || wa.map_state != IsViewable) { continue; @@ -1114,7 +1157,7 @@ void send_wm_take_focus(Window w) Atom *protos; int n; if (XGetWMProtocols(dpy, w, &protos, &n)) { - for (int i = 0; i < n; ++i) { + for (int i = 0; i < n; i++) { if (protos[i] == wm_take_focus) { XEvent ev = { .xclient = {.type = ClientMessage, .window = w, .message_type = wm_protocols, .format = 32}}; @@ -1164,7 +1207,7 @@ void setup(void) GrabModeAsync, GrabModeAsync, None, None); XSync(dpy, False); - for (int i = 0; i < LASTEvent; ++i) { + for (int i = 0; i < LASTEvent; i++) { evtable[i] = hdl_dummy; } @@ -1308,7 +1351,7 @@ void tile(void) } } - for (int m = 0; m < monsn; ++m) { + for (int m = 0; m < monsn; m++) { int mon_x = mons[m].x; int mon_y = mons[m].y; int mon_w = mons[m].w; @@ -1387,7 +1430,7 @@ void tile(void) c->y = wc.y; c->w = wc.width; c->h = wc.height; - ++i; + i++; } } update_borders(); @@ -1513,7 +1556,7 @@ void update_monitors(void) scr_width = XDisplayWidth(dpy, DefaultScreen(dpy)); scr_height = XDisplayHeight(dpy, DefaultScreen(dpy)); - for (int s = 0; s < ScreenCount(dpy); ++s) { + for (int s = 0; s < ScreenCount(dpy); s++) { Window scr_root = RootWindow(dpy, s); XDefineCursor(dpy, scr_root, c_normal); } @@ -1521,7 +1564,7 @@ void update_monitors(void) if (XineramaIsActive(dpy)) { info = XineramaQueryScreens(dpy, &monsn); mons = malloc(sizeof *mons * monsn); - for (int i = 0; i < monsn; ++i) { + for (int i = 0; i < monsn; i++) { mons[i].x = info[i].x_org; mons[i].y = info[i].y_org; mons[i].w = info[i].width; @@ -1545,10 +1588,9 @@ void update_net_client_list(void) { Window wins[MAXCLIENTS]; int n = 0; - for (int ws = 0; ws < NUM_WORKSPACES; ++ws) { + for (int ws = 0; ws < NUM_WORKSPACES; ws++) { for (Client *c = workspaces[ws]; c; c = c->next) { - wins[n++] = c->win; /* has to be n++ or well get an off by one error - i think */ + wins[n++] = c->win; } } Atom prop = XInternAtom(dpy, "_NET_CLIENT_LIST", False); @@ -1567,7 +1609,7 @@ int xerr(Display *dpy, XErrorEvent *ee) {X_ConfigureWindow, BadMatch}, }; - for (size_t i = 0; i < sizeof(ignore) / sizeof(ignore[0]); ++i) { + for (size_t i = 0; i < sizeof(ignore) / sizeof(ignore[0]); i++) { if ((ignore[i].req == 0 || ignore[i].req == ee->request_code) && (ignore[i].code == ee->error_code)) { return 0; } diff --git a/sxwm b/sxwm new file mode 100755 index 0000000..70f8fe8 Binary files /dev/null and b/sxwm differ -- cgit v1.2.3