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_RESET_WINDOW_SIZE,
GHOSTTY_ACTION_INITIAL_SIZE, GHOSTTY_ACTION_INITIAL_SIZE,
GHOSTTY_ACTION_CELL_SIZE, GHOSTTY_ACTION_CELL_SIZE,
GHOSTTY_ACTION_RENDER,
GHOSTTY_ACTION_INSPECTOR, GHOSTTY_ACTION_INSPECTOR,
GHOSTTY_ACTION_SHOW_GTK_INSPECTOR, GHOSTTY_ACTION_SHOW_GTK_INSPECTOR,
GHOSTTY_ACTION_RENDER_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), .new_window => |msg| try self.newWindow(rt_app, msg),
.close => |surface| self.closeSurface(surface), .close => |surface| self.closeSurface(surface),
.surface_message => |msg| try self.surfaceMessage(msg.surface, msg.message), .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), .redraw_inspector => |surface| self.redrawInspector(rt_app, surface),
// If we're quitting, then we set the quit flag and stop // 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; 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; 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 { 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. /// The cell size has changed to the given dimensions in pixels.
cell_size: CellSize, 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. /// Control whether the inspector is shown or hidden.
inspector: Inspector, inspector: Inspector,
@ -311,6 +316,7 @@ pub const Action = union(Key) {
reset_window_size, reset_window_size,
initial_size, initial_size,
cell_size, cell_size,
render,
inspector, inspector,
show_gtk_inspector, show_gtk_inspector,
render_inspector, render_inspector,

View File

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

View File

@ -380,6 +380,8 @@ pub const Application = extern struct {
.quit_timer => try Action.quitTimer(self, value), .quit_timer => try Action.quitTimer(self, value),
.render => Action.render(self, target),
// Unimplemented // Unimplemented
.quit, .quit,
.close_window, .close_window,
@ -883,6 +885,13 @@ const Action = struct {
.stop => {}, .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 /// This sets various GTK-related environment variables as necessary

View File

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const adw = @import("adw"); const adw = @import("adw");
const gdk = @import("gdk");
const gobject = @import("gobject"); const gobject = @import("gobject");
const gtk = @import("gtk"); const gtk = @import("gtk");
@ -94,7 +95,7 @@ pub const Surface = extern struct {
/// the terminal in reaction to internal changes. If there are external /// the terminal in reaction to internal changes. If there are external
/// events that invalidate the surface, such as the widget moving parents, /// events that invalidate the surface, such as the widget moving parents,
/// then we should force a redraw. /// then we should force a redraw.
fn redraw(self: *Self) void { pub fn redraw(self: *Self) void {
const priv = self.private(); const priv = self.private();
priv.gl_area.queueRender(); priv.gl_area.queueRender();
} }
@ -188,6 +189,13 @@ pub const Surface = extern struct {
self, self,
.{}, .{},
); );
_ = gtk.GLArea.signals.render.connect(
gl_area,
*Self,
glareaRender,
self,
.{},
);
} }
fn dispose(self: *Self) callconv(.C) void { fn dispose(self: *Self) callconv(.C) void {
@ -277,6 +285,24 @@ pub const Surface = extern struct {
surface.renderer.displayUnrealized(); 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{ const RealizeError = Allocator.Error || error{
GLAreaError, GLAreaError,
RendererError, RendererError,

View File

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

View File

@ -524,6 +524,7 @@ pub fn performAction(
.open_url => self.openUrl(value), .open_url => self.openUrl(value),
.show_child_exited => return try self.showChildExited(target, value), .show_child_exited => return try self.showChildExited(target, value),
.progress_report => return try self.handleProgressReport(target, value), .progress_report => return try self.handleProgressReport(target, value),
.render => self.render(target),
// Unimplemented // Unimplemented
.close_all_windows, .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 { fn quitTimer(self: *App, mode: apprt.action.QuitTimer) void {
switch (mode) { switch (mode) {
.start => self.startQuitTimer(), .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. /// Redraw the inspector for the given surface.
pub fn redrawInspector(self: *App, surface: *Surface) void { pub fn redrawInspector(self: *App, surface: *Surface) void {
_ = self; _ = self;