aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/superpowers/specs/2026-06-11-wallp-merge-design.md184
1 files changed, 184 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-06-11-wallp-merge-design.md b/docs/superpowers/specs/2026-06-11-wallp-merge-design.md
new file mode 100644
index 0000000..5f23772
--- /dev/null
+++ b/docs/superpowers/specs/2026-06-11-wallp-merge-design.md
@@ -0,0 +1,184 @@
+# wallp — Unified Wallpaper Manager — Design
+
+Date: 2026-06-11
+
+## Overview
+
+Single bash script `wallp` replacing two scripts:
+
+- `multiwal.sh` — interactive wallpaper setter (qarma picker, two screens).
+- `qar-lastwall.sh` — restores last-session wallpapers at session start.
+
+Command-line flags pick the action. qarma is used **only** for GUI (file picker,
+selection menu, dialogs, help). `swaybg` actually sets wallpapers and needs no
+qarma. Per-output PID tracking allows updating a single screen without blanking
+the other (the old `pkill swaybg` killed both). A config file holds defaults;
+flags override where applicable.
+
+Two-screen setup:
+
+- Horizontal screen — logical `H`, physical output from conf `OUTPUT_H` (e.g. `DP-1`).
+- Vertical screen — logical `V`, physical output from conf `OUTPUT_V` (e.g. `DP-3`).
+
+## CLI
+
+```
+wallp # help screen
+wallp --help / -h # help screen
+wallp --set # qarma picker: menu H/V/Both -> file picker(s)
+wallp --set H=<file> # set horizontal only, no GUI
+wallp --set V=<file> # set vertical only, no GUI
+wallp --set H=<f> V=<f> # set both, no GUI
+wallp --restore # restore last session from persistent state
+wallp --theme <name> # override conf theme (combine with --set/--restore)
+```
+
+Rules:
+
+- Bare invocation or `--help`/`-h` → help screen. Shown in a qarma window when
+ `$WAYLAND_DISPLAY` is set, otherwise printed to stdout.
+- `--set` with no `H=`/`V=` args:
+ - `$WAYLAND_DISPLAY` set → qarma selection flow.
+ - no display → error: "no display: pass H=<file> and/or V=<file>". Exit non-zero.
+- `--set` with `H=`/`V=` args → set those outputs directly, no GUI (works
+ headless; swaybg does not need qarma).
+- `--restore` → no display required (intended for session-start autostart).
+- `--theme <name>` → overrides conf `THEME` for this invocation.
+- Unknown flag → error message + help, exit non-zero.
+
+Logical `H=`/`V=` keys map to physical `OUTPUT_H`/`OUTPUT_V` from conf, so output
+renames only touch the conf, not command lines or muscle memory.
+
+## Config — `~/.config/wallp/wallp.conf`
+
+Format: simple `key=value`, one per line. Parsed manually (no shell sourcing —
+avoids code execution from the conf). Blank lines and lines starting with `#`
+ignored. Leading `~` in path values expanded to `$HOME`.
+
+Keys:
+
+```
+THEME=sexy-splurge
+OUTPUT_H=DP-1
+OUTPUT_V=DP-3
+DEFAULT_H=/home/danix/Pictures/wallpapers/SFW/wallhaven-4yd27g_2560x1080.png
+DEFAULT_V=/home/danix/Pictures/wallpapers/SFW/wallhaven-gwzqjl_2560x1080.png
+```
+
+Behavior:
+
+- **Conf file missing** → write a commented template to the conf path, tell the
+ user (stdout + notify-send if available) to fill it in and re-run, then
+ **exit 0 without touching any wallpaper**. Applies to every action.
+- **Conf present, required path/output key missing or empty** → hard error
+ naming the missing key, exit non-zero, no wallpaper change. Required keys:
+ `OUTPUT_H`, `OUTPUT_V`, `DEFAULT_H`, `DEFAULT_V`.
+- **THEME** is the one exception: if absent, built-in fallback `sexy-splurge`
+ is used. `--theme` flag also overrides it.
+
+An example conf is shipped in the repo (`wallp.conf.example`).
+
+## State Files
+
+Runtime pointers (volatile, in `~/.cache`, reset on reboot):
+
+- `~/.cache/wal/wal` — H wallpaper path. Read by pywal and apps.
+- `~/.cache/wal/wal2` — V wallpaper path.
+- `~/.cache/wal/wpaper` — symlink to current H image (maintained by wallp).
+
+Persistent pointers (survive reboot, in `~/.config`):
+
+- `~/.config/wal/wal` — H wallpaper path.
+- `~/.config/wal/wal2` — V wallpaper path.
+
+PID tracking (runtime only, meaningless after reboot):
+
+- `~/.cache/wallp/H.pid` — swaybg PID for horizontal output.
+- `~/.cache/wallp/V.pid` — swaybg PID for vertical output.
+
+wallp writes **all** pointer files directly (cache + config) on set and restore.
+This moves persistence out of `wal.sh` and into wallp. `wal.sh` is reduced to its
+theme-app glue only (dunst symlink+restart, kitty symlink); it loses the
+wal/wal2/wpaper copy logic. `wal.sh` remains the wal `-o` hook for future use.
+
+## Set Flow
+
+For each chosen output (H and/or V):
+
+1. Resolve the file path (from qarma picker or `H=`/`V=` arg). Validate it
+ exists; if not, error and skip that output (do not blank it).
+2. Selective kill: read `<X>.pid`; if the PID is alive, `kill` it. The other
+ output's swaybg is left untouched.
+3. `swaybg -o <OUTPUT> -i <file> -m fill &`; save the new PID to `<X>.pid`.
+4. Write the pointer to cache (`wal`/`wal2`) and config (`wal`/`wal2`).
+
+After all chosen outputs are done:
+
+5. Update `~/.cache/wal/wpaper` symlink → current H image.
+6. Run `wal --backend colorz -nq --theme <THEME> -o ~/bin/wal.sh`.
+7. `notify-send` color-theme update.
+
+qarma selection flow (`--set`, display present, no args):
+
+- qarma list/menu: choose `H` / `V` / `Both` (no initial yes/no confirmation).
+- File picker per chosen output: `qarma --file-selection --preview-images 500
+ --width 1300 --height 600` with a per-output title.
+- Picker cancelled → skip that output (no error).
+
+## Restore Flow (`--restore`)
+
+For each output H/V:
+
+1. If the persistent pointer (`~/.config/wal/wal` for H, `wal2` for V) exists →
+ read the path, selective-kill that output's old PID, `swaybg`, save PID, and
+ sync the pointer to `~/.cache/wal/`.
+2. If no persistent pointer for that output → use `DEFAULT_H`/`DEFAULT_V` from
+ conf, write both pointers (cache + config), swaybg, save PID.
+
+After both outputs:
+
+3. Update `wpaper` symlink → H image.
+4. Run wal theme + notify (same as set steps 6-7).
+
+No display required. Replaces `qar-lastwall.sh`. Intended for session-start
+autostart.
+
+## Error Handling
+
+- Missing/invalid file for an output → error, skip that output, do not blank it.
+- qarma cancel → skip output, no error.
+- Dead or missing PID file → start fresh swaybg, no kill attempt.
+- GUI needed but no display → clear error, exit non-zero.
+- Required binary missing (`swaybg`, `wal`, `qarma` when GUI needed,
+ `notify-send` optional) → checked at start; error and exit if a required one
+ is absent. `notify-send` treated as optional (skip notification if absent).
+- Conf missing → generate template, instruct user, exit 0, no change.
+- Required conf key missing → hard error, exit non-zero, no change.
+
+## Testing
+
+The script is side-effecting (swaybg, wal, filesystem). Strategy:
+
+- Factor pure logic into functions: conf parsing, arg parsing, `~` expansion,
+ logical→physical output mapping, file-existence validation.
+- Test with bats (or a stub harness): place fake `swaybg`, `wal`, `qarma`,
+ `notify-send` as executable stubs on `PATH` in a temp dir; point `HOME` at a
+ temp dir.
+- Assertions:
+ - Conf-missing path generates the template and changes no wallpaper.
+ - Missing required key hard-errors.
+ - `--set V=<file>` writes V pointers (cache + config) and leaves `H.pid`
+ untouched (partial update does not blank H).
+ - Selective kill targets only the changed output's PID.
+ - Restore falls back to `DEFAULT_*` when no persistent pointer exists.
+ - `~` in conf paths expands to `$HOME`.
+- Manual smoke test on the real two-screen setup.
+
+## Migration Notes
+
+- `wal.sh` lines 16-27 (wal/wal2/wpaper copy + symlink) move into wallp; remove
+ them from `wal.sh`, keep dunst + kitty glue.
+- Old `qar-lastwall.sh` read `~/.config/wal/*`; old `multiwal.sh` wrote
+ `~/.cache/wal/*` — this mismatch bug is resolved: wallp writes both.
+- Old default-wallpaper paths had a literal quoted `~` (swaybg would not expand)
+ — fixed via `~`→`$HOME` expansion on conf load.