From e265934bb16c76cb47144d4625d19626b1ab36f6 Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Mon, 31 Aug 2026 15:43:14 -0400 Subject: [PATCH 1/3] Use Omasnap for screenshots --- agents/skills/visual-verification.md | 5 +- bin/omarchy-capture-screenshot | 81 +++--------------- bin/omarchy-clipboard-open | 2 +- config/imv/config | 4 +- default/agents/skills/omarchy/capture.md | 6 +- default/hypr/apps/screenshot-selection.lua | 5 +- default/hypr/apps/system.lua | 2 - default/uwsm/default | 4 +- docs/file-layout.md | 1 - install/omarchy-base.packages | 2 +- manual/12-screenshots-recording.md | 21 +++-- manual/14-omarchy-cli.md | 2 +- manual/46-faq.md | 6 +- migrations/1788129995.sh | 13 +++ shell/Commons/Util.qml | 2 +- test/shell.d/clipboard-test.sh | 12 +-- test/shell.d/omasnap-test.sh | 99 ++++++++++++++++++++++ test/shell.d/screenshot-sanity-test.sh | 20 ++--- 18 files changed, 169 insertions(+), 118 deletions(-) create mode 100644 migrations/1788129995.sh create mode 100644 test/shell.d/omasnap-test.sh diff --git a/agents/skills/visual-verification.md b/agents/skills/visual-verification.md index 56dc8e78..7df6caa1 100644 --- a/agents/skills/visual-verification.md +++ b/agents/skills/visual-verification.md @@ -15,10 +15,7 @@ Take a full-screen screenshot without opening the editor: omarchy capture screenshot fullscreen save ``` -The command prints the saved path and writes to the configured Pictures -directory. Use `omarchy screenshot` for the interactive smart-region flow. -Capture reference and candidate states as separate images when changing a -layer-shell surface or layout, then compare both. +The command writes to Omasnap's configured screenshot directory. Use `omarchy screenshot` for the interactive editor flow. Capture reference and candidate states as separate images when changing a layer-shell surface or layout, then compare both. Record a short full-screen video for animation, transition, timing, capture, or screen-recording changes: diff --git a/bin/omarchy-capture-screenshot b/bin/omarchy-capture-screenshot index 6f7b91bf..ec383fcd 100755 --- a/bin/omarchy-capture-screenshot +++ b/bin/omarchy-capture-screenshot @@ -2,81 +2,22 @@ # omarchy:summary=Take a screenshot # omarchy:group=capture -# omarchy:args=[smart|region|windows|fullscreen] [slurp|copy|save] [--editor=] +# omarchy:args=[smart|region|windows|fullscreen|scroll] [copy|save] # omarchy:examples=omarchy screenshot | omarchy capture screenshot region # omarchy:aliases=omarchy screenshot -[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs -OUTPUT_DIR="${OMARCHY_SCREENSHOT_DIR:-${XDG_PICTURES_DIR:-$HOME/Pictures}}" - -if [[ ! -d $OUTPUT_DIR ]]; then - mkdir -p "$OUTPUT_DIR" - omarchy-notification-send "Created screenshot directory: $OUTPUT_DIR" -t 2000 +if [[ -n ${OMARCHY_SCREENSHOT_DIR:-} && -z ${OMASNAP_SCREENSHOT_DIR:-} ]]; then + export OMASNAP_SCREENSHOT_DIR="$OMARCHY_SCREENSHOT_DIR" fi -pkill slurp && exit 0 - -SCREENSHOT_EDITOR="${OMARCHY_SCREENSHOT_EDITOR:-tensaku-edit}" - -# Parse --editor flag from any position -ARGS=() +omasnap_args=() for arg in "$@"; do - if [[ $arg == --editor=* ]]; then - SCREENSHOT_EDITOR="${arg#--editor=}" - else - ARGS+=("$arg") - fi + case "$arg" in + copy) omasnap_args+=(--copy) ;; + save) omasnap_args+=(--save) ;; + slurp) ;; + *) omasnap_args+=("$arg") ;; + esac done -set -- "${ARGS[@]}" -MODE="${1:-smart}" -PROCESSING="${2:-slurp}" - -# The picker leaves the screen freeze running (PID on its first output line) -# so grim captures the frozen overlay rather than live content shifting -# during teardown. -# -# Software-composited cursors (Hyprland's fallback on GPUs without working -# hardware cursors) are baked into the frames grim captures, so force -# hardware cursors until after grim runs and restore the setting on exit. -NO_HW_CURSORS=$(hyprctl getoption cursor:no_hardware_cursors -j | jq '.int') - -set_no_hw_cursors() { - hyprctl eval "hl.config({ cursor = { no_hardware_cursors = $1 } })" &>/dev/null || - hyprctl keyword cursor:no_hardware_cursors "$1" &>/dev/null -} - -cleanup() { - [[ -n $FREEZE_PID ]] && kill $FREEZE_PID 2>/dev/null - set_no_hw_cursors "$NO_HW_CURSORS" -} -trap cleanup EXIT - -set_no_hw_cursors 0 -{ read -r FREEZE_PID; read -r SELECTION; } < <(omarchy-capture-region "$MODE" --keep-freeze) - -[[ -z $SELECTION ]] && exit 0 - -FILENAME="screenshot-$(date +'%Y-%m-%d_%H-%M-%S').png" -FILEPATH="$OUTPUT_DIR/$FILENAME" - -case "$PROCESSING" in - slurp) - grim -g "$SELECTION" "$FILEPATH" || exit 1 - echo "$FILEPATH" - wl-copy --type image/png <"$FILEPATH" - - # Best-effort: the screenshot is already saved and on the clipboard, so a - # notification outage must not report the capture itself as failed. - omarchy-notification-send "Screenshot saved to clipboard and file" "Edit with Super + Alt + , (or click this)" \ - --image "$FILEPATH" \ - --exec "$SCREENSHOT_EDITOR" "$FILEPATH" || true - ;; - copy) - grim -g "$SELECTION" - | wl-copy --type image/png - ;; - save) - grim -g "$SELECTION" "$FILEPATH" || exit 1 - echo "$FILEPATH" - ;; -esac +exec omasnap "${omasnap_args[@]}" diff --git a/bin/omarchy-clipboard-open b/bin/omarchy-clipboard-open index 98f26bb2..827fe263 100755 --- a/bin/omarchy-clipboard-open +++ b/bin/omarchy-clipboard-open @@ -30,7 +30,7 @@ open_image() { local path="$1" [[ -r $path ]] || exit 1 - exec tensaku-edit "$path" + exec omasnap "$path" } open_text() { diff --git a/config/imv/config b/config/imv/config index f96aa6a3..5de2530e 100644 --- a/config/imv/config +++ b/config/imv/config @@ -12,5 +12,5 @@ # Rotate the currently open image by 90 degrees = exec mogrify -rotate 90 "$imv_current_file" -# Edit the current image in Tensaku and quit the viewer - = exec tensaku-edit "$imv_current_file" & ; quit +# Edit the current image in Omasnap and quit the viewer + = exec omasnap "$imv_current_file" & ; quit diff --git a/default/agents/skills/omarchy/capture.md b/default/agents/skills/omarchy/capture.md index 621bc298..4390fe75 100644 --- a/default/agents/skills/omarchy/capture.md +++ b/default/agents/skills/omarchy/capture.md @@ -10,12 +10,10 @@ omarchy screenshot # Interactive smart-region flow omarchy capture screenshot region # Select a region omarchy capture screenshot windows # Pick a window omarchy capture screenshot fullscreen save # Full screen, straight to disk (no editor) +omarchy capture screenshot scroll # Capture and stitch a scrolling region ``` -The first argument picks the mode (`smart|region|windows|fullscreen`), the -second what happens with it (`slurp|copy|save`). `save` skips the annotation -editor and prints the saved path. Screenshots land in the configured Pictures -directory (override with `OMARCHY_SCREENSHOT_DIR`). +The first argument picks the Omasnap mode (`smart|region|windows|fullscreen|scroll`). With no second argument, the selection opens in Omasnap's annotation editor; `copy` or `save` skips the editor and sends the screenshot straight to that destination. Screenshots land in `~/Pictures/Screenshots` by default (override with `OMASNAP_SCREENSHOT_DIR`; the legacy `OMARCHY_SCREENSHOT_DIR` is also honored by the Omarchy command). ## Screen Recording diff --git a/default/hypr/apps/screenshot-selection.lua b/default/hypr/apps/screenshot-selection.lua index f4e3b2fd..4c93f703 100644 --- a/default/hypr/apps/screenshot-selection.lua +++ b/default/hypr/apps/screenshot-selection.lua @@ -1,2 +1,5 @@ --- Remove the 1px border around the slurp region selection used by screenshots. +-- Remove the 1px border around the slurp region selection used by recordings, OCR, and QR capture. hl.layer_rule({ match = { namespace = "selection" }, no_anim = true, animation = "none" }) + +-- Keep the Omasnap overlay immediate and out of screen shares. +hl.layer_rule({ match = { namespace = "^omasnap$" }, no_anim = true, animation = "none", no_screen_share = true }) diff --git a/default/hypr/apps/system.lua b/default/hypr/apps/system.lua index 789e3e03..3235e7b9 100644 --- a/default/hypr/apps/system.lua +++ b/default/hypr/apps/system.lua @@ -27,8 +27,6 @@ o.window("org.omarchy.about", { float = true }) o.window("org.omarchy.about", { center = true }) o.window("org.omarchy.about", { size = { 920, 480 } }) -o.window("dev.tensaku.Tensaku", { float = true }) -o.window("dev.tensaku.Tensaku", { center = true }) o.window("omacalc", { float = true }) -- Fullscreen screensaver. diff --git a/default/uwsm/default b/default/uwsm/default index d2ad7cc3..ba98b166 100644 --- a/default/uwsm/default +++ b/default/uwsm/default @@ -10,8 +10,8 @@ export TERMINAL=xdg-terminal-exec # Used by terminal programs to open files with the selected Omarchy default editor export EDITOR="omarchy-launch-editor --inline" -# Use a custom directory for screenshots (remember to make the directory!) -# export OMARCHY_SCREENSHOT_DIR="$HOME/Pictures/Screenshots" +# Use a custom directory for screenshots +# export OMASNAP_SCREENSHOT_DIR="$HOME/Pictures/Screenshots" # Use a custom directory for screenrecordings (remember to make the directory!) # export OMARCHY_SCREENRECORD_DIR="$HOME/Videos/Screencasts" diff --git a/docs/file-layout.md b/docs/file-layout.md index f261085f..73c48c4f 100644 --- a/docs/file-layout.md +++ b/docs/file-layout.md @@ -116,7 +116,6 @@ default/** ──► omarchy-settings /usr/share/omarchy ├─ hypr/toggles/*.lua (flags, │ single-window-aspect-ratio, window-no-gaps) /etc/skel/.local/state/omarchy/toggles/hypr/ ├─ nautilus-python/extensions/*.py /etc/skel/.local/share/nautilus-python/extensions/ - ├─ tensaku/state.toml /etc/skel/.local/state/tensaku/state.toml ├─ uwsm/env.d/10-omarchy /usr/share/uwsm/env.d/ ├─ environment.d/*.conf /usr/lib/environment.d/ ├─ fontconfig/conf.avail/50-omarchy.conf /usr/share/fontconfig/conf.avail/ diff --git a/install/omarchy-base.packages b/install/omarchy-base.packages index 0a8e27cc..b3df3e20 100644 --- a/install/omarchy-base.packages +++ b/install/omarchy-base.packages @@ -96,6 +96,7 @@ omacalc omacut omawrite omarchy-nvim +omasnap pacman-contrib pamixer pinta @@ -114,7 +115,6 @@ qt6-multimedia-ffmpeg quickshell ripgrep ruby -tensaku sddm slurp socat diff --git a/manual/12-screenshots-recording.md b/manual/12-screenshots-recording.md index 9c476231..b3447b57 100644 --- a/manual/12-screenshots-recording.md +++ b/manual/12-screenshots-recording.md @@ -13,13 +13,13 @@ Everything you can grab off the screen hangs off the Print Screen key. One key o ## Screenshots -Hit `Print Screen` and the screen freezes so nothing shifts under you while you aim. Drag a box for a freeform region, or just click once and the shot snaps to whatever rectangle you clicked in — a window if you landed on one, the whole monitor if you landed on the bar or in a gap. Changed your mind? Hit `Print Screen` again to dismiss the picker. +Hit `Print Screen` and Omasnap captures the focused monitor before its overlay appears, so nothing shifts under you while you aim. Drag a freeform region, or use the tabs across the top to switch between Region, Scrolling Region, Window, and Fullscreen capture. Changed your mind? Hit `Print Screen` again to dismiss Omasnap. -The result goes two places at once: a PNG in your pictures directory, and the clipboard, so you can paste it straight into a chat window with `Super + V`. A notification pops up with a thumbnail. Click it (or hit `Super + Alt + ,` to invoke the last notification) and the shot opens in Tensaku, the annotation editor, where you can draw arrows and boxes on it before you send it. +After you select an area, Omasnap opens its annotation editor. It can draw arrows, lines, shapes, highlights, numbered markers, text, and secure redactions; crop or cut out part of the image; OCR its text; and add a backdrop. Press `Enter` to copy and save the finished PNG, `Ctrl + C` to copy it without saving, `Ctrl + S` to save it without copying, or `P` to pin it above your windows. -Files land in `~/Pictures` by default, named `screenshot-2026-08-13_14-22-05.png`. If you'd rather keep them in their own folder, set `OMARCHY_SCREENSHOT_DIR` — see [the FAQ](46-faq.md) for where to put session environment variables. Omarchy creates the directory for you if it isn't there. You can swap the editor too with `OMARCHY_SCREENSHOT_EDITOR`. +Files land in `~/Pictures/Screenshots` by default, with a name such as `screenshot-2026-08-13_14-22-05-firefox.png`. Set `OMASNAP_SCREENSHOT_DIR` to use another directory — see [the FAQ](46-faq.md) for where to put session environment variables. Omasnap creates the directory when it saves the first shot. -From the terminal, `omarchy screenshot` takes the same shot, and you can be explicit about it: `omarchy capture screenshot region` for freeform only, `windows` to snap to window and monitor rectangles, or `fullscreen` to skip the picker entirely and grab the focused monitor. A second argument of `copy` puts the shot only on the clipboard, and `save` only on disk. +From the terminal, `omarchy screenshot` opens the same overlay, and you can choose its starting mode: `omarchy capture screenshot region`, `windows`, `fullscreen`, or `scroll`. A second argument of `copy` or `save` bypasses the annotation editor and sends the shot straight to that destination. ### Driving the picker from the keyboard @@ -27,16 +27,19 @@ While the selection is up, you don't have to use the mouse at all: | Key | Function | | --- | -------- | +| `Space` | Step through Region, Scrolling Region, and Window modes | +| `S` | Toggle scrolling-region mode | +| `Super + Arrow keys` | Move among windows in Window mode | | `Return` | Capture the highlighted window | -| `Ctrl + Return` | Capture the whole screen | -| `Tab` / `Ctrl + Tab` | Highlight the next / previous window | -| Arrow keys | Highlight the window in that direction | +| `Ctrl + A` | Capture the full focused monitor | +| `R` | Restore the last region drawn in this session | +| `Esc` | Dismiss Omasnap | -The arrows and Tab move the cursor to the window they pick, so the highlight follows along and you can see what you're about to capture. These bindings only exist while a selection is on screen, so they can't collide with anything in your own config. +These bindings only exist while Omasnap is open, so they can't collide with anything in your own config. ## Screen recording -`Alt + Print Screen` opens _Trigger > Capture > Screenrecord_, which asks what you want on the soundtrack: no audio, desktop audio, desktop plus microphone, or desktop plus microphone plus webcam. That last one only shows up if you actually have a camera plugged in. Pick one and you get the same picker as a screenshot: drag a region, or click a window or monitor. +`Alt + Print Screen` opens _Trigger > Capture > Screenrecord_, which asks what you want on the soundtrack: no audio, desktop audio, desktop plus microphone, or desktop plus microphone plus webcam. That last one only shows up if you actually have a camera plugged in. Pick one and Omarchy's recording picker lets you drag a region or click a window or monitor. Recording runs on gpu-screen-recorder, which encodes on the GPU at 60fps and falls back to the CPU if it has to. The result is an MP4 in `~/Videos`, named `screenrecording-2026-08-13_14-22-05.mp4`. Set `OMARCHY_SCREENRECORD_DIR` to change that — but note that unlike the screenshot directory, this one has to exist already, or the recording refuses to start. diff --git a/manual/14-omarchy-cli.md b/manual/14-omarchy-cli.md index fa5d0a05..76f386e8 100644 --- a/manual/14-omarchy-cli.md +++ b/manual/14-omarchy-cli.md @@ -50,7 +50,7 @@ Capture commands — Screenshots and screen recording: omarchy capture qr Decode a QR code from a screenshot region omarchy capture screenrecording [--fullscreen] [--with-desktop-audio] [--with-microphone-audio] [--with-webcam] [--webcam-device=] [--webcam-size=] [--resolution=] [--stop-recording] Start or stop screen recording omarchy capture screenrecording with webcam Pick a webcam and start a screen recording with it - omarchy capture screenshot [smart|region|windows|fullscreen] [slurp|copy|save] [--editor=] Take a screenshot + omarchy capture screenshot [smart|region|windows|fullscreen|scroll] [copy|save] Take a screenshot omarchy capture text Extract text from a screenshot region with OCR omarchy capture webcam resize Resize the active webcam recording overlay ``` diff --git a/manual/46-faq.md b/manual/46-faq.md index 21b11db9..8985439b 100644 --- a/manual/46-faq.md +++ b/manual/46-faq.md @@ -54,15 +54,15 @@ Automatic discovery, where printers on the network appear without being added, i ### How do I change where screenshots or screenrecordings are saved? -If you want screenshots to be saved to `~/Pictures/Screenshots` instead of just `~/Pictures`, you can add this to a file under `~/.config/uwsm/env.d/` (like `~/.config/uwsm/env.d/capture`): +Omasnap saves screenshots to `~/Pictures/Screenshots` by default. To use another directory, add this to a file under `~/.config/uwsm/env.d/` (like `~/.config/uwsm/env.d/capture`): ``` -export OMARCHY_SCREENSHOT_DIR="$HOME/Pictures/Screenshots" +export OMASNAP_SCREENSHOT_DIR="$HOME/Pictures/Captures" ``` You can do the same for screenrecordings using `OMARCHY_SCREENRECORD_DIR`. -Just remember to create the directory you want to save to and restart Omarchy for this to take effect. +Omasnap creates its screenshot directory automatically. Create the screenrecording directory yourself, then restart Omarchy for either environment change to take effect. ### How do I get the speakers + webcam working on my Apple Studio Display? diff --git a/migrations/1788129995.sh b/migrations/1788129995.sh new file mode 100644 index 00000000..041a3ef8 --- /dev/null +++ b/migrations/1788129995.sh @@ -0,0 +1,13 @@ +echo "Replace Tensaku with Omasnap" + +omarchy-pkg-add omasnap + +imv_config="$HOME/.config/imv/config" +if [[ -f $imv_config ]]; then + sed -i --follow-symlinks \ + -e 's/^# Edit the current image in Tensaku and quit the viewer$/# Edit the current image in Omasnap and quit the viewer/' \ + -e 's|^ = exec tensaku-edit "$imv_current_file" & ; quit$| = exec omasnap "$imv_current_file" \& ; quit|' \ + "$imv_config" +fi + +omarchy-pkg-drop tensaku diff --git a/shell/Commons/Util.qml b/shell/Commons/Util.qml index 14af44fe..cacc98d2 100644 --- a/shell/Commons/Util.qml +++ b/shell/Commons/Util.qml @@ -61,7 +61,7 @@ QtObject { // Run an argv vector without a shell interpreting it: the constant `exec "$@"` // means the args only ever land in positional parameters, which bash expands // without re-tokenizing — so untrusted data ($(id), a filename) stays literal. - // The login shell (-l) keeps the PATH/session env GUI targets (tensaku, mpv, + // The login shell (-l) keeps the PATH/session env GUI targets (omasnap, mpv, // xdg-open) need. Prefer this over execDetached for anything built from input. function execArgv(argv) { Quickshell.execDetached(["bash", "-lc", 'exec "$@"', "bash"].concat(argv)) diff --git a/test/shell.d/clipboard-test.sh b/test/shell.d/clipboard-test.sh index 962d529e..5580a694 100644 --- a/test/shell.d/clipboard-test.sh +++ b/test/shell.d/clipboard-test.sh @@ -277,12 +277,12 @@ printf '%s\n' "$1" >"$EDITOR_PATH_OUT" cat "$1" >"$EDITOR_TEXT_OUT" SH -cat >"$TMPDIR/bin/tensaku-edit" <<'SH' +cat >"$TMPDIR/bin/omasnap" <<'SH' #!/bin/bash -printf '%s\n' "$*" >"$TENSAKU_OUT" +printf '%s\n' "$*" >"$OMASNAP_OUT" SH -chmod +x "$TMPDIR/bin/wl-copy" "$TMPDIR/bin/wl-paste" "$TMPDIR/bin/wtype" "$TMPDIR/bin/omarchy-launch-browser" "$TMPDIR/bin/omarchy-launch-editor" "$TMPDIR/bin/tensaku-edit" +chmod +x "$TMPDIR/bin/wl-copy" "$TMPDIR/bin/wl-paste" "$TMPDIR/bin/wtype" "$TMPDIR/bin/omarchy-launch-browser" "$TMPDIR/bin/omarchy-launch-editor" "$TMPDIR/bin/omasnap" capture_output=$(XDG_RUNTIME_DIR="$TMPDIR" XDG_STATE_HOME="$TMPDIR/state" PATH="$TMPDIR/bin:$PATH" "$ROOT/shell/plugins/clipboard/capture.sh") [[ $capture_output == '{"type":"text","text":"terminal copy"}' ]] || fail "clipboard capture records normal text events" @@ -513,8 +513,8 @@ pass "clipboard open helper opens text entries in editor" [[ $(<"$TMPDIR/editor-path") == "$TMPDIR"/state/omarchy/clipboard-open/clipboard.*.txt ]] || fail "clipboard open helper writes text entries to a temporary file" pass "clipboard open helper writes text entries to a temporary file" -TENSAKU_OUT="$TMPDIR/tensaku" HOME="$TMPDIR/home" PATH="$TMPDIR/bin:$PATH" \ +OMASNAP_OUT="$TMPDIR/omasnap" HOME="$TMPDIR/home" PATH="$TMPDIR/bin:$PATH" \ "$ROOT/bin/omarchy-clipboard-open" --history-index 2 -[[ $(<"$TMPDIR/tensaku") == "$TMPDIR/image.png" ]] || fail "clipboard open helper opens image entries in Tensaku" -pass "clipboard open helper opens image entries in Tensaku" +[[ $(<"$TMPDIR/omasnap") == "$TMPDIR/image.png" ]] || fail "clipboard open helper opens image entries in Omasnap" +pass "clipboard open helper opens image entries in Omasnap" diff --git a/test/shell.d/omasnap-test.sh b/test/shell.d/omasnap-test.sh new file mode 100644 index 00000000..342e5f8f --- /dev/null +++ b/test/shell.d/omasnap-test.sh @@ -0,0 +1,99 @@ +#!/bin/bash + +set -euo pipefail + +source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" + +packages="$ROOT/install/omarchy-base.packages" +migration="$ROOT/migrations/1788129995.sh" + +grep -qxF omasnap "$packages" || fail "fresh installs include Omasnap" +! grep -qxF tensaku "$packages" || fail "fresh installs no longer include Tensaku" +pass "fresh installs use Omasnap as the screenshot editor" + +grep -Fq 'namespace = "^omasnap$"' "$ROOT/default/hypr/apps/screenshot-selection.lua" || + fail "Omasnap has a layer rule" +grep -Fq 'no_screen_share = true' "$ROOT/default/hypr/apps/screenshot-selection.lua" || + fail "the Omasnap overlay is excluded from screen sharing" +! grep -Fq 'dev.tensaku.Tensaku' "$ROOT/default/hypr/apps/system.lua" || + fail "the removed Tensaku window rules are gone" +pass "Hyprland applies Omasnap's overlay policy without stale Tensaku rules" + +test_tmp=$(mktemp -d) +trap 'rm -rf "$test_tmp"' EXIT + +stub_bin="$test_tmp/bin" +mkdir -p "$stub_bin" + +cat >"$stub_bin/omasnap" <<'SH' +#!/bin/bash +printf '%s\t%s\n' "${OMASNAP_SCREENSHOT_DIR:-}" "$*" >>"$OMASNAP_TEST_LOG" +SH +chmod +x "$stub_bin/omasnap" + +capture_log="$test_tmp/capture.log" +OMASNAP_TEST_LOG="$capture_log" PATH="$stub_bin:$PATH" \ + "$ROOT/bin/omarchy-capture-screenshot" +[[ $(<"$capture_log") == $'\t' ]] || fail "the default screenshot opens Omasnap without extra arguments" + +: >"$capture_log" +OMASNAP_TEST_LOG="$capture_log" OMARCHY_SCREENSHOT_DIR="$test_tmp/legacy-output" PATH="$stub_bin:$PATH" \ + "$ROOT/bin/omarchy-capture-screenshot" windows copy +[[ $(<"$capture_log") == "$test_tmp/legacy-output"$'\twindows --copy' ]] || + fail "the screenshot command maps the legacy directory and copy argument to Omasnap" + +: >"$capture_log" +OMASNAP_TEST_LOG="$capture_log" OMARCHY_SCREENSHOT_DIR="$test_tmp/legacy-output" OMASNAP_SCREENSHOT_DIR="$test_tmp/native-output" PATH="$stub_bin:$PATH" \ + "$ROOT/bin/omarchy-capture-screenshot" fullscreen save +[[ $(<"$capture_log") == "$test_tmp/native-output"$'\tfullscreen --save' ]] || + fail "the native Omasnap directory wins while legacy save syntax still works" + +: >"$capture_log" +OMASNAP_TEST_LOG="$capture_log" PATH="$stub_bin:$PATH" \ + "$ROOT/bin/omarchy-capture-screenshot" region slurp +[[ $(<"$capture_log") == $'\tregion' ]] || fail "the former default slurp argument remains a harmless compatibility no-op" + +: >"$capture_log" +OMASNAP_TEST_LOG="$capture_log" PATH="$stub_bin:$PATH" \ + "$ROOT/bin/omarchy-capture-screenshot" scroll --save +[[ $(<"$capture_log") == $'\tscroll --save' ]] || fail "native Omasnap modes and flags pass through unchanged" + +pass "the Omarchy screenshot route delegates compatible arguments to Omasnap" + +cat >"$stub_bin/omarchy-pkg-add" <<'SH' +#!/bin/bash +printf 'add\t%s\n' "$*" >>"$OMASNAP_MIGRATION_LOG" +SH +cat >"$stub_bin/omarchy-pkg-drop" <<'SH' +#!/bin/bash +printf 'drop\t%s\n' "$*" >>"$OMASNAP_MIGRATION_LOG" +SH +chmod +x "$stub_bin/omarchy-pkg-add" "$stub_bin/omarchy-pkg-drop" + +migration_home="$test_tmp/home" +mkdir -p "$migration_home/.config/imv" "$migration_home/dotfiles" +cat >"$migration_home/dotfiles/imv.config" <<'EOF' +[binds] + +# Edit the current image in Tensaku and quit the viewer + = exec tensaku-edit "$imv_current_file" & ; quit + = exec custom-editor "$imv_current_file" & ; quit +EOF +ln -s "$migration_home/dotfiles/imv.config" "$migration_home/.config/imv/config" + +migration_log="$test_tmp/migration.log" +OMASNAP_MIGRATION_LOG="$migration_log" HOME="$migration_home" PATH="$stub_bin:$PATH" \ + bash -euo pipefail "$migration" >/dev/null + +[[ $(sed -n '1p' "$migration_log") == $'add\tomasnap' ]] || fail "the migration installs Omasnap first" +[[ $(sed -n '2p' "$migration_log") == $'drop\ttensaku' ]] || fail "the migration removes Tensaku after Omasnap is ready" +grep -Fq '# Edit the current image in Omasnap and quit the viewer' "$migration_home/.config/imv/config" || + fail "the migration updates the stock imv editor comment" +grep -Fq ' = exec omasnap "$imv_current_file" & ; quit' "$migration_home/.config/imv/config" || + fail "the migration sends the stock imv edit binding to Omasnap" +grep -Fq ' = exec custom-editor "$imv_current_file" & ; quit' "$migration_home/.config/imv/config" || + fail "the migration preserves custom imv bindings" +[[ -L $migration_home/.config/imv/config ]] || fail "the migration preserves a dotfile-managed imv symlink" +[[ $(stat -c '%a' "$migration") == 644 ]] || fail "the Omasnap migration has mode 0644" + +pass "the migration swaps packages and safely updates only the stock imv binding" diff --git a/test/shell.d/screenshot-sanity-test.sh b/test/shell.d/screenshot-sanity-test.sh index 636642ed..756ffc65 100755 --- a/test/shell.d/screenshot-sanity-test.sh +++ b/test/shell.d/screenshot-sanity-test.sh @@ -25,13 +25,13 @@ if ! command -v quickshell >/dev/null 2>&1; then exit 0 fi -if pgrep -x slurp >/dev/null 2>&1; then - pass "slurp is already running; skipping screenshot sanity test" +if pgrep -x omasnap >/dev/null 2>&1; then + pass "omasnap is already running; skipping screenshot sanity test" exit 0 fi require_command hyprctl -require_command grim +require_command omasnap require_command jq require_command python3 @@ -118,13 +118,13 @@ jq -e ' fail_with_log "screenshot test shell rendered visible bar widgets" } -screenshot=$( - OMARCHY_PATH="$test_root" \ - OMARCHY_SCREENSHOT_DIR="$screenshot_dir" \ - HOME="$test_home" \ - PATH="$stub_bin:$ROOT/bin:$PATH" \ - "$ROOT/bin/omarchy" capture screenshot fullscreen save 2>"$screenshot_err" | tail -n 1 -) +OMARCHY_PATH="$test_root" \ +OMASNAP_SCREENSHOT_DIR="$screenshot_dir" \ +HOME="$test_home" \ +PATH="$stub_bin:$ROOT/bin:$PATH" \ + "$ROOT/bin/omarchy" capture screenshot fullscreen save >/dev/null 2>"$screenshot_err" + +screenshot=$(find "$screenshot_dir" -maxdepth 1 -type f -name '*.png' -print -quit) [[ -n $screenshot && -f $screenshot ]] || fail_with_log "fullscreen screenshot was captured" From c0ba99670d5cc3a52832e079053e59182c9b6acd Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Mon, 21 Sep 2026 02:14:54 -0400 Subject: [PATCH 2/3] Clean up legacy screenshot tools in Omasnap migration --- migrations/1788129995.sh | 9 ++++-- test/shell.d/omasnap-test.sh | 63 +++++++++++++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/migrations/1788129995.sh b/migrations/1788129995.sh index 041a3ef8..965e01db 100644 --- a/migrations/1788129995.sh +++ b/migrations/1788129995.sh @@ -1,13 +1,18 @@ -echo "Replace Tensaku with Omasnap" +echo "Replace Satty and Tensaku with Omasnap" omarchy-pkg-add omasnap +# The old source installer left a NoDisplay entry that overrides the packaged launcher. +rm -f "$HOME/.local/share/applications/omasnap.desktop" + imv_config="$HOME/.config/imv/config" if [[ -f $imv_config ]]; then sed -i --follow-symlinks \ -e 's/^# Edit the current image in Tensaku and quit the viewer$/# Edit the current image in Omasnap and quit the viewer/' \ + -e 's/^# Edit the current image in Satty and quit the viewer$/# Edit the current image in Omasnap and quit the viewer/' \ -e 's|^ = exec tensaku-edit "$imv_current_file" & ; quit$| = exec omasnap "$imv_current_file" \& ; quit|' \ + -e 's|^ = exec satty --filename "$imv_current_file" & ; quit$| = exec omasnap "$imv_current_file" \& ; quit|' \ "$imv_config" fi -omarchy-pkg-drop tensaku +omarchy-pkg-drop satty tensaku diff --git a/test/shell.d/omasnap-test.sh b/test/shell.d/omasnap-test.sh index 342e5f8f..abf3293c 100644 --- a/test/shell.d/omasnap-test.sh +++ b/test/shell.d/omasnap-test.sh @@ -9,7 +9,8 @@ migration="$ROOT/migrations/1788129995.sh" grep -qxF omasnap "$packages" || fail "fresh installs include Omasnap" ! grep -qxF tensaku "$packages" || fail "fresh installs no longer include Tensaku" -pass "fresh installs use Omasnap as the screenshot editor" +! grep -qxF satty "$packages" || fail "fresh installs no longer include Satty" +pass "fresh installs use Omasnap as the screenshot tool" grep -Fq 'namespace = "^omasnap$"' "$ROOT/default/hypr/apps/screenshot-selection.lua" || fail "Omasnap has a layer rule" @@ -63,6 +64,7 @@ pass "the Omarchy screenshot route delegates compatible arguments to Omasnap" cat >"$stub_bin/omarchy-pkg-add" <<'SH' #!/bin/bash printf 'add\t%s\n' "$*" >>"$OMASNAP_MIGRATION_LOG" +exit "${OMASNAP_PACKAGE_STATUS:-0}" SH cat >"$stub_bin/omarchy-pkg-drop" <<'SH' #!/bin/bash @@ -82,11 +84,16 @@ EOF ln -s "$migration_home/dotfiles/imv.config" "$migration_home/.config/imv/config" migration_log="$test_tmp/migration.log" -OMASNAP_MIGRATION_LOG="$migration_log" HOME="$migration_home" PATH="$stub_bin:$PATH" \ - bash -euo pipefail "$migration" >/dev/null +run_migration() { + : >"$migration_log" + OMASNAP_MIGRATION_LOG="$migration_log" HOME="$migration_home" PATH="$stub_bin:$PATH" \ + bash -euo pipefail "$migration" >/dev/null +} + +run_migration [[ $(sed -n '1p' "$migration_log") == $'add\tomasnap' ]] || fail "the migration installs Omasnap first" -[[ $(sed -n '2p' "$migration_log") == $'drop\ttensaku' ]] || fail "the migration removes Tensaku after Omasnap is ready" +[[ $(sed -n '2p' "$migration_log") == $'drop\tsatty tensaku' ]] || fail "the migration removes Satty and Tensaku after Omasnap is ready" grep -Fq '# Edit the current image in Omasnap and quit the viewer' "$migration_home/.config/imv/config" || fail "the migration updates the stock imv editor comment" grep -Fq ' = exec omasnap "$imv_current_file" & ; quit' "$migration_home/.config/imv/config" || @@ -97,3 +104,51 @@ grep -Fq ' = exec custom-editor "$imv_current_file" & ; quit' "$migratio [[ $(stat -c '%a' "$migration") == 644 ]] || fail "the Omasnap migration has mode 0644" pass "the migration swaps packages and safely updates only the stock imv binding" + +cat >"$migration_home/dotfiles/imv.config" <<'EOF' +[binds] + +# Edit the current image in Satty and quit the viewer + = exec satty --filename "$imv_current_file" & ; quit + = exec custom-editor "$imv_current_file" & ; quit +EOF +cp "$migration_home/dotfiles/imv.config" "$test_tmp/imv-before" +legacy_desktop="$migration_home/.local/share/applications/omasnap.desktop" +mkdir -p "$(dirname "$legacy_desktop")" +cat >"$legacy_desktop" <<'EOF' +[Desktop Entry] +Type=Application +Name=Omasnap +Exec=omasnap +NoDisplay=true +EOF +if OMASNAP_PACKAGE_STATUS=1 run_migration; then + fail "Omasnap install failure stops the migration" +fi +[[ $(<"$migration_log") == $'add\tomasnap' ]] || fail "install failure leaves old screenshot packages installed" +cmp -s "$test_tmp/imv-before" "$migration_home/dotfiles/imv.config" || fail "install failure leaves the imv binding untouched" +[[ -f $legacy_desktop ]] || fail "install failure preserves the existing launcher entry" +pass "Omasnap install failure preserves the previous screenshot setup" + +run_migration +[[ ! -e $legacy_desktop && ! -L $legacy_desktop ]] || fail "the migration removes the old user-local Omasnap desktop entry" +pass "the migration removes the desktop entry that hides the packaged launcher" +grep -Fq '# Edit the current image in Omasnap and quit the viewer' "$migration_home/.config/imv/config" || + fail "the migration updates the stock Satty comment" +grep -Fq ' = exec omasnap "$imv_current_file" & ; quit' "$migration_home/.config/imv/config" || + fail "the migration replaces the stock Satty binding before removing Satty" +grep -Fq ' = exec custom-editor "$imv_current_file" & ; quit' "$migration_home/.config/imv/config" || + fail "the Satty migration preserves custom bindings" +[[ -L $migration_home/.config/imv/config ]] || fail "the Satty migration preserves the imv symlink" +pass "the migration upgrades the stock Satty binding to Omasnap" + +cp "$migration_home/dotfiles/imv.config" "$test_tmp/imv-migrated" +run_migration +cmp -s "$test_tmp/imv-migrated" "$migration_home/dotfiles/imv.config" || fail "rerunning the migration preserves the updated imv config" +pass "the migration can be rerun" + +printf ' = exec custom-editor "$imv_current_file" & ; quit\n' >"$migration_home/dotfiles/imv.config" +cp "$migration_home/dotfiles/imv.config" "$test_tmp/imv-custom" +run_migration +cmp -s "$test_tmp/imv-custom" "$migration_home/dotfiles/imv.config" || fail "the migration preserves a custom edit shortcut" +pass "custom imv edit shortcuts remain unchanged" From 95120838d3c75f152879ee9d8eaa024bf3cf5404 Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Mon, 21 Sep 2026 02:14:55 -0400 Subject: [PATCH 3/3] Document Omasnap's default capture flow --- agents/skills/visual-verification.md | 2 +- default/agents/skills/omarchy/capture.md | 5 +++-- manual/12-screenshots-recording.md | 11 ++++++----- manual/46-faq.md | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/agents/skills/visual-verification.md b/agents/skills/visual-verification.md index 7df6caa1..a8ed63d7 100644 --- a/agents/skills/visual-verification.md +++ b/agents/skills/visual-verification.md @@ -15,7 +15,7 @@ Take a full-screen screenshot without opening the editor: omarchy capture screenshot fullscreen save ``` -The command writes to Omasnap's configured screenshot directory. Use `omarchy screenshot` for the interactive editor flow. Capture reference and candidate states as separate images when changing a layer-shell surface or layout, then compare both. +The command writes to Omasnap's configured screenshot directory. Use `omarchy screenshot` for the interactive capture flow, which copies the capture and shows a timed preview. Use `omarchy screenshot --editor=overlay` to test annotation before output. Capture reference and candidate states as separate images when changing a layer-shell surface or layout, then compare both. Record a short full-screen video for animation, transition, timing, capture, or screen-recording changes: diff --git a/default/agents/skills/omarchy/capture.md b/default/agents/skills/omarchy/capture.md index 4390fe75..a898db86 100644 --- a/default/agents/skills/omarchy/capture.md +++ b/default/agents/skills/omarchy/capture.md @@ -10,10 +10,11 @@ omarchy screenshot # Interactive smart-region flow omarchy capture screenshot region # Select a region omarchy capture screenshot windows # Pick a window omarchy capture screenshot fullscreen save # Full screen, straight to disk (no editor) -omarchy capture screenshot scroll # Capture and stitch a scrolling region +omarchy capture screenshot scroll # Capture and stitch a scrolling region +omarchy screenshot --editor=overlay # Opt into annotation before output ``` -The first argument picks the Omasnap mode (`smart|region|windows|fullscreen|scroll`). With no second argument, the selection opens in Omasnap's annotation editor; `copy` or `save` skips the editor and sends the screenshot straight to that destination. Screenshots land in `~/Pictures/Screenshots` by default (override with `OMASNAP_SCREENSHOT_DIR`; the legacy `OMARCHY_SCREENSHOT_DIR` is also honored by the Omarchy command). +The first argument picks the Omasnap mode (`smart|region|windows|fullscreen|scroll`). By default, a capture copies to the clipboard and shows a preview for 10 seconds. Use the preview's Edit action to annotate, or pass `--editor=overlay` or `--editor=window` to edit before output. A second argument of `copy` or `save` skips the preview and sends the screenshot straight to that destination. Saved screenshots land in `~/Pictures/Screenshots` by default (override with `OMASNAP_SCREENSHOT_DIR`; the legacy `OMARCHY_SCREENSHOT_DIR` is also honored by the Omarchy command). ## Screen Recording diff --git a/manual/12-screenshots-recording.md b/manual/12-screenshots-recording.md index b3447b57..41d6052d 100644 --- a/manual/12-screenshots-recording.md +++ b/manual/12-screenshots-recording.md @@ -13,13 +13,15 @@ Everything you can grab off the screen hangs off the Print Screen key. One key o ## Screenshots -Hit `Print Screen` and Omasnap captures the focused monitor before its overlay appears, so nothing shifts under you while you aim. Drag a freeform region, or use the tabs across the top to switch between Region, Scrolling Region, Window, and Fullscreen capture. Changed your mind? Hit `Print Screen` again to dismiss Omasnap. +Hit `Print Screen` and Omasnap captures the focused monitor before its overlay appears, so nothing shifts under you while you aim. Drag a freeform region, click a window to capture it, or click open space to capture the whole monitor. Press `S` before drawing to capture a scrolling region. Changed your mind? Hit `Print Screen` again to dismiss Omasnap. -After you select an area, Omasnap opens its annotation editor. It can draw arrows, lines, shapes, highlights, numbered markers, text, and secure redactions; crop or cut out part of the image; OCR its text; and add a backdrop. Press `Enter` to copy and save the finished PNG, `Ctrl + C` to copy it without saving, `Ctrl + S` to save it without copying, or `P` to pin it above your windows. +After you select an area, Omasnap copies the capture to the clipboard and shows a preview for 10 seconds. Use the preview's pin button or `Ctrl + P` to keep it on screen, or choose Edit to annotate it. -Files land in `~/Pictures/Screenshots` by default, with a name such as `screenshot-2026-08-13_14-22-05-firefox.png`. Set `OMASNAP_SCREENSHOT_DIR` to use another directory — see [the FAQ](46-faq.md) for where to put session environment variables. Omasnap creates the directory when it saves the first shot. +The annotation editor can draw arrows, lines, shapes, highlights, numbered markers, text, and secure redactions; crop or cut out part of the image; OCR its text; and add a backdrop. In the editor, press `Enter` to copy and save the finished PNG, `Ctrl + C` to copy it without saving, or `Ctrl + S` to save it without copying. -From the terminal, `omarchy screenshot` opens the same overlay, and you can choose its starting mode: `omarchy capture screenshot region`, `windows`, `fullscreen`, or `scroll`. A second argument of `copy` or `save` bypasses the annotation editor and sends the shot straight to that destination. +Saved screenshots land in `~/Pictures/Screenshots` by default, with a name such as `screenshot-2026-08-13_14-22-05-firefox.png`. Set `OMASNAP_SCREENSHOT_DIR` to use another directory — see [the FAQ](46-faq.md) for where to put session environment variables. Omasnap creates the directory when it saves the first shot. + +From the terminal, `omarchy screenshot` opens the same overlay, and you can choose its starting mode: `omarchy capture screenshot region`, `windows`, `fullscreen`, or `scroll`. A second argument of `copy` or `save` skips the preview and sends the shot straight to that destination. To edit before output, use `omarchy screenshot --editor=overlay` for a fullscreen editor or `omarchy screenshot --editor=window` for a separate window. ### Driving the picker from the keyboard @@ -27,7 +29,6 @@ While the selection is up, you don't have to use the mouse at all: | Key | Function | | --- | -------- | -| `Space` | Step through Region, Scrolling Region, and Window modes | | `S` | Toggle scrolling-region mode | | `Super + Arrow keys` | Move among windows in Window mode | | `Return` | Capture the highlighted window | diff --git a/manual/46-faq.md b/manual/46-faq.md index 8985439b..5def15d6 100644 --- a/manual/46-faq.md +++ b/manual/46-faq.md @@ -54,7 +54,7 @@ Automatic discovery, where printers on the network appear without being added, i ### How do I change where screenshots or screenrecordings are saved? -Omasnap saves screenshots to `~/Pictures/Screenshots` by default. To use another directory, add this to a file under `~/.config/uwsm/env.d/` (like `~/.config/uwsm/env.d/capture`): +Saved screenshots go to `~/Pictures/Screenshots` by default. To use another directory, add this to a file under `~/.config/uwsm/env.d/` (like `~/.config/uwsm/env.d/capture`): ``` export OMASNAP_SCREENSHOT_DIR="$HOME/Pictures/Captures"