#!/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; }