#!/bin/bash # omarchy:summary=Pick a screen region over frozen screen content # omarchy:args=[region|windows|smart|fullscreen] [--keep-freeze] [--match-monitor] # omarchy:hidden=true # Prints the picked geometry in slurp's "X,Y WxH" format, or exits 1 when the # pick is cancelled. Shared by screenshot and screen recording so the picker # UX stays identical. # # region freeform selection # windows snap selection to a monitor or window rectangle # smart freeform with window/monitor rects hinted; a bare click # (area < 20px^2) snaps to the rectangle it landed in # fullscreen the focused monitor, no interaction # # --keep-freeze leave the hyprpicker screen freeze running and print its # PID as the first output line (empty when no freeze was # started); the caller owns killing it # --match-monitor print "monitor:NAME" instead when the picked geometry # exactly matches a monitor FULLSCREEN_MARKER="${XDG_RUNTIME_DIR:-/tmp}/omarchy-capture-region-fullscreen" # Pressing Return while slurp is open captures the entire focused monitor: # a bind scoped to slurp's layer surface (default/hypr/bindings/utilities.lua) # invokes this mode, which flags the intent and dismisses slurp. if [[ ${1:-} == "--take-fullscreen" ]]; then pgrep -x slurp >/dev/null || exit 0 touch "$FULLSCREEN_MARKER" pkill -x slurp exit 0 fi MODE=smart KEEP_FREEZE=false MATCH_MONITOR=false for arg in "$@"; do case $arg in --keep-freeze) KEEP_FREEZE=true ;; --match-monitor) MATCH_MONITOR=true ;; *) MODE=$arg ;; esac done # accounting for portrait/transformed displays JQ_MONITOR_GEO=' def format_geo: .x as $x | .y as $y | (.width / .scale | floor) as $w | (.height / .scale | floor) as $h | .transform as $t | if $t == 1 or $t == 3 then "\($x),\($y) \($h)x\($w)" else "\($x),\($y) \($w)x\($h)" end; ' get_rectangles() { local active_workspace=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .activeWorkspace.id') hyprctl monitors -j | jq -r --arg ws "$active_workspace" "${JQ_MONITOR_GEO} .[] | select(.activeWorkspace.id == (\$ws | tonumber)) | format_geo" hyprctl clients -j | jq -r --arg ws "$active_workspace" '.[] | select(.workspace.id == ($ws | tonumber)) | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"' } focused_monitor_geo() { hyprctl monitors -j | jq -r "${JQ_MONITOR_GEO} .[] | select(.focused == true) | format_geo" } # Runs slurp; an empty result with the fullscreen marker present means Return # was pressed, so the focused monitor is the selection. pick() { local selection rm -f "$FULLSCREEN_MARKER" selection=$(slurp "$@" 2>/dev/null) if [[ -z $selection && -e $FULLSCREEN_MARKER ]]; then rm -f "$FULLSCREEN_MARKER" selection=$(focused_monitor_geo) fi printf '%s' "$selection" } FREEZE_PID="" freeze_screen() { hyprpicker -r -z >/dev/null 2>&1 & FREEZE_PID=$! sleep .1 } cleanup_freeze() { [[ $KEEP_FREEZE == true ]] && return [[ -n $FREEZE_PID ]] && kill $FREEZE_PID 2>/dev/null } trap cleanup_freeze EXIT case "$MODE" in region) freeze_screen SELECTION=$(pick) ;; windows) freeze_screen SELECTION=$(get_rectangles | pick -r) ;; fullscreen) SELECTION=$(focused_monitor_geo) ;; smart | *) RECTS=$(get_rectangles) freeze_screen SELECTION=$(echo "$RECTS" | pick) # A bare click (area < 20px^2) snaps to whichever rectangle it landed in, # so users don't end up with accidental 2px captures. X and Y can be # negative (Hyprland monitor positions in multi-display layouts). if [[ $SELECTION =~ ^(-?[0-9]+),(-?[0-9]+)[[:space:]]([0-9]+)x([0-9]+)$ ]] && ((BASH_REMATCH[3] * BASH_REMATCH[4] < 20)); then click_x=${BASH_REMATCH[1]} click_y=${BASH_REMATCH[2]} while IFS= read -r rect; do [[ $rect =~ ^(-?[0-9]+),(-?[0-9]+)[[:space:]]([0-9]+)x([0-9]+)$ ]] || continue rect_x=${BASH_REMATCH[1]} rect_y=${BASH_REMATCH[2]} rect_width=${BASH_REMATCH[3]} rect_height=${BASH_REMATCH[4]} if ((click_x >= rect_x && click_x < rect_x + rect_width && click_y >= rect_y && click_y < rect_y + rect_height)); then SELECTION="${rect_x},${rect_y} ${rect_width}x${rect_height}" break fi done <<<"$RECTS" fi ;; esac [[ $KEEP_FREEZE == true ]] && echo "$FREEZE_PID" [[ -n $SELECTION ]] || exit 1 if [[ $MATCH_MONITOR == true ]]; then monitor=$(hyprctl monitors -j | jq -r --arg geo "$SELECTION" "${JQ_MONITOR_GEO} .[] | select(format_geo == \$geo) | .name" | head -1) if [[ -n $monitor ]]; then echo "monitor:$monitor" exit 0 fi fi echo "$SELECTION"