libghostty: add z-layer filtering, viewport positioning, and source rects for kitty graphics placements#12147
Merged
Merged
Conversation
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
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==).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 isALL(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. ReturnsGHOSTTY_NO_VALUEwhen 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
ghostty_kitty_graphics_placement_iterator_setghostty_kitty_graphics_placement_viewport_posghostty_kitty_graphics_placement_source_rectNew Types
GhosttyKittyPlacementLayerALL,BELOW_BG,BELOW_TEXT,ABOVE_TEXTGhosttyKittyGraphicsPlacementIteratorOptionLAYER)