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

4.0 KiB

name, description
name description
niri-all-monitor-screenshot-fix 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.