diff options
-rw-r--r-- | LICENSE | 2 | ||||
-rw-r--r-- | README.md | 187 | ||||
-rw-r--r-- | defsxrc | 69 | ||||
-rw-r--r-- | src/defs.h | 3 | ||||
-rw-r--r-- | src/parser.c | 342 | ||||
-rw-r--r-- | src/parser.h | 7 | ||||
-rw-r--r-- | src/sxwm.c | 45 |
7 files changed, 383 insertions, 272 deletions
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE.
\ No newline at end of file @@ -1,164 +1,151 @@ <div align="center"> - <img src="images/sxwm_logo.png" width="30%"> - <h4>High Performance</h4> - <h4>Easy Config</h4> + <img src="images/sxwm_logo.png" width="30%"> + <h2>sxwm</h2> + <b>Minimal. Fast. Configurable. Tiling Window Manager for X11</b> + <br> + <sub>By Abhinav Prasai (2025)</sub> + <br><br> + <img src="https://img.shields.io/github/v/release/uint23/sxwm?style=flat-square"> + <img src="https://img.shields.io/github/license/uint23/sxwm?style=flat-square"> </div> -<details> -<summary><h2>Patch Notes</h2></summary> -### v1.1.1 -- **NEW**: *Xinerama Support*, *Can swap windows holding Mod + Shift + Dragging*. -- **FIXED**: New windows in `global_floating` mode will spawn in the middle. -</details> +--- -<a href="1"><img src="images/1.png" width="45%" align="right"></a> +## Features -Here we have a **minimal**, **tiling**, and **configurable** window manager. -- **Tiling & Floating**: Seamlessly switch between layouts. -- **Workspaces**: Workspaces work with your bar. -- **Bars work too**: BAR BAR BAR?! Why not try [sxbar](https://github.com/uint23/sxbar) -- **Lightweight**: Single C file plus a small header and config. -- **Easy Config**: All settings in `config`. -<br> +- **Tiling & Floating**: Switch seamlessly between layouts. +- **Workspaces**: 9 workspaces, fully integrated with your bar. +- **Live Config Reload**: Change your config and reload instantly with a keybind. +- **Easy Configuration**: Human-friendly `sxwmrc` file, no C required. +- **Master-Stack Layout**: Productive, DWM-inspired workflow. +- **Mouse Support**: Move, swap, resize, and focus windows with the mouse. +- **Zero Dependencies**: Only `libX11` and `Xinerama` required. +- **Lightweight**: Single C file, minimal headers, compiles in seconds. +- **Bar Friendly**: Works great with [sxbar](https://github.com/uint23/sxbar). +- **Xinerama Support**: Multi-monitor ready. +- **Fast**: Designed for speed and low resource usage. -<a href="2"><img src="images/2.png" width="45%" align="right"></a> +--- -- **Master-Stack**: Use the DWM native and super productive layout. -- **Keyboard-driven**: Full coverage via `MOD` + keys. -- **Mouse Support**: Focus under cursor, move, swap & resize with mouse. -- **Zero Dependencies**: Only requires `libX11`. -- **Compiles on a Toaster**: As long as it has a decently modern compiler. +## Screenshots + +<a href="1"><img src="images/1.png" width="50%" align="right"></a> +<a href="2"><img src="images/2.png" width="50%" align="right"></a> <br clear="right"> --- -## Default Configuration - -All options reside in `config` (which is just a header-file) with clear comments. -Keybindings are also easy to understand and quick to implement. -No more bindsym or C code -```c -CMD(terminal, "st"); -CMD(browser, "firefox"); +## Patch Notes -static const Binding binds[] = -{ -/*————< MODIFIER(S) >< KEY >—————< FUNCTION >——*/ - -/*———————< Here are your functions calls >————— — */ +<details> +<summary><strong>Click to expand</strong></summary> - CALL(MOD|SHIFT, e, quit), - CALL(MOD|SHIFT, q, close_focused), +#### v1.1.1 +- **NEW**: Xinerama support, swap windows with Mod + Shift + Drag. +- **FIXED**: New windows in `global_floating` mode spawn centered. - CALL(MOD, j, focus_next), - CALL(MOD, k, focus_prev), +</details> - CALL(MOD|SHIFT, j, move_master_next), - CALL(MOD|SHIFT, k, move_master_prev), +--- - CALL(MOD, equal, inc_gaps), - CALL(MOD, minus, dec_gaps), +## Default Configuration - CALL(MOD, space, toggle_floating), - CALL(MOD|SHIFT, space, toggle_floating_global), - ..... -``` +All options are in `sxwmrc` (which uses a simple DSL). +Keybindings are easy to read and edit. +No recompiling, no C code, just edit and reload! --- ## Default Keybindings -**Window Management** +### Window Management | Combo | Action | | ---------------------------- | ------------------------- | -| `Mouse` | Focus under cursor | -| `MOD` + `Left Mouse` | Move window by mouse | -| `MOD` + `Right Mouse` | Resize window by mouse | +| Mouse | Focus under cursor | +| `MOD` + Left Mouse | Move window by mouse | +| `MOD` + Right Mouse | Resize window by mouse | | `MOD` + `j` / `k` | Focus next / previous | | `MOD` + `Shift` + `j` / `k` | Move in master stack | | `MOD` + `Space` | Toggle floating | | `MOD` + `Shift` + `Space` | Toggle all floating | -| `MOD` + `=` / `-` | Inc/Dec gaps | +| `MOD` + `=` / `-` | Increase/Decrease gaps | | `MOD` + `f` | Fullscreen toggle | -| `MOD` + `c` | Center window | | `MOD` + `q` | Close focused window | | `MOD` + `1-9` | Switch workspace 1–9 | | `MOD` + `Shift` + `1-9` | Move window to WS 1–9 | -**Programs** +### Programs -| Combo | Action | Programs (by default) | -| -------------------- | ---------- | --------- | -| `MOD` + `Return` | Terminal | `st` | -| `MOD` + `b` | Browser | `firefox` | +| Combo | Action | Program | +| -------------------- | ---------- | ---------- | +| `MOD` + `Return` | Terminal | `st` | +| `MOD` + `b` | Browser | `firefox` | +| `MOD` + `p` | Launcher | `dmenu_run`| --- ## Dependencies -- `libX11` (Xorg client library) `Xinerama` (if you want multi-monitor support) -- GCC / Clang & Make +- `libX11` (Xorg client library) +- `Xinerama` +- GCC or Clang & Make --- -## Makefile Targets - -Below are the available `make` targets for streamlining common tasks: +## Build & Install -| Target | Description | -| ---------------- | ------------------------------------------------------------------- | -| `make` or `make all` | Compile the source files into the `sxwm` binary. | -| `make clean` | Remove object files (`*.o`) and build artifacts. | -| `make install` | Install `sxwm` to `$(PREFIX)/bin` (default `/usr/local/bin`). | -| `make uninstall` | Remove the installed binary from `$(PREFIX)/bin`. | -| `make clean install` | Runs `make clean` then `make install`. | +### Arch Linux (AUR) -> You can override the install directory by specifying `PREFIX` or `DESTDIR`, for example: -> ```sh -> make install PREFIX=$HOME/.local -> ``` - ---- +```sh +yay -S sxwm +``` -## Installation +### Build from Source -### Arch linux - AUR +```sh +git clone --depth=1 https://github.com/uint23/sxwm.git +cd sxwm/ +make +sudo make clean install +``` - ```bash - yay -S sxwm - ``` +### Run -### Build from source +Add to your `~/.xinitrc`: +```sh +exec sxwm +``` -1. **Clone repository** +--- - ```bash - git clone --depth=1 https://github.com/uint23/sxwm.git - cd sxwm/ - make - sudo make clean install - ``` +## Makefile Targets -2. **Run** +| Target | Description | +| --------------------- | --------------------------------------------------- | +| `make` / `make all` | Build the `sxwm` binary | +| `make clean` | Remove object files and build artifacts | +| `make install` | Install `sxwm` to `$(PREFIX)/bin` (default `/usr/local/bin`) | +| `make uninstall` | Remove the installed binary | +| `make clean install` | Clean and then install | - Add `sxwm` to `~/.xinitrc`: - ```bash - exec sxwm - ``` +> Override install directory with `PREFIX` or `DESTDIR`: +> ```sh +> make install PREFIX=$HOME/.local +> ``` --- ## Thanks & Inspiration -- [dwm](https://dwm.suckless.org) - Tiling & source code -- [i3](https://i3wm.org) - Making configuring easy -- [sowm](https://github.com/dylanaraps/sowm) - README inspo :) -- [tinywm](http://incise.org/tinywm.html) - idk, just cool to see how a wm works +- [dwm](https://dwm.suckless.org) — Tiling & source code +- [i3](https://i3wm.org) — Easy configuration +- [sowm](https://github.com/dylanaraps/sowm) — README inspiration +- [tinywm](http://incise.org/tinywm.html) — Minimal X11 WM --- <p align="center"> <em>Contributions welcome! Open issues or submit PRs.</em> -</p> +</p>
\ No newline at end of file @@ -1,17 +1,70 @@ # Colour Themes: -border_focused_colour : #c0cbff -border_unfocused_colour : #555555 -border_swap_colour : #fff4c0 +focused_border_colour : #c0cbff +unfocused_border_colour : #555555 +swap_border_colour : #fff4c0 # General Options: -master_coverage : 60% -gaps : 10 +gaps : 10 +border_width : 1 +master_coverage : 60 # Percentage of screen width +resize_master_amount : 1 +snap_distance : 5 # Keybinds: # Commands must be surrounded with "" # Function calls don't need this -mod_key : alt +mod_key : super -bind : [mod + shift + return] : "st" -bind : [mod + j] : focus_next +# --- Application Launchers --- +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 + +# --- Focus Movement --- +bind : [mod + j] : focus_next +bind : [mod + k] : focus_prev + +# --- Master/Stack Movement --- +bind : [mod + shift + j] : move_master_next +bind : [mod + shift + k] : move_master_prev + +# --- Master Area Resize --- +bind : [mod + l] : master_increase +bind : [mod + h] : master_decrease + +# --- Gaps --- +bind : [mod + equal] : increase_gaps +bind : [mod + minus] : decrease_gaps + +# --- Floating/Fullscreen --- +bind : [mod + space] : toggle_floating +bind : [mod + shift + space] : global_floating +bind : [mod + shift + f] : fullscreen + +# --- Reload Config --- +bind : [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 @@ -1,6 +1,6 @@ /* See LICENSE for more information on use */ #pragma once -#define SXWM_VERSION "sxwm ver. 1.2" +#define SXWM_VERSION "sxwm ver. 1.4" #define SXWM_AUTHOR "(C) Abhinav Prasai 2025" #define SXWM_LICINFO "See LICENSE for more info" @@ -60,7 +60,6 @@ void moveto_ws9(void) { move_to_workspace(8); update_net_client_list(); }\ #define UDIST(a,b) abs((int)(a) - (int)(b)) #define MAXCLIENTS 99 -#define MAXGAPS 100 typedef enum { DRAG_NONE, diff --git a/src/parser.c b/src/parser.c index 4eca3c2..ae22651 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 200809L /* for strdup */ #include <ctype.h> #include <linux/limits.h> #include <stdio.h> @@ -8,204 +9,257 @@ #include <X11/keysymdef.h> #include "parser.h" +#define MAX_LINE 512 -static struct { const char *n; 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}, - {"floating", toggle_floating}, - {"global_floating", toggle_floating_global}, - {"fullscreen", toggle_fullscreen}, +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 } }; +/* helpers */ +static char* +strip(char *s) +{ + 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; +} + +static char* +strip_quotes(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; +} + +static const char** build_argv(char *cmdline) +{ + 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; +} + +unsigned int +parse_mods(const char *mods, Config *user_config) +{ + 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; +} + +KeySym +parse_keysym(const char *key) +{ + 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; +} + void -handler(char *command, char *arg, - unsigned int mods, KeySym keysym, - Action action, Bool is_func, - Config *user_config) +handler(char *command, char *arg, int mods, KeySym keysym, Action action, + Bool is_func, Config *user_config) { 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; + } + } + + if (slot == user_config->bindsn) + user_config->bindsn++; + + Binding *b = &user_config->binds[slot]; + b->mods = mods; + b->keysym = keysym; + b->is_func = is_func; + if (is_func) { - /* look up function by name */ - for (unsigned long i = 0; i < LENGTH(call_table); ++i) { - if (strcmp(arg, call_table[i].n) == 0) { - user_config->binds[user_config->bindsn].action.fn = call_table[i].fn; - user_config->binds[user_config->bindsn].is_func = True; - user_config->binds[user_config->bindsn].mods = mods; - user_config->binds[user_config->bindsn].keysym = keysym; - ++user_config->bindsn; - return; + 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; } } - fprintf(stderr, "sxwmrc: unknown function call: %s\n", arg); } else { - user_config->binds[user_config->bindsn].action.cmd = action.cmd; - user_config->binds[user_config->bindsn].is_func = False; - user_config->binds[user_config->bindsn].mods = mods; - user_config->binds[user_config->bindsn].keysym = keysym; - ++user_config->bindsn; + b->action.cmd = action.cmd; } return; } - /* TODO USE A TABLE */ - 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, "focus_border_colour") == 0) user_config->border_foc_col = parse_col(arg); - else if (strcmp(command, "unfocus_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_coverage") == 0) user_config->master_width = 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); + 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_coverage") == 0) user_config->master_width = 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 command: %s\n", command); + fprintf(stderr, "sxwmrc: unknown setting '%s'\n", command); } - -void +int parser(Config *user_config) { char *home = getenv("HOME"); if (!home) { - fputs("sxwmrc: HOME environment variable not set\n", stderr); - return; + fputs("sxwmrc: HOME not set\n", stderr); + return -1; } - char sxwmrc[PATH_MAX]; - snprintf(sxwmrc, sizeof(sxwmrc), "%s/.config/sxwmrc", home); - FILE *f = fopen(sxwmrc, "r"); + char path[PATH_MAX]; + snprintf(path, sizeof(path), "%s/.config/sxwmrc", home); + FILE *f = fopen(path, "r"); if (!f) { - fprintf(stderr, "sxwmrc: file not found: %s\n", sxwmrc); - return; + fprintf(stderr, "sxwmrc: cannot open '%s'\n", path); + return -1; } - char line[512]; + char line[MAX_LINE]; + int lineno = 0; while (fgets(line, sizeof(line), f)) { + lineno++; char *s = strip(line); - if (!*s || *s == '#' || *s == '\n') - continue; + if (!*s || *s == '#') continue; - char *c = strchr(s, ':'); - if (!c) { - fprintf(stderr, "sxwmrc: invalid line (no colon): %s\n", s); + /* split key : value */ + char *sep = strchr(s, ':'); + if (!sep) { + fprintf(stderr, "sxwmrc:%d: missing ':'\n", lineno); continue; } - *c = '\0'; + *sep = '\0'; char *key = strip(s); - char *val = strip(c+1); + char *val = strip(sep + 1); if (strcmp(key, "bind") == 0) { - char *d = strchr(val, ':'); - if (!d) { - fprintf(stderr, "sxwmrc: invalid bind (no action): %s\n", val); + /* bind parsing */ + char *mid = strchr(val, ':'); + if (!mid) { + fprintf(stderr, "sxwmrc:%d: bind missing action\n", lineno); continue; } - *d = '\0'; + *mid = '\0'; char *combo = strip(val); - char *act = strip(d+1); + char *act = strip(mid + 1); - if (*combo == '[') combo++; + if (*combo == '[') { + combo++; + } size_t L = strlen(combo); - if (L && combo[L-1] == ']') combo[L-1] = '\0'; + if (L && combo[L-1] == ']') { + combo[L-1] = '\0'; + } + /* parse mods & key */ unsigned int mods = 0; - KeySym ks = 0; - char part[64]; - char *tok = strtok(combo, "+"); - while (tok) { + char key_part[64] = {0}; + char tokbuf[MAX_LINE]; + strncpy(tokbuf, combo, sizeof(tokbuf)-1); + tokbuf[sizeof(tokbuf)-1] = '\0'; + + for (char *tok = strtok(tokbuf, "+"); tok; tok = strtok(NULL, "+")) { char *p = strip(tok); - for (size_t i=0; p[i]; i++) p[i] = tolower((unsigned char)p[i]); - 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 { - strncpy(part, tok, sizeof(part)-1); - part[sizeof(part)-1] = '\0'; - ks = parse_keysym(strip(part)); - } - tok = strtok(NULL, "+"); + 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); } + KeySym ks = parse_keysym(key_part); + if (!ks) continue; + Action a = { .cmd = NULL }; Bool is_fn = False; if (*act == '"') { - char *cmdstr = strip_quotes(act); - a.cmd = build_argv(cmdstr); + 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); } - handler(key, act, mods, ks, a, is_fn, user_config); + + handler("bind", act, mods, ks, a, is_fn, user_config); } else { - handler(key, val, 0, 0, (Action){0}, False, user_config); + /* normal settings */ + handler(key, val, 0, 0, (Action){ .cmd = NULL }, False, user_config); } } fclose(f); -} - -char * -strip(char *str) -{ - while (*str == ' ' || *str == '\t') str++; - char *end = str + strlen(str) - 1; - while (end > str && (*end==' '||*end=='\t'||*end=='\r'||*end=='\n')) - *end-- = '\0'; - return str; -} - - char * -strip_quotes(char *s) -{ - if (*s == '"') s++; - size_t n = strlen(s); - if (n && s[n-1] == '"') s[n-1] = '\0'; - return s; -} - -unsigned int -parse_mods(const char *mods, Config *user_config) -{ - unsigned int m = 0; - if (strstr(mods, "mod")) m |= user_config->modkey; - if (strstr(mods, "shift")) m |= ShiftMask; - if (strstr(mods, "ctrl")) m |= ControlMask; - if (strstr(mods, "alt")) m |= Mod1Mask; - return m; -} - -KeySym -parse_keysym(const char *key) -{ - KeySym ks = XStringToKeysym(key); - if (ks == NoSymbol) { - fprintf(stderr, "sxwmrc: unknown keysym: %s\n", key); - return 0; - } - return ks; -} - -static const char ** -build_argv(char *cmdline) -{ - 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++] = tok; - tok = strtok(NULL, " \t"); - } - argv[argc] = NULL; - return (const char **)argv; + return 0; } diff --git a/src/parser.h b/src/parser.h index 29e2435..b2bff05 100644 --- a/src/parser.h +++ b/src/parser.h @@ -2,10 +2,7 @@ #include "defs.h" #define MAX_ARGS 64 -void handler(char *command, char *arg, unsigned int mods, KeySym keysym, Action action, Bool is_func, Config *user_config); -void parser(Config *user_config); +void handler(char *command, char *arg, int mods, KeySym keysym, Action action, Bool is_func, Config *user_config); +int parser(Config *user_config); unsigned int parse_mods(const char *mods, Config *user_config); KeySym parse_keysym(const char *key); -char* strip_quotes(char *s); -char* strip(char *str); -static const char** build_argv(char *cmdline); @@ -33,6 +33,7 @@ #include "parser.h" void add_client(Window w); +void apply_user_config(void); void change_workspace(int ws); int clean_mask(int mask); /* void close_focused(void); */ @@ -187,6 +188,16 @@ add_client(Window w) XRaiseWindow(dpy, w); } +void +apply_user_config(void) +{ + gaps = user_config.gaps; + border_foc_col = user_config.border_foc_col; + border_ufoc_col = user_config.border_ufoc_col; + border_swap_col = user_config.border_swap_col; + master_frac = (float)user_config.master_width / 100.0f; +} + int clean_mask(int mask) { @@ -291,10 +302,8 @@ grab_keys(void) KeyCode keycode; int modifiers[] = { 0, LockMask, Mod2Mask, LockMask|Mod2Mask }; - /* ungrab all keys */ XUngrabKey(dpy, AnyKey, AnyModifier, root); - - for (unsigned int i = 0; i < LENGTH(user_config.binds); ++i) { + 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, @@ -530,7 +539,7 @@ hdl_keypress(XEvent *xev) KeySym keysym = XLookupKeysym(&xev->xkey, 0); unsigned int mods = clean_mask(xev->xkey.state); - for (unsigned int i = 0; i < LENGTH(user_config.binds); ++i) { + 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) { @@ -818,11 +827,9 @@ hdl_root_property(XEvent *xev) void inc_gaps(void) { - if (gaps < MAXGAPS) { - ++gaps; - tile(); - update_borders(); - } + ++gaps; + tile(); + update_borders(); } void @@ -983,7 +990,16 @@ void reload_config(void) { puts("sxwm: reloading config..."); - /* parser(&user_config); */ + memset(user_config.binds, 0, sizeof(user_config.binds)); + init_defaults(); + if (parser(&user_config)) { + fprintf(stderr, "sxrc: error parsing config file\n"); + init_defaults(); + } + apply_user_config(); + grab_keys(); + tile(); + update_borders(); } void @@ -1053,7 +1069,11 @@ setup(void) setup_atoms(); other_wm(); init_defaults(); - /* parser(&user_config); */ + if (parser(&user_config)) { + fprintf(stderr, "sxrc: error parsing config file\n"); + init_defaults(); + } + apply_user_config(); grab_keys(); c_normal = XCreateFontCursor(dpy, XC_left_ptr); @@ -1464,10 +1484,11 @@ change_workspace(int ws) return; } - /* unmap old desktop */ + /* unmap old desktop for (Client *c = workspaces[current_ws]; c; c=c->next) { XUnmapWindow(dpy, c->win); } + */ /* for compositors like picom-animations */ XSync(dpy, False); |