78 lines
1.8 KiB
Bash
78 lines
1.8 KiB
Bash
# Ghostty spawn-or-focus logic for Niri:
|
|
# If no Ghostty windows exist, spawn one.
|
|
# If focused window is not Ghostty, focus the first Ghostty instance.
|
|
# If Ghostty is focused and only one instance exists, spawn + consume into stack.
|
|
# If Ghostty is focused and two instances already exist, spawn a new separate one.
|
|
# Cycle repeats: focus first > allow stack of 2 > reset on 3rd.
|
|
|
|
APP_ID="com.mitchellh.ghostty"
|
|
APP_CMD="ghostty"
|
|
|
|
WINDOW_DATA=$(niri msg -j windows)
|
|
|
|
readarray -t GHOSTTY_IDS < <(
|
|
echo "$WINDOW_DATA" | jq -r --arg app_id "$APP_ID" '
|
|
[ .[] | select(.app_id == $app_id) ]
|
|
| sort_by(.layout.pos_in_scrolling_layout // [0,0])
|
|
| .[].id
|
|
'
|
|
)
|
|
|
|
COUNT=${#GHOSTTY_IDS[@]}
|
|
|
|
FOCUSED_IS_GHOSTTY=$(
|
|
echo "$WINDOW_DATA" | jq -r --arg app_id "$APP_ID" '
|
|
any(.[]; .app_id == $app_id and .is_focused)
|
|
'
|
|
)
|
|
|
|
spawn_normal() {
|
|
"$APP_CMD" &
|
|
}
|
|
|
|
spawn_and_consume() {
|
|
local initial_ids=("$@")
|
|
"$APP_CMD" &
|
|
local pid=$!
|
|
|
|
for _ in {1..50}; do
|
|
readarray -t after_ids < <(
|
|
niri msg -j windows | jq -r --arg app_id "$APP_ID" '
|
|
[ .[] | select(.app_id == $app_id) ]
|
|
| sort_by(.layout.pos_in_scrolling_layout // [0,0])
|
|
| .[].id
|
|
'
|
|
)
|
|
|
|
NEW_ID=""
|
|
for id in "${after_ids[@]}"; do
|
|
[[ " ${initial_ids[*]} " == *" $id "* ]] || NEW_ID="$id"
|
|
done
|
|
|
|
if [ -n "$NEW_ID" ]; then
|
|
niri msg action focus-window --id "${initial_ids[$((${#initial_ids[@]} - 1))]}"
|
|
niri msg action consume-window-into-column
|
|
break
|
|
fi
|
|
sleep 0.05
|
|
done
|
|
|
|
wait "$pid" 2>/dev/null || true
|
|
}
|
|
|
|
if ((COUNT == 0)); then
|
|
spawn_normal
|
|
exit 0
|
|
fi
|
|
|
|
if [ "$FOCUSED_IS_GHOSTTY" != "true" ]; then
|
|
niri msg action focus-window --id "${GHOSTTY_IDS[0]}"
|
|
exit 0
|
|
fi
|
|
|
|
if ((COUNT % 2 == 0)); then
|
|
spawn_normal
|
|
else
|
|
spawn_and_consume "${GHOSTTY_IDS[@]}"
|
|
fi
|