#!/usr/bin/env bash # hypr-snap.sh # Move a window in a direction. If already at the edge, snap to fill that edge. # Works dynamically across any monitor configuration. # # Usage: hypr-snap.sh # # Suggested binds in hyprland.conf: # bind = $mainMod SHIFT, left, exec, hypr-snap.sh l # bind = $mainMod SHIFT, right, exec, hypr-snap.sh r # bind = $mainMod SHIFT, up, exec, hypr-snap.sh u # bind = $mainMod SHIFT, down, exec, hypr-snap.sh d DIRECTION=$1 if [[ -z "$DIRECTION" ]]; then echo "Usage: hypr-snap.sh " exit 1 fi # --- get active window info --- 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_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] RES_T=$(echo "$MON" | jq '.reserved[0]') RES_B=$(echo "$MON" | jq '.reserved[1]') RES_L=$(echo "$MON" | jq '.reserved[2]') RES_R=$(echo "$MON" | jq '.reserved[3]') # usable area on this monitor, accounting for scale and reserved regions USE_X=$(echo "$MON" | jq "($MON_X + $RES_L) | floor") USE_Y=$(echo "$MON" | jq "($MON_Y + $RES_T) | floor") USE_W=$(echo "$MON" | jq "((.width / $MON_SCALE) - $RES_L - $RES_R) | floor") USE_H=$(echo "$MON" | jq "((.height / $MON_SCALE) - $RES_T - $RES_B) | floor") USE_R=$((USE_X + USE_W)) USE_B=$((USE_Y + USE_H)) 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 hyprctl dispatch togglefloating fi hyprctl dispatch moveactive exact "$x" "$y" hyprctl dispatch resizeactive exact "$w" "$h" } case $DIRECTION in l) if [[ "$WIN_X" -le "$USE_X" ]]; then snap "$USE_X" "$USE_Y" "$USE_W" "$USE_H" else hyprctl dispatch movewindoworgroup l fi ;; r) if [[ "$WIN_R" -ge "$USE_R" ]]; then snap "$USE_X" "$USE_Y" "$USE_W" "$USE_H" else hyprctl dispatch movewindoworgroup r fi ;; u) if [[ "$WIN_Y" -le "$USE_Y" ]]; then snap "$USE_X" "$USE_Y" "$USE_W" "$USE_H" else hyprctl dispatch movewindoworgroup u fi ;; d) if [[ "$WIN_B" -ge "$USE_B" ]]; then snap "$USE_X" "$USE_Y" "$USE_W" "$USE_H" else hyprctl dispatch movewindoworgroup d fi ;; *) echo "Unknown direction: $DIRECTION. Use l, r, u, or d." exit 1 ;; esac