Files
command-center/agent/managed-skills/niri-all-monitor-screenshot-fix/SKILL.md
T

45 lines
4.0 KiB
Markdown

---
name: niri-all-monitor-screenshot-fix
description: "Fix flameshot screenshot failures on niri with 2+ outputs: confirm portal outputs.len()==1 census, retire flameshot binds for niri-native equivalents, absolute script paths (niri spawn-sh PATH lacks ~/.local/bin)"
---
# Niri all-monitor screenshot fix (flameshot retirement)
## Symptom fingerprints
- "Bunch of flameshot errors after a delay" when docked (2+ outputs); fine on one output.
- Journal census (ground truth): `journalctl --user -u niri --since today | grep -i screenshot`
- FAIL: `WARN niri::niri: error taking a screenshot: Condition failed: outputs.len() == 1 (2 vs 1)` — one press of flameshot full emits 3 WARNs (composited screen + per-output portal requests).
- SUCCESS: `DEBUG niri::niri: saving screenshot to ...` — per-file lines.
- Timeline: count WARNs before/after a config reload to attribute presses to config states.
## Root cause
Flameshot 14 on Wayland captures via xdg-desktop-portal → xdg-desktop-portal-gnome → niri's GNOME-Screenshot compatibility D-Bus API → `screenshot_all_outputs` → `ensure!(outputs.len() == 1)` (FIXME upstream). Upstream: niri#4313 (closed duplicate, unfixed in 26.04/8ed0da4), flameshot#4449.
- NOT just `full`: live-verified docked, `flameshot full` AND `flameshot screen` both hang ~15 s (exit 124 under timeout), write no file. Assume ALL flameshot capture modes dead with 2+ outputs.
## Fix: retire flameshot binds; niri-native replacements (blankpad layout)
| Chord | Action |
|---|---|
| Print / Ctrl+Shift+1 / Mod+Shift+S | `spawn-sh "/home/blank/.omp/scripts/screenshot-desk.sh"` — per-monitor PNGs |
| Alt+Print / Ctrl+Shift+2 | `screenshot-screen;` — focused monitor → screenshot-path + clipboard |
| Ctrl+Print / Ctrl+Shift+3 | `screenshot;` — interactive UI (Space saves, Esc cancels; single-output selection by design) |
- Misc: `screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png"` at CONFIG ROOT (it is `config.screenshot_path`; a KDL `output { }` block REQUIRES a name arg — bare `output {}` is a parse error).
- KDL comments are `//`, never `#` (parses as identifiers → cryptic "identifiers cannot be used as arguments").
- niri 26.04 screenshot UI: "allows only single-output selections for now" (src/ui/screenshot_ui.rs) — no built-in all-monitor composite; script needed.
## All-monitor script (scripts/screenshot-desk.sh)
Per active output (`niri msg --json outputs | jq -r .[].name`): `niri msg action focus-monitor <m>` → sleep 0.15 → `niri msg action screenshot-screen --path "<abs>/… <connector>.png"` → restore prior focused monitor (`niri msg --json focused-output | jq -r .name`). No grim, no portal. `--path` must be absolute.
## THE SPAWN-SH PATH TRAP
niri's spawn-sh PATH = system dirs only; `~/.local/bin` ABSENT. Proof:
`tr '\0' '\n' < /proc/$(pgrep -x niri | head -1)/environ | grep ^PATH`
→ any bare user-script name in a keybind fails SILENTLY (no journal error, no file). Rule: keybinds use absolute script paths (`/home/blank/.omp/scripts/...`). Audit existing binds for bare names (desk.sh was dead too).
## Verifying a keybind end-to-end without a keyboard
Reproduce niri's child env exactly:
`env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl HOME=$HOME USER=$USER LOGNAME=$LOGNAME XDG_RUNTIME_DIR=/run/user/$(id -u) WAYLAND_DISPLAY=wayland-1 NIRI_SOCKET=/run/user/$(id -u)/niri.$WAYLAND_DISPLAY.$(pgrep -x niri | head -1).sock sh -c "/abs/path/script"`
NIRI_SOCKET is NOT in niri's own environ (it is set on niri's children); socket path convention: `$XDG_RUNTIME_DIR/niri.<wl-display>.<niri-pid>.sock`.
## Deploy mechanics (blankpad command-center)
Live niri config = symlinks into the ~/.omp main checkout ("the checkout is the deployment"). Merge to main → niri auto-reloads (~1 s later journal `DEBUG niri_config: loaded config from ...`); verify that DEBUG line as the reload proof. Manual fallback: Mod+Shift+/. `niri msg` has NO keybinds subcommand — keybind proof = overlay (Mod+Shift+Escape) + journal census.