diff --git a/dotfiles/zz-blankpad/niri/.config/niri/cfg/keybinds.kdl b/dotfiles/zz-blankpad/niri/.config/niri/cfg/keybinds.kdl index de6cc4d..e69a326 100644 --- a/dotfiles/zz-blankpad/niri/.config/niri/cfg/keybinds.kdl +++ b/dotfiles/zz-blankpad/niri/.config/niri/cfg/keybinds.kdl @@ -15,7 +15,7 @@ binds { // --- Noctalia --- 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+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+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"; } @@ -161,6 +161,11 @@ binds { Print hotkey-overlay-title="Screenshot: flameshot full" { spawn-sh "flameshot full"; } Ctrl+Print hotkey-overlay-title="Screenshot: flameshot region" { spawn-sh "flameshot gui"; } 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 ─── // Use this when a fullscreen app blocks your keybinds. diff --git a/dotfiles/zz-blankpad/niri/.config/niri/cfg/misc.kdl b/dotfiles/zz-blankpad/niri/.config/niri/cfg/misc.kdl index 6bebc66..fe5f12c 100644 --- a/dotfiles/zz-blankpad/niri/.config/niri/cfg/misc.kdl +++ b/dotfiles/zz-blankpad/niri/.config/niri/cfg/misc.kdl @@ -1,5 +1,9 @@ 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 { ELECTRON_OZONE_PLATFORM_HINT "auto" diff --git a/omp-docs/tools/niri/index.md b/omp-docs/tools/niri/index.md index 3a208fb..932bef0 100644 --- a/omp-docs/tools/niri/index.md +++ b/omp-docs/tools/niri/index.md @@ -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 | | [[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) | +| [[screenshots|screenshots.md]] | reference | Screenshot bind matrix: flameshot vs niri-native, 2+ output limits, all-monitor capture | --- diff --git a/omp-docs/tools/niri/keybindings.md b/omp-docs/tools/niri/keybindings.md index 046bbe0..34d1e8c 100644 --- a/omp-docs/tools/niri/keybindings.md +++ b/omp-docs/tools/niri/keybindings.md @@ -21,7 +21,7 @@ | `Mod+B` | Open Browser: firefox | | `Mod+Shift+Return` | Open Wallpaper Selector: noctalia wallpaper toggle | | `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+ALT+L` | Lock Screen: noctalia lock | | `Mod+Shift+Q` | Session Menu: noctalia sessionMenu | @@ -166,6 +166,7 @@ | `Print` | Screenshot: flameshot full | | `Ctrl+Print` | Screenshot: flameshot region | | `Alt+Print` | Screenshot: flameshot screen | +| `Mod+Shift+S` | Screenshot: all monitors (per-monitor files) | ## Emergency Escape Key diff --git a/omp-docs/tools/niri/screenshots.md b/omp-docs/tools/niri/screenshots.md new file mode 100644 index 0000000..d45e144 --- /dev/null +++ b/omp-docs/tools/niri/screenshots.md @@ -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 .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 diff --git a/scripts/screenshot-desk.sh b/scripts/screenshot-desk.sh new file mode 100755 index 0000000..82eddb1 --- /dev/null +++ b/scripts/screenshot-desk.sh @@ -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 .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; }