diff --git a/hypr/lua/binds/capture.lua b/hypr/lua/binds/capture.lua index 9561b4a..29cfa09 100644 --- a/hypr/lua/binds/capture.lua +++ b/hypr/lua/binds/capture.lua @@ -5,10 +5,13 @@ local scripts = os.getenv("HOME") .. "/.config/hypr/scripts/" -- ------------------------------------------------------------- screenshots -- PRINT selects a region, CTRL grabs the focused window, SHIFT saves to disk -- instead of the clipboard. -hl.bind("PRINT", hl.dsp.exec_cmd('grim -g "$(slurp)" - | wl-copy')) -hl.bind("SHIFT + PRINT", hl.dsp.exec_cmd('grim -g "$(slurp)" ~/Pictures/Screenshots/$(date +\'%Y-%m-%d_%H-%M-%S\').png')) -hl.bind("CTRL + PRINT", hl.dsp.exec_cmd(scripts .. "screenshot_window.sh copy")) -hl.bind("CTRL + SHIFT + PRINT", hl.dsp.exec_cmd(scripts .. "screenshot_window.sh save")) +-- All four go through scripts/shot.sh, which also posts a notification with +-- the capture as its thumbnail (Open, Edit with satty, Save). +local shot = scripts .. "shot.sh " +hl.bind("PRINT", hl.dsp.exec_cmd(shot .. "region copy"), { description = "screenshot an area to the clipboard" }) +hl.bind("SHIFT + PRINT", hl.dsp.exec_cmd(shot .. "region save"), { description = "screenshot an area to a file" }) +hl.bind("CTRL + PRINT", hl.dsp.exec_cmd(shot .. "window copy"), { description = "screenshot the window to the clipboard" }) +hl.bind("CTRL + SHIFT + PRINT", hl.dsp.exec_cmd(shot .. "window save"), { description = "screenshot the window to a file" }) -- ------------------------------------------------------- replay and camera -- On release, so the shortcut is not caught mid-chord. diff --git a/hypr/scripts/shot.sh b/hypr/scripts/shot.sh new file mode 100755 index 0000000..22846ef --- /dev/null +++ b/hypr/scripts/shot.sh @@ -0,0 +1,73 @@ +#!/bin/sh +# Screenshots with a receipt: every capture lands on the clipboard and comes +# back as a notification with its own thumbnail, so a keypress that used to +# vanish silently now shows what it took. +# +# shot.sh region copy pick an area, copy it +# shot.sh region save pick an area, save it to ~/Pictures/Screenshots +# shot.sh window copy the focused window, copy it +# shot.sh window save the focused window, save it +# +# A copy is kept in $XDG_RUNTIME_DIR only so the notification has a picture +# to show; its Save action moves it into ~/Pictures/Screenshots. Edit opens +# satty when it is installed. Cancelling the region picker does nothing. + +set -eu + +target=${1:-region} +mode=${2:-copy} + +dir="$HOME/Pictures/Screenshots" +stamp=$(date +'%Y-%m-%d_%H-%M-%S') + +case "$target" in + region) + geometry=$(slurp) || exit 0 + name="$stamp.png" + ;; + window) + info=$(hyprctl activewindow -j) + geometry=$(printf '%s' "$info" | jq -r 'if .at then "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])" else empty end') + if [ -z "$geometry" ]; then + notify-send -a Screenshot "Screenshot" "No window is focused." + exit 1 + fi + app=$(printf '%s' "$info" | jq -r '.class // "unknown"' | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_-]/_/g') + name="${app}_$stamp.png" + ;; + *) + echo "usage: shot.sh region|window copy|save" >&2 + exit 2 + ;; +esac + +if [ "$mode" = save ]; then + mkdir -p "$dir" + file="$dir/$name" +else + file="${XDG_RUNTIME_DIR:-/tmp}/shot-$name" +fi + +grim -g "$geometry" "$file" +wl-copy --type image/png < "$file" + +title=$([ "$mode" = save ] && echo "Screenshot saved" || echo "Screenshot copied") +body=$([ "$mode" = save ] && echo "${file#"$HOME"/}" || echo "On the clipboard") + +set -- --action=open=Open +command -v satty >/dev/null 2>&1 && set -- "$@" --action=edit=Edit +[ "$mode" = copy ] && set -- "$@" --action=save=Save + +# notify-send waits for the notification to close and prints the action +# that was chosen, so run it in the background and act on the answer. +( + choice=$(notify-send -a Screenshot -i "$file" -h "string:image-path:$file" \ + "$@" "$title" "$body") || exit 0 + case "$choice" in + open) xdg-open "$file" ;; + edit) satty --filename "$file" --output-filename "$dir/edited_$name" --copy-command wl-copy ;; + save) mkdir -p "$dir" && mv "$file" "$dir/$name" \ + && notify-send -a Screenshot -i "$dir/$name" -h "string:image-path:$dir/$name" \ + "Screenshot saved" "${dir#"$HOME"/}/$name" ;; + esac +) >/dev/null 2>&1 & diff --git a/quickshell/components/NotifCard.qml b/quickshell/components/NotifCard.qml index 4bf06a7..f92ad8c 100644 --- a/quickshell/components/NotifCard.qml +++ b/quickshell/components/NotifCard.qml @@ -185,7 +185,14 @@ Item { id: inline x: 1 y: 1 - source: root.notif?.image || "" + // A path given as an image hint (notify-send -h image-path:…) + // comes back routed through the icon provider, which treats + // it as an icon name and returns a placeholder. Load the file. + source: { + const img = root.notif?.image || ""; + if (img.startsWith("image://icon//")) return "file://" + img.slice("image://icon/".length); + return img.startsWith("/") ? "file://" + img : img; + } sourceSize.height: 90 fillMode: Image.PreserveAspectFit asynchronous: true