Skip to content

libghostty: add z-layer filtering, viewport positioning, and source rects for kitty graphics placements#12147

Merged
mitchellh merged 4 commits into
mainfrom
push-vwvmooppmrxu
Apr 6, 2026
Merged

libghostty: add z-layer filtering, viewport positioning, and source rects for kitty graphics placements#12147
mitchellh merged 4 commits into
mainfrom
push-vwvmooppmrxu

Conversation

@mitchellh
Copy link
Copy Markdown
Contributor

Based on the Ghostling implementation, these are APIs that will help other implementors:

Z-layer filtering. The placement iterator now supports a configurable layer filter via a new ghostty_kitty_graphics_placement_iterator_set() option API. When a layer is set, ghostty_kitty_graphics_placement_next() skips placements whose z-index doesn't match the requested layer. The three layers follow the kitty protocol z-index conventions (below background, below text, above text) and map directly to distinct rendering passes. Default is ALL (no filtering, existing behavior).

Viewport-relative positioning. ghostty_kitty_graphics_placement_viewport_pos() converts a placement's internal pin to viewport-relative grid coordinates. The row value can be negative for placements that have partially scrolled above the viewport. Returns GHOSTTY_NO_VALUE when the placement is entirely off-screen or is a virtual (unicode placeholder) placement, so the renderer can skip it without extra math.

Source rectangle resolution. ghostty_kitty_graphics_placement_source_rect() applies kitty protocol semantics (0 = full image dimension) and clamps to image bounds, returning pixel coordinates ready for texture sampling.

New APIs

Function Description
ghostty_kitty_graphics_placement_iterator_set Set an option on a placement iterator (currently: z-layer filter)
ghostty_kitty_graphics_placement_viewport_pos Get viewport-relative grid position of the current placement
ghostty_kitty_graphics_placement_source_rect Get the resolved source rectangle in pixels for the current placement

New Types

Type Description
GhosttyKittyPlacementLayer Z-layer classification: ALL, BELOW_BG, BELOW_TEXT, ABOVE_TEXT
GhosttyKittyGraphicsPlacementIteratorOption Settable iterator options (currently: LAYER)

Add a placement_iterator_set function that configures iterator
properties via an enum, following the same pattern as other set
functions in the C API (e.g. render_state_set). The first settable
option is a z-layer filter.

The GhosttyKittyPlacementLayer enum classifies placements into three
layers based on kitty protocol z-index conventions: below background
(z < INT32_MIN/2), below text (INT32_MIN/2 <= z < 0), and above text
(z >= 0). The default is ALL which preserves existing behavior.

When a layer filter is set, placement_iterator_next automatically
skips non-matching placements, so embedders no longer need to
reimplement the z-index bucketing logic or iterate all placements
three times per frame just to filter by layer.
Add ghostty_kitty_graphics_placement_viewport_pos which converts a
placement's internal pin to viewport-relative grid coordinates.
The returned row can be negative when the placement's origin has
scrolled above the viewport, allowing embedders to compute the
correct destination rectangle for partially visible images.

Returns GHOSTTY_NO_VALUE only when the placement is completely
outside the viewport (bottom edge above the viewport or top edge
at or below the last row), so embedders do not need to perform
their own visibility checks. Partially visible placements always
return GHOSTTY_SUCCESS with their true signed coordinates.
Add ghostty_kitty_graphics_placement_source_rect which returns the
fully resolved and clamped source rectangle for a placement. This
applies kitty protocol semantics (width/height of 0 means full
image dimension) and clamps the result to the actual image bounds,
eliminating ~20 lines of protocol-aware logic from each embedder.
@mitchellh mitchellh added this to the 1.4.0 milestone Apr 6, 2026
@mitchellh mitchellh requested a review from a team as a code owner April 6, 2026 19:40
mitchellh added a commit to ghostty-org/ghostling that referenced this pull request Apr 6, 2026
Use the new libghostty APIs from ghostty-org/ghostty#12147 to replace
manual logic in render_kitty_images:

The iterator layer filter (placement_iterator_set with a
GhosttyKittyPlacementLayer) replaces the manual z-index read and
switch/case filtering. The placement_viewport_pos call replaces
a 3-step viewport origin lookup (grid_ref, point_from_grid_ref,
manual subtraction) plus the off-screen and virtual-placement
checks. The placement_source_rect call replaces four individual
source field reads plus the "0 = full dimension" expansion and
bounds clamping.

This removes ~70 lines and drops the term_rows parameter from
both render_kitty_images and render_terminal.
Fix three categories of test bugs in the kitty graphics C API tests:

The placement iterator reset in getTyped was clobbering the
layer_filter field when reinitializing the iterator struct,
causing the layer filter test to see unfiltered placements.
Preserve layer_filter across resets.

The viewport position tests were not accounting for the default
cursor_movement=after behavior of the kitty display command,
which calls index() for each row of the placement before the
test scroll sequence. Add C=1 to suppress cursor movement so
the scroll math in the tests is correct.

The source_rect tests used an 88-character all-A base64 payload
which decodes to 66 bytes, but a 4x4 RGBA image requires exactly
64 bytes. Fix the payload to use proper base64 padding (AA==).
@mitchellh mitchellh merged commit fdb6e3d into main Apr 6, 2026
100 checks passed
@mitchellh mitchellh deleted the push-vwvmooppmrxu branch April 6, 2026 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant