This commit is contained in:
committer@tuxwarrior
2026-05-25 20:25:12 -05:00
parent 38dc35699d
commit fb18726fd3
+54 -39
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# hypr-snap.sh # hypr-snap.sh
# Move a window in a direction. If already at the edge, snap to fill that edge. # Move a window in a direction. If already touching that edge, snap to fill
# Works dynamically across any monitor configuration. # the full usable area of the monitor. Works across any monitor configuration.
# #
# Usage: hypr-snap.sh <l|r|u|d> # Usage: hypr-snap.sh <l|r|u|d>
# #
@@ -18,71 +18,86 @@ if [[ -z "$DIRECTION" ]]; then
exit 1 exit 1
fi fi
# --- get active window info ---
WIN=$(hyprctl activewindow -j) WIN=$(hyprctl activewindow -j)
WIN_X=$(echo "$WIN" | jq '.at[0]')
WIN_Y=$(echo "$WIN" | jq '.at[1]')
WIN_W=$(echo "$WIN" | jq '.size[0]')
WIN_H=$(echo "$WIN" | jq '.size[1]')
WIN_R=$((WIN_X + WIN_W))
WIN_B=$((WIN_Y + WIN_H))
# --- get the focused monitor info ---
MON=$(hyprctl monitors -j | jq '.[] | select(.focused == true)') MON=$(hyprctl monitors -j | jq '.[] | select(.focused == true)')
MON_X=$(echo "$MON" | jq '.x')
MON_Y=$(echo "$MON" | jq '.y')
MON_SCALE=$(echo "$MON" | jq '.scale')
# reserved areas (e.g. status bar): [top, bottom, left, right] # Do all math inside jq to avoid shell integer truncation and floating point issues.
RES_T=$(echo "$MON" | jq '.reserved[0]') # A window is considered "at the edge" when it is within TOLERANCE pixels of it.
RES_B=$(echo "$MON" | jq '.reserved[1]') DATA=$(jq -n \
RES_L=$(echo "$MON" | jq '.reserved[2]') --argjson win "$WIN" \
RES_R=$(echo "$MON" | jq '.reserved[3]') --argjson mon "$MON" '
($mon.width / $mon.scale | floor) as $mw |
($mon.height / $mon.scale | floor) as $mh |
($mon.reserved[2]) as $res_l |
($mon.reserved[3]) as $res_r |
($mon.reserved[0]) as $res_t |
($mon.reserved[1]) as $res_b |
{
win_x: $win.at[0],
win_y: $win.at[1],
win_r: ($win.at[0] + $win.size[0]),
win_b: ($win.at[1] + $win.size[1]),
floating: $win.floating,
# usable area on this monitor, accounting for scale and reserved regions use_x: ($mon.x + $res_l),
USE_X=$(echo "$MON" | jq "($MON_X + $RES_L) | floor") use_y: ($mon.y + $res_t),
USE_Y=$(echo "$MON" | jq "($MON_Y + $RES_T) | floor") use_w: ($mw - $res_l - $res_r),
USE_W=$(echo "$MON" | jq "((.width / $MON_SCALE) - $RES_L - $RES_R) | floor") use_h: ($mh - $res_t - $res_b),
USE_H=$(echo "$MON" | jq "((.height / $MON_SCALE) - $RES_T - $RES_B) | floor") use_r: ($mon.x + $mw - $res_r),
USE_R=$((USE_X + USE_W)) use_b: ($mon.y + $mh - $res_b)
USE_B=$((USE_Y + USE_H)) }
')
WIN_X=$(echo "$DATA" | jq '.win_x')
WIN_Y=$(echo "$DATA" | jq '.win_y')
WIN_R=$(echo "$DATA" | jq '.win_r')
WIN_B=$(echo "$DATA" | jq '.win_b')
FLOATING=$(echo "$DATA" | jq '.floating')
USE_X=$(echo "$DATA" | jq '.use_x')
USE_Y=$(echo "$DATA" | jq '.use_y')
USE_W=$(echo "$DATA" | jq '.use_w')
USE_H=$(echo "$DATA" | jq '.use_h')
USE_R=$(echo "$DATA" | jq '.use_r')
USE_B=$(echo "$DATA" | jq '.use_b')
# How many pixels past the edge the window needs to reach before snapping.
# movewindoworgroup moves in steps, so set this to at least one step size.
TOLERANCE=50
snap() { snap() {
local x=$1 y=$2 w=$3 h=$4
# if window is tiled, make it floating first so we can freely position/resize it
FLOATING=$(echo "$WIN" | jq '.floating')
if [[ "$FLOATING" != "true" ]]; then if [[ "$FLOATING" != "true" ]]; then
hyprctl dispatch togglefloating hyprctl dispatch togglefloating
fi fi
hyprctl dispatch moveactive exact "$x" "$y" hyprctl dispatch moveactive exact "$USE_X" "$USE_Y"
hyprctl dispatch resizeactive exact "$w" "$h" hyprctl dispatch resizeactive exact "$USE_W" "$USE_H"
} }
case $DIRECTION in case $DIRECTION in
l) l)
if [[ "$WIN_X" -le "$USE_X" ]]; then if [[ "$WIN_X" -le $((USE_X + TOLERANCE)) ]]; then
snap "$USE_X" "$USE_Y" "$USE_W" "$USE_H" snap
else else
hyprctl dispatch movewindoworgroup l hyprctl dispatch movewindoworgroup l
fi fi
;; ;;
r) r)
if [[ "$WIN_R" -ge "$USE_R" ]]; then if [[ "$WIN_R" -ge $((USE_R - TOLERANCE)) ]]; then
snap "$USE_X" "$USE_Y" "$USE_W" "$USE_H" snap
else else
hyprctl dispatch movewindoworgroup r hyprctl dispatch movewindoworgroup r
fi fi
;; ;;
u) u)
if [[ "$WIN_Y" -le "$USE_Y" ]]; then if [[ "$WIN_Y" -le $((USE_Y + TOLERANCE)) ]]; then
snap "$USE_X" "$USE_Y" "$USE_W" "$USE_H" snap
else else
hyprctl dispatch movewindoworgroup u hyprctl dispatch movewindoworgroup u
fi fi
;; ;;
d) d)
if [[ "$WIN_B" -ge "$USE_B" ]]; then if [[ "$WIN_B" -ge $((USE_B - TOLERANCE)) ]]; then
snap "$USE_X" "$USE_Y" "$USE_W" "$USE_H" snap
else else
hyprctl dispatch movewindoworgroup d hyprctl dispatch movewindoworgroup d
fi fi