Skip to content

libghostty: C APIs for Kitty Graphics inspection#12145

Merged
mitchellh merged 11 commits intomainfrom
libvt-kitty
Apr 6, 2026
Merged

libghostty: C APIs for Kitty Graphics inspection#12145
mitchellh merged 11 commits intomainfrom
libvt-kitty

Conversation

@mitchellh
Copy link
Copy Markdown
Contributor

@mitchellh mitchellh commented Apr 6, 2026

This adds a C API for inspecting Kitty graphics image storage, images, and placements from a terminal instance.

I think this is enough of the API surface area for a renderer to draw images. But I'll have to add it to Ghostling to be sure.

Example

#include <stdint.h>
#include <stdio.h>
#include <ghostty/vt.h>

/* After creating a terminal and transmitting a Kitty graphics image... */

/* Get the kitty graphics storage from the terminal. */
GhosttyKittyGraphics graphics = NULL;
ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_KITTY_GRAPHICS, &graphics);

/* Iterate over all placements. */
GhosttyKittyGraphicsPlacementIterator iter = NULL;
ghostty_kitty_graphics_placement_iterator_new(NULL, &iter);
ghostty_kitty_graphics_get(graphics,
    GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR, &iter);

while (ghostty_kitty_graphics_placement_next(iter)) {
  uint32_t image_id = 0;
  ghostty_kitty_graphics_placement_get(iter,
      GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID, &image_id);

  /* Look up the image and query its properties. */
  GhosttyKittyGraphicsImage image = ghostty_kitty_graphics_image(graphics, image_id);
  uint32_t width = 0, height = 0;
  GhosttyKittyImageFormat format = 0;
  ghostty_kitty_image_get(image, GHOSTTY_KITTY_IMAGE_DATA_WIDTH, &width);
  ghostty_kitty_image_get(image, GHOSTTY_KITTY_IMAGE_DATA_HEIGHT, &height);
  ghostty_kitty_image_get(image, GHOSTTY_KITTY_IMAGE_DATA_FORMAT, &format);
  printf("image %u: %ux%u format=%d\n", image_id, width, height, format);

  /* Compute rendered pixel size and grid size. */
  uint32_t px_w, px_h, cols, rows;
  ghostty_kitty_graphics_placement_pixel_size(iter, image, terminal, &px_w, &px_h);
  ghostty_kitty_graphics_placement_grid_size(iter, image, terminal, &cols, &rows);
  printf("  rendered: %ux%u px, %ux%u cells\n", px_w, px_h, cols, rows);
}

ghostty_kitty_graphics_placement_iterator_free(iter);

API

Functions

Function Description
ghostty_kitty_graphics_get Query data from a kitty graphics storage (e.g. placement iterator)
ghostty_kitty_graphics_image Look up an image by its image ID
ghostty_kitty_graphics_image_get Query image properties (ID, dimensions, format, compression, pixel data)
ghostty_kitty_graphics_placement_iterator_new Create a new placement iterator
ghostty_kitty_graphics_placement_iterator_free Free a placement iterator
ghostty_kitty_graphics_placement_next Advance the iterator to the next placement
ghostty_kitty_graphics_placement_get Query placement properties (image ID, offsets, source rect, z-index, etc.)
ghostty_kitty_graphics_placement_rect Compute the bounding grid rectangle for a placement
ghostty_kitty_graphics_placement_pixel_size Compute the rendered pixel dimensions of a placement
ghostty_kitty_graphics_placement_grid_size Compute the grid cell dimensions of a placement

Types

Type Description
GhosttyKittyGraphics Opaque handle to image storage (borrowed from terminal)
GhosttyKittyGraphicsImage Opaque handle to a single image
GhosttyKittyGraphicsPlacementIterator Opaque handle to a placement iterator
GhosttyKittyGraphicsData Enum for ghostty_kitty_graphics_get data kinds
GhosttyKittyGraphicsImageData Enum for ghostty_kitty_image_get data kinds
GhosttyKittyGraphicsPlacementData Enum for ghostty_kitty_graphics_placement_get data kinds
GhosttyKittyImageFormat Image pixel format (RGB, RGBA, PNG, gray, gray+alpha)
GhosttyKittyImageCompression Image compression (none, zlib)

Add a C API for iterating over Kitty graphics placements via the
new GhosttyKittyGraphics opaque handle. The API follows the same
pattern as the render state row iterator: allocate an iterator with
ghostty_kitty_graphics_placement_iterator_new, populate it from a
graphics handle via ghostty_kitty_graphics_get with the
PLACEMENT_ITERATOR data kind, advance with
ghostty_kitty_graphics_placement_next, and query per-placement
fields with ghostty_kitty_graphics_placement_get.
Add a GhosttyKittyGraphicsImage opaque type and API for looking up
images by ID and querying their properties. This complements the
existing placement iterator by allowing direct image introspection.

The new ghostty_kitty_graphics_image() function looks up an image by
its ID from the storage, returning a borrowed opaque handle. Properties
are queried via ghostty_kitty_image_get() using the new
GhosttyKittyGraphicsImageData enum, which exposes id, number, width,
height, format, compression, and a borrowed data pointer with length.

Format and compression are exposed as their own C enum types
(GhosttyKittyImageFormat and GhosttyKittyImageCompression) rather
than raw integers.
Convert the Transmission.Format, Transmission.Medium, and
Transmission.Compression types from plain Zig enums to lib.Enum so
they get a C-compatible backing type when building with c_abi. This
lets the C API layer reuse the types directly instead of maintaining
separate mirror enums.

Move Format.bpp() to a standalone Transmission.formatBpp() function
since lib.Enum types cannot have decls.

In the C API layer, rename kitty_gfx to kitty_storage and command to
kitty_cmd for clarity, and simplify the format/compression getters
to direct assignment now that the types are shared.
Expose Placement.rect() from the Zig kitty graphics storage as a new
C API function ghostty_kitty_graphics_placement_rect(). It takes the
terminal, image handle, and a positioned placement iterator, and
writes the bounding grid rectangle into a GhosttySelection out param.
Virtual placements return GHOSTTY_NO_VALUE.

Move all opaque handle typedefs (GhosttyTerminal, GhosttyKittyGraphics,
GhosttyRenderState, GhosttySgrParser, GhosttyFormatter, GhosttyOsc*)
into types.h so they are available everywhere without circular includes
and Doxygen renders them in the correct @InGroup sections.
…Size

Expose Placement.pixelSize() and Placement.gridSize() as new C API
functions ghostty_kitty_graphics_placement_pixel_size() and
ghostty_kitty_graphics_placement_grid_size(). Both take the placement
iterator, image handle, and terminal, returning their results via
out params.

Rename the internal Zig method from calculatedSize to pixelSize to
pair naturally with gridSize — one returns pixels, the other grid
cells. Updated all callers including the renderer.
The test transmits an image with f=24 (24-bit RGB) but was asserting
that the format field equals .rgba (32-bit). Corrected the expectation
to .rgb to match the transmitted pixel format.
@mitchellh mitchellh requested review from a team as code owners April 6, 2026 17:12
@mitchellh mitchellh added this to the 1.4.0 milestone Apr 6, 2026
…image_get

Rename the public API function to follow the consistent
ghostty_kitty_graphics_* naming convention used by the other
kitty graphics API symbols.
The PlacementIterator, PlacementMap, and PlacementIteratorWrapper
types in the C API were unconditionally referencing
kitty_storage.ImageStorage, which transitively pulled in
Image.transmit_time (std.time.Instant). On wasm32-freestanding,
std.time.Instant requires posix.timespec which does not exist,
causing a compilation error.

Gate these types behind build_options.kitty_graphics, matching the
existing pattern used for KittyGraphics and ImageHandle. When
kitty graphics is disabled, they fall back to opaque/void types.
Add early-return guards to placement_iterator_new and
placement_iterator_free which directly operate on the wrapper
struct.
Add the inverse of ghostty_terminal_grid_ref(), converting a grid
reference back to coordinates in a requested coordinate system
(active, viewport, screen, or history). This wraps the existing
internal PageList.pointFromPin and is placed on the terminal API
since it requires terminal-owned PageList state to resolve the
top-left anchor for each coordinate system.

Returns GHOSTTY_NO_VALUE when the ref falls outside the requested
range, e.g. a scrollback ref cannot be expressed in active
coordinates.
@mitchellh mitchellh merged commit 800cc64 into main Apr 6, 2026
174 of 178 checks passed
@mitchellh mitchellh deleted the libvt-kitty branch April 6, 2026 19:09
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