niri: fix screenshots on 2+ outputs — Mod+Shift+S captures all monitors
flameshot full dies docked: its portal path hits niri's screenshot_all_outputs ensure!(outputs.len()==1) (upstream niri#4313, niri 26.04), so every Print press on the home desk produces error bubbles. niri's built-in screenshot UI selects only one output, so add scripts/screenshot-desk.sh: per-monitor focus + screenshot-screen with explicit --path, focus restored, one PNG per monitor in ~/Pictures/Screenshots. Bind Mod+Shift+S (Frank's call); noctalia settings moves to Mod+Shift+O. Restore screenshot-path (was null, now root-level as config.screenshot_path requires) for UI saves. Live- verified docked: valid 1920x1080 PNGs for eDP-1 + DP-2, focus restored; bats 27/27 incl. niri validate on both desk profiles.
This commit is contained in:
@@ -15,7 +15,7 @@ binds {
|
|||||||
// --- Noctalia ---
|
// --- Noctalia ---
|
||||||
Mod+Shift+Return hotkey-overlay-title="Open Wallpaper Selector: noctalia wallpaper toggle" { spawn-sh "noctalia msg panel-toggle wallpaper"; }
|
Mod+Shift+Return hotkey-overlay-title="Open Wallpaper Selector: noctalia wallpaper toggle" { spawn-sh "noctalia msg panel-toggle wallpaper"; }
|
||||||
Mod+S hotkey-overlay-title="Open Control Center: noctalia controlCenter" { spawn-sh "noctalia msg panel-toggle control-center"; }
|
Mod+S hotkey-overlay-title="Open Control Center: noctalia controlCenter" { spawn-sh "noctalia msg panel-toggle control-center"; }
|
||||||
Mod+Shift+S hotkey-overlay-title="Open Settings: noctalia settings" { spawn-sh "noctalia msg settings-toggle"; }
|
Mod+Shift+O hotkey-overlay-title="Open Settings: noctalia settings" { spawn-sh "noctalia msg settings-toggle"; }
|
||||||
Mod+D hotkey-overlay-title="Open App Launcher: noctalia launcher" { spawn-sh "noctalia msg panel-toggle launcher"; }
|
Mod+D hotkey-overlay-title="Open App Launcher: noctalia launcher" { spawn-sh "noctalia msg panel-toggle launcher"; }
|
||||||
Mod+ALT+L hotkey-overlay-title="Lock Screen: noctalia lock" { spawn-sh "noctalia msg session lock"; }
|
Mod+ALT+L hotkey-overlay-title="Lock Screen: noctalia lock" { spawn-sh "noctalia msg session lock"; }
|
||||||
Mod+Shift+Q hotkey-overlay-title="Session Menu: noctalia sessionMenu" { spawn-sh "noctalia msg panel-toggle session"; }
|
Mod+Shift+Q hotkey-overlay-title="Session Menu: noctalia sessionMenu" { spawn-sh "noctalia msg panel-toggle session"; }
|
||||||
@@ -161,6 +161,11 @@ binds {
|
|||||||
Print hotkey-overlay-title="Screenshot: flameshot full" { spawn-sh "flameshot full"; }
|
Print hotkey-overlay-title="Screenshot: flameshot full" { spawn-sh "flameshot full"; }
|
||||||
Ctrl+Print hotkey-overlay-title="Screenshot: flameshot region" { spawn-sh "flameshot gui"; }
|
Ctrl+Print hotkey-overlay-title="Screenshot: flameshot region" { spawn-sh "flameshot gui"; }
|
||||||
Alt+Print hotkey-overlay-title="Screenshot: flameshot screen" { spawn-sh "flameshot screen"; }
|
Alt+Print hotkey-overlay-title="Screenshot: flameshot screen" { spawn-sh "flameshot screen"; }
|
||||||
|
// Full-desk capture: one PNG per connected monitor via
|
||||||
|
// scripts/screenshot-desk.sh (symlinked into ~/.local/bin). Works docked
|
||||||
|
// (2+ outputs), where flameshot full is dead and niri's built-in
|
||||||
|
// screenshot UI selects only one output.
|
||||||
|
Mod+Shift+S hotkey-overlay-title="Screenshot: all monitors (per-monitor files)" { spawn-sh "screenshot-desk.sh"; }
|
||||||
|
|
||||||
// ─── Emergency Escape Key ───
|
// ─── Emergency Escape Key ───
|
||||||
// Use this when a fullscreen app blocks your keybinds.
|
// Use this when a fullscreen app blocks your keybinds.
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
prefer-no-csd
|
prefer-no-csd
|
||||||
screenshot-path null
|
// Default save path for niri-native captures (screenshot UI,
|
||||||
|
// screenshot-screen). scripts/screenshot-desk.sh (Mod+Shift+S) writes
|
||||||
|
// one file per monitor here; flameshot full is dead on 2+ outputs
|
||||||
|
// docked — see omp-docs/tools/niri/screenshots.md.
|
||||||
|
screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png"
|
||||||
|
|
||||||
environment {
|
environment {
|
||||||
ELECTRON_OZONE_PLATFORM_HINT "auto"
|
ELECTRON_OZONE_PLATFORM_HINT "auto"
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ Column-based scrollable tiling. Columns are cycled with Mod+Left/Right (or Mod+H
|
|||||||
| [[tips|tips.md]] | howto | Practical tips for working with niri |
|
| [[tips|tips.md]] | howto | Practical tips for working with niri |
|
||||||
| [[displays|displays.md]] | reference | Desk-profile system: EDID-keyed outputs, hotplug auto-switch, portrait transforms, GPU notes |
|
| [[displays|displays.md]] | reference | Desk-profile system: EDID-keyed outputs, hotplug auto-switch, portrait transforms, GPU notes |
|
||||||
| [[keybindings|keybindings.md]] | reference | GENERATED keybinding cheat sheet (scripts/gen-keybinds.sh) |
|
| [[keybindings|keybindings.md]] | reference | GENERATED keybinding cheat sheet (scripts/gen-keybinds.sh) |
|
||||||
|
| [[screenshots|screenshots.md]] | reference | Screenshot bind matrix: flameshot vs niri-native, 2+ output limits, all-monitor capture |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
| `Mod+B` | Open Browser: firefox |
|
| `Mod+B` | Open Browser: firefox |
|
||||||
| `Mod+Shift+Return` | Open Wallpaper Selector: noctalia wallpaper toggle |
|
| `Mod+Shift+Return` | Open Wallpaper Selector: noctalia wallpaper toggle |
|
||||||
| `Mod+S` | Open Control Center: noctalia controlCenter |
|
| `Mod+S` | Open Control Center: noctalia controlCenter |
|
||||||
| `Mod+Shift+S` | Open Settings: noctalia settings |
|
| `Mod+Shift+O` | Open Settings: noctalia settings |
|
||||||
| `Mod+D` | Open App Launcher: noctalia launcher |
|
| `Mod+D` | Open App Launcher: noctalia launcher |
|
||||||
| `Mod+ALT+L` | Lock Screen: noctalia lock |
|
| `Mod+ALT+L` | Lock Screen: noctalia lock |
|
||||||
| `Mod+Shift+Q` | Session Menu: noctalia sessionMenu |
|
| `Mod+Shift+Q` | Session Menu: noctalia sessionMenu |
|
||||||
@@ -166,6 +166,7 @@
|
|||||||
| `Print` | Screenshot: flameshot full |
|
| `Print` | Screenshot: flameshot full |
|
||||||
| `Ctrl+Print` | Screenshot: flameshot region |
|
| `Ctrl+Print` | Screenshot: flameshot region |
|
||||||
| `Alt+Print` | Screenshot: flameshot screen |
|
| `Alt+Print` | Screenshot: flameshot screen |
|
||||||
|
| `Mod+Shift+S` | Screenshot: all monitors (per-monitor files) |
|
||||||
|
|
||||||
## Emergency Escape Key
|
## Emergency Escape Key
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
type: reference
|
||||||
|
title: Screenshot Matrix
|
||||||
|
description: Which screenshot binds work on blankpad as a function of output count — flameshot full is dead on 2+ outputs (niri D-Bus screencopy single-output limit, upstream niri#4313); Mod+Shift+S runs scripts/screenshot-desk.sh, the niri-native all-monitor capture.
|
||||||
|
tags:
|
||||||
|
- niri
|
||||||
|
- flameshot
|
||||||
|
- screenshots
|
||||||
|
- multi-monitor
|
||||||
|
- portal
|
||||||
|
verified: 2026-10-14
|
||||||
|
---
|
||||||
|
|
||||||
|
# Screenshot Matrix
|
||||||
|
|
||||||
|
Three capture stacks coexist on blankpad: **flameshot** (portal → niri
|
||||||
|
D-Bus screenshot API), niri's built-in **screenshot UI**, and
|
||||||
|
**scripts/screenshot-desk.sh** (drives niri per-output actions). The
|
||||||
|
flameshot full-screen path breaks the moment the laptop docks to a
|
||||||
|
second output.
|
||||||
|
|
||||||
|
## Bind matrix by output count
|
||||||
|
|
||||||
|
| Bind | Tool | 1 output (portable) | 2+ outputs (docked home) |
|
||||||
|
|------|------|---------------------|--------------------------|
|
||||||
|
| `Print` / `Ctrl+Shift+1` | `flameshot full` | ✅ | ❌ error bubbles |
|
||||||
|
| `Alt+Print` / `Ctrl+Shift+2` | `flameshot screen` (focused) | ✅ | ✅ single-output request |
|
||||||
|
| `Ctrl+Print` / `Ctrl+Shift+3` | `flameshot gui` (region) | ✅ | ✅ (watch scaling on mixed-res, [flameshot#4449](https://github.com/flameshot-org/flameshot/issues/4449)) |
|
||||||
|
| `Mod+Shift+S` | `screenshot-desk.sh` — one PNG **per monitor** | ✅ | ✅ the docked full-desk path |
|
||||||
|
|
||||||
|
`Mod+Shift+S` used to open noctalia settings; noctalia settings moved to
|
||||||
|
**`Mod+Shift+O`**.
|
||||||
|
|
||||||
|
## Why `flameshot full` dies docked
|
||||||
|
|
||||||
|
- Flameshot 14 full-screen capture → xdg-desktop-portal →
|
||||||
|
`xdg-desktop-portal-gnome` → niri's GNOME-Screenshot compatibility D-Bus
|
||||||
|
service.
|
||||||
|
- That service calls `Niri::screenshot_all_outputs` (src/niri.rs), which
|
||||||
|
starts with `ensure!(outputs.len() == 1)` (FIXME: multi-scale/crop
|
||||||
|
unsupported). On a 2-output virtual screen the request is refused;
|
||||||
|
flameshot pops an error bubble after the portal round-trip — the
|
||||||
|
"bunch of errors after a delay".
|
||||||
|
- Compositor-side fingerprint (`journalctl --user -u niri`):
|
||||||
|
`WARN niri::niri: error taking a screenshot: Condition failed: outputs.len() == 1 (2 vs 1)`
|
||||||
|
- Upstream: [niri#4313](https://github.com/niri-wm/niri/issues/4313)
|
||||||
|
(identical stack: niri 26.04 + Flameshot 14 + portal-gnome; closed as
|
||||||
|
duplicate, unfixed in 26.04/8ed0da4).
|
||||||
|
|
||||||
|
## Why not niri's built-in `screenshot` UI
|
||||||
|
|
||||||
|
niri 26.04's default `screenshot` action opens the interactive
|
||||||
|
screenshot UI, and its selection is single-output by design
|
||||||
|
("this implementation allows only single-output selections for now",
|
||||||
|
src/ui/screenshot_ui.rs). One press = one monitor.
|
||||||
|
|
||||||
|
## The all-monitor path: `scripts/screenshot-desk.sh`
|
||||||
|
|
||||||
|
- Bind: `Mod+Shift+S` in [[keybindings|keybindings.md]].
|
||||||
|
- Deploy form: symlink `~/.local/bin/screenshot-desk.sh` →
|
||||||
|
`~/.omp/scripts/screenshot-desk.sh` (same convention as `desk.sh`).
|
||||||
|
- Algorithm: for each active output from `niri msg --json outputs`,
|
||||||
|
`focus-monitor` → `screenshot-screen --path` (absolute, one PNG),
|
||||||
|
then restore the previously focused monitor. All niri-native, no
|
||||||
|
grim, no portal.
|
||||||
|
- Files: `~/Pictures/Screenshots/Screenshot from
|
||||||
|
YYYY-MM-DD HH-MM-SS <connector>.png` (dir overridable via
|
||||||
|
`SCREENSHOT_DIR`). Also honors `screenshot-path` in misc.kdl for the
|
||||||
|
UI/screenshot-screen default when no `--path` is passed.
|
||||||
|
- Verified 2026-10-14 docked: two valid PNGs (eDP-1, DP-2), focus
|
||||||
|
restored.
|
||||||
|
|
||||||
|
## Census commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
niri msg outputs # how many outputs live
|
||||||
|
journalctl --user -u niri --since today | grep -i screenshot # portal-path failures
|
||||||
|
pgrep -a flameshot # daemon state
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [[displays|displays.md]] — desk profiles: 1 output portable vs 2 docked
|
||||||
|
- [[keybindings|keybindings.md]] — generated cheat sheet (source of the binds)
|
||||||
|
- [[noctalia-shell|noctalia-shell]] — shell settings moved to Mod+Shift+O
|
||||||
Executable
+45
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# screenshot-desk.sh — capture EVERY connected monitor to disk, one PNG each.
|
||||||
|
#
|
||||||
|
# niri 26.04 has no single "screenshot all outputs" action (the screenshot
|
||||||
|
# UI selects a single output only, and the GNOME-compat D-Bus screenshot
|
||||||
|
# that flameshot 14 uses is hard-limited to one output — niri#4313).
|
||||||
|
# This script drives niri's own per-output primitives:
|
||||||
|
# focus-monitor + screenshot-screen, once per connected output,
|
||||||
|
# then restores the previously focused monitor.
|
||||||
|
#
|
||||||
|
# Usage: screenshot-desk.sh # bound to Mod+Shift+S in keybinds.kdl
|
||||||
|
# SCREENSHOT_DIR=/tmp screenshot-desk.sh
|
||||||
|
#
|
||||||
|
# Output naming mirrors niri's screenshot-path default:
|
||||||
|
# "$SCREENSHOT_DIR/Screenshot from YYYY-MM-DD HH-MM-SS <connector>.png"
|
||||||
|
# Files land in ~/Pictures/Screenshots by default (same dir as niri's
|
||||||
|
# screenshot-path in cfg/misc.kdl).
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
out_dir="${SCREENSHOT_DIR:-$HOME/Pictures/Screenshots}"
|
||||||
|
mkdir -p "$out_dir"
|
||||||
|
ts="$(date +'%Y-%m-%d %H-%M-%S')"
|
||||||
|
|
||||||
|
focused() { niri msg --json focused-output | jq -r .name; }
|
||||||
|
|
||||||
|
prev="$(focused)"
|
||||||
|
count=0
|
||||||
|
|
||||||
|
# niri msg --json outputs: active outputs only (disabled/lid-closed absent).
|
||||||
|
while IFS= read -r mon; do
|
||||||
|
[ "$mon" != "$prev" ] && niri msg action focus-monitor "$mon"
|
||||||
|
# Let the compositor settle a frame after focus move (focus-driven
|
||||||
|
# highlights/animations are rendered async).
|
||||||
|
sleep 0.15
|
||||||
|
file="$out_dir/Screenshot from $ts $mon.png"
|
||||||
|
niri msg action screenshot-screen --path "$file"
|
||||||
|
echo "$file"
|
||||||
|
count=$((count + 1))
|
||||||
|
done < <(niri msg --json outputs | jq -r '.[].name')
|
||||||
|
|
||||||
|
# Restore the original focus (no-op if it's where we ended up).
|
||||||
|
now="$(focused)"
|
||||||
|
[ "$now" != "$prev" ] && niri msg action focus-monitor "$prev"
|
||||||
|
[ "$count" -gt 0 ] || { echo "no active outputs" >&2; exit 1; }
|
||||||
Reference in New Issue
Block a user