feat(displays): hotplug auto-switch for display profiles (item 15b)
All checks were successful
Check / eval (push) Successful in 2m57s

nomarchy-display-profile gains `match <outputs>`: an exact set match
wins, else the largest profile whose named outputs are all connected;
any tie prints nothing — the watcher must never flap between ambiguous
layouts. nomarchy-display-profile-watch (exec-once when profiles are
declared, the keyboard-watcher poll pattern — session units race
Hyprland IPC on relogin) reacts to output-set CHANGES only, reads
settings.displayProfileAuto from the live state each time (the menu's
new Auto-switch row toggles it instantly, no rebuild), and applies via
the tool — so an auto-pick persists a concrete profile that the next
rebuild bakes. A separate boolean rather than an "auto" pseudo-profile
for exactly that bake semantics.

Verified: V0 (flake check); V1 — a scratch 4-profile downstream builds;
tool + watcher pass bash -n; the match matrix exercised end-to-end:
three exact picks, an unambiguous-superset pick, a tie -> none, a
no-fit -> none; the watcher is exec-once'd in the rendered config; the
menu renders the Auto-switch row. Remains: V3 real dock/undock
(HARDWARE-QUEUE, rides the slice-a entry). Slice c (workspace binding)
stays, tagged optional.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Bernardo Magri
2026-07-05 18:14:07 +01:00
parent 9df18261f9
commit 1921839e0e
7 changed files with 122 additions and 12 deletions

View File

@@ -71,12 +71,14 @@ the *same* outputs. **Plan (designed 2026-07-05, iteration #27):**
- **Slices:** (a) ✓ shipped 2026-07-05 (iteration #28): option +
overlay (pure `modules/home/monitor-rules.nix`, unit-tested by
checks.display-profiles) + `nomarchy-display-profile` applier + menu
Profiles row + template example — V3 (real dock) queued; (b)
opt-in hotplug auto-switch: a socket2 watcher on monitoradded/
removed picks the profile whose named-output set matches connected
outputs (exact match, else largest subset, ties = no switch) —
decide the flag shape (`settings.displayProfile = "auto"` vs a
separate boolean) at implementation; (c) optional per-profile
Profiles row + template example — V3 (real dock) queued; (b)
shipped 2026-07-05 (iteration #29): hotplug auto-switch — `match`
subcommand (exact set, else unambiguous largest subset, ties =
none) + a poll watcher (exec-once, the keyboard-watcher pattern)
gated live on `settings.displayProfileAuto` (a separate boolean,
NOT an "auto" pseudo-profile, so auto-picks persist concrete
profiles that rebuilds bake) + menu Auto-switch row — V3 rides the
slice-a dock test; (c) optional per-profile
`workspaces = { "1" = "DP-3"; }` → Hyprland `workspace` keywords.
- **Non-goals:** no kanshi (fights Hyprland's output management —
decided in ROADMAP), nwg-displays stays a find-the-values helper.

View File

@@ -148,6 +148,11 @@ QA machine), the **T14s** (webcam case).
overlay); "Base layout" restores; a menu resolution pick made
earlier must NOT re-enable a profile-disabled panel after the
next rebuild.
- [ ] **Display profiles auto-switch, slice b (item 15)** — same setup,
then menu Profiles Auto-switch on: plugging the dock/monitor
applies the matching profile within ~3s (toast names it);
unplugging switches back; Auto-switch off stops that; with two
profiles naming the same outputs, no flapping (ties do nothing).
- [ ] **Color picker (item 13, final slice)** — SUPER+CTRL+P (or Tools
Color picker): hyprpicker's zoom loupe appears; click a pixel →
toast shows the hex and `wl-paste` yields it; Esc cancels with no

View File

@@ -17,6 +17,28 @@ Template:
---
## 2026-07-05 — display profiles auto-switch (iteration #29, item 15b)
- **Task:** BACKLOG NEXT#15 slice b — opt-in hotplug auto-switch.
- **Did:** nomarchy-display-profile gains `match <outputs>` (exact set
→ else unambiguous largest subset → ties/none = exit 1);
nomarchy-display-profile-watch polls `hyprctl monitors all` every 3s
(exec-once, the keyboard-watcher pattern — session units race
Hyprland IPC), reacts only to CHANGES, reads settings.displayProfileAuto
LIVE each change (instant menu toggle, no rebuild) and applies via
the tool, so auto-picks persist concrete profiles that rebuilds
bake. Chose a separate boolean over an "auto" pseudo-profile for
exactly that bake semantics. Menu: Auto-switch (on/off) row in
Profiles. Template + README notes.
- **Verified:** V0; V1 — scratch 4-profile downstream builds; both
scripts bash -n; match matrix exercised: exact ×3, unambiguous
subset, tie → none, no-fit → none; watcher exec-once present; menu
renders with the row. Real hotplug needs a session+dock → V3 (rides
the slice-a queue entry).
- **Pending:** V3. Slice c (workspace binding) remains, tagged
optional.
- **Next suggestion:** #16 greeter theming — item 15's remaining
slice c is optional; a fresh item keeps variety.
## 2026-07-05 — display profiles slice a (iteration #28, item 15a)
- **Task:** BACKLOG NEXT#15 slice a, per the #27 design: option +
overlay + applier + menu + template example.