A lightweight yet intelligent window-aware screenshot tool for Wayland. Latchshot freezes the current desktop, snaps to the window under the pointer, and falls back to a freely drawn region when you drag.
Latchshot targets compositors that expose the Wayland protocols needed by its custom overlay. The compositor must support:
wlr-layer-shell-unstable-v1(zwlr_layer_shell_v1)viewporter(wp_viewporter)- At least one supported capture path:
ext-image-copy-capture-v1together with an output source fromext-image-capture-source-v1wlr-screencopy-unstable-v1, together withxdg-output-unstable-v1
| Compositor | Status | Selection support |
|---|---|---|
| Niri | Supported | Window snapping and free-form regions |
| Sway | Supported | Window snapping and free-form regions |
| Hyprland | Supported | Window snapping and free-form regions |
| Mango | Supported | Window snapping and free-form regions |
| Other compatible Wayland compositors | Best effort | Free-form regions only |
| KDE Plasma | Intentionally unsupported | — |
| GNOME | Intentionally unsupported | — |
The generic backend is selected automatically for unknown compositors.
KDE Plasma and GNOME remain intentionally out of scope because Latchshot targets this protocol stack rather than portal- or desktop-shell-specific screenshot flows.
Copying to clipboard (the default destiniation) also requires wl-copy from wl-clipboard.
Clicking a highlighted window uses native toplevel capture when available,
preserving compositor-provided transparency such as rounded corners. Latchshot
uses Wayland's
ext-image-copy-capture-v1
with foreign-toplevel identifiers, or Niri's ScreenshotWindow IPC. Niri may
also copy the intermediate image to the clipboard.
If native capture is unavailable or fails, Latchshot crops the frozen desktop
frame; pass --prefer-crop to enforce cropping even when the protocol is supported.
The overlay remains rectangular because Wayland does not expose compositor corner masks. Other projects, like HyprCapture, use compositor-specific hacks to capture rounded corners and introduced lots of complexity. I intentionally avoids this path.
With Cargo:
cargo install latchshotAll compositor integrations are enabled by default. Use --no-default-features
and --features to select which ones to include:
| Feature | Capability |
|---|---|
niri |
Niri IPC scene discovery |
niri-capture |
Native window screenshots through Niri's ScreenshotWindow IPC; enables niri |
sway |
Sway IPC window discovery |
hyprland |
Hyprland IPC window discovery |
mango |
Mango IPC window discovery |
For example, include Niri and its native capture path without other compositor integrations:
latchshot = { version = "*", default-features = false, features = ["niri", "niri-capture"] }The generic Wayland backend, standard Wayland capture, and free-form region selection are always available.
Run directly:
nix run github:so1ve/latchshotWith a Nix flake, add Latchshot to the inputs:
inputs.latchshot.url = "github:so1ve/latchshot";Then add the package to a NixOS configuration:
{ inputs, pkgs, ... }:
{
environment.systemPackages = [
inputs.latchshot.packages.${pkgs.stdenv.hostPlatform.system}.default
];
}Alternatively, use the overlay to make pkgs.latchshot available:
{ inputs, pkgs, ... }:
{
nixpkgs.overlays = [
inputs.latchshot.overlays.default
];
environment.systemPackages = [
pkgs.latchshot
];
}Use the project cache for prebuilt Nix artifacts when available:
nix.settings = {
extra-substituters = [ "https://so1ve.cachix.org" ];
extra-trusted-public-keys = [
"so1ve.cachix.org-1:51jcW4FkJhiLcqPsiUx3nglRP469les8F9zjFxio1nw="
];
};Run Latchshot with no destination to copy the selected screenshot to the clipboard:
latchshotDuring selection:
- Move the pointer to highlight the window underneath it.
- Left-click a highlighted window to capture it.
- Left-drag to select an arbitrary region.
- Press F to capture the output under the pointer.
- Press Esc or right-click to cancel.
Save directly to a file:
latchshot --output ~/Pictures/screenshot.pngWrite PNG data to standard output:
latchshot --stdout > screenshot.pngDestinations can be combined. For example, this saves the screenshot to a file, streams it to standard output, and copies it to the clipboard:
latchshot --output ~/Pictures/screenshot.png --stdout --clipboard > screenshot-copy.pngTo disable animation:
latchshot --no-animationTo disable desktop notifications:
latchshot --no-notifyTo always crop clicked windows from the frozen desktop frame instead of using native window capture:
latchshot --prefer-cropPrint the discovered scene as JSON for diagnostics:
latchshot --windowsRun latchshot --help for all options. Set RUST_LOG=latchshot=debug for additional diagnostics.
Annotate with Satty, save the result as a
timestamped file under ~/Pictures, and play the desktop's screenshot sound.
Press Enter in Satty when finished:
file="$HOME/Pictures/latchshot-$(date +'%Y-%m-%d_%H-%M-%S').png"; latchshot --stdout | satty --filename - --output-filename "$file" --actions-on-enter=save-to-file,exit; test -s "$file" && canberra-gtk-play --id=screen-captureThe equivalent workflow with Swappy writes the annotated image when Swappy exits:
file="$HOME/Pictures/latchshot-$(date +'%Y-%m-%d_%H-%M-%S').png"; latchshot --stdout | swappy --file - --output-file "$file"; test -s "$file" && canberra-gtk-play --id=screen-captureLatchshot can also be used as a Rust library. See the API documentation on docs.rs for details.
GPT was used to generate compositor adapters for Hyprland, Sway and MangoWM, which I do not use. Doc comments and tests are generated under my guidance.
