Commit Graph

12127 Commits

Author SHA1 Message Date
Michael Grant
84a2ccdbcb build: warn that --enable-sixel is deprecated 2026-08-25 12:02:20 +01:00
Michael Grant
87400d67b0 Improve image fallback rendering 2026-08-25 11:53:39 +01:00
Michael Grant
2a535f7d82 image: keep the scrolled-off portion of a placement instead of discarding it
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).
2026-08-25 11:24:14 +01:00
Michael Grant
4e2abff2d6 window-copy: avoid erasing and needlessly re-flashing images during copy-mode redraws
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.
2026-08-25 11:24:14 +01:00
Michael Grant
e40ef98b1e image: extend existing placements when a pane grows wider
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.
2026-08-25 11:24:14 +01:00
Michael Grant
ebb44d4715 image: report damage narrowly instead of flagging the whole pane for redraw
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().
2026-08-25 11:24:14 +01:00
Michael Grant
e63e4fe0d0 regress: add failing test for border-status redraw bug
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).
2026-08-25 11:23:52 +01:00
Michael Grant
f42cc5d956 regress: fix contradictory terminal-features assertions in image-support.sh
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.
2026-08-25 11:23:52 +01:00
Michael Grant
56e9ca2dbe screen-redraw: erase only cells a pane owns, not its raw rectangle
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.
2026-08-25 11:23:52 +01:00
Michael Grant
a80e2d1af7 sixel: preserve image aspect across client geometries
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.
2026-08-25 11:23:52 +01:00
Michael Grant
b094564203 build: rename image support option 2026-08-25 11:23:52 +01:00
Michael Grant
c0e38f3748 Cleanup and simplification. 2026-08-25 11:23:52 +01:00
Michael Grant
45f32d71ef Fix indents. 2026-08-25 11:23:52 +01:00
Michael Grant
40cd869d77 Readability and clarity. 2026-08-25 11:23:52 +01:00
Michael Grant
4c3983e286 image: add manual visual checks 2026-08-25 11:23:52 +01:00
Michael Grant
c2426fcf08 image: preserve fractional cell extents 2026-08-25 11:23:52 +01:00
Michael Grant
c97ceaffe8 image: select backend after terminal setup 2026-08-25 11:23:52 +01:00
Michael Grant
047308b156 image: retain ordered placements in the grid
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.
2026-08-25 11:23:52 +01:00
Michael Grant
cf80845be7 Change some names of things for clarity. 2026-08-25 11:23:52 +01:00
Michael Grant
b6dbf10057 Redraw SIXEL images before or after text depending on which was placed first in the cell. 2026-08-25 11:23:52 +01:00
Michael Grant
54d3f77c2c The implementation now distinguishes a newly placed image cell from one later overwritten by text. On a SIXEL terminal, damaged cells are omitted from image output; on Kitty they remain ordinary positional placements. 2026-08-25 11:22:26 +01:00
Michael Grant
ed63826b15 Cleanup. 2026-08-25 11:22:26 +01:00
Michael Grant
b89f8b0624 Update Kitty image names 2026-08-25 11:22:26 +01:00
Michael Grant
c1cab6ea34 More cleanup of "histogram" name. 2026-08-25 11:22:26 +01:00
Michael Grant
89a7dcc8ab Shorten image and SIXEL names 2026-08-25 11:22:26 +01:00
Michael Grant
48b6641d97 Avoid overflow in image cell size calculation 2026-08-25 11:22:26 +01:00
Michael Grant
37b71800b5 Move image cell drawing into image.c 2026-08-25 11:22:26 +01:00
Michael Grant
5c9ae058bf Expose image backend flags 2026-08-25 11:22:26 +01:00
Michael Grant
db7ec915ea Do not enable sync for SIXEL 2026-08-25 11:22:26 +01:00
Michael Grant
04644c7267 Comment sixel_from_image(). 2026-08-25 11:22:26 +01:00
Michael Grant
d53f8eff9e Add comments to image functions 2026-08-25 11:22:26 +01:00
Michael Grant
03efb5e293 Preserve text behind transparent Kitty images. 2026-08-25 11:22:26 +01:00
Michael Grant
2603f84b0a Revert "Clear text beneath SIXEL image placements."
This reverts commit 64cea48f91.
2026-08-25 11:22:26 +01:00
Michael Grant
e5bcf59768 Clear text beneath SIXEL image placements. 2026-08-25 11:22:26 +01:00
Michael Grant
69ee9cf7f4 Ordinary text writes replaced the entire grid cell, dropping GRID_FLAG_IMAGE and releasing the
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
2026-08-25 11:22:26 +01:00
Michael Grant
ae0fa8068c Preserve Kitty image crop width after cell rounding. 2026-08-25 11:22:26 +01:00
Michael Grant
3442c1f26f Fix underlay bookkeeping bug. 2026-08-25 11:22:26 +01:00
Michael Grant
b6c709307e Dither alpha in SIXEL output 2026-08-25 11:22:26 +01:00
Michael Grant
002d38cb6b Revert "Clear text beneath graphical images"
This reverts commit fb589fd9f9.
2026-08-25 11:22:26 +01:00
Michael Grant
fb931f1676 Use compact image references in grid cells 2026-08-25 11:22:26 +01:00
Michael Grant
ba2dc2cfb6 Clear text beneath graphical images 2026-08-25 11:22:26 +01:00
Michael Grant
628acfd802 Pass through wrapped Kitty graphics 2026-08-25 11:22:26 +01:00
Michael Grant
95b6adbd61 Simplify image support terminology 2026-08-25 11:22:26 +01:00
Michael Grant
0b2739c62c Use one image support switch 2026-08-25 11:22:26 +01:00
Michael Grant
596de59d11 Make image types opaque 2026-08-25 11:22:26 +01:00
Michael Grant
7d2d187db4 Inline basic image fallback renderer 2026-08-25 11:22:26 +01:00
Michael Grant
674cdd94f5 Add bptato's test to the regression test script. 2026-08-25 11:22:26 +01:00
Michael Grant
75b606c3df The two Chawan symptoms now have matching fixes:
- Layout corruption: C=1 is respected.
  - Lingering remnants: tmux now tracks Kitty’s (image ID, placement ID) identity, replaces moved placements, and honors
    placement-specific d=i,...,p=... deletion.
2026-08-25 11:22:26 +01:00
Michael Grant
d674f34f25 Support Kitty Unicode placeholder image transmission
- Parse Kitty graphics commands wrapped in tmux passthrough sequences.
  - Accept unpadded base64 payloads emitted by icat.
  - Handle chunked transfers whose final chunk omits m.
  - Track virtual image placements.
  - Convert Unicode placeholders into shared image cells for Kitty and SIXEL clients.
  - Add regression coverage for wrapped, chunked, unpadded input.
2026-08-25 11:22:26 +01:00
Michael Grant
8b44703b41 Fix SIXEL median-cut palette generation 2026-08-25 11:22:26 +01:00