3.0 KiB
3.0 KiB
name, description
| name | description |
|---|---|
| niri-multi-monitor-screenshot-capture | Diagnose flameshot screenshot failures on niri with 2+ outputs (portal single-output limit) and capture all monitors via niri-native per-output actions |
Niri multi-monitor screenshot capture
Flameshot works on a single niri output, dies the moment a second output connects. Diagnose via compositor journal, capture full desk with niri-native per-output actions — not grim, not portal.
Diagnose (one pass)
journalctl --user -u niri --since today | grep -i screenshotWARN niri::niri: error taking a screenshot: Condition failed: outputs.len() == 1 (2 vs 1)→ flameshot's portal path (xdg-desktop-portal-gnome → niri GNOME-Screenshot D-Bus →screenshot_all_outputsensure!(outputs.len()==1)). Upstream niri#4313, unfixed in 26.04. Symptoms: error bubbles appearing after a delay (portal round-trip), count = number of hotkey presses.
niri msg outputs— count active outputs. 1 output = flameshot fine; the bug is dock-state-dependent (portable works, docked breaks).- Per-mode status:
flameshot screen(focused output) works docked;flameshot guiregion works (mixed-res scaling bug = flameshot#4449);flameshot fulldead on 2+.
Capture all monitors (niri-native)
niri 26.04 has NO all-output capture: screenshot UI is single-output by design (screenshot_ui.rs: "allows only single-output selections for now"); D-Bus path hard-limited. Script pattern:
prev=$(niri msg --json focused-output | jq -r .name)
while IFS= read -r mon; do
[ "$mon" != "$prev" ] && niri msg action focus-monitor "$mon"
sleep 0.15 # let compositor render a frame after focus move
niri msg action screenshot-screen --path "$out/Screenshot from $ts $mon.png"
done < <(niri msg --json outputs | jq -r '.[].name')
# restore focus: niri msg action focus-monitor "$prev"
CLI facts (niri msg action screenshot-screen --help): --path must be ABSOLUTE; -d/--write-to-disk default true (also saves per screenshot-path); -p/--show-pointer default true.
KDL gotchas (bit me twice; bats niri validate catches them)
- KDL line comments are
//, NEVER#—#= parse storm "identifiers cannot be used as arguments". screenshot-pathis a ROOT-level config node (config.screenshot_pathin config.rs); do NOT nest it inoutput {}— root-level bare node validates and works;output { ... }without a name/match arg fails: "additional argumentnameis required".- Root-level
prefer-no-csdis a silent no-op (output-section property) — root unknown nodes only warn.
Verify
- Run the script live;
fileeach PNG (valid dimensions per monitor);niri msg --json focused-outputequals pre-run monitor. bats tests/incl. niri-config assembly validate on every desk profile before commit.- Deploy: symlink script into
~/.local/bin(reposcripts/convention, likedesk.sh); bindspawn-sh "name"in keybinds.kdl; niri hot-reloads config on file change.