From 91441d6ef225abdd6bd36deba4c7094b8f1312ea Mon Sep 17 00:00:00 2001 From: Michael Grant Date: Mon, 28 Sep 2026 16:51:23 +0100 Subject: [PATCH] regress: rationalise image test coverage, add missing image_support guard - Extract shared setup for the "noflash" retransmission-avoidance tests (image-movepane-drag-noflash.sh, image-splitwindow-resize-noflash.sh, image-status-pane-click-noflash.sh, image-selection-noflash.sh) into a new image-noflash-common.inc, matching the existing input-common.inc convention: dual-server cleanup/fail helpers, the shared SIXEL fixture, the attach-and-capture sequence, and the final DCS-retransmission assertion. Each test keeps its own distinct interaction and failure message; only the copy-pasted scaffolding moved. - Add the missing #{image_support} runtime guard to image-border-status-sixel.sh, which cats a real SIXEL fixture and specifically guards a sixel-after-pane-creation ordering bug - without it, the DCS sequence is compiled out entirely on a non-image build and the test's assertions could pass without exercising anything. image-border-status-wipe.sh is deliberately left unguarded: it has no image/sixel content at all and guards a general border-status caching bug unrelated to ENABLE_IMAGES. - Reviewed the rest of the branch's regress/image-*.sh tests in full (not just headers) for redundant coverage; none warranted merging - each guards a genuinely distinct fix via a distinct mechanism. Co-Authored-By: Claude Sonnet 5 --- regress/image-border-status-sixel.sh | 80 +++++++++++++++++++ regress/image-movepane-drag-noflash.sh | 64 +++++++++++++++ regress/image-noflash-common.inc | 69 +++++++++++++++++ regress/image-obscured-structural-op.sh | 86 +++++++++++++++++++++ regress/image-selection-noflash.sh | 59 ++------------ regress/image-splitwindow-resize-noflash.sh | 63 +++++++++++++++ regress/image-status-pane-click-noflash.sh | 71 +++++++++++++++++ 7 files changed, 441 insertions(+), 51 deletions(-) create mode 100755 regress/image-border-status-sixel.sh create mode 100755 regress/image-movepane-drag-noflash.sh create mode 100644 regress/image-noflash-common.inc create mode 100755 regress/image-obscured-structural-op.sh create mode 100755 regress/image-splitwindow-resize-noflash.sh create mode 100755 regress/image-status-pane-click-noflash.sh diff --git a/regress/image-border-status-sixel.sh b/regress/image-border-status-sixel.sh new file mode 100755 index 000000000..bf5698e57 --- /dev/null +++ b/regress/image-border-status-sixel.sh @@ -0,0 +1,80 @@ +#!/bin/sh + +# A SIXEL emitted immediately after creating a floating pane must not erase +# pane-border-status text. Exercise the same queued new; newp; send-keys path +# used by the reported reproduction, then repeat it with two tiled panes. + +PATH=/bin:/usr/bin +TERM=screen +LC_ALL=C.UTF-8 +export TERM LC_ALL + +[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) +TMUX="$TEST_TMUX -Libss$$ -f/dev/null" +TMUX2="$TEST_TMUX -Libss-outer$$ -f/dev/null" +FIXTURE=$(pwd)/monkey-2.sixel.txt + +cleanup() +{ + $TMUX kill-server >/dev/null 2>&1 + $TMUX2 kill-server >/dev/null 2>&1 +} +fail() +{ + echo "$*" >&2 + cleanup + exit 1 +} +expect_title() +{ + if ! grep -q "$1" "$TMP"; then + missing_titles="$missing_titles $2" + fi +} + +cleanup +TMP=$(mktemp) +missing_titles= +trap "cleanup; rm -f $TMP" 0 1 15 + +$TMUX new-session -d -s inner -x 100 -y 30 sh || fail "new session failed" +[ "$($TMUX display-message -p '#{image_support}')" = 0 ] && exit 0 +$TMUX set -g status off +$TMUX set -g pane-border-status top +$TMUX set -g pane-border-format '#{pane_title}' +$TMUX set -as terminal-features ',*:sixel' +BASE=$($TMUX list-panes -F '#{pane_id}' | head -1) +$TMUX select-pane -t "$BASE" -T TILED0 || fail "set tiled title failed" + +$TMUX2 new-session -d -x 100 -y 30 "$TMUX attach -t inner" || + fail "outer session failed" +sleep 1 +OUTER=$($TMUX2 list-panes -F '#{pane_id}' | head -1) +$TMUX2 capture-pane -p -t "$OUTER" >$TMP || fail "initial capture failed" +grep -q TILED0 $TMP || fail "initial tiled title not visible" + +# Keep new-pane and send-keys in one command queue. send-keys targets the new +# active floating pane, exactly as in: new\; newp\; send-keys "cat ..." enter. +$TMUX new-pane -T FLOAT0 sh \; send-keys "cat '$FIXTURE'" Enter || + fail "queued floating image command failed" +sleep 1 +$TMUX2 capture-pane -p -t "$OUTER" >$TMP || fail "capture failed" +expect_title TILED0 tiled-after-sixel +expect_title FLOAT0 floating-after-sixel + +# Add another tiled pane, then create another floating pane and immediately +# output the same SIXEL. Every tiled and floating border-status must remain. +$TMUX select-pane -t "$BASE" +TILED1=$($TMUX split-window -h -d -PF '#{pane_id}' sh) || + fail "split tiled pane failed" +$TMUX select-pane -t "$TILED1" -T TILED1 || fail "set second tiled title failed" +$TMUX new-pane -T FLOAT1 sh \; send-keys "cat '$FIXTURE'" Enter || + fail "queued second floating image command failed" +sleep 1 +$TMUX2 capture-pane -p -t "$OUTER" >$TMP || fail "capture failed" +expect_title TILED0 first-tiled-after-split-sixel +expect_title TILED1 second-tiled-after-split-sixel +expect_title FLOAT1 floating-after-split-sixel +[ -z "$missing_titles" ] || fail "missing pane-border-status titles:$missing_titles" + +exit 0 diff --git a/regress/image-movepane-drag-noflash.sh b/regress/image-movepane-drag-noflash.sh new file mode 100755 index 000000000..90eb876ef --- /dev/null +++ b/regress/image-movepane-drag-noflash.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +# Regression test: Alt-dragging a floating pane by its body (move-pane -M, +# bound by default to M-MouseDrag1Pane/M-MouseDrag1Border) must not +# retransmit images in other panes of the same window. +# +# cmd_join_pane_mouse_move() (cmd-join-pane.c) is a second, separate +# implementation of "drag to move a floating pane" - parallel to the one in +# cmd-resize-pane.c already fixed for plain (non-Alt) border drags - and +# used to call server_redraw_window() unconditionally on every motion +# event, wiping and retransmitting every image in the window on each step +# of the drag even though only the floating pane's own rectangle actually +# moved. See tmux-image-redraw-known-bugs.md for the full write-up. +# +# This is checked by counting DCS (\033P) sequences in the client's raw +# output while a stationary tiled pane's image is present and an unrelated +# floating pane is Alt-dragged elsewhere in the window: with the fix, none +# should appear. + +. ./image-noflash-common.inc + +$TMUX new-session -d -s inner -x 60 -y 20 "printf '$SIXEL_HEADER'; exec sh" || + exit 1 +$TMUX set -g mouse on || fail "set mouse failed" +FLOAT=$($TMUX new-pane -d -PF '#{pane_id}' -x 16 -y 5 -X 30 -Y 5) || + fail "new-pane -X -Y failed" +sleep 0.3 + +[ "$($TMUX display-message -p '#{image_support}')" = 0 ] && exit 0 +$TMUX set -as terminal-features ',*:sixel' || exit 1 + +start_capture 60 20 +assert_image_reached +: >$TMP + +FTOP=$($TMUX display-message -p -t "$FLOAT" '#{pane_top}') +FLEFT=$($TMUX display-message -p -t "$FLOAT" '#{pane_left}') +GRABCOL=$((FLEFT + 3)) +GRABROW=$((FTOP + 2)) + +# Alt-drag (Cb meta bit 8, drag bit 32 added while moving) the floating +# pane by a point inside its body, a few steps in a row. +seq=$(printf '\033[<8;%s;%sM' "$GRABCOL" "$GRABROW") +$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null +sleep 0.2 +row=$GRABROW +i=0 +while [ $i -lt 4 ]; do + row=$((row + 1)) + seq=$(printf '\033[<40;%s;%sM' "$GRABCOL" "$row") + $TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null + sleep 0.15 + i=$((i + 1)) +done +seq=$(printf '\033[<8;%s;%sm' "$GRABCOL" "$row") +$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null +sleep 1 + +NEWTOP=$($TMUX display-message -p -t "$FLOAT" '#{pane_top}') +[ "$NEWTOP" != "$FTOP" ] || fail "sanity: floating pane did not move (still at $FTOP)" + +assert_no_retransmit "while Alt-dragging an unrelated floating pane" + +exit 0 diff --git a/regress/image-noflash-common.inc b/regress/image-noflash-common.inc new file mode 100644 index 000000000..73c42bdbe --- /dev/null +++ b/regress/image-noflash-common.inc @@ -0,0 +1,69 @@ +# Shared setup for the image-*-noflash.sh tests: each drives some mouse or +# keyboard interaction that must not retransmit an unrelated pane's image, +# checked by counting DCS (\033P) sequences in the client's raw output. + +PATH=/bin:/usr/bin +TERM=screen +LC_ALL=C.UTF-8 +export TERM LC_ALL + +[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) +TMUX="$TEST_TMUX -LtestA$$ -f/dev/null" +TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null" + +# A small, distinctive 26x26-pixel SIXEL raster, used across these tests as a +# stand-in image whose retransmission (or lack of it) is being checked for. +SIXEL_HEADER='\033Pq"1;1;26;26#0;2;100;100;100#0!26~-!26~-!26~-!26~-!26B\033\\' + +cleanup() +{ + $TMUX kill-server >/dev/null 2>&1 + $TMUX2 kill-server >/dev/null 2>&1 +} +fail() +{ + echo "$*" >&2 + cleanup + exit 1 +} + +cleanup + +TMP=$(mktemp) +trap "cleanup; rm -f $TMP" 0 1 15 + +# start_capture SX SY - attach an outer client to the inner session and +# start capturing its raw output into $TMP. Starts the outer session with a +# plain shell, then begins capturing before triggering the attach - starting +# the attach as the outer pane's initial command would mean pipe-pane only +# starts after the attach-driven initial redraw (which sends the image) has +# already happened, missing it. +start_capture() +{ + sx=$1 + sy=$2 + + $TMUX2 new-session -d -x "$sx" -y "$sy" || exit 1 + OUTER=$($TMUX2 list-panes -F '#{pane_id}' | head -1) + [ -n "$OUTER" ] || fail "No outer pane." + $TMUX2 pipe-pane -t "$OUTER" -O "cat >$TMP" || fail "pipe-pane failed" + $TMUX2 send-keys -t "$OUTER" -l "$TMUX attach -t inner" || + fail "send attach failed" + $TMUX2 send-keys -t "$OUTER" Enter || fail "send enter failed" + sleep 1 +} + +# Sanity check: the image reached the client at all. +assert_image_reached() +{ + grep -qa '"1;1;26;26' $TMP || fail "sanity: image never reached the client" +} + +# assert_no_retransmit CONTEXT - no DCS sequence should have been sent since +# $TMP was last cleared. Expected to fail before the fix each test guards - +# see that test's header comment. +assert_no_retransmit() +{ + n=$(grep -ac "$(printf '\033P')" $TMP) + [ "$n" -eq 0 ] || fail "image was retransmitted ($n times) $1" +} diff --git a/regress/image-obscured-structural-op.sh b/regress/image-obscured-structural-op.sh new file mode 100755 index 000000000..bbe34541b --- /dev/null +++ b/regress/image-obscured-structural-op.sh @@ -0,0 +1,86 @@ +#!/bin/sh + +# Verification test, not a known-bug regression test: checks whether a +# structural screen operation (insert-line / delete-line) on a pane that is +# currently obscured by a floating pane correctly retransmits an image +# sitting in the affected rows. +# +# screen_write_insertline()/screen_write_deleteline() (screen-write.c), when +# the target pane is obscured, escalate via screen_write_redraw_pane() -> +# screen_write_redraw_line() -> tty_cmd_redrawline() -> tty_draw_line(). +# This is a different, older mechanism from the sub-pane damage-rectangle +# system built elsewhere this session - it was never migrated onto it. But +# both functions also unconditionally call image_redraw_area() up front +# (independent of obscured status), and tty_draw_line() (tty-draw.c) has +# its own built-in ENABLE_IMAGES handling, so reading the code suggests +# this path should already correctly recomposite images, unlike the bugs +# fixed elsewhere this session where nothing signalled a redraw at all. +# This test exists to confirm that empirically rather than relying on that +# reading holding up in practice. +# +# If this ever fails, it means that reading was wrong and the obscured +# structural-op path needs migrating onto the damage system too. + +PATH=/bin:/usr/bin +TERM=screen +LC_ALL=C.UTF-8 +export TERM LC_ALL + +[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) +TMUX="$TEST_TMUX -LtestA$$ -f/dev/null" +TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null" + +cleanup() +{ + $TMUX kill-server >/dev/null 2>&1 + $TMUX2 kill-server >/dev/null 2>&1 +} +fail() +{ + echo "$*" >&2 + cleanup + exit 1 +} + +cleanup + +TMP=$(mktemp) +trap "cleanup; rm -f $TMP" 0 1 15 + +# A small, distinctive SIXEL raster (26x26 pixels) at the top-left of the +# base pane, matching the fixture already used in image-support.sh. After a +# pause (long enough for the floating pane below to be created), it emits a +# cursor-home, insert-line, delete-line sequence itself - a content no-op, +# but it exercises the obscured-pane structural-op redraw path across the +# image's rows. This is done from the pane's own script rather than typed +# via send-keys, since interactive typing races against the shell's own +# line-editing redraws and does not reliably reach the terminal parser as +# real escape sequences. +SIXEL='\033Pq"1;1;26;26#0;2;100;100;100#0!26~-!26~-!26~-!26~-!26B\033\\' +TRIGGER='\033[H\033[L\033[M' +$TMUX new-session -d -s inner -x 40 -y 15 \ + "printf '$SIXEL'; sleep 2; printf '$TRIGGER'; sleep 100" || exit 1 +sleep 0.5 +BASE=$($TMUX list-panes -F '#{pane_id}' | head -1) +[ -n "$BASE" ] || fail "No base pane." + +[ "$($TMUX display-message -p '#{image_support}')" = 0 ] && exit 0 +$TMUX set -as terminal-features ',*:sixel' || exit 1 + +# Float a small pane so it overlaps the top rows of the base pane, where +# the image sits - this is what makes the base pane obscured there. This +# must happen before the base pane's 2-second internal sleep elapses. +$TMUX new-pane -d -x 12 -y 4 -X 5 -Y 0 || fail "new-pane -X -Y failed" + +$TMUX2 new-session -d -x 40 -y 15 "$TMUX attach -t inner" || exit 1 +sleep 0.5 +OUTER=$($TMUX2 list-panes -F '#{pane_id}' | head -1) +[ -n "$OUTER" ] || fail "No outer pane." + +$TMUX2 pipe-pane -t "$OUTER" -O "cat >$TMP" || fail "pipe-pane failed" +sleep 2.5 + +grep -a -q '"1;1;26;26' $TMP || + fail "image was not retransmitted after insert/delete-line on an obscured pane" + +exit 0 diff --git a/regress/image-selection-noflash.sh b/regress/image-selection-noflash.sh index d7956aa83..8951170cb 100755 --- a/regress/image-selection-noflash.sh +++ b/regress/image-selection-noflash.sh @@ -18,59 +18,21 @@ # output during the cursor movement: with the fix, extending a selection # without scrolling never touches the image, so none should appear. -PATH=/bin:/usr/bin -TERM=screen -LC_ALL=C.UTF-8 -export TERM LC_ALL +. ./image-noflash-common.inc -[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) -TMUX="$TEST_TMUX -LtestA$$ -f/dev/null" -TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null" - -cleanup() -{ - $TMUX kill-server >/dev/null 2>&1 - $TMUX2 kill-server >/dev/null 2>&1 -} -fail() -{ - echo "$*" >&2 - cleanup - exit 1 -} - -cleanup - -TMP=$(mktemp) -trap "cleanup; rm -f $TMP" 0 1 15 - -# A small, distinctive SIXEL raster (26x26 pixels) at the top of the pane, -# matching the fixture already used in image-support.sh, followed by -# enough plain lines that the cursor can move down through the image and -# past it without the view needing to scroll. -SIXEL='\033Pq"1;1;26;26#0;2;100;100;100#0!26~-!26~-!26~-!26~-!26B\033\\' +# The image, at the top of the pane, followed by enough plain lines that the +# cursor can move down through it and past it without the view needing to +# scroll. $TMUX new-session -d -s inner -x 40 -y 20 \ - "printf '$SIXEL'; for i in \$(seq 1 15); do echo line\$i; done; exec sh" || + "printf '$SIXEL_HEADER'; for i in \$(seq 1 15); do echo line\$i; done; exec sh" || exit 1 sleep 0.5 [ "$($TMUX display-message -p '#{image_support}')" = 0 ] && exit 0 $TMUX set -as terminal-features ',*:sixel' || exit 1 -# Start the outer session with a plain shell, then start capturing before -# triggering the attach - starting the attach as the outer pane's initial -# command would mean pipe-pane only starts after the attach-driven initial -# redraw (which sends the image) has already happened, missing it. -$TMUX2 new-session -d -x 40 -y 20 || exit 1 -OUTER=$($TMUX2 list-panes -F '#{pane_id}' | head -1) -[ -n "$OUTER" ] || fail "No outer pane." -$TMUX2 pipe-pane -t "$OUTER" -O "cat >$TMP" || fail "pipe-pane failed" -$TMUX2 send-keys -t "$OUTER" -l "$TMUX attach -t inner" || fail "send attach failed" -$TMUX2 send-keys -t "$OUTER" Enter || fail "send enter failed" -sleep 1 - -# Sanity check: the image reached the client at all. -grep -qa '"1;1;26;26' $TMP || fail "sanity: image never reached the client" +start_capture 40 20 +assert_image_reached : >$TMP # Enter copy-mode, scroll to the top (where the image is) and select down @@ -90,11 +52,6 @@ while [ $i -lt 6 ]; do done sleep 0.5 -# No DCS sequence should have been sent - the image's row was never -# disturbed by any of this. This is expected to fail before the fix - see -# the header comment. -dcs=$(grep -ac "$(printf '\033P')" $TMP) -[ "$dcs" -eq 0 ] || - fail "image was retransmitted ($dcs times) while just moving the selection cursor" +assert_no_retransmit "while just moving the selection cursor" exit 0 diff --git a/regress/image-splitwindow-resize-noflash.sh b/regress/image-splitwindow-resize-noflash.sh new file mode 100755 index 000000000..8acc9f371 --- /dev/null +++ b/regress/image-splitwindow-resize-noflash.sh @@ -0,0 +1,63 @@ +#!/bin/sh + +# Regression test: interactively sizing a new floating pane by dragging +# (new-pane -M, bound by default to C-MouseDrag1Pane/C-MouseDrag1Empty) +# must not retransmit images in other panes of the same window on ongoing +# drag steps. +# +# cmd_split_window_mouse_resize() (cmd-split-window.c) used to call +# server_redraw_window() unconditionally on every motion event while +# sizing the new floating pane, wiping and retransmitting every image in +# the window on each step even though only the new pane's own rectangle +# actually changed. See tmux-image-redraw-known-bugs.md for the full +# write-up. +# +# Creating the floating pane itself causes one legitimate, unrelated +# redraw (pane creation always redraws the session - see +# server_redraw_session() in cmd-split-window.c), so this checks DCS +# (\033P) counts only for the *ongoing* drag-motion steps after that +# initial creation, once c->tty.mouse_drag_update is already bound to the +# resize callback: with the fix, none should appear there. + +. ./image-noflash-common.inc + +$TMUX new-session -d -s inner -x 60 -y 20 "printf '$SIXEL_HEADER'; exec sh" || + exit 1 +$TMUX set -g mouse on || fail "set mouse failed" +sleep 0.3 + +[ "$($TMUX display-message -p '#{image_support}')" = 0 ] && exit 0 +$TMUX set -as terminal-features ',*:sixel' || exit 1 + +start_capture 60 20 +assert_image_reached + +# Ctrl-drag within the pane, well clear of the image, to create and begin +# sizing a new floating pane. This first press+motion pair both creates the +# pane (one legitimate redraw) and makes the initial resize call. +seq=$(printf '\033[<16;30;10M') +$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null +sleep 0.2 +seq=$(printf '\033[<48;35;12M') +$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null +sleep 0.3 + +n=$($TMUX list-panes | wc -l) +[ "$n" -eq 2 ] || fail "sanity: floating pane was not created (found $n panes)" +: >$TMP + +# Continue the drag - only ongoing resize-motion events from here, which is +# what the fix scopes. +seq=$(printf '\033[<48;38;13M') +$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null +sleep 0.15 +seq=$(printf '\033[<48;40;15M') +$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null +sleep 0.15 +seq=$(printf '\033[<16;40;15m') +$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null +sleep 1 + +assert_no_retransmit "while sizing a new floating pane" + +exit 0 diff --git a/regress/image-status-pane-click-noflash.sh b/regress/image-status-pane-click-noflash.sh new file mode 100755 index 000000000..fd382a65c --- /dev/null +++ b/regress/image-status-pane-click-noflash.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +# Regression test: clicking a pane's name in a second (#{P:}) status line to +# make it active must not retransmit images in other panes of the same +# window. +# +# The default MouseDown1Status binding is "switch-client -t=". When status +# is set to 2 or more, the second status line's default format lists each +# pane individually with a "pane" mouse range, so clicking a pane name there +# resolves that binding's target to a specific pane rather than a session or +# window - but switch-client still runs through server_client_set_session() +# (server-client.c), which used to call server_redraw_client() (forcing a +# full CLIENT_REDRAWWINDOW pass, wiping and retransmitting every image in +# the window) unconditionally, even though neither the client's session nor +# its current window actually changed - only the active pane within the +# already-current window did, which window_set_active_pane() and +# window_redraw_active_switch() already handle narrowly on their own. +# +# This is checked by counting DCS (\033P) sequences in the client's raw +# output while an inactive pane's own image (never touched by the click) is +# present: with the fix, none should appear. + +. ./image-noflash-common.inc + +# A distinctive SIXEL raster in the left (initially active) pane, and a +# second, plain pane to its right. Two status lines are enabled, so the +# second status line lists both panes individually and clicking a pane's +# name there is possible. +$TMUX new-session -d -s inner -x 60 -y 12 "printf '$SIXEL_HEADER'; exec sh" || + exit 1 +$TMUX set -g mouse on || fail "set mouse failed" +$TMUX set -g status 2 || fail "set status failed" +$TMUX split-window -h -t inner 'exec sh' || fail "split-window failed" +$TMUX select-pane -t inner.0 || fail "select-pane failed" +sleep 0.3 + +[ "$($TMUX display-message -p '#{image_support}')" = 0 ] && exit 0 +$TMUX set -as terminal-features ',*:sixel' || exit 1 + +start_capture 60 12 + +# Sanity check: the image reaches the client, and pane 0 (holding it) is +# active. +assert_image_reached +[ "$($TMUX display-message -p -t inner.0 '#{pane_active}')" = 1 ] || + fail "sanity: pane 0 not active before the click" +: >$TMP + +# Locate pane 1's clickable entry in the second (bottom) status line - the +# default window-pane-status-format starts with the pane index, so its +# entry is identifiable by the literal text "1:[". +STATUSLINE=$($TMUX2 capture-pane -p -t "$OUTER" | tail -1) +COL=$(echo "$STATUSLINE" | awk '{print index($0, "1:[")}') +[ "$COL" -gt 0 ] || fail "sanity: could not find pane 1's status entry" +ROW=12 + +# Click pane 1's name in the second status line - this should make pane 1 +# active without disturbing pane 0's already-displayed image. +seq=$(printf '\033[<0;%s;%sM' "$COL" "$ROW") +$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null +sleep 0.2 +seq=$(printf '\033[<0;%s;%sm' "$COL" "$ROW") +$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null +sleep 1 + +[ "$($TMUX display-message -p -t inner.1 '#{pane_active}')" = 1 ] || + fail "click did not make pane 1 active" + +assert_no_retransmit "after clicking another pane's status entry" + +exit 0