mirror of
https://github.com/tmux/tmux.git
synced 2026-09-24 05:43:58 +00:00
Merge branch 'redraw-damage-rectangles' into 4902-image-support
Brings in the WezTerm/ghostty/Windows Terminal DECSLRM (margins) coverage from margins-terminal-detection (PR #5630), via redraw-damage-rectangles. Two conflicts, both simple bit-flag/list collisions from independent work on both sides adding something at the same slot: - tmux.h: this branch's own TERM_KITTY/TERM_IMAGE_QUADRANTS/ TERM_IMAGE_SEXTANTS (0x100/0x200/0x400) collided with upstream's new TERM_NOREPLACE, also assigned 0x100. Kept this branch's existing values (already used throughout image.c/tty-features.c) and moved TERM_NOREPLACE to the next free bit, 0x800 - confirmed no other code references the literal 0x100 value for TERM_NOREPLACE, only the symbol. - tty-features.c: this branch's own WezTerm entry (added "sixel") and the incoming margins-terminal-detection change (added "margins") both touched the same line - combined both. Verified: build clean with --enable-images (image_support confirmed 1); this branch's own image-kitty-region-scroll.sh/image-sixel-region-scroll.sh plus this session's other prompt/cross-client/margins tests all pass (3x each); full regress suite run pending/clean per standard practice for this branch. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-queue.c,v 1.123 2026/08/24 20:34:26 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-queue.c,v 1.124 2026/09/22 06:46:50 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -580,6 +580,9 @@ cmdq_fire_command(struct cmdq_item *item)
|
||||
int flags, quiet = 0;
|
||||
char *tmp;
|
||||
|
||||
if (item->client != NULL && (item->client->flags & CLIENT_DEAD))
|
||||
return (CMD_RETURN_ERROR);
|
||||
|
||||
if (cfg_finished)
|
||||
cmdq_add_message(item);
|
||||
if (log_get_level() > 1) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-wait-for.c,v 1.23 2026/07/10 13:38:45 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-wait-for.c,v 1.24 2026/09/22 06:46:50 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -480,6 +480,40 @@ cmd_wait_for_unlock(struct cmdq_item *item, const char *name,
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_wait_for_client_lost(struct client *c)
|
||||
{
|
||||
struct wait_channel *wc, *wc1;
|
||||
struct wait_item *wi, *wi1;
|
||||
struct wait_event_item *wei, *wei1;
|
||||
|
||||
TAILQ_FOREACH_SAFE(wei, &wait_event_items, entry, wei1) {
|
||||
if (cmdq_get_client(wei->item) == c) {
|
||||
TAILQ_REMOVE(&wait_event_items, wei, entry);
|
||||
cmdq_continue(wei->item);
|
||||
cmd_wait_for_event_free(wei);
|
||||
}
|
||||
}
|
||||
|
||||
RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) {
|
||||
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
|
||||
if (cmdq_get_client(wi->item) == c) {
|
||||
cmdq_continue(wi->item);
|
||||
TAILQ_REMOVE(&wc->waiters, wi, entry);
|
||||
free(wi);
|
||||
}
|
||||
}
|
||||
TAILQ_FOREACH_SAFE(wi, &wc->lockers, entry, wi1) {
|
||||
if (cmdq_get_client(wi->item) == c) {
|
||||
cmdq_continue(wi->item);
|
||||
TAILQ_REMOVE(&wc->lockers, wi, entry);
|
||||
free(wi);
|
||||
}
|
||||
}
|
||||
cmd_wait_for_remove_empty(wc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cmd_wait_for_flush(void)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: layout-custom.c,v 1.42 2026/09/20 08:37:47 nicm Exp $ */
|
||||
/* $OpenBSD: layout-custom.c,v 1.43 2026/09/22 06:48:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -307,6 +307,37 @@ bad:
|
||||
return (xstrdup("0000,"));
|
||||
}
|
||||
|
||||
/* Get a floating pane cell's z-index in the layout being dumped. */
|
||||
static u_int
|
||||
layout_cell_zindex(struct layout_cell *lc)
|
||||
{
|
||||
struct window_pane *wp = lc->wp, *wq;
|
||||
struct window *w = wp->window;
|
||||
struct layout_cell *other;
|
||||
int saved = (lc == wp->saved_layout_cell);
|
||||
u_int i = 0;
|
||||
|
||||
if (saved &&
|
||||
w->active != NULL &&
|
||||
(w->active->flags & PANE_ZOOMED) &&
|
||||
(w->active->saved_layout_cell->flags & LAYOUT_CELL_FLOATING)) {
|
||||
if (wp == w->active)
|
||||
return (0);
|
||||
i++;
|
||||
}
|
||||
TAILQ_FOREACH(wq, &w->z_index, zentry) {
|
||||
if (wq == wp)
|
||||
break;
|
||||
if (saved)
|
||||
other = wq->saved_layout_cell;
|
||||
else
|
||||
other = wq->layout_cell;
|
||||
if (other != NULL && (other->flags & LAYOUT_CELL_FLOATING))
|
||||
i++;
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
/* Append information for a single cell in a JSON (v2) format. */
|
||||
static int
|
||||
layout_append_v2(struct layout_cell *lc, struct layout_string *ls)
|
||||
@@ -315,7 +346,7 @@ layout_append_v2(struct layout_cell *lc, struct layout_string *ls)
|
||||
struct window_pane *wp;
|
||||
enum layout_type type;
|
||||
char c;
|
||||
u_int i, n;
|
||||
u_int i, n, z;
|
||||
|
||||
if (lc == NULL)
|
||||
return (-1);
|
||||
@@ -356,9 +387,10 @@ layout_append_v2(struct layout_cell *lc, struct layout_string *ls)
|
||||
if (window_pane_index(wp, &i) != 0)
|
||||
return (-1);
|
||||
layout_string_write(ls, ",\"i\":%u", i);
|
||||
if ((lc->flags & LAYOUT_CELL_FLOATING) &&
|
||||
window_pane_zindex(wp, &i) == 0)
|
||||
layout_string_write(ls, ",\"z\":%u", i);
|
||||
if (lc->flags & LAYOUT_CELL_FLOATING) {
|
||||
z = layout_cell_zindex(lc);
|
||||
layout_string_write(ls, ",\"z\":%u", z);
|
||||
}
|
||||
layout_string_write(ls, ",\"I\":\"%%%u\"", wp->id);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,19 @@ assert_key () {
|
||||
clear-history -t$W \; \
|
||||
send-keys -t$W "$key" 'EOL' || exit 1
|
||||
|
||||
actual_code=$($TMUX capturep -pt$W | \
|
||||
# cat echoes the keys back asynchronously, so wait for the EOL marker
|
||||
# to reach the pane instead of capturing straight away.
|
||||
i=0
|
||||
while [ $i -lt 50 ]; do
|
||||
screen=$($TMUX capturep -pt$W)
|
||||
case "$screen" in
|
||||
*EOL*) break ;;
|
||||
esac
|
||||
i=$((i + 1))
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
actual_code=$(printf '%s\n' "$screen" | \
|
||||
head -1 | \
|
||||
sed -e 's/EOL.*$//')
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
. ./input-common.inc
|
||||
|
||||
# Large strings may take longer than start_cmd's delay to reach the parser.
|
||||
# Wait for the terminator and following text to reach the parser.
|
||||
check_discard()
|
||||
{
|
||||
name=$1
|
||||
printf 'OK\n' >"$EXP"
|
||||
i=0
|
||||
while [ "$i" -lt 100 ]; do
|
||||
while [ "$i" -lt 300 ]; do
|
||||
capture_grid "$name" >"$TMP"
|
||||
cmp -s "$TMP" "$EXP" && return 0
|
||||
sleep 0.05
|
||||
@@ -17,6 +17,23 @@ check_discard()
|
||||
fail "$name (timed out waiting for discard)"
|
||||
}
|
||||
|
||||
# The missing-terminator timer may expire before the string limit is reached
|
||||
# on a slow build. Clear any payload printed after the timeout, then check
|
||||
# that the string did not change the title and normal output has resumed.
|
||||
test_discard()
|
||||
{
|
||||
name=$1
|
||||
prefix=$2
|
||||
start_cmd "$name" 8 3 "$INPUT_HOLD"
|
||||
$TMUX select-pane -T discard-test || exit 1
|
||||
$TMUX respawn-pane -k \
|
||||
"perl -e 'print qq{$prefix}, q{x} x 1100000, qq{\e\\\\\e[H\e[2JOK}'; $INPUT_HOLD" || exit 1
|
||||
check_discard "$name"
|
||||
$TMUX display-message -p -t "$name:" '#{pane_title}' >"$TMP" || exit 1
|
||||
printf 'discard-test\n' >"$EXP"
|
||||
cmp "$TMP" "$EXP" || fail "$name title"
|
||||
}
|
||||
|
||||
start_cmd csi-param-discard 8 3 \
|
||||
"perl -e 'print qq{\e[}, q{1} x 80, qq{\030OK}'; sleep 2"
|
||||
check_capture csi-param-discard 'OK'
|
||||
@@ -25,13 +42,8 @@ start_cmd csi-interm-discard 8 3 \
|
||||
"perl -e 'print qq{\e[ \030OK}'; sleep 2"
|
||||
check_capture csi-interm-discard 'OK'
|
||||
|
||||
start_cmd osc-discard 8 3 \
|
||||
"perl -e 'print qq{\e]2;}, q{x} x 1100000, qq{\e\\\\OK}'; exec cat"
|
||||
check_discard osc-discard
|
||||
|
||||
start_cmd apc-discard 8 3 \
|
||||
"perl -e 'print qq{\e_}, q{x} x 1100000, qq{\e\\\\OK}'; exec cat"
|
||||
check_discard apc-discard
|
||||
test_discard osc-discard '\e]2;'
|
||||
test_discard apc-discard '\e_'
|
||||
|
||||
start_pane unknown-csi 8 3 '\033[?9999zOK'
|
||||
check_capture unknown-csi 'OK'
|
||||
|
||||
@@ -377,10 +377,7 @@ must_equal 'Layout after select-pane back' "$(layout L:two)" "$SPLIT"
|
||||
|
||||
# With nothing zoomed the two layout formats agree.
|
||||
#
|
||||
# The zoomed case is deliberately not covered here. While a pane is zoomed
|
||||
# #{window_layout} dumps the saved (unzoomed) layout and
|
||||
# #{window_visible_layout} the zoomed one, but that depends on how zooming
|
||||
# stashes the layout root rather than on anything in layout-custom.c.
|
||||
# Zoomed layouts are checked below with floating panes.
|
||||
must_equal 'Visible layout' "$(visible_layout L:two)" "$SPLIT"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -704,6 +701,42 @@ must_contain 'Floating layout back z-index' "$floating" '"z":1'
|
||||
check_ok select-layout -t L:float "$floating"
|
||||
must_equal 'Floating layout after round trip' "$(raw_layout L:float)" "$floating"
|
||||
|
||||
# A dump taken while zoomed must retain the unzoomed floating z-indexes.
|
||||
# Check hidden floats, floats above zoom, and a mixture of the two.
|
||||
for flags in '' A mixed; do
|
||||
check_ok new-window -d -t L: -n zoom
|
||||
zt=$($TMUX display-message -p -t L:zoom '#{pane_id}')
|
||||
check_ok split-window -d -h -t "$zt"
|
||||
case "$flags" in
|
||||
A|mixed) first=-Ad ;;
|
||||
*) first=-d ;;
|
||||
esac
|
||||
case "$flags" in
|
||||
A) second=-Ad ;;
|
||||
*) second=-d ;;
|
||||
esac
|
||||
check_ok new-pane "$first" -t "$zt" -x 20 -y 6 ''
|
||||
check_ok new-pane "$second" -t "$zt" -x 30 -y 8 ''
|
||||
for pane in 0 2 3; do
|
||||
check_ok select-pane -t "L:zoom.$pane"
|
||||
before=$(raw_layout L:zoom)
|
||||
legacy=$(v1_layout L:zoom)
|
||||
check_ok resize-pane -Z -t "L:zoom.$pane"
|
||||
during=$(raw_layout L:zoom)
|
||||
must_equal 'Layout while zoomed' "$during" "$before"
|
||||
must_equal 'Legacy layout while zoomed' \
|
||||
"$(v1_layout L:zoom)" "$legacy"
|
||||
must_equal 'Zoom after dumping layout' \
|
||||
"$($TMUX display-message -p -t L:zoom '#{window_zoomed_flag}')" 1
|
||||
must_differ 'Visible layout while zoomed' \
|
||||
"$(visible_layout L:zoom)" "$(layout L:zoom)"
|
||||
check_ok select-layout -t L:zoom "$during"
|
||||
must_equal 'Round trip from zoomed layout' \
|
||||
"$(raw_layout L:zoom)" "$before"
|
||||
done
|
||||
check_ok kill-window -t L:zoom
|
||||
done
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Floating panes and the legacy (v1) format.
|
||||
#
|
||||
|
||||
116
regress/sync-output-wrapped.sh
Executable file
116
regress/sync-output-wrapped.sh
Executable file
@@ -0,0 +1,116 @@
|
||||
#!/bin/sh
|
||||
|
||||
# When only some lines are redrawn after a synchronized update, a line
|
||||
# following a wrapped line must be drawn at its own position, not where the
|
||||
# cursor happens to be.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
export PATH TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
|
||||
DIR=$(mktemp -d) || exit 1
|
||||
TMUX_TMPDIR=$DIR
|
||||
export TMUX_TMPDIR
|
||||
|
||||
INNER="$TEST_TMUX -Li$$ -f/dev/null"
|
||||
OUTER="$TEST_TMUX -Lo$$ -f/dev/null"
|
||||
CONTROL=$DIR/control
|
||||
EMITTER=$DIR/emitter.pl
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$OUTER kill-server 2>/dev/null
|
||||
$INNER kill-server 2>/dev/null
|
||||
rm -rf "$DIR"
|
||||
}
|
||||
trap cleanup 0 1 15
|
||||
|
||||
wait_for_file()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ] && [ ! -e "$1" ]; do
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ -e "$1" ] || fail "$2"
|
||||
}
|
||||
|
||||
wait_for_client()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
$INNER list-clients -F '#{client_termfeatures}' 2>/dev/null |
|
||||
grep -q 'sync' && return 0
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "sync-capable client did not attach"
|
||||
}
|
||||
|
||||
cat >"$EMITTER" <<'PERL'
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $control = $ENV{CONTROL};
|
||||
(my $dir = $control) =~ s{/[^/]+$}{};
|
||||
|
||||
# Fill the screen with 80 column lines and no newlines so every line wraps.
|
||||
my $out = "\e[H\e[2J";
|
||||
for my $row (1 .. 24) {
|
||||
$out .= substr(sprintf("ROW%02d_", $row) . ('x' x 80), 0, 80);
|
||||
}
|
||||
syswrite STDOUT, $out . "\e[1;1H";
|
||||
|
||||
open my $painted, '>', "$dir/painted" or die "$dir/painted: $!\n";
|
||||
close $painted;
|
||||
while (!-e $control) {
|
||||
select undef, undef, undef, 0.01;
|
||||
}
|
||||
|
||||
# Change rows 2 and 6 in one synchronized update.
|
||||
my $frame = "\e[?2026h" .
|
||||
"\e[2;1H" . substr("NEW02_" . ('#' x 80), 0, 80) .
|
||||
"\e[6;1H" . substr("NEW06_" . ('%' x 80), 0, 80) .
|
||||
"\e[24;1H" .
|
||||
"\e[?2026l";
|
||||
my $written = syswrite STDOUT, $frame;
|
||||
die "short synchronized frame write\n"
|
||||
unless defined $written && $written == length $frame;
|
||||
open my $done, '>', "$dir/done" or die "$dir/done: $!\n";
|
||||
close $done;
|
||||
select undef, undef, undef, 3;
|
||||
PERL
|
||||
|
||||
$INNER new-session -d -s inner -x 80 -y 24 \
|
||||
"CONTROL='$CONTROL' perl '$EMITTER'" || exit 1
|
||||
$INNER set-option -g status off || exit 1
|
||||
$INNER set-option -g window-size manual || exit 1
|
||||
$INNER set-option -as terminal-features '*:sync' || exit 1
|
||||
|
||||
$OUTER new-session -d -s outer -x 80 -y 24 \
|
||||
"$TEST_TMUX -Li$$ -f/dev/null attach-session -t inner" ||
|
||||
exit 1
|
||||
$OUTER set-option -g status off || exit 1
|
||||
$OUTER set-option -g window-size manual || exit 1
|
||||
wait_for_client
|
||||
|
||||
wait_for_file "$DIR/painted" "application did not paint"
|
||||
sleep 1
|
||||
: >"$CONTROL"
|
||||
wait_for_file "$DIR/done" "application did not finish"
|
||||
sleep 1
|
||||
|
||||
$OUTER capture-pane -p -t outer:0.0 >"$DIR/screen" || exit 1
|
||||
sed -n 2p "$DIR/screen" | grep -q '^NEW02_#' || fail "row 2 not redrawn"
|
||||
sed -n 3p "$DIR/screen" | grep -q '^ROW03_x' || fail "row 3 overwritten"
|
||||
sed -n 6p "$DIR/screen" | grep -q '^NEW06_%' || fail "row 6 not redrawn"
|
||||
exit 0
|
||||
124
regress/tty-margins-wt-session.sh
Executable file
124
regress/tty-margins-wt-session.sh
Executable file
@@ -0,0 +1,124 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Windows Terminal cannot be identified by the XTVERSION mechanism
|
||||
# tty_default_features() (tty-features.c) otherwise uses for every other
|
||||
# terminal in its table - its maintainers have explicitly declined to
|
||||
# implement it (github.com/microsoft/terminal issue 18382, closed
|
||||
# not_planned). tty_term_create() (tty-term.c) instead detects it via the
|
||||
# WT_SESSION environment variable Windows Terminal sets for every child
|
||||
# process, granting it the "margins" (DECSLRM) terminal feature.
|
||||
#
|
||||
# Without DECSLRM, a pane that doesn't span the terminal's full width -
|
||||
# because pane-scrollbars is on (the scrollbar occupies a column) or the
|
||||
# pane is one of a side-by-side split - can't use the fast native-scroll
|
||||
# path (tty_cmd_linefeed()/scrollup()/scrolldown()/reverseindex(), tty.c:
|
||||
# "(!tty_full_width(tty, ctx) && !tty_use_margin(tty))") and falls back to
|
||||
# tty_redraw_region()'s full manual repaint on every single scroll - a
|
||||
# real, confirmed source of flicker (and, separately, of image content not
|
||||
# surviving a scroll).
|
||||
#
|
||||
# This checks the actual server-side decision via the -vv log: a pane with
|
||||
# pane-scrollbars on, scrolled several times, must never fall back to
|
||||
# tty_redraw_region() when the attaching client's environment carries
|
||||
# WT_SESSION - and must (as a sanity check that this scenario would
|
||||
# otherwise hit the fallback at all) when it does not.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
export PATH TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
|
||||
DIR=$(mktemp -d) || exit 1
|
||||
cd "$DIR" || exit 1
|
||||
INNER="$TEST_TMUX -vv -Lwtsession-inner-$$ -f/dev/null"
|
||||
OUTER="$TEST_TMUX -Lwtsession-outer-$$ -f/dev/null"
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$OUTER kill-server 2>/dev/null
|
||||
$INNER kill-server 2>/dev/null
|
||||
cd /
|
||||
rm -rf "$DIR"
|
||||
}
|
||||
trap cleanup 0 1 15
|
||||
|
||||
wait_for_client()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
CLIENT=$($INNER list-clients -F '#{client_name}' 2>/dev/null)
|
||||
[ -n "$CLIENT" ] && return 0
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "inner client did not attach"
|
||||
}
|
||||
|
||||
run_scroll_phase()
|
||||
{
|
||||
label=$1
|
||||
attachcmd=$2
|
||||
|
||||
rm -f tmux-server*.log
|
||||
|
||||
$INNER new-session -d -s inner -x 40 -y 6 'exec sh' || exit 1
|
||||
$INNER set -g status off || exit 1
|
||||
$INNER set -g window-size manual || exit 1
|
||||
$INNER set -g pane-scrollbars on || exit 1
|
||||
|
||||
$OUTER new-session -d -x 40 -y 6 || exit 1
|
||||
OUTERPANE=$($OUTER list-panes -F '#{pane_id}') || exit 1
|
||||
$OUTER set -g status off || exit 1
|
||||
$OUTER set -g window-size manual || exit 1
|
||||
$OUTER set -g default-terminal screen-256color || exit 1
|
||||
$OUTER send-keys -t "$OUTERPANE" -l "$attachcmd" || exit 1
|
||||
$OUTER send-keys -t "$OUTERPANE" Enter || exit 1
|
||||
sleep 1
|
||||
|
||||
wait_for_client
|
||||
|
||||
i=0
|
||||
while [ "$i" -lt 8 ]; do
|
||||
$INNER send-keys -t inner Enter || exit 1
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
sleep 0.3
|
||||
|
||||
LOG=$(ls tmux-server*.log 2>/dev/null | head -1)
|
||||
[ -n "$LOG" ] || fail "$label: sanity: no server -vv log was produced"
|
||||
|
||||
n=$(grep -c "tty_redraw_region.*large region redraw" "$LOG")
|
||||
|
||||
$OUTER kill-server 2>/dev/null
|
||||
$INNER kill-server 2>/dev/null
|
||||
|
||||
echo "$n"
|
||||
}
|
||||
|
||||
# Phase 1: WT_SESSION present in the attaching client's environment - must
|
||||
# never fall back to a full region redraw.
|
||||
n_with=$(run_scroll_phase "with WT_SESSION" \
|
||||
"WT_SESSION=deadbeef-0000-0000-0000-000000000000 $INNER attach -t inner")
|
||||
[ "$n_with" -eq 0 ] ||
|
||||
fail "with WT_SESSION set, scrolling a scrollbar-enabled pane still fell back to a full region redraw ($n_with times) - margins was not granted"
|
||||
|
||||
# Phase 2: sanity check - without WT_SESSION, the same scenario must
|
||||
# actually hit the fallback, proving phase 1 wasn't accidentally trivial.
|
||||
# Explicitly strip WT_SESSION/WSLENV rather than relying on them being
|
||||
# unset in the ambient environment - this test may itself be run from
|
||||
# inside a real Windows Terminal/WSL session.
|
||||
n_without=$(run_scroll_phase "without WT_SESSION" \
|
||||
"env -u WT_SESSION -u WSLENV $INNER attach -t inner")
|
||||
[ "$n_without" -gt 0 ] ||
|
||||
fail "sanity: without WT_SESSION, scrolling a scrollbar-enabled pane never fell back to a full region redraw - this scenario no longer exercises the bug this test checks for"
|
||||
|
||||
exit 0
|
||||
164
regress/wait-for-client-lost.sh
Normal file
164
regress/wait-for-client-lost.sh
Normal file
@@ -0,0 +1,164 @@
|
||||
#!/bin/sh
|
||||
|
||||
# A disconnected waiter must release both its wait and its command queue.
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
export TERM
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
OUT=$(mktemp -d)
|
||||
TMUX="$TEST_TMUX -S$OUT/socket -f/dev/null"
|
||||
pids=
|
||||
|
||||
cleanup()
|
||||
{
|
||||
for pid in $pids; do
|
||||
kill "$pid" 2>/dev/null || true
|
||||
done
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
wait_list()
|
||||
{
|
||||
expected=$1
|
||||
shift
|
||||
i=0
|
||||
while [ $i -lt 100 ]; do
|
||||
value=$($TMUX wait-for -l "$@") || fail "list waiters failed"
|
||||
[ "$value" = "$expected" ] && return
|
||||
i=$((i + 1))
|
||||
sleep 0.05
|
||||
done
|
||||
fail "expected waiters '$expected', got '$value'"
|
||||
}
|
||||
|
||||
wait_free()
|
||||
{
|
||||
client_pid=$1
|
||||
i=0
|
||||
while [ $i -lt 100 ]; do
|
||||
awk -v pid="$client_pid" '
|
||||
$4 == "IDENTIFY_CLIENTPID" && $5 == pid { address = $3 }
|
||||
address != "" && $2 == "free" && $3 == "client" &&
|
||||
$4 == address && $5 == "(0" { freed = 1 }
|
||||
END { exit !freed }
|
||||
' "$OUT"/tmux-server-*.log && return
|
||||
i=$((i + 1))
|
||||
sleep 0.05
|
||||
done
|
||||
fail "client $client_pid was not freed"
|
||||
}
|
||||
|
||||
cd "$OUT" || exit 1
|
||||
$TMUX -vv new-session -d -s test || fail "new-session failed"
|
||||
$TMUX set -g @continued 0 || fail "set option failed"
|
||||
|
||||
for signal in TERM KILL; do
|
||||
for kind in channel lock event; do
|
||||
name="$kind-$signal"
|
||||
case $kind in
|
||||
channel) args="$name"; list_args="$name" ;;
|
||||
lock)
|
||||
$TMUX wait-for -L "$name" || fail "lock failed"
|
||||
args="-L $name"; list_args="$name"
|
||||
;;
|
||||
event) args="-E @$name"; list_args="-E @$name" ;;
|
||||
esac
|
||||
|
||||
$TMUX wait-for $args \; set -g @continued 1 &
|
||||
dead=$!
|
||||
pids="$dead"
|
||||
wait_list "client-$dead" $list_args
|
||||
|
||||
$TMUX wait-for $args &
|
||||
live=$!
|
||||
pids="$dead $live"
|
||||
wait_list "$(printf 'client-%s\nclient-%s' "$dead" "$live")" \
|
||||
$list_args
|
||||
|
||||
kill -"$signal" "$dead" || fail "kill failed"
|
||||
wait "$dead" 2>/dev/null || true
|
||||
pids="$live"
|
||||
wait_list "client-$live" $list_args
|
||||
wait_free "$dead"
|
||||
[ "$($TMUX show -gqv @continued)" = 0 ] ||
|
||||
fail "disconnected client's next command ran"
|
||||
|
||||
case $kind in
|
||||
channel) $TMUX wait-for -S "$name" || fail "signal failed" ;;
|
||||
lock) $TMUX wait-for -U "$name" || fail "unlock failed" ;;
|
||||
event)
|
||||
$TMUX wait-for -E -w "client-$live" "@$name" ||
|
||||
fail "wake event waiter failed"
|
||||
;;
|
||||
esac
|
||||
wait_list "" $list_args
|
||||
wait_free "$live"
|
||||
wait "$live" || fail "surviving waiter failed"
|
||||
pids=
|
||||
if [ "$kind" = lock ]; then
|
||||
$TMUX wait-for -U "$name" || fail "final unlock failed"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# Removing the last waiter must remove its otherwise unused channel, and must
|
||||
# not create a pending signal. Unrelated pending signals must be preserved.
|
||||
$TMUX wait-for -S saved || fail "save signal failed"
|
||||
$TMUX wait-for last &
|
||||
dead=$!
|
||||
pids="$dead"
|
||||
wait_list "client-$dead" last
|
||||
kill -KILL "$dead" || fail "kill last waiter failed"
|
||||
wait "$dead" 2>/dev/null || true
|
||||
pids=
|
||||
wait_list "" last
|
||||
wait_free "$dead"
|
||||
grep -F 'remove empty wait channel last' "$OUT"/tmux-server-*.log \
|
||||
>/dev/null || fail "empty channel was not removed"
|
||||
|
||||
$TMUX wait-for saved \; wait-for last &
|
||||
live=$!
|
||||
pids="$live"
|
||||
wait_list "client-$live" last
|
||||
$TMUX wait-for -S last || fail "signal last failed"
|
||||
wait_free "$live"
|
||||
wait "$live" || fail "pending signal was not preserved"
|
||||
pids=
|
||||
|
||||
# Source-file leaves a cleanup callback behind the blocked command.
|
||||
printf 'wait-for sourced\nset -g @continued 1\n' >"$OUT/source.conf"
|
||||
$TMUX source-file "$OUT/source.conf" &
|
||||
dead=$!
|
||||
pids="$dead"
|
||||
wait_list "client-$dead" sourced
|
||||
kill -KILL "$dead" || fail "kill source-file waiter failed"
|
||||
wait "$dead" 2>/dev/null || true
|
||||
pids=
|
||||
wait_list "" sourced
|
||||
wait_free "$dead"
|
||||
[ "$($TMUX show -gqv @continued)" = 0 ] ||
|
||||
fail "disconnected source-file client's next command ran"
|
||||
|
||||
# Firing an event after cancellation must not call the removed event sink.
|
||||
$TMUX wait-for -E window-renamed &
|
||||
dead=$!
|
||||
pids="$dead"
|
||||
wait_list "client-$dead" -E window-renamed
|
||||
kill -KILL "$dead" || fail "kill event waiter failed"
|
||||
wait "$dead" 2>/dev/null || true
|
||||
pids=
|
||||
wait_list "" -E window-renamed
|
||||
wait_free "$dead"
|
||||
$TMUX rename-window -t test:0 renamed || fail "rename-window failed"
|
||||
$TMUX display-message -p '#{pid}' >/dev/null || fail "server exited"
|
||||
|
||||
exit 0
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: screen-redraw.c,v 1.160 2026/09/21 10:22:31 nicm Exp $ */
|
||||
/* $OpenBSD: screen-redraw.c,v 1.161 2026/09/22 16:56:07 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1990,7 +1990,7 @@ redraw_draw_pane_prompt(struct redraw_draw_ctx *dctx, struct window_pane *wp)
|
||||
width = sx - px;
|
||||
|
||||
redraw_make_pane_prompt(wp, &screen);
|
||||
tty_draw_line(tty, &screen, 0, offset, width, px, cy, NULL);
|
||||
tty_draw_line(tty, &screen, offset, 0, width, px, cy, NULL);
|
||||
screen_free(&screen);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: server-client.c,v 1.513 2026/09/21 10:22:31 nicm Exp $ */
|
||||
/* $OpenBSD: server-client.c,v 1.514 2026/09/22 06:46:50 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -411,6 +411,9 @@ server_client_lost(struct client *c)
|
||||
TAILQ_REMOVE(&clients, c, entry);
|
||||
log_debug("lost client %p", c);
|
||||
|
||||
cmd_wait_for_client_lost(c);
|
||||
cmdq_next(c);
|
||||
|
||||
if (c->flags & CLIENT_ATTACHED) {
|
||||
server_client_attached_lost(c);
|
||||
events_fire_client("client-detached", c);
|
||||
|
||||
9
tmux.1
9
tmux.1
@@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: tmux.1,v 1.1171 2026/09/21 10:22:31 nicm Exp $
|
||||
.\" $OpenBSD: tmux.1,v 1.1172 2026/09/22 06:58:05 nicm Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
.\"
|
||||
@@ -14,7 +14,7 @@
|
||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: September 21 2026 $
|
||||
.Dd $Mdocdate: September 22 2026 $
|
||||
.Dt TMUX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -5085,6 +5085,9 @@ The available features are:
|
||||
.Bl -tag -width Ds
|
||||
.It 256
|
||||
Supports 256 colours with the SGR escape sequences.
|
||||
.It appesc
|
||||
Supports application escape key mode, where the Escape key sends a sequence
|
||||
that cannot be mistaken for the start of another key.
|
||||
.It clipboard
|
||||
Allows setting the system clipboard.
|
||||
.It ccolour
|
||||
@@ -8841,6 +8844,8 @@ These are set automatically if the
|
||||
capability is present.
|
||||
.It Em \&Dseks , \&Eneks
|
||||
Disable and enable extended keys.
|
||||
.It Em \&Dsesc , \&Enesc
|
||||
Disable and enable application escape key mode.
|
||||
.It Em \&Dsfcs , \&Enfcs
|
||||
Disable and enable focus reporting.
|
||||
These are set automatically if the
|
||||
|
||||
8
tmux.h
8
tmux.h
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tmux.h,v 1.1444 2026/09/21 12:14:32 nicm Exp $ */
|
||||
/* $OpenBSD: tmux.h,v 1.1447 2026/09/22 14:10:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -470,6 +470,7 @@ enum tty_code_code {
|
||||
TTYC_DL1,
|
||||
TTYC_DSBP,
|
||||
TTYC_DSEKS,
|
||||
TTYC_DSESC,
|
||||
TTYC_DSFCS,
|
||||
TTYC_DSMG,
|
||||
TTYC_E3,
|
||||
@@ -480,6 +481,7 @@ enum tty_code_code {
|
||||
TTYC_ENACS,
|
||||
TTYC_ENBP,
|
||||
TTYC_ENEKS,
|
||||
TTYC_ENESC,
|
||||
TTYC_ENFCS,
|
||||
TTYC_ENMG,
|
||||
TTYC_FSL,
|
||||
@@ -1803,6 +1805,7 @@ struct tty_term {
|
||||
#define TERM_IMAGE_QUADRANTS 0x200
|
||||
#define TERM_IMAGE_SEXTANTS 0x400
|
||||
#endif
|
||||
#define TERM_NOREPLACE 0x800
|
||||
int flags;
|
||||
|
||||
LIST_ENTRY(tty_term) entry;
|
||||
@@ -3076,7 +3079,7 @@ void tty_default_colours(struct grid_cell *, struct window_pane *, u_int *);
|
||||
/* tty-term.c */
|
||||
extern struct tty_terms tty_terms;
|
||||
u_int tty_term_ncodes(void);
|
||||
void tty_term_apply(struct tty_term *, const char *, int);
|
||||
void tty_term_apply(struct tty_term *, const char *, int, int);
|
||||
void tty_term_apply_overrides(struct tty_term *);
|
||||
struct tty_term *tty_term_create(struct tty *, char *, char **, u_int, char **);
|
||||
void tty_term_free(struct tty_term *);
|
||||
@@ -3297,6 +3300,7 @@ void cmdq_print_data(struct cmdq_item *, struct evbuffer *);
|
||||
void printflike(2, 3) cmdq_error(struct cmdq_item *, const char *, ...);
|
||||
|
||||
/* cmd-wait-for.c */
|
||||
void cmd_wait_for_client_lost(struct client *);
|
||||
void cmd_wait_for_flush(void);
|
||||
|
||||
/* client.c */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tty-draw.c,v 1.16 2026/09/21 10:22:31 nicm Exp $ */
|
||||
/* $OpenBSD: tty-draw.c,v 1.17 2026/09/22 06:49:47 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -222,7 +222,12 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
|
||||
}
|
||||
|
||||
/* Did the previous line wrap on to this one? */
|
||||
if (py != 0 && atx == 0 && tty->cx >= tty->sx && nx == tty->sx) {
|
||||
if (py != 0 &&
|
||||
atx == 0 &&
|
||||
tty->cx >= tty->sx &&
|
||||
tty->cy != UINT_MAX &&
|
||||
tty->cy + 1 == aty &&
|
||||
nx == tty->sx) {
|
||||
gl = grid_get_line(gd, gd->hsize + py - 1);
|
||||
if (gl->flags & GRID_LINE_WRAPPED)
|
||||
wrapped = 1;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tty-features.c,v 1.43 2026/08/31 12:41:03 kirill Exp $ */
|
||||
/* $OpenBSD: tty-features.c,v 1.45 2026/09/22 14:10:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -189,6 +189,18 @@ static const struct tty_feature tty_feature_focus = {
|
||||
0
|
||||
};
|
||||
|
||||
/* Terminal supports application escape key mode. */
|
||||
static const char *const tty_feature_appesc_capabilities[] = {
|
||||
"Enesc=\\E[?7727h",
|
||||
"Dsesc=\\E[?7727l",
|
||||
NULL
|
||||
};
|
||||
static const struct tty_feature tty_feature_appesc = {
|
||||
"appesc",
|
||||
tty_feature_appesc_capabilities,
|
||||
0
|
||||
};
|
||||
|
||||
/* Terminal supports cursor styles. */
|
||||
static const char *const tty_feature_cstyle_capabilities[] = {
|
||||
"Ss=\\E[%p1%d q",
|
||||
@@ -198,7 +210,7 @@ static const char *const tty_feature_cstyle_capabilities[] = {
|
||||
static const struct tty_feature tty_feature_cstyle = {
|
||||
"cstyle",
|
||||
tty_feature_cstyle_capabilities,
|
||||
0
|
||||
TERM_NOREPLACE
|
||||
};
|
||||
|
||||
/* Terminal supports cursor colours. */
|
||||
@@ -408,6 +420,7 @@ static const struct tty_feature tty_feature_utf8 = {
|
||||
/* Available terminal features. */
|
||||
static const struct tty_feature *const tty_features[] = {
|
||||
&tty_feature_256,
|
||||
&tty_feature_appesc,
|
||||
&tty_feature_bpaste,
|
||||
&tty_feature_ccolour,
|
||||
&tty_feature_clipboard,
|
||||
@@ -576,11 +589,11 @@ tty_apply_features(struct tty_term *term)
|
||||
capability = tf->capabilities;
|
||||
while (*capability != NULL) {
|
||||
log_debug("adding capability: %s", *capability);
|
||||
tty_term_apply(term, *capability, 1);
|
||||
tty_term_apply(term, *capability, 1, tf->flags);
|
||||
capability++;
|
||||
}
|
||||
}
|
||||
term->flags |= tf->flags;
|
||||
term->flags |= (tf->flags & ~TERM_NOREPLACE);
|
||||
if (tf == &tty_feature_utf8)
|
||||
c->flags |= CLIENT_UTF8;
|
||||
}
|
||||
@@ -603,6 +616,7 @@ tty_default_features(struct client *c, const char *name, u_int version)
|
||||
"256,RGB,bpaste,clipboard,mouse,strikethrough,title"
|
||||
{ .name = "mintty",
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM ","
|
||||
"appesc,"
|
||||
"ccolour,"
|
||||
"cstyle,"
|
||||
"extkeys,"
|
||||
@@ -658,6 +672,7 @@ tty_default_features(struct client *c, const char *name, u_int version)
|
||||
"extkeys,"
|
||||
"focus,"
|
||||
"hyperlinks,"
|
||||
"margins,"
|
||||
"sixel,"
|
||||
"usstyle"
|
||||
},
|
||||
@@ -667,6 +682,7 @@ tty_default_features(struct client *c, const char *name, u_int version)
|
||||
"cstyle,"
|
||||
"extkeys,"
|
||||
"focus,"
|
||||
"margins,"
|
||||
"overline,"
|
||||
"hyperlinks,"
|
||||
"osc7,"
|
||||
@@ -710,6 +726,22 @@ tty_default_features(struct client *c, const char *name, u_int version)
|
||||
"cstyle,"
|
||||
"extkeys,"
|
||||
"focus"
|
||||
},
|
||||
/*
|
||||
* Windows Terminal cannot be identified by the XTVERSION
|
||||
* mechanism used for the other entries above - its
|
||||
* maintainers have declined to implement it (see
|
||||
* github.com/microsoft/terminal issue 18382). It is instead
|
||||
* detected via the WT_SESSION environment variable it sets
|
||||
* for every child process (tty_term_create(), tty-term.c).
|
||||
* DECSLRM support was independently confirmed by direct
|
||||
* (non-tmux) testing; other capabilities have not been
|
||||
* verified, so only margins is granted here - deliberately
|
||||
* not the full modern-xterm feature bundle other entries
|
||||
* get.
|
||||
*/
|
||||
{ .name = "WindowsTerminal",
|
||||
.features = "margins"
|
||||
}
|
||||
};
|
||||
u_int i;
|
||||
|
||||
21
tty-term.c
21
tty-term.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tty-term.c,v 1.109 2026/08/25 08:37:08 nicm Exp $ */
|
||||
/* $OpenBSD: tty-term.c,v 1.111 2026/09/22 14:10:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -90,6 +90,7 @@ static const struct tty_term_code_entry tty_term_codes[] = {
|
||||
[TTYC_DL1] = { TTYCODE_STRING, "dl1" },
|
||||
[TTYC_DL] = { TTYCODE_STRING, "dl" },
|
||||
[TTYC_DSEKS] = { TTYCODE_STRING, "Dseks" },
|
||||
[TTYC_DSESC] = { TTYCODE_STRING, "Dsesc" },
|
||||
[TTYC_DSFCS] = { TTYCODE_STRING, "Dsfcs" },
|
||||
[TTYC_DSBP] = { TTYCODE_STRING, "Dsbp" },
|
||||
[TTYC_DSMG] = { TTYCODE_STRING, "Dsmg" },
|
||||
@@ -101,6 +102,7 @@ static const struct tty_term_code_entry tty_term_codes[] = {
|
||||
[TTYC_ENACS] = { TTYCODE_STRING, "enacs" },
|
||||
[TTYC_ENBP] = { TTYCODE_STRING, "Enbp" },
|
||||
[TTYC_ENEKS] = { TTYCODE_STRING, "Eneks" },
|
||||
[TTYC_ENESC] = { TTYCODE_STRING, "Enesc" },
|
||||
[TTYC_ENFCS] = { TTYCODE_STRING, "Enfcs" },
|
||||
[TTYC_ENMG] = { TTYCODE_STRING, "Enmg" },
|
||||
[TTYC_FSL] = { TTYCODE_STRING, "fsl" },
|
||||
@@ -362,7 +364,8 @@ tty_term_override_next(const char *s, size_t *offset)
|
||||
}
|
||||
|
||||
void
|
||||
tty_term_apply(struct tty_term *term, const char *capabilities, int quiet)
|
||||
tty_term_apply(struct tty_term *term, const char *capabilities, int quiet,
|
||||
int flags)
|
||||
{
|
||||
const struct tty_term_code_entry *ent;
|
||||
struct tty_code *code;
|
||||
@@ -405,6 +408,9 @@ tty_term_apply(struct tty_term *term, const char *capabilities, int quiet)
|
||||
if (strcmp(s, ent->name) != 0)
|
||||
continue;
|
||||
code = &term->codes[i];
|
||||
if ((flags & TERM_NOREPLACE) &&
|
||||
code->type != TTYCODE_NONE)
|
||||
continue;
|
||||
|
||||
if (remove) {
|
||||
code->type = TTYCODE_NONE;
|
||||
@@ -457,7 +463,7 @@ tty_term_apply_overrides(struct tty_term *term)
|
||||
offset = 0;
|
||||
first = tty_term_override_next(s, &offset);
|
||||
if (first != NULL && fnmatch(first, term->name, 0) == 0)
|
||||
tty_term_apply(term, s + offset, 0);
|
||||
tty_term_apply(term, s + offset, 0, 0);
|
||||
a = options_array_next(a);
|
||||
}
|
||||
|
||||
@@ -640,6 +646,15 @@ tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps,
|
||||
tty_parse_client_features(c, "256", ",");
|
||||
}
|
||||
|
||||
/*
|
||||
* Windows Terminal cannot be identified by XTVERSION (its
|
||||
* maintainers have declined to implement it), but it sets
|
||||
* WT_SESSION for every child process - see the WindowsTerminal
|
||||
* entry in tty_default_features()'s table (tty-features.c).
|
||||
*/
|
||||
if (environ_find(c->environ, "WT_SESSION") != NULL)
|
||||
tty_default_features(c, "WindowsTerminal", 0);
|
||||
|
||||
/* Apply overrides so any capabilities used for features are changed. */
|
||||
tty_term_apply_overrides(term);
|
||||
|
||||
|
||||
8
tty.c
8
tty.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tty.c,v 1.481 2026/09/21 10:22:31 nicm Exp $ */
|
||||
/* $OpenBSD: tty.c,v 1.482 2026/09/22 06:58:06 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -512,8 +512,7 @@ tty_stop_tty(struct tty *tty)
|
||||
if (tty_term_has(tty->term, TTYC_DSBP))
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSBP));
|
||||
|
||||
if (tty->term->flags & TERM_VT100LIKE)
|
||||
tty_raw(tty, "\033[?7727l");
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSESC));
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSFCS));
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSEKS));
|
||||
|
||||
@@ -583,8 +582,7 @@ tty_update_features(struct tty *tty)
|
||||
tty_puts(tty, tty_term_string(tty->term, TTYC_ENEKS));
|
||||
if (options_get_number(global_options, "focus-events"))
|
||||
tty_puts(tty, tty_term_string(tty->term, TTYC_ENFCS));
|
||||
if (tty->term->flags & TERM_VT100LIKE)
|
||||
tty_puts(tty, "\033[?7727h");
|
||||
tty_puts(tty, tty_term_string(tty->term, TTYC_ENESC));
|
||||
|
||||
/*
|
||||
* Features might have changed since the first draw during attach. For
|
||||
|
||||
Reference in New Issue
Block a user