dwm

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 9ba6c8e751a1bf236b6e3f0839121d78a4a940f7
parent 5edcc108408680b98f9b95cae84203211bc0cb8a
Author: Kris Yotam <krisyotam@protonmail.com>
Date:   Sun, 15 Feb 2026 23:04:35 -0600

Rebind reading mode to Super+Q, add directional tagmondir, enable selfrestart

- Super+Q: reading mode (RRR, 3 vertical panes)
- Super+Shift+Q: killclient (close window)
- Super+Arrow: send focused window to monitor in that direction
- Remove Super+Shift+Comma/Period tagmon bindings
- Remove Super+Shift+R reading mode binding
- Enable SELFRESTART_PATCH for in-place dwm reload
- Add .claude/CLAUDE.md with development rules

Diffstat:
A.claude/CLAUDE.md | 164+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mconfig.def.h | 61++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mpatches.def.h | 2+-
3 files changed, 221 insertions(+), 6 deletions(-)

diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md @@ -0,0 +1,164 @@ +# DWM - Development Rules + +## Build System: dwm-flexipatch + +This is a **flexipatch** build. Patches are toggled via `#define` flags, NOT by applying `.diff` files. + +### Critical File Hierarchy + +| File | Role | Committed? | +|------|------|------------| +| `config.def.h` | **Source of truth** for all configuration | YES | +| `patches.def.h` | **Source of truth** for patch enable/disable flags | YES | +| `config.h` | Local working copy (generated from `config.def.h`) | NO (gitignored) | +| `patches.h` | Local working copy (generated from `patches.def.h`) | NO (gitignored) | +| `config.mk` | Compiler/linker flags, library paths | YES | +| `dwm.c` | Core window manager (includes config.h at line 878) | YES | +| `patch/*.c` `patch/*.h` | Patch implementations and headers | YES | +| `patch/include.c` `patch/include.h` | Conditional patch includes (do NOT edit by hand) | YES | + +### Rules for Editing Configuration + +1. **ALWAYS edit `config.def.h`** for keybindings, layouts, rules, colors, and custom functions. +2. **ALWAYS edit `patches.def.h`** to enable/disable patches (`#define PATCH_NAME 0` or `1`). +3. **ALSO update `config.h` and `patches.h`** to match, so local builds work without regenerating. +4. **NEVER edit only `config.h` or `patches.h`** — those are gitignored and will be lost. +5. When `config.h` does not exist, `make` generates it by copying `config.def.h`. Same for `patches.h`. + +### Build & Deploy Process + +**Local build (this desktop):** +```bash +cd /home/krisyotam/dev/dwm +sudo make clean install +``` + +**Deploy to laptop (khr1st):** +```bash +# 1. Commit and push from desktop +cd /home/krisyotam/dev/dwm +git add config.def.h patches.def.h +git commit -m "description" +git push + +# 2. SSH to laptop, pull, rebuild +ssh khr1st +cd ~/.local/src/dwm && git pull && sudo make clean install + +# 3. Self-restart dwm (preserves all windows — no session kill) +# Trigger via sysact menu or a keybinding mapped to self_restart +``` + +**NEVER** tell the user to "restart dwm" or "log out and back in" without mentioning self_restart. The SELFRESTART_PATCH is enabled and does an in-place `execv()` that preserves all window positions. + +--- + +## Code Style (Suckless C Conventions) + +### Formatting +- **Indentation:** Tabs (width 8). Never spaces for indentation. +- **Brace style:** K&R — opening brace on same line, closing at column 0. +- **Line length:** ~80 characters preferred, not strictly enforced. +- **No trailing whitespace.** + +### Naming +- `CamelCase` for types and structs: `Client`, `Monitor`, `Layout`, `Key`, `Button` +- `lowercase` or `lowercasemultiword` for functions: `focusmon`, `tagmon`, `sendmon`, `killclient` +- `UPPERCASE` for macros and constants: `MODKEY`, `NUMTAGS`, `CLEANMASK`, `SHCMD` +- Enum values: `SchemeNorm`, `SchemeSel`, `NetSupported` + +### Functions +```c +static void +functionname(const Arg *arg) +{ + /* body indented with tabs */ +} +``` +- Return type on its own line. +- Function name on the next line. +- Opening brace on its own line (for function definitions only — NOT for if/for/while). +- Minimize variable declarations; declare at top of scope. + +### Comments +- `/* C89-style block comments */` preferred in source. +- `// C99 inline comments` acceptable in config files for brief annotations. +- Preprocessor guards: `#endif // PATCH_NAME` + +### Conditional Compilation (Patch Guards) +```c +#if SOME_PATCH +/* patch-specific code */ +#endif // SOME_PATCH +``` +- Always include the patch name in the `#endif` comment. +- Custom (non-patch) code added to `config.def.h` does NOT need guards. + +### Example: Adding a Custom Function in config.def.h +Custom functions go **before** the `static const Key keys[]` array. They can reference any forward-declared function from `dwm.c` (`sendmon`, `focusmon`, `arrange`, `focus`, `selmon`, `mons`, etc.) because `config.h` is included after all declarations in `dwm.c`. + +--- + +## Layout Array Reference + +The layout array uses **flextile-deluxe**. Index matters for keybindings. + +| Index | Symbol | Layout | Notes | +|-------|--------|--------|-------| +| 0 | `[]=` | Tile | Default | +| 1 | `><>` | Floating | | +| 2 | `[M]` | Monocle | | +| 3 | `\|\|\|` | Columns | | +| 4 | `>M>` | Floating master | | +| 5 | `[D]` | Deck | | +| 6 | `TTT` | Bottom stack | | +| 7 | `===` | Bottom stack horiz | | +| 8 | `\|M\|` | Centered master | | +| 9 | `-M-` | Centered master horiz | | +| 10 | `:::` | Gappless grid | | +| 11 | `[\\]` | Fibonacci dwindle | | +| 12 | `(@)` | Fibonacci spiral | | +| 13 | `[T]` | Tatami mats | | +| 14 | `RRR` | Reading mode (3 vertical panes) | Custom: nmaster=3 | + +**When referencing layouts in keybindings, ALWAYS verify the index by counting from 0 in the `layouts[]` array.** Off-by-one errors here cause the wrong layout to activate with no obvious error. + +--- + +## Currently Enabled Patches + +Patches set to `1` in `patches.def.h`: + +**Bar:** BAR_DWMBLOCKS, BAR_LTSYMBOL, BAR_STATUS, BAR_STATUSCMD, BAR_TAGS, BAR_WINTITLE, BAR_HIDEVACANTTAGS + +**Core:** CFACTS, COOL_AUTOSTART, CYCLELAYOUTS, PERTAG, RESTARTSIG, SCRATCHPADS, SEAMLESS_RESTART, SELFRESTART, SHIFTTAG, SHIFTVIEW, STACKER, STICKY, SWALLOW, TOGGLEFULLSCREEN, VANITYGAPS, XRESOURCES + +**Layouts:** BSTACK, CENTEREDMASTER, CENTEREDFLOATINGMASTER, COLUMNS, DECK, FIBONACCI_DWINDLE, FIBONACCI_SPIRAL, NROWGRID, TILE, MONOCLE + +--- + +## Current Custom Keybindings + +| Binding | Action | +|---------|--------| +| Super+Q | Reading mode (RRR layout) | +| Super+Shift+Q | Kill client (close window) | +| Super+Backspace | sysact (system actions menu) | +| Super+Left/Right/Up/Down | Send window to monitor in that direction | +| Super+Comma/Period | Focus previous/next monitor | +| Super+T | Tile layout | +| Super+F | Floating layout | + +--- + +## Rules for Making Changes + +1. **Read before writing.** Always read the relevant section of `config.def.h` before modifying it. Understand the surrounding `#if` guards. +2. **Count layout indices.** Never assume a layout index. Count from 0 in the `layouts[]` array every time. +3. **Check for keybinding conflicts.** Before adding a new binding, grep for the key symbol (e.g., `XK_w`) across `config.def.h` to find all uses and check which patches guard them. +4. **Test compilation.** Clang diagnostics on `config.h` standalone are ALWAYS false positives (missing types like `Arg`, `Client`, `Monitor`). The only valid test is `make` in the repo root. +5. **Keep both files in sync.** Every edit to `config.def.h` must also be applied to `config.h` (and vice versa for patches). +6. **Preserve removed bindings as comments.** When removing a keybinding, comment it out with a `// removed: reason` note rather than deleting the line, so the history is visible. +7. **Do not modify `dwm.c` unless absolutely necessary.** Configuration belongs in `config.def.h`. New functions go in `config.def.h` (before the keys array) or as a new file in `patch/`. +8. **Do not modify `patch/include.c` or `patch/include.h`** unless adding a completely new patch file to the `patch/` directory. +9. **Commit messages:** Imperative mood, concise. Example: `"Rebind reading mode to Super+Q, add directional tagmon"`. No "Co-Authored-By" lines. diff --git a/config.def.h b/config.def.h @@ -1055,6 +1055,53 @@ ResourcePref resources[] = { }; #endif // XRESOURCES_PATCH +/* Send focused window to the monitor in the given direction (0=left, 1=right, 2=up, 3=down). + * Does nothing if no monitor exists in that direction. */ +static void +tagmondir(const Arg *arg) +{ + Client *c = selmon->sel; + Monitor *m, *best = NULL; + int dist, bestdist = 99999; + + if (!c || !mons->next) + return; + + for (m = mons; m; m = m->next) { + if (m == selmon) + continue; + switch (arg->i) { + case 0: /* left */ + if (m->mx + m->mw <= selmon->mx) { + dist = selmon->mx - m->mx; + if (dist < bestdist) { bestdist = dist; best = m; } + } + break; + case 1: /* right */ + if (m->mx >= selmon->mx + selmon->mw) { + dist = m->mx - selmon->mx; + if (dist < bestdist) { bestdist = dist; best = m; } + } + break; + case 2: /* up */ + if (m->my + m->mh <= selmon->my) { + dist = selmon->my - m->my; + if (dist < bestdist) { bestdist = dist; best = m; } + } + break; + case 3: /* down */ + if (m->my >= selmon->my + selmon->mh) { + dist = m->my - selmon->my; + if (dist < bestdist) { bestdist = dist; best = m; } + } + break; + } + } + + if (best) + sendmon(c, best); +} + static const Key keys[] = { /* modifier key function argument */ @@ -1090,8 +1137,8 @@ static const Key keys[] = { /* System */ { MODKEY, XK_BackSpace, spawn, {.v = (const char*[]){ "sysact", NULL } } }, - { MODKEY|ShiftMask, XK_q, spawn, {.v = (const char*[]){ "sysact", NULL } } }, - { MODKEY, XK_q, killclient, {0} }, + { MODKEY|ShiftMask, XK_q, killclient, {0} }, // close window + { MODKEY, XK_q, setlayout, {.v = &layouts[14]} }, // reading mode (RRR) #if KEYMODES_PATCH { MODKEY, XK_Escape, setkeymode, {.ui = COMMANDMODE} }, @@ -1275,7 +1322,7 @@ static const Key keys[] = { #endif // XRDB_PATCH | XRESOURCES_PATCH { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, - { MODKEY|ShiftMask, XK_r, setlayout, {.v = &layouts[14]} }, // reading mode + /* { MODKEY|ShiftMask, XK_r, setlayout, {.v = &layouts[14]} }, // removed: reading mode moved to Super+q */ #if COLUMNS_LAYOUT /* { MODKEY, XK_c, setlayout, {.v = &layouts[3]} }, // removed: Super+c now dcreate */ #endif // COLUMNS_LAYOUT @@ -1343,8 +1390,12 @@ static const Key keys[] = { #endif // SCRATCHPAD_ALT_1_PATCH { MODKEY, XK_comma, focusmon, {.i = -1 } }, { MODKEY, XK_period, focusmon, {.i = +1 } }, - { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, - { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + /* { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, // removed: send window via Super+Arrow instead */ + /* { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, // removed: send window via Super+Arrow instead */ + { MODKEY, XK_Left, tagmondir, {.i = 0 } }, // send window to left monitor + { MODKEY, XK_Right, tagmondir, {.i = 1 } }, // send window to right monitor + { MODKEY, XK_Up, tagmondir, {.i = 2 } }, // send window to upper monitor + { MODKEY, XK_Down, tagmondir, {.i = 3 } }, // send window to lower monitor #if FOCUSADJACENTTAG_PATCH { MODKEY, XK_Left, viewtoleft, {0} }, // note keybinding conflict with focusdir { MODKEY, XK_Right, viewtoright, {0} }, // note keybinding conflict with focusdir diff --git a/patches.def.h b/patches.def.h @@ -1118,7 +1118,7 @@ /* Allows restarting dwm without the dependency of an external script. * https://dwm.suckless.org/patches/selfrestart/ */ -#define SELFRESTART_PATCH 0 +#define SELFRESTART_PATCH 1 /* Floating windows being sent to another monitor will be centered. * https://dwm.suckless.org/patches/sendmoncenter/