79 lines
1.9 KiB
Bash
Executable File
79 lines
1.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# focus-dir.sh - focus the nearest window in a given direction (h/j/k/l)
|
|
# Usage: focus-dir.sh h|j|k|l (or left/down/up/right)
|
|
|
|
DIR=$1
|
|
|
|
if [ -z "$DIR" ]; then
|
|
echo "Usage: $0 h|j|k|l"
|
|
exit 1
|
|
fi
|
|
|
|
# --- get current desktop ---
|
|
CUR_DESKTOP=$(xdotool get_desktop)
|
|
|
|
# --- get focused window geometry ---
|
|
FOCUSED=$(xdotool getactivewindow)
|
|
read -r FX FY FW FH < <(xdotool getwindowgeometry --shell "$FOCUSED" | awk -F= '
|
|
/^X=/ {x=$2} /^Y=/ {y=$2} /^WIDTH=/ {w=$2} /^HEIGHT=/ {h=$2}
|
|
END {print x, y, w, h}
|
|
')
|
|
FCX=$((FX + FW / 2))
|
|
FCY=$((FY + FH / 2))
|
|
|
|
# --- get list of normal windows on current desktop ---
|
|
ALL_WINDOWS=$(wmctrl -l -x | awk '$2!="-1" {print $1}')
|
|
|
|
BEST=""
|
|
BEST_DIST=""
|
|
|
|
for w in $ALL_WINDOWS; do
|
|
wid=$(printf "%d" "$w")
|
|
|
|
[ "$wid" = "$FOCUSED" ] && continue
|
|
|
|
win_desktop=$(xdotool get_desktop_for_window "$wid" 2>/dev/null) || continue
|
|
[ "$win_desktop" = "$CUR_DESKTOP" ] || continue
|
|
|
|
read -r WX WY WW WH < <(xdotool getwindowgeometry --shell "$wid" | awk -F= '
|
|
/^X=/ {x=$2} /^Y=/ {y=$2} /^WIDTH=/ {w=$2} /^HEIGHT=/ {h=$2}
|
|
END {print x, y, w, h}
|
|
')
|
|
WCX=$((WX + WW / 2))
|
|
WCY=$((WY + WH / 2))
|
|
|
|
DX=$((WCX - FCX))
|
|
DY=$((WCY - FCY))
|
|
|
|
case "$DIR" in
|
|
h|left)
|
|
[ "$DX" -ge 0 ] && continue
|
|
;;
|
|
l|right)
|
|
[ "$DX" -le 0 ] && continue
|
|
;;
|
|
k|up)
|
|
[ "$DY" -ge 0 ] && continue
|
|
;;
|
|
j|down)
|
|
[ "$DY" -le 0 ] && continue
|
|
;;
|
|
*)
|
|
echo "Invalid direction: $DIR"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# Manhattan distance, weighted to prefer windows roughly in line
|
|
DIST=$(( (DX<0?-DX:DX) + (DY<0?-DY:DY) ))
|
|
|
|
if [ -z "$BEST_DIST" ] || [ "$DIST" -lt "$BEST_DIST" ]; then
|
|
BEST_DIST=$DIST
|
|
BEST=$wid
|
|
fi
|
|
done
|
|
|
|
if [ -n "$BEST" ]; then
|
|
xdotool windowactivate "$BEST"
|
|
fi
|