mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-06-02 18:08:11 +00:00
vt: expose dirty state in C API
Switch RenderState.Dirty to lib.Enum so it uses C-compatible enum backing when building the C ABI target. Add GhosttyRenderStateDirty and new ghostty_render_state_dirty_get/set declarations to the render header, then wire both functions through src/terminal/c/main.zig and the lib_vt export table.
This commit is contained in:
@@ -49,6 +49,22 @@ extern "C" {
|
||||
*/
|
||||
typedef struct GhosttyRenderState* GhosttyRenderState;
|
||||
|
||||
/**
|
||||
* Dirty state of a render state after update.
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
typedef enum {
|
||||
/** Not dirty at all; rendering can be skipped. */
|
||||
GHOSTTY_RENDER_STATE_DIRTY_FALSE = 0,
|
||||
|
||||
/** Some rows changed; renderer can redraw incrementally. */
|
||||
GHOSTTY_RENDER_STATE_DIRTY_PARTIAL = 1,
|
||||
|
||||
/** Global state changed; renderer should redraw everything. */
|
||||
GHOSTTY_RENDER_STATE_DIRTY_FULL = 2,
|
||||
} GhosttyRenderStateDirty;
|
||||
|
||||
/**
|
||||
* Create a new render state instance.
|
||||
*
|
||||
@@ -79,6 +95,34 @@ GhosttyResult ghostty_render_state_new(const GhosttyAllocator* allocator,
|
||||
GhosttyResult ghostty_render_state_update(GhosttyRenderState state,
|
||||
GhosttyTerminal terminal);
|
||||
|
||||
/**
|
||||
* Get the current dirty state of a render state.
|
||||
*
|
||||
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param[out] out_dirty On success, receives the current dirty state
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` is
|
||||
* NULL
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
GhosttyResult ghostty_render_state_dirty_get(GhosttyRenderState state,
|
||||
GhosttyRenderStateDirty* out_dirty);
|
||||
|
||||
/**
|
||||
* Set the dirty state of a render state.
|
||||
*
|
||||
* This can be used by callers to clear dirty state after handling updates.
|
||||
*
|
||||
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param dirty The dirty state to set
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` is
|
||||
* NULL or `dirty` is not a recognized enum value
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
GhosttyResult ghostty_render_state_dirty_set(GhosttyRenderState state,
|
||||
GhosttyRenderStateDirty dirty);
|
||||
|
||||
/**
|
||||
* Free a render state instance.
|
||||
*
|
||||
|
||||
@@ -189,6 +189,8 @@ comptime {
|
||||
@export(&c.formatter_free, .{ .name = "ghostty_formatter_free" });
|
||||
@export(&c.render_state_new, .{ .name = "ghostty_render_state_new" });
|
||||
@export(&c.render_state_update, .{ .name = "ghostty_render_state_update" });
|
||||
@export(&c.render_state_dirty_get, .{ .name = "ghostty_render_state_dirty_get" });
|
||||
@export(&c.render_state_dirty_set, .{ .name = "ghostty_render_state_dirty_set" });
|
||||
@export(&c.render_state_free, .{ .name = "ghostty_render_state_free" });
|
||||
@export(&c.terminal_new, .{ .name = "ghostty_terminal_new" });
|
||||
@export(&c.terminal_free, .{ .name = "ghostty_terminal_free" });
|
||||
|
||||
@@ -39,6 +39,8 @@ pub const formatter_free = formatter.free;
|
||||
pub const render_state_new = render.new;
|
||||
pub const render_state_free = render.free;
|
||||
pub const render_state_update = render.update;
|
||||
pub const render_state_dirty_get = render.dirty_get;
|
||||
pub const render_state_dirty_set = render.dirty_set;
|
||||
|
||||
pub const sgr_new = sgr.new;
|
||||
pub const sgr_free = sgr.free;
|
||||
|
||||
@@ -14,6 +14,9 @@ const RenderStateWrapper = struct {
|
||||
/// C: GhosttyRenderState
|
||||
pub const RenderState = ?*RenderStateWrapper;
|
||||
|
||||
/// C: GhosttyRenderStateDirty
|
||||
pub const Dirty = renderpkg.RenderState.Dirty;
|
||||
|
||||
pub fn new(
|
||||
alloc_: ?*const CAllocator,
|
||||
result: *RenderState,
|
||||
@@ -47,6 +50,26 @@ pub fn update(
|
||||
return .success;
|
||||
}
|
||||
|
||||
pub fn dirty_get(
|
||||
state_: RenderState,
|
||||
out_dirty: *Dirty,
|
||||
) callconv(.c) Result {
|
||||
const state = state_ orelse return .invalid_value;
|
||||
out_dirty.* = state.state.dirty;
|
||||
return .success;
|
||||
}
|
||||
|
||||
pub fn dirty_set(
|
||||
state_: RenderState,
|
||||
dirty_: c_int,
|
||||
) callconv(.c) Result {
|
||||
const state = state_ orelse return .invalid_value;
|
||||
const dirty = std.meta.intToEnum(Dirty, dirty_) catch
|
||||
return .invalid_value;
|
||||
state.state.dirty = dirty;
|
||||
return .success;
|
||||
}
|
||||
|
||||
pub fn free(state_: RenderState) callconv(.c) void {
|
||||
const state = state_ orelse return;
|
||||
const alloc = state.alloc;
|
||||
@@ -80,6 +103,60 @@ test "render: update invalid value" {
|
||||
try testing.expectEqual(Result.invalid_value, update(state, null));
|
||||
}
|
||||
|
||||
test "render: dirty get/set invalid value" {
|
||||
var state: RenderState = null;
|
||||
try testing.expectEqual(Result.success, new(
|
||||
&lib_alloc.test_allocator,
|
||||
&state,
|
||||
));
|
||||
defer free(state);
|
||||
|
||||
var dirty: Dirty = .false;
|
||||
try testing.expectEqual(Result.invalid_value, dirty_get(null, &dirty));
|
||||
try testing.expectEqual(Result.invalid_value, dirty_set(
|
||||
null,
|
||||
@intFromEnum(Dirty.full),
|
||||
));
|
||||
}
|
||||
|
||||
test "render: dirty get/set" {
|
||||
var state: RenderState = null;
|
||||
try testing.expectEqual(Result.success, new(
|
||||
&lib_alloc.test_allocator,
|
||||
&state,
|
||||
));
|
||||
defer free(state);
|
||||
|
||||
var dirty: Dirty = undefined;
|
||||
try testing.expectEqual(Result.success, dirty_get(state, &dirty));
|
||||
try testing.expectEqual(Dirty.false, dirty);
|
||||
|
||||
try testing.expectEqual(Result.success, dirty_set(
|
||||
state,
|
||||
@intFromEnum(Dirty.partial),
|
||||
));
|
||||
try testing.expectEqual(Result.success, dirty_get(state, &dirty));
|
||||
try testing.expectEqual(Dirty.partial, dirty);
|
||||
|
||||
try testing.expectEqual(Result.success, dirty_set(
|
||||
state,
|
||||
@intFromEnum(Dirty.full),
|
||||
));
|
||||
try testing.expectEqual(Result.success, dirty_get(state, &dirty));
|
||||
try testing.expectEqual(Dirty.full, dirty);
|
||||
}
|
||||
|
||||
test "render: dirty set invalid enum value" {
|
||||
var state: RenderState = null;
|
||||
try testing.expectEqual(Result.success, new(
|
||||
&lib_alloc.test_allocator,
|
||||
&state,
|
||||
));
|
||||
defer free(state);
|
||||
|
||||
try testing.expectEqual(Result.invalid_value, dirty_set(state, 99));
|
||||
}
|
||||
|
||||
test "render: update" {
|
||||
var terminal: terminal_c.Terminal = null;
|
||||
try testing.expectEqual(Result.success, terminal_c.new(
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
const std = @import("std");
|
||||
const build_options = @import("terminal_options");
|
||||
const assert = @import("../quirks.zig").inlineAssert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||
const fastmem = @import("../fastmem.zig");
|
||||
const lib = @import("../lib/main.zig");
|
||||
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
|
||||
const color = @import("color.zig");
|
||||
const cursor = @import("cursor.zig");
|
||||
const highlight = @import("highlight.zig");
|
||||
@@ -222,20 +225,20 @@ pub const RenderState = struct {
|
||||
style: Style,
|
||||
};
|
||||
|
||||
// Dirty state
|
||||
pub const Dirty = enum {
|
||||
/// Not dirty at all. Can skip rendering if prior state was
|
||||
/// already rendered.
|
||||
false,
|
||||
// Dirty state.
|
||||
pub const Dirty = lib.Enum(lib_target, &.{
|
||||
// Not dirty at all. Can skip rendering if prior state was
|
||||
// already rendered.
|
||||
"false",
|
||||
|
||||
/// Partially dirty. Some rows changed but not all. None of the
|
||||
/// global state changed such as colors.
|
||||
partial,
|
||||
// Some rows changed but not all. None of the global state
|
||||
// changed such as colors.
|
||||
"partial",
|
||||
|
||||
/// Fully dirty. Global state changed or dimensions changed. All rows
|
||||
/// should be redrawn.
|
||||
full,
|
||||
};
|
||||
// Global state changed or dimensions changed. All rows should
|
||||
// be redrawn.
|
||||
"full",
|
||||
});
|
||||
|
||||
const SelectionCache = struct {
|
||||
selection: Selection,
|
||||
|
||||
Reference in New Issue
Block a user