A Wayland native snapshot and editor tool, inspired by Snappy on macOS. Works great with grim, slurp and sway. But can easily work with other screen copy tools that can output a final image to stdout. See below.
Output of grim (or any tool outputting an image file):
grim -g "$(slurp)" - | swappy -f -Swappshot a PNG file:
swappy -f "~/Desktop/my-gnome-saved-file.png"Print final surface to stdout (useful to pipe with other tools):
grim -g "$(slurp)" - | swappy -f - -o - | pngquant -Grab a swappshot from a specific window under Sway, using swaymsg and jq:
grim -g "$(swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp)" - | swappy -f -The config file is located at $XDG_CONFIG_HOME/swappy/config or at $HOME/.config/swappy/config.
If no user config exists, swappy falls back to swappy/config in each directory listed in $XDG_CONFIG_DIRS (default: /etc/xdg/swappy/config). This lets distributions ship a system-wide default. Only the first file found is loaded: a user config replaces the system one entirely, keys are not merged.
The file follows the GLib conf format. See the man page for details. There is example config file here.
The following lines can be used as swappy's default:
[Default]
save_dir=$HOME/Desktop
save_filename_format=swappy-%Y%m%d-%H%M%S.png
show_panel=false
show_decorations=true
line_size=5
text_size=20
text_font=sans-serif
paint_mode=brush
early_exit=false
fill_shape=false
auto_save=false
custom_color=rgba(193,125,17,1)
transparent=false
transparency=50
save_diris where swappshots will be saved, can contain env variables, when it does not exist, swappy attempts to create it first, but does not abort if directory creation failssave_filename_format: is the filename template, if it contains a date format, this will be parsed into a timestamp. Format is detailed in strftime(3). If this date format is missing, filename will have no timestampshow_panelis used to toggle the paint panel on or off upon startupshow_decorationsis used to toggle the toolbar, window decorations and image gutter on or off upon startup (setting it tofalseleaves only the image, use keyboard shortcuts to edit). The--no-decorationscommand-line option does the same for a single run, overriding the configline_sizeis the default line size (must be between 1 and 50)text_sizeis the default text size (must be between 10 and 50)text_fontis the font used to render text, its format is pango friendlypaint_modeis the mode activated at application start (must be one of: brush|text|rectangle|ellipse|arrow|blur|crop, matching is case-insensitive)early_exitis used to make the application exit after saving the picture or copying it to the clipboardfill_shapeis used to toggle shape filling (for the rectangle and ellipsis tools) on or off upon startupauto_saveis used to toggle auto saving of final buffer tosave_dirupon exitcustom_coloris used to set a default value for the custom colortransparencyis used to set transparency of everything that is drawn during startuptransparentis used to toggle transparency during startup
The swappy window can be resized, and the image scales to fit it. On tiling compositors such as Sway and Hyprland, this means swappy opens as a regular tiled window.
Swappy 1.8.0 and earlier opened with a fixed size. Tiling compositors float fixed-size windows automatically, so swappy used to open floating without any configuration.
To keep swappy floating, add a window rule that matches its app id, swappy:
Sway (~/.config/sway/config):
for_window [app_id="swappy"] floating enable
Hyprland (Lua config, ~/.config/hypr/hyprland.lua):
hl.window_rule({ match = { class = "^(swappy)$" }, float = true })Other compositors usually have an equivalent rule that matches on app id.
Ctrl+b: Toggle Paint Panel
b: Switch to Brushet: Switch to Text (Editor)rs: Switch to Rectangle (Square)o: Switch to Ellipse (Circle)a: Switch to Arrowd: Switch to Blur (dstands for droplet)c: Switch to Crop
R: Use Red ColorG: Use Green ColorB: Use Blue ColorC: Use Custom ColorMinus: Reduce Stroke SizePlus: Increase Stroke SizeEqual: Reset Stroke Sizef: Toggle Shape Fillingxk: Clear Paints (cannot be undone)T: Toggle Transparency
Ctrl: Center Shape (Rectangle, Ellipse & Blur) based on draw startShift: Constrain Shape to Square (Rectangle & Blur) or Circle (Ellipse)
Ctrl+z: UndoCtrl+Shift+zorCtrl+y: RedoCtrl+s: Save to file (see man page)Ctrl+Shift+s: Save to file with a "Save As" dialogCtrl+c: Copy to clipboardEscapeorqorCtrl+w: Quit swappy
- Copy: While swappy is open, the copied image is offered in every image format GTK supports (
image/png,image/bmp,image/tiff, ...), so applications that need a format other than PNG (e.g. Remmina) can paste it. When swappy exits, it hands the image towl-copy, as PNG only. If you don't have wl-clipboard installed, the clipboard is lost when you close swappy. This is because GTK 3.24 has not implemented persistent storage on wayland backend yet. We need to do it on the Wayland level, or wait for GTK 4. - Fonts: Swappy relies on Font Awesome 5 being present to properly render the icons. On Arch you can simply install those with:
sudo pacman -S otf-font-awesome - Output Format: Only PNG is supported.
Install dependencies (on Arch, name can vary for other distros):
- meson
- ninja
- cairo
- pango
- gtk
- glib2
- scdoc
Optional dependencies:
wl-clipboard(to make sure the copy is saved if you close swappy)otf-font-awesome(to draw the paint icons properly)
Then run:
meson setup build
ninja -C buildThis section is for developers, maintainers and translators.
To add support to a new locale or when translations are updated:
- Update
src/po/LINGUAS(when new locales are added) - Generate a new
pofile (ignore and do not commit potential noise in other files):
ninja -C build swappy-update-poTo rebuild the base template (should happen less often):
ninja -C build swappy-potSee the meson documentation for details.
Pull requests are welcome. This project uses conventional commits to automate changelog generation.
We rely on standard-version which is part of the JavaScript ecosystem but works well with any project.
./script/github-releaseMake sure everything is valid in the Draft release, then publish the draft.
Release tarballs are signed with this PGP key: F44D05A50F6C9EB5C81BCF966A6B35DBE9442683
MIT