1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
|
# 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
Persistent state (wallp-owned, `~/.config/wallp/`, survives reboot):
- `~/.config/wallp/wall_h` — H wallpaper path.
- `~/.config/wallp/wall_v` — V wallpaper path.
- `~/.config/wallp/theme` — last-used theme name.
- `~/.config/wallp/wallp.conf` — config (see Config section).
Runtime state (volatile, reset on reboot):
- `~/.cache/wal/wpaper` — symlink to current H image. **Kept** because it has
external consumers (rofi themes under `~/.config/rofi/darknix/*.rasi`). wallp
maintains it.
- `~/.cache/wallp/H.pid` — swaybg PID for horizontal output.
- `~/.cache/wallp/V.pid` — swaybg PID for vertical output.
Dropped (no external consumer; confirmed via grep over `~/bin` and `~/.config`):
- `~/.cache/wal/wal`, `~/.cache/wal/wal2` — only the replaced scripts wrote
these; nothing else reads them.
- `~/.config/wal/wal`, `~/.config/wal/wal2` — superseded by `~/.config/wallp/`.
wallp owns all its persistence directly in `~/.config/wallp/`. 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.
Note: `~/.cache/wal/colors.json` is pywal-native (written by `wal` itself, read
by `pywal_sublime.py`); not touched by wallp.
## Theme Persistence
The last-used theme is persisted to `~/.config/wallp/theme` and survives reboot.
Conf `THEME` is only the first-run default. Precedence on every action:
1. `--theme <name>` flag → use it.
2. else persisted `~/.config/wallp/theme` (if present).
3. else conf `THEME`.
4. else built-in `sexy-splurge`.
Whatever theme is resolved gets persisted to `~/.config/wallp/theme`. This means
once a theme is set it sticks (for both `--set` and `--restore`) until changed
via `--theme`. `--restore` thus brings back the last-used theme, not the conf
default.
## 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. Persist the path to `~/.config/wallp/wall_h` (H) or `wall_v` (V).
After all chosen outputs are done:
5. Update `~/.cache/wal/wpaper` symlink → current H image (for rofi).
6. Resolve theme (see Theme Persistence), persist to `~/.config/wallp/theme`.
7. Run `wal --backend colorz -nq --theme <THEME> -o ~/bin/wal.sh`.
8. `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/wallp/wall_h` for H, `wall_v` for V)
exists → read the path, selective-kill that output's old PID, `swaybg`,
save PID.
2. If no persistent pointer for that output → use `DEFAULT_H`/`DEFAULT_V` from
conf, persist it (`wall_h`/`wall_v`), swaybg, save PID.
After both outputs:
3. Update `wpaper` symlink → H image.
4. Resolve theme (persisted theme wins, see Theme Persistence), persist it,
run wal theme + notify (same as set steps 7-8).
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 `~/.config/wallp/wall_v` and leaves `H.pid`
untouched (partial update does not blank H).
- Theme persistence: `--theme X` writes `~/.config/wallp/theme`; a later
no-flag run resolves X (persisted wins over conf THEME).
- 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) — remove the wal/wal2
copy lines (16,19,22-23) entirely; the `wpaper` symlink moves into wallp.
Keep dunst + kitty glue (lines 7,13). `wal.sh` stays the wal `-o` hook.
- Old `qar-lastwall.sh` read `~/.config/wal/*`; old `multiwal.sh` wrote
`~/.cache/wal/*` — mismatch bug resolved: wallp uses a single owned location
`~/.config/wallp/`.
- Old default-wallpaper paths had a literal quoted `~` (swaybg would not expand)
— fixed via `~`→`$HOME` expansion on conf load.
- `~/.cache/wal/wpaper` retained — consumed by `~/.config/rofi/darknix/*.rasi`.
- `~/.cache/wal/wal` + `wal2` dropped — no external consumer (grep-verified).
|