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>
Brings in the WezTerm/ghostty/Windows Terminal DECSLRM (margins) coverage
from margins-terminal-detection (PR #5630), plus whatever independent
upstream progress that branch's master base had accumulated since this
branch last merged from master.
Conflict in screen-redraw.c's redraw_draw_pane_prompt(): this branch's own
earlier refactor (extracting redraw_make_pane_prompt(), reused by both the
normal redraw path and the Finding-2 damage-composition fix) collided with
an independent upstream fix on master (nicm, "Get x and y the right way
round, fixes crash when opening a mode prompt when the client is offset
into the window") that swapped tty_draw_line()'s px/py argument order in
this same function - this branch had diverged before that fix landed and
still had the pre-fix (buggy) order. Resolved by keeping this branch's
own refactor with the corrected argument order, verified against
tty_draw_line()'s signature (px, py - the prompt's screen is always
exactly one row, so py must be 0 and px must be the horizontal offset;
the pre-fix order passed the offset as the row instead, matching the
described crash). The other, structurally identical call site added this
session for Finding 2 (redraw_damage_draw_pane_prompt()) already had the
correct order and needed no change.
Verified: build clean; the new tty-margins-wt-session.sh and this
session's existing wide-character/prompt/cross-client tests all pass
(3x each); full regress suite passes clean twice, with only the same
pre-existing, unrelated failures already characterized this session
(prompt-words-history.sh, and untracked image-*-noflash scratch tests
from unrelated work, absent from this branch's own tracked suite).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* refs/remotes/tmux-openbsd/master:
Add a feature for mintty's application escape to avoid dodgy terminals whinging about not supporting it, GitHub issue 5626 from Pete Dietl.
Only rely on the previous line wrapping when the cursor is actually on it, GitHub issue 5625 from Ben Maurer.
Correctly write Z indexes to v2 layouts if zoomed, GitHub issue 5624.
Do not leak waiting clients (in wait-for) if they are killed, GitHub issue 5614.
`(~c->flags & CLIENT_ALLREDRAWFLAGS)` - for a multi-bit mask, ~x & MASK
means "at least one of these bits is unset" (almost always true), not
"none of these bits are set" as the comment and surrounding logic
clearly intend. Every floating-pane drag command unconditionally sets
CLIENT_REDRAWBORDERS (server_redraw_window_borders(), called from
cmd-resize-pane.c/cmd-join-pane.c/cmd-split-window.c) alongside
reporting window damage, so this fallback fired on every single drag
step: redraw_client_damage(c) ran here, then ran again a few lines
later at the CLIENT_ALLREDRAWFLAGS block for the exact same
rectangles. Confirmed via the server's own -vv log: a 6-step drag
produced 12 "composing damage" lines in matched pairs (identical
position and size, milliseconds apart) with no fix, 6 with it.
No memory-safety issue - redraw_client_damage() only reads w->damage,
never frees it - just wasted work rendering the same rectangles twice
per pass.
Fix: `(c->flags & CLIENT_ALLREDRAWFLAGS) == 0`, matching the comment's
actual intent.
regress/floating-pane-drag-no-double-composite.sh drags a floating
pane and asserts no two consecutive "composing damage" log lines share
the same position and size (comparing both together, since distinct
drag steps commonly share the same rectangle size and only the
position differs). Verified failing 3/3 against the pre-fix code (all
6 rectangles doubled each run) and passing 5/5 against the fix.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
server_client_key_callback()'s mouse-drag dispatch opens a
synchronized-output frame (tty_sync_start()) before running the drag
callback, on every single drag motion event - deliberately, so a fast-
path write and any later damage-composed correction land in one atomic
terminal update instead of two visible frames. But
server_client_check_redraw() later in the same pass checks
EVBUFFER_LENGTH(tty->out) != 0 to decide whether to defer this pass's
redraw, and nothing drains tty->out in between (the actual write
happens later, via libevent) - so the frame-open sequence just queued
(8 bytes: "\033[?2026h" on a synchronized-output-capable terminal)
makes that check see "outstanding output" and defer against itself,
escalating the drag's damage to a full-window redraw on every single
motion event. Confirmed via the server's own -vv log: a 6-step drag
produced five "redraw deferred (8 left)" lines, one per motion event,
with no fix.
Fix: record how much was already queued at the instant the sync frame
opened (tty->sync_offset), and have the redraw check discount
anything queued after that point - it's already part of the frame
this pass is committed to flushing, not a reason to defer. If the
buffer was genuinely non-empty before the frame opened, sync_offset
holds that real backlog and deferral still happens correctly.
regress/floating-pane-drag-sync-no-self-defer.sh drags a floating pane
on a synchronized-output-capable terminal and asserts the server log
never shows the self-inflicted 8-byte deferral. Verified failing 3/3
against the pre-fix code (5 occurrences per run, matching the manual
-vv repro) and passing 5/5 against the fix.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* refs/remotes/tmux-openbsd/master:
Remove popups and all the associated overlay machinery (they were the last user of it). display-popup stays but becomes an (undocumented) compatibility command to open a floating pane.
Fix typo (too few 0s) in CLIENT_CONTROL_DISCARD, from someone in GitHub issue 5622.
window_pane_redraw_floating() (called by every floating-pane drag/resize
command) had two conflicting redraw paths: a precise damage-rectangle
path for the dragged pane, and an unconditional server_redraw_window()
added to fix border-status recomposition (aa6b52ef) that silently
defeated it, redrawing every pane - including retransmitting unrelated
images - on every drag tick.
Chasing the border-status bug back further: it was actually caused by
an upstream regression (824a0729) that split CLIENT_REDRAWWINDOW's
redraw flags into REDRAW_ALL vs. REDRAW_ALL & ~REDRAW_OVERLAY, silently
breaking every literal `flags == REDRAW_ALL` check downstream
(REDRAW_IS_ALL()), including the one that decides whether a pane's
border-status title should be forced to recompose even when its text
hasn't logically changed. Fix this properly instead of reaching for
server_redraw_window() again: decouple overlay-drawing from the shared
flags value (it's only ever read in the one place that repaints an
overlay) so redraw_screen() can pass a genuinely literal REDRAW_ALL for
a window redraw. This also fixes a second-client-attach bug where a new
client's pane titles never appeared until their text changed, since the
per-pane title cache is shared across clients.
Also fixed a real, independent bug in server-client.c found along the
way: `~c->flags & CLIENT_ALLREDRAWFLAGS` is a 6-bit mask, so `~x & MASK`
tests "any bit unset" (almost always true) rather than "no bits set" as
intended - causing damage to be composed and transmitted twice on every
floating-drag tick.
With server_redraw_window() gone, a second problem surfaced: deferred
client redraws (common under a busy tty) still escalated any pending
window damage to a full CLIENT_REDRAWWINDOW redraw, because
server_client_loop() frees w->damage unconditionally every pass with no
tracking of whether a deferred client actually got to consume it. Fix
this by giving each client a copy of missed damage (c->pending_damage,
reusing the existing merge/collapse/16-entry-cap logic damage lists
already have) keyed by the window's id, so a client can compose it
precisely on a later pass instead of resending everything. Window ids
are monotonic and never reused, so a stale id is enough to detect and
discard damage left over from a window the client has since switched
away from or that has been destroyed.
Verified with regress/image-border-status-wipe.sh,
regress/floating-pane-drag-scrollbar-strip.sh,
regress/image-movepane-drag-noflash.sh, and
regress/image-splitwindow-resize-noflash.sh (5 runs each), the full
regress suite (twice), an ASAN/UBSAN debug build, and manual repros for
a window switch and a window destroy mid-defer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* refs/remotes/tmux-openbsd/master:
Add remain-on-exit failed-key and a -D flag to new-pane to have a modal pane wait for Escape/C-c. Both to allow better compatibility with popups.
Fixes the four bugs caught by the regression tests added in aed1209c
(popup-drag-status-line.sh, popup-drag-wide-character.sh,
popup-drag-pane-prompt.sh, switch-client-redraw.sh), based on fixes
from Michael K. Darling (github.com/darlingm/tmux, pr5516-regression-
fixes), reviewed and adapted:
- server-client.c: server_client_set_session()'s check for whether the
client's window actually changed compared old->curw to s->curw, but
when old == s these read the same, already-updated field, so a
same-session window switch was never detected. Compare against the
client's own cached redraw scene instead (redraw_client_has_window(),
new in screen-redraw.c/tmux.h). Taken from darlingm as-is.
- popup.c: popup_damage() only translated a popup's client-coordinate
rectangle into window coordinates, so a popup dragged across the
status line never triggered a status-line redraw once it moved away -
status_redraw()'s own "skip if content unchanged" optimization
suppressed it, since only the popup moved, not the status content.
Now detects overlap with the status line and forces a redraw via the
existing (previously unused) CLIENT_REDRAWSTATUSALWAYS flag, and
properly clips the reported rectangle to the pane area for
status-at-top/bottom/off. Taken from darlingm as-is.
- screen-redraw.c: redraw_draw_damage_rect() clipped a span to a damage
rectangle's raw geometric edges, which have no idea what's in the
grid, so a clip edge could land mid-character and tear a wide
character in half. Added redraw_damage_grow_span_clip(): widen the
clip by one cell on each edge that isn't already at the span's own
boundary. Reimplemented simpler than darlingm's version (which walked
grid cells per span type via a switch and direct grid lookups) -
since no grid cell is ever wider than two columns, an unconditional
one-cell margin is always enough to pull a split character back in,
with no need to inspect grid content at all.
- screen-redraw.c: redraw_draw_damage_rect() also never re-overlaid a
pane's active in-pane prompt after drawing its underlying content, so
damage crossing a prompt row erased it until an unrelated redraw
restored it. Factored the existing full-redraw prompt-building code
into a shared redraw_make_pane_prompt() helper and added
redraw_damage_draw_pane_prompt(), which recomposes the prompt over
the drawn range. Taken from darlingm as-is.
All 9 regression tests in regress/ now pass. redraw_damage_grow_span_clip
was verified independently by disabling it and confirming
popup-drag-wide-character.sh reproduces its original failure.
Co-Authored-By: Michael K. Darling <darlingm@gmail.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* refs/remotes/tmux-openbsd/master:
Do not leak exit message on client free, from Jeong, Heon.
Tidy up args_make_commands reference counting to fix a memory leak, from Jeong, Heon.
* refs/remotes/tmux-openbsd/master:
Correct a comparison ('\0' should be 0).
If a pane has no scrollbar, don't bother to redraw it, and if redraw is deferred change scrollbar redraws into redraw-all-scrollbars not redraw entire window. GitHub issue 5529.
* refs/remotes/tmux-openbsd/master:
Do not leak cached status line, from Jeong, Heon.
Free pane fallback range when freeing pane, from Jeong, Heon.
Do not leak path when destroying client, from Jeong, Heon.
Do not leak format when drawing preview, from Jeong, Heon.
Do not leak buffer name on failure, from Jeong, Heon.
redraw_client_damage() (added previously, unused until now) is called
from server_client_check_redraw()'s normal redraw pass, and
server_client_any_pane_redraw() now also checks for pending window
damage so a client with only damage (no PANE_REDRAW/PANE_REDRAWSCROLLBAR
flags) still gets its redraw pass run.
server_client_check_redraw() now returns whether the redraw was deferred
(waiting for outstanding tty output to drain) rather than performed. A
deferred redraw no longer escalates to a full CLIENT_REDRAWWINDOW to
avoid losing what was pending - server_client_loop() now only clears
PANE_REDRAW, PANE_REDRAWSCROLLBAR and window damage once every client
viewing a window actually drew this pass (tracked via a new per-window
redraw_deferred flag), otherwise they're left in place and retried in
their normal, narrowly-scoped form.
server_client_set_session() now redraws only if the client's session or
current window actually changed, not on every call (e.g. switch-client
-t= from clicking a pane name in the status line resolves here even
when nothing besides the active pane changed).
A drag callback's mouse_drag_update() now opens a sync region itself
(tty_sync_start()) before its first write, so a fast-path write it makes
directly and a later correction arriving via redraw_client_damage() end
up in the same atomic terminal update instead of two visible frames.
* refs/remotes/tmux-openbsd/master:
If writing a file fails, propagate the error to the server via a new message. Use a client flag rather than bumping the protocol version. GitHub issue 5451.
Add default terminal features for Rio, GitHub issue 5489 from Raphael Amorim.
* refs/remotes/tmux-openbsd/master:
Do not attempt to drain write buffer on stuck clients, since it requires a weird dance to make libevent do it. Instead, just ignore the client and destroy the buffer normally if not drained in 10 seconds.
* refs/remotes/tmux-openbsd/master:
Do not let a stuck client prevent the server from exiting - give up after 10 seconds. GitHub issue 5444 from Ben Maurer.
* refs/remotes/tmux-openbsd/master:
Clip floating panes exactly at window edge, don't let the border creep into the first outside column.
Invalidate scene when window is resized.
Add a -C flag to new-pane to have a modal pane close when the mouse is clicked outside it, GitHub issue 5400.
* refs/remotes/tmux-openbsd/master:
Remove the active-pane flag for now, there are some gaps in how this works and I don't like it. May come back in a different form (maybe just for windows).