Files
tmux/regress/image-border-status-wipe.sh
Michael Grant cfd1b81dc7 Implement generalised image support
Support Kitty and SIXEL input and output with grid-resident image layers, history and copy-mode integration, text fallback rendering, and damage-rectangle redraws.

Consolidate the image work through 250f96b4b onto the redraw-damage-rectangles-new base, excluding the superseded redraw implementation and its historical merges. The original history is preserved in backup/4902-image-support-before-master-rebase-20261003.
2026-10-07 18:22:35 +02:00

152 lines
5.5 KiB
Bash

#!/bin/sh
# Regression test for a border-status caching bug: window_make_pane_status()
# (window-border.c) gates the physical redraw of a pane's border-status
# title on a logical content diff (grid_compare against a cached copy), not
# on whether the physical screen cells were disturbed by something else in
# the meantime - such as a floating pane's own border, drawn on top of a
# tiled pane's border-status row, sliding across it and then away again.
# See tmux-image-redraw-known-bugs.md ("border-status text cache ignores
# physical damage") for the full write-up.
#
# Reproduction: a tiled pane with pane-border-status on has a floating pane
# dragged, by mouse, from directly over its border-status row to somewhere
# else. The tiled pane's title should reappear once the floating pane has
# moved off it; without the fix it stays blank.
#
# The drag starts and ends away from row 0 rather than grabbing the
# floating pane's border while it is already sitting on row 0: when a
# floating pane's own border-status row exactly coincides with the tiled
# pane's row 0, mouse hit-testing on that row attributes clicks to the
# tiled pane, not the floating one on top of it (an unrelated tmux quirk,
# not what this test is about). That only matters for the initial press,
# though - once a drag is under way, further motion events go straight to
# the already-bound per-pane callback without re-resolving which pane owns
# the coordinates, so starting the grab on an unambiguous row and dragging
# through row 0 works fine.
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
}
# drag COL ROW [ROW ...]
#
# Write one continuous mouse-1 gesture at column COL: a press at the first
# ROW, a drag update at each subsequent ROW in turn, and a release at the
# last ROW - all 1-based positions sent to the outer pane holding the
# inner client. This matches the default MouseDown1Border/MouseDrag1Border
# bindings used to move or resize a floating pane by its border.
#
# This must be one continuous press/drag/.../release gesture, not several
# separate drag() calls chained together: releasing clears the per-pane
# drag callback binding, so a later press has to be re-hit-tested from
# scratch, which only works reliably away from row 0 (see the header
# comment). A drag already under way is not re-hit-tested per motion
# event, so it can safely pass through row 0 as an intermediate waypoint.
drag()
{
col="$1"
shift
row="$1"
shift
seq=$(printf '\033[<0;%s;%sM' "$col" "$row")
$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null
sleep 0.2
while [ $# -gt 1 ]; do
row="$1"
shift
seq=$(printf '\033[<32;%s;%sM' "$col" "$row")
$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null
sleep 0.15
done
row="$1"
seq=$(printf '\033[<0;%s;%sm' "$col" "$row")
$TMUX2 send-keys -t "$OUTER" -l "$seq" 2>/dev/null
sleep 1
}
cleanup
TMP=$(mktemp)
trap "cleanup; rm -f $TMP" 0 1 15
$TMUX new-session -d -s inner -x 60 -y 20 'sh -c "sleep 100"' || exit 1
$TMUX set -g mouse on
$TMUX set -g pane-border-status top
$TMUX set -g default-command 'sh -c "sleep 100"'
BASE=$($TMUX list-panes -F '#{pane_id}' | head -1)
[ -n "$BASE" ] || fail "No base pane."
$TMUX select-pane -t "$BASE" -T TILEDTITLE || fail "set base title failed"
# Float a pane well clear of row 0 to start - its own top border must not
# coincide with the base pane's border-status row for the initial mouse
# press to unambiguously hit it (see the header comment). -x/-y are the
# pane's outer size including its 2-cell border frame, so request 2 more
# than the desired 14x3 content area (see layout_floating_args_parse()).
FLOAT=$($TMUX new-pane -d -PF '#{pane_id}' -x 16 -y 5 -X 5 -Y 5 -T FLOATTITLE) ||
fail "new-pane -X -Y failed"
FTOP=$($TMUX display-message -p -t "$FLOAT" '#{pane_top}')
FLEFT=$($TMUX display-message -p -t "$FLOAT" '#{pane_left}')
FWIDTH=$($TMUX display-message -p -t "$FLOAT" '#{pane_width}')
$TMUX2 new-session -d -x 60 -y 20 "$TMUX attach -t inner" || exit 1
sleep 1
OUTER=$($TMUX2 list-panes -F '#{pane_id}' | head -1)
[ -n "$OUTER" ] || fail "No outer pane."
# Sanity check: the base pane's title is visible now (the float starts
# well clear of row 0).
$TMUX2 capturep -p -t "$OUTER" >$TMP || fail "capture failed"
head -1 $TMP | grep -q TILEDTITLE ||
fail "base title not visible before the drag - test setup is wrong"
# Drag the float up by its top border (an unambiguous row - not row 0) so
# it ends up covering row 0, hiding the base pane's title behind its own
# border, then continue the same drag back down again so it ends clear of
# row 0 once more - one continuous gesture the whole way (see drag()'s
# comment for why).
GRABCOL=$((FLEFT + FWIDTH / 2))
waypoints="$FTOP"
row=$FTOP
while [ "$row" != 1 ]; do
row=$((row - 1))
waypoints="$waypoints $row"
done
while [ "$row" != "$FTOP" ]; do
row=$((row + 1))
waypoints="$waypoints $row"
done
drag $((GRABCOL + 1)) $waypoints
drag $((GRABCOL + 1)) 1 $((GRABCOL + 1)) "$FTOP"
$TMUX2 capturep -p -t "$OUTER" >$TMP || fail "capture failed"
# The base pane's title should be visible again now the floating pane has
# moved off its border-status row. This is expected to fail before the fix
# - see the header comment.
head -1 $TMP | grep -q TILEDTITLE ||
fail "base pane title still blank after floating pane moved away"
exit 0