# 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= # set horizontal only, no GUI wallp --set V= # set vertical only, no GUI wallp --set H= V= # set both, no GUI wallp --restore # restore last session from persistent state wallp --theme # 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= and/or V=". 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 ` → 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 `.pid`; if the PID is alive, `kill` it. The other output's swaybg is left untouched. 3. `swaybg -o -i -m fill &`; save the new PID to `.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 -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=` 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.