Files
omarchycn/bin/omarchy-capture-region
T

121 lines
3.8 KiB
Bash
Executable File

#!/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
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])"'
}
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=$(slurp 2>/dev/null)
;;
windows)
freeze_screen
SELECTION=$(get_rectangles | slurp -r 2>/dev/null)
;;
fullscreen)
SELECTION=$(hyprctl monitors -j | jq -r "${JQ_MONITOR_GEO} .[] | select(.focused == true) | format_geo")
;;
smart | *)
RECTS=$(get_rectangles)
freeze_screen
SELECTION=$(echo "$RECTS" | slurp 2>/dev/null)
# 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"