feat(display): menu-driven per-output resolution, in-flake

Phase 3 of the in-flake-state philosophy (mirroring night-light + the
keyboard-layout watcher): a System ▸ Display menu item picks an output's
resolution and persists it into the flake instead of a runtime-only tweak.

- rofi.nix: the `display` case reads `hyprctl monitors -j` (auto-skips the
  chooser with one output), lists the output's advertised modes (rounded
  refresh, deduped, highest-first) plus the preferred/highres/highrr
  tokens, applies the pick INSTANTLY via `hyprctl keyword monitor` —
  keeping the output's current position + scale, so only the resolution
  changes — then persists it with `nomarchy-theme-sync set
  settings.monitors.<name> <mode> --no-switch` (no rebuild).
- theme.nix: seed `settings.monitors = {}` (output-name -> "WxH@R") so a
  sparse/older state file still evaluates; exposed via nomarchy.settings.
- hyprland.nix: `resolvedMonitors` overlays settings.monitors onto
  nomarchy.monitors by name — a declared output keeps its other fields
  with only the resolution swapped, an undeclared output (wildcard-only,
  e.g. the laptop panel) becomes a fresh rule. So a later rebuild bakes
  the menu pick into the generated monitor rule — the monitor twin of the
  keyboard graduation. The menu pick wins over a hand-set resolution (it's
  the explicit live action).

Monitor connector names are dot-free, so a direct dotted set-path is safe
(no whole-map read-modify-write like the keyboard watcher needs).

VM-verified via a headless-Hyprland nixosTest (run + removed; too heavy
for a CI gate): the graduation baked the rule into the generated
hyprland.conf, the set/get round-trip persisted, and `hyprctl keyword
monitor` actually changed the reported resolution. Only the interactive
rofi picker isn't headlessly driveable (same caveat as the keyboard watcher).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Bernardo Magri
2026-06-30 23:08:39 +01:00
parent aac678335c
commit 4024da791f
4 changed files with 95 additions and 8 deletions

View File

@@ -592,10 +592,15 @@ how to override it. Items marked ✓ are shipped.
(no kanshi — it fights Hyprland's own output management). `nwg-displays`
ships behind `nomarchy.displays.enable` as an interactive arranger (a
helper to find values; the declarative config stays the source of truth —
its output file isn't sourced). Remaining: true docked/undocked **profile
switching** of the *same* outputs (Hyprland's per-output rules cover the
common "external connects → arrange" case, not multi-layout toggles), and
optionally workspace-to-monitor binding.
its output file isn't sourced). The System ▸ **Display** menu picks an
output's resolution from its advertised modes: applied live via `hyprctl
keyword monitor` (current position + scale kept) and persisted to the
in-flake state (`settings.monitors.<name>`, no rebuild), overlaid onto
`nomarchy.monitors` by name so the next rebuild bakes it in — the monitor
twin of the keyboard-layout graduation. Remaining: true docked/undocked
**profile switching** of the *same* outputs (Hyprland's per-output rules
cover the common "external connects → arrange" case, not multi-layout
toggles), and optionally workspace-to-monitor binding.
- ✓ **Night light / blue-light filter:** `nomarchy.nightlight` (opt-in) —
a scheduled colour-temperature shift via `hyprsunset` (Hyprland-native),
warm at night, identity (no shift) by day. `modules/home/nightlight.nix`