There is no way to query a terminal for whether it moves SIXEL image
content along with the rest of a scrolling region, so tmux always
redrew the image after every scroll rather than assuming the terminal
did it for free the way Kitty placements already are (IMAGE_BACKEND_
SCROLLS). Add a server option, default on, that lets sixel opt into the
same trust; image_backend_flags() now ORs SCROLLS in for the sixel
backend when it's set.
Splitting SCROLLS out surfaced a second, unrelated property the two
image_backend_flags() checks had been conflating: whether a backend
also respects its own cell boundaries rather than bleeding pixels onto
neighbouring rows, which is what the "redraw a pane's border-status
after a GRAPHICAL-only redraw" guard in screen-redraw.c was actually
testing for. Give that its own IMAGE_BACKEND_CLIPPED flag (kitty only)
so turning sixel-region-scrolling on doesn't also disable that
unrelated border-status protection.
Includes a regress test proving the scroll-skip decision is wired
correctly with the option on and off, and a manual visual test
(tools/sixel-scroll-region-test.sh + tools/sixel-ruler.six, a numbered
colour-band SIXEL image) for checking real terminals by eye, since nothing
here can verify what a given terminal actually renders.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
With ENABLE_IMAGES compiled in, the primary DA reply correctly grows
from "\033[?1;2c" (7 bytes) to "\033[?1;2;4c" (9 bytes), advertising
sixel support. The test still expected the old byte count, so it read
only the first 7 bytes of the new reply and reported the truncation
point as a corrupted terminator. Check #{image_support} and expect
whichever reply matches the build.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The test's session used the default $SHELL - the developer's own
interactive bash, whose PS1 embeds an OSC 0 title-setter for tmux/xterm
TERM types (common on this machine, not test-controlled). That redrew
the terminal title on every prompt, clobbering the test's own
OSC-2-set-title assertions regardless of how long it waited afterwards.
Use bash --noprofile --norc, matching the pattern already used by
style-trim.sh.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
layout_append() returned failure for the version 1 (old) layout format
when a window's tree has no tiled cell anywhere - e.g. a window left
with only floating panes after the last tiled pane closed. layout_dump()
turns that failure into NULL, surfacing as an empty #{window_layout}
instead of the minimal valid placeholder body a control client or
select-layout round-trip expects. Return success with nothing written
instead, which composes into the checksum-prefixed empty body via the
existing formatting path.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-c was taken as a literal string, so run-shell -c '#{pane_current_path}'
tried to chdir into that literal text instead of the target pane's
directory, silently falling back to the server's own cwd. Expand it
through a format tree built from the command's target the same way the
shell-command argument already is.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
For window-size manual, clients_calculate_size() always returned
xpixel/ypixel as 0, even though the window's real w->xpixel/ypixel are
usually nonzero. recalculate_size()'s "did anything actually change"
check compares the computed size against the window's current size
before deciding whether to call resize_window() again, and a 0 vs.
nonzero pixel mismatch meant that check could never match for a
manually-sized window - so any unrelated recalculate_size() call (e.g.
another client disconnecting) re-ran resize_window() and re-fired
window-resized with stale old-size data, even though nothing about the
window had changed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
format_cb_session_bell_flag() and its activity/silence siblings had
their "not set" return inside the RB_FOREACH loop, so they only ever
examined the first winlink in tree order and returned immediately
regardless of its state - never checking any other window in the
session. The silence variant also read ft->wl (the display target)
instead of the loop variable, so it ignored the window it was even
supposed to be looking at.
Move the "not set" return after the loop so every winlink is checked,
and use the loop variable throughout.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
window_destroy() called window_unzoom() before tearing anything down.
layout_fix_panes() inside that resizes panes, which fires the
pane-resized hook; the hook's event payload takes and drops its own
reference on the window, and since w->references was already 0 at that
point, dropping it reached 0 again and re-entered window_destroy() from
inside itself - freeing w and its panes while the outer call was still
using them.
Pin the window's reference count across window_unzoom() so that
reentrant drop can't reach zero again.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
utf8_add_to_width_cache() looped `for (wc = wc_start; wc <= wc_end; wc++)`
with wc a signed wchar_t. Setting codepoint-widths to a range ending at
exactly WCHAR_MAX (e.g. U+7FFFFFFF) made wc overflow to a negative value
on increment, so the loop condition stayed true forever - an unbounded
insert loop that crashes the server. Iterate with an explicit break after
processing wc_end instead of relying on post-increment comparison.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The redraw loop hands images to the sixel backend one grid line at a
time, so a placement N rows tall arrives as N separate one-row
rectangles - each a full scale/encode pass and its own DCS sequence
carrying its own copy of the palette. Hold a run of vertically
adjacent rows back in struct sixel_output and write it as a single
SIXEL once the run ends (image_draw_flush, called from the redraw
loop after each pane/line pass).
Also make image_tty_update() report whether the backend actually
changed, and skip the client redraw in tty_update_features() when it
didn't. That function runs on every DA/secondary DA/extended DA
answer, most of which just confirm what's already known; the redraw
it triggers repaints from tmux's grid and discards anything a pane
wrote via DCS passthrough that tmux doesn't model - visibly flashing
images away right after they're drawn.
Ported from paranoidi's fork (commit 98cc26d) onto the damage-rectangle
based redraw introduced on this branch; the three image_draw_flush()
call sites are placed at the equivalent point in redraw_draw_pane_lines(),
redraw_draw_lines(), and redraw_draw_damage_rect(). Verified against
tmux/tmux#5445.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* refs/remotes/tmux-openbsd/master:
Rather than allowing floating panes to remain outside the window and invisible after resize, move them and resize them so they are fully inside the window. GitHub issue 5582 from Noam Stolero.
* 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.
* refs/remotes/tmux-openbsd/master:
Add a nesting limit for v1 layouts, reported by M Khalilov, fix based on issue 5572 from Afonso Januário. Also tweak some language while here.
* refs/remotes/tmux-openbsd/master:
Draw bottom border with pane status line at the top.
Bound the memory used by buffered control mode command replies (to 64 MB), GitHub issue 5565 from kagari dot shusei at proton dot me.
Do not adjust prompt position on invalid Unicode, from Kaixuan Li.
* refs/remotes/tmux-openbsd/master:
Add new layout format which includes floating panes. The new format is now a JSON subset which is less fragile and easier to handle than the old custom format. The old (version 1) format is still supported for control mode clients for now - they must set the new-layouts flag to receive the new format. From Dane Jensen.
now a JSON subset which is less fragile and easier to handle than the
old custom format. The old (version 1) format is still supported for
control mode clients for now - they must set the new-layouts flag to
receive the new format. From Dane Jensen.
* refs/remotes/tmux-openbsd/master:
Add a function to find last pane index, from Dane Jensen.
Add a parser for a subset of JSON, will be used for new layout strings (and maybe some other stuff), from Dane Jensen.
Add capture-pane -I to show times.