#!/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