44 lines
3.0 KiB
Markdown
44 lines
3.0 KiB
Markdown
---
|
|
name: niri-multi-monitor-screenshot-capture
|
|
description: 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)
|
|
|
|
1. `journalctl --user -u niri --since today | grep -i screenshot`
|
|
- `WARN 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_outputs` `ensure!(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.
|
|
2. `niri msg outputs` — count active outputs. 1 output = flameshot fine; the bug is dock-state-dependent (portable works, docked breaks).
|
|
3. Per-mode status: `flameshot screen` (focused output) works docked; `flameshot gui` region works (mixed-res scaling bug = flameshot#4449); `flameshot full` dead 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:
|
|
|
|
```bash
|
|
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-path` is a ROOT-level config node (`config.screenshot_path` in config.rs); do NOT nest it in `output {}` — root-level bare node validates and works; `output { ... }` without a name/match arg fails: "additional argument `name` is required".
|
|
- Root-level `prefer-no-csd` is a silent no-op (output-section property) — root unknown nodes only warn.
|
|
|
|
## Verify
|
|
|
|
- Run the script live; `file` each PNG (valid dimensions per monitor); `niri msg --json focused-output` equals pre-run monitor.
|
|
- `bats tests/` incl. niri-config assembly validate on every desk profile before commit.
|
|
- Deploy: symlink script into `~/.local/bin` (repo `scripts/` convention, like `desk.sh`); bind `spawn-sh "name"` in keybinds.kdl; niri hot-reloads config on file change.
|