apprt/gtk-ng: hook up surface render

This commit is contained in:
Mitchell Hashimoto
2025-07-18 12:22:17 -07:00
parent 2ab5d3cd81
commit f0a0333bc0
8 changed files with 71 additions and 20 deletions

View File

@ -729,6 +729,7 @@ typedef enum {
GHOSTTY_ACTION_RESET_WINDOW_SIZE,
GHOSTTY_ACTION_INITIAL_SIZE,
GHOSTTY_ACTION_CELL_SIZE,
GHOSTTY_ACTION_RENDER,
GHOSTTY_ACTION_INSPECTOR,
GHOSTTY_ACTION_SHOW_GTK_INSPECTOR,
GHOSTTY_ACTION_RENDER_INSPECTOR,

View File

@ -260,7 +260,7 @@ fn drainMailbox(self: *App, rt_app: *apprt.App) !void {
.new_window => |msg| try self.newWindow(rt_app, msg),
.close => |surface| self.closeSurface(surface),
.surface_message => |msg| try self.surfaceMessage(msg.surface, msg.message),
.redraw_surface => |surface| self.redrawSurface(rt_app, surface),
.redraw_surface => |surface| try self.redrawSurface(rt_app, surface),
.redraw_inspector => |surface| self.redrawInspector(rt_app, surface),
// If we're quitting, then we set the quit flag and stop
@ -286,9 +286,26 @@ pub fn focusSurface(self: *App, surface: *Surface) void {
self.focused_surface = surface;
}
fn redrawSurface(self: *App, rt_app: *apprt.App, surface: *apprt.Surface) void {
fn redrawSurface(
self: *App,
rt_app: *apprt.App,
surface: *apprt.Surface,
) !void {
if (!self.hasRtSurface(surface)) return;
rt_app.redrawSurface(surface);
// TODO: Remove this in a separate PR. We should transition to
// the `render` apprt action completely. This is only to make
// our initial gtk-ng work touch less things.
if (@hasDecl(apprt.App, "redrawSurface")) {
rt_app.redrawSurface(surface);
return;
}
_ = try rt_app.performAction(
.{ .surface = surface.core() },
.render,
{},
);
}
fn redrawInspector(self: *App, rt_app: *apprt.App, surface: *apprt.Surface) void {

View File

@ -162,6 +162,11 @@ pub const Action = union(Key) {
/// The cell size has changed to the given dimensions in pixels.
cell_size: CellSize,
/// The target should be re-rendered. This usually has a specific
/// surface target but if the app is targeted then all active
/// surfaces should be redrawn.
render,
/// Control whether the inspector is shown or hidden.
inspector: Inspector,
@ -311,6 +316,7 @@ pub const Action = union(Key) {
reset_window_size,
initial_size,
cell_size,
render,
inspector,
show_gtk_inspector,
render_inspector,

View File

@ -79,12 +79,6 @@ pub fn performIpc(
return false;
}
/// Close the given surface.
pub fn redrawSurface(self: *App, surface: *Surface) void {
_ = self;
_ = surface;
}
/// Redraw the inspector for the given surface.
pub fn redrawInspector(self: *App, surface: *Surface) void {
_ = self;

View File

@ -380,6 +380,8 @@ pub const Application = extern struct {
.quit_timer => try Action.quitTimer(self, value),
.render => Action.render(self, target),
// Unimplemented
.quit,
.close_window,
@ -883,6 +885,13 @@ const Action = struct {
.stop => {},
}
}
pub fn render(_: *Application, target: apprt.Target) void {
switch (target) {
.app => {},
.surface => |v| v.rt_surface.surface.redraw(),
}
}
};
/// This sets various GTK-related environment variables as necessary

View File

@ -1,6 +1,7 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const adw = @import("adw");
const gdk = @import("gdk");
const gobject = @import("gobject");
const gtk = @import("gtk");
@ -94,7 +95,7 @@ pub const Surface = extern struct {
/// the terminal in reaction to internal changes. If there are external
/// events that invalidate the surface, such as the widget moving parents,
/// then we should force a redraw.
fn redraw(self: *Self) void {
pub fn redraw(self: *Self) void {
const priv = self.private();
priv.gl_area.queueRender();
}
@ -188,6 +189,13 @@ pub const Surface = extern struct {
self,
.{},
);
_ = gtk.GLArea.signals.render.connect(
gl_area,
*Self,
glareaRender,
self,
.{},
);
}
fn dispose(self: *Self) callconv(.C) void {
@ -277,6 +285,24 @@ pub const Surface = extern struct {
surface.renderer.displayUnrealized();
}
fn glareaRender(
_: *gtk.GLArea,
_: *gdk.GLContext,
self: *Self,
) callconv(.c) c_int {
// If we don't have a surface then we failed to initialize for
// some reason and there's nothing to draw to the GLArea.
const priv = self.private();
const surface = priv.core_surface orelse return 1;
surface.renderer.drawFrame(true) catch |err| {
log.warn("failed to draw frame err={}", .{err});
return 0;
};
return 1;
}
const RealizeError = Allocator.Error || error{
GLAreaError,
RendererError,

View File

@ -6,10 +6,6 @@ template $GhosttySurface: Adw.Bin {
orientation: vertical;
hexpand: true;
Label {
label: "Hello";
}
GLArea gl_area {
hexpand: true;
vexpand: true;

View File

@ -524,6 +524,7 @@ pub fn performAction(
.open_url => self.openUrl(value),
.show_child_exited => return try self.showChildExited(target, value),
.progress_report => return try self.handleProgressReport(target, value),
.render => self.render(target),
// Unimplemented
.close_all_windows,
@ -881,6 +882,13 @@ fn handleProgressReport(_: *App, target: apprt.Target, value: terminal.osc.Comma
}
}
fn render(_: *App, target: apprt.Target) void {
switch (target) {
.app => {},
.surface => |v| v.rt_surface.redraw(),
}
}
fn quitTimer(self: *App, mode: apprt.action.QuitTimer) void {
switch (mode) {
.start => self.startQuitTimer(),
@ -1479,12 +1487,6 @@ fn stopQuitTimer(self: *App) void {
}
}
/// Close the given surface.
pub fn redrawSurface(self: *App, surface: *Surface) void {
_ = self;
surface.redraw();
}
/// Redraw the inspector for the given surface.
pub fn redrawInspector(self: *App, surface: *Surface) void {
_ = self;