image_write() handles an image taller than the pane by scrolling the
screen up to make room, but only ever created spans for the rows that
ended up on screen afterwards - the rows immediately scrolled off (up to
origin_y of them) were pushed into history as blank, spanless rows and
that part of the image was permanently discarded. Unlike width, which has
no "scroll right" to recover a permanent clip, height already has
ordinary scrollback, so this was pure waste: scrolling back up just
showed empty space where part of the image used to be.
image_write() now also calls image_extend_row() for those origin_y rows,
capped to however many real history rows screen_write_scrollup() actually
created (it clamps its own request to one scroll-region height per call,
so a single call may not push everywhere origin_y implies - looping it
until the full amount is pushed, done here too, makes that gap rare, but
the cap keeps the fill-in safe even if it isn't).
window_copy_write_one() used to write text/highlight styling directly
over image-covered cells via the normal path, which - since a character
write typically clears whatever pixel content a terminal was showing
there - erased the image with nothing to redraw it back in. Image-covered
cells now bypass styling and go straight into the grid instead (a
non-graphical client's ASCII fallback for the image still depends on this
same write, so it can't just be skipped).
window_copy_write_line()'s call to image_redraw_area() used to fire
unconditionally on every redraw, needlessly recompositing (and briefly
flashing) the image on every single cursor step even after the erasure
above was fixed, even though nothing about the image had changed. It now
only fires when window_copy_update_image_refresh() (new) determines the
view's underlying history position actually moved since the last redraw.
Also adds window_copy_visible_has_images(), used by a later commit's
scroll-region fix as a bypass to a full redraw when the visible range
carries image data - line insert/delete only shifts character cells, not
already-sent image pixels, so scroll's normal fast path leaves stale or
missing image content behind.
image_write() only ever creates spans for as much of an image as fit in
the pane at the time it was placed - the rest of the image's pixels are
still retained (struct image is immutable and kept for as long as any
placement references it), but nothing revisited that clipping decision,
so a pane that was too narrow when an image was displayed stayed clipped
forever, even after growing wide enough to fit the rest. Unlike height,
which recovers via ordinary scrollback, there is no equivalent "scroll
right" - this is the only way the extra width is ever recovered.
image_grid_resize_width() finds every placement referenced in a grid's
rows, works out how far its spans already reach and its origin column,
and extends them (via a new image_extend_row(), factored out of
image_write()'s own span-building loop) up to whichever is smaller: the
image's own full width or the new pane width. window_pane_resize() calls
it after a pane grows wider.
image_redraw_area() used to unconditionally flag the whole pane
(PANE_REDRAW) whenever any part of it needed an image recomposited - a
pane can be much taller than the area actually disturbed (a small scroll
region, or a single line insert/delete far from where an image sits), so
this erased and retransmitted every image anywhere in the pane regardless
of proximity to the affected area. Report damage for just the area via
redraw_damage_window() instead.
image_redraw_scroll() similarly now scopes to the current scroll region
rather than redrawing the whole pane via image_redraw_all().
window_make_pane_status() gates physical redraw of border-status text on
a logical content diff, not physical damage - if something else disturbs
those cells, the text stays blank because tmux believes nothing changed.
This test currently fails and is expected to keep failing until the
general damage-tracking redraw work lands (see IMAGE-REDRAW-PLAN.md).
Three adjacent blocks shared one 'set -as terminal-features' setting
with contradictory requirements - fallback text, then real SIXEL, then
fallback text again in a single client attach. terminal-features is
only detected at client attach, not live, so this needs detach/reattach
between blocks rather than toggling the option in place.
image_redraw_start() was called with a pane's full nominal geometry
rather than the cells it actually owns in the current scene. When a
floating pane occluded part of that rectangle, the erase blanked the
floating pane's on-screen content, and the following text redraw
correctly skipped those cells (not owned by this pane), leaving them
blank with nothing to restore them.
Scale SIXEL rasters uniformly when clients have different cell dimensions, while retaining the original logical cell canvas as blank padding.
Map crops using real cell boundaries so partial final cells are not stretched or compressed.
Replace the per-cell image marker with sparse placement spans attached to
grid lines. A placement owns all of its spans and records the input
protocol, application image and placement IDs, z-index, and creation order.
This retains overlapping image layers without storing a list in every grid
cell. Grid operations move, split, clip, and remove only the affected spans.
Use the input protocol to determine image/text interaction: later text
damages SIXEL spans, while Kitty placements remain and are ordered by their
z-index. Rendering then adapts that one logical scene for each client,
rather than changing its semantics according to whether the outer terminal
uses Kitty or SIXEL.
mage reference. Deferred pane redraws explain the intermittent “image never appears” behavior.
Fixed:
- Preserves image metadata while updating the text underlay in the collected ASCII path: grid.c:779
- Handles the single-cell/non-ASCII path and schedules an image redraw: screen-write.c:2631
- Uses the requested if/else for new_id.
- Adds a deterministic regression reproducing point (2): regress/image-support.sh:240
This matches Kitty’s requirement that normal text operations must not affect graphics; graphics require
explicit deletion. Kitty graphics protocol