diff --git a/include/ghostty.h b/include/ghostty.h index fb4c850dc..c422c3584 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -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, diff --git a/src/App.zig b/src/App.zig index 28539c557..c4c7ad55b 100644 --- a/src/App.zig +++ b/src/App.zig @@ -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 { diff --git a/src/apprt/action.zig b/src/apprt/action.zig index 425e39974..da97fc04b 100644 --- a/src/apprt/action.zig +++ b/src/apprt/action.zig @@ -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, diff --git a/src/apprt/gtk-ng/App.zig b/src/apprt/gtk-ng/App.zig index d6fd02e38..f630f7533 100644 --- a/src/apprt/gtk-ng/App.zig +++ b/src/apprt/gtk-ng/App.zig @@ -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; diff --git a/src/apprt/gtk-ng/class/application.zig b/src/apprt/gtk-ng/class/application.zig index c115d59cc..de7715e74 100644 --- a/src/apprt/gtk-ng/class/application.zig +++ b/src/apprt/gtk-ng/class/application.zig @@ -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 diff --git a/src/apprt/gtk-ng/class/surface.zig b/src/apprt/gtk-ng/class/surface.zig index d515bfd65..d88748fd1 100644 --- a/src/apprt/gtk-ng/class/surface.zig +++ b/src/apprt/gtk-ng/class/surface.zig @@ -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, diff --git a/src/apprt/gtk-ng/ui/1.2/surface.blp b/src/apprt/gtk-ng/ui/1.2/surface.blp index 3fde1d1c0..2b406ce49 100644 --- a/src/apprt/gtk-ng/ui/1.2/surface.blp +++ b/src/apprt/gtk-ng/ui/1.2/surface.blp @@ -6,10 +6,6 @@ template $GhosttySurface: Adw.Bin { orientation: vertical; hexpand: true; - Label { - label: "Hello"; - } - GLArea gl_area { hexpand: true; vexpand: true; diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index 99120992e..e32d0c8ca 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -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;