From 2e9ee1645536fade0a7fdb531b1326055c7b7dff Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 19 Jul 2025 14:03:42 -0700 Subject: [PATCH 1/2] core: remove Surface.shouldClose This was a noop in all of our apprts and I think is a holdover from the glfw days. --- src/App.zig | 12 ------------ src/apprt/embedded.zig | 9 --------- src/apprt/gtk-ng/Surface.zig | 5 ----- src/apprt/gtk/Surface.zig | 9 --------- 4 files changed, 35 deletions(-) diff --git a/src/App.zig b/src/App.zig index effef0c5f..69667dcb9 100644 --- a/src/App.zig +++ b/src/App.zig @@ -132,18 +132,6 @@ pub fn destroy(self: *App) void { /// events. This should be called by the application runtime on every loop /// tick. pub fn tick(self: *App, rt_app: *apprt.App) !void { - // If any surfaces are closing, destroy them - var i: usize = 0; - while (i < self.surfaces.items.len) { - const surface = self.surfaces.items[i]; - if (surface.shouldClose()) { - surface.close(false); - continue; - } - - i += 1; - } - // Drain our mailbox try self.drainMailbox(rt_app); } diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index c21f57ffb..bd1ffd460 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -705,15 +705,6 @@ pub const Surface = struct { ); } - pub fn setShouldClose(self: *Surface) void { - _ = self; - } - - pub fn shouldClose(self: *const Surface) bool { - _ = self; - return false; - } - pub fn getCursorPos(self: *const Surface) !apprt.CursorPos { return self.cursor_pos; } diff --git a/src/apprt/gtk-ng/Surface.zig b/src/apprt/gtk-ng/Surface.zig index 71e57a1bc..0b69dd529 100644 --- a/src/apprt/gtk-ng/Surface.zig +++ b/src/apprt/gtk-ng/Surface.zig @@ -30,11 +30,6 @@ pub fn close(self: *Self, process_active: bool) void { _ = process_active; } -pub fn shouldClose(self: *Self) bool { - _ = self; - return false; -} - pub fn getTitle(self: *Self) ?[:0]const u8 { _ = self; return null; diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index d3849781f..43e378487 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -877,15 +877,6 @@ pub fn controlInspector( }; } -pub fn setShouldClose(self: *Surface) void { - _ = self; -} - -pub fn shouldClose(self: *const Surface) bool { - _ = self; - return false; -} - pub fn getContentScale(self: *const Surface) !apprt.ContentScale { const gtk_scale: f32 = scale: { const widget = self.gl_area.as(gtk.Widget); From aadb2c05e5e6585faa8f47bd930250099fe130d8 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 19 Jul 2025 14:18:50 -0700 Subject: [PATCH 2/2] apprt/gtk-ng: hook up Surface.close --- src/apprt/gtk-ng/Surface.zig | 3 +-- src/apprt/gtk-ng/class/surface.zig | 35 +++++++++++++++++++++++++ src/apprt/gtk-ng/class/window.zig | 42 ++++++++++++++++++++++++++---- src/apprt/gtk-ng/ui/1.5/window.blp | 2 +- 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/src/apprt/gtk-ng/Surface.zig b/src/apprt/gtk-ng/Surface.zig index 0b69dd529..dd5d15b3a 100644 --- a/src/apprt/gtk-ng/Surface.zig +++ b/src/apprt/gtk-ng/Surface.zig @@ -26,8 +26,7 @@ pub fn rtApp(self: *Self) *ApprtApp { } pub fn close(self: *Self, process_active: bool) void { - _ = self; - _ = process_active; + self.surface.close(process_active); } pub fn getTitle(self: *Self) ?[:0]const u8 { diff --git a/src/apprt/gtk-ng/class/surface.zig b/src/apprt/gtk-ng/class/surface.zig index 447bd59f4..c3a2aeef8 100644 --- a/src/apprt/gtk-ng/class/surface.zig +++ b/src/apprt/gtk-ng/class/surface.zig @@ -54,6 +54,29 @@ pub const Surface = extern struct { }; }; + pub const signals = struct { + /// Emitted whenever the surface would like to be closed for any + /// reason. + /// + /// The surface view does NOT handle its own close confirmation. + /// If there is a process alive then the boolean parameter will + /// specify it and the parent widget should handle this request. + /// + /// This signal lets the containing widget decide how closure works. + /// This lets this Surface widget be used as a split, tab, etc. + /// without it having to be aware of its own semantics. + pub const @"close-request" = struct { + pub const name = "close-request"; + pub const connect = impl.connect; + const impl = gobject.ext.defineSignal( + name, + Self, + &.{bool}, + void, + ); + }; + }; + const Private = struct { /// The configuration that this surface is using. config: ?*Config = null, @@ -374,6 +397,15 @@ pub const Surface = extern struct { //--------------------------------------------------------------- // Libghostty Callbacks + pub fn close(self: *Self, process_active: bool) void { + signals.@"close-request".impl.emit( + self, + null, + .{process_active}, + null, + ); + } + pub fn getContentScale(self: *Self) apprt.ContentScale { const priv = self.private(); const gl_area = priv.gl_area; @@ -1341,6 +1373,9 @@ pub const Surface = extern struct { properties.config.impl, }); + // Signals + signals.@"close-request".impl.register(.{}); + // Virtual methods gobject.Object.virtual_methods.dispose.implement(class, &dispose); gobject.Object.virtual_methods.finalize.implement(class, &finalize); diff --git a/src/apprt/gtk-ng/class/window.zig b/src/apprt/gtk-ng/class/window.zig index 81ea376fa..6e30389a0 100644 --- a/src/apprt/gtk-ng/class/window.zig +++ b/src/apprt/gtk-ng/class/window.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const assert = std.debug.assert; const adw = @import("adw"); const gobject = @import("gobject"); const gtk = @import("gtk"); @@ -23,7 +24,9 @@ pub const Window = extern struct { }); const Private = struct { - _todo: u8, + /// The surface in the view. + surface: *Surface = undefined, + pub var offset: c_int = 0; }; @@ -33,8 +36,20 @@ pub const Window = extern struct { fn init(self: *Self, _: *Class) callconv(.C) void { gtk.Widget.initTemplate(self.as(gtk.Widget)); + + const surface = self.private().surface; + _ = Surface.signals.@"close-request".connect( + surface, + *Self, + surfaceCloseRequest, + self, + .{}, + ); } + //--------------------------------------------------------------- + // Virtual methods + fn dispose(self: *Self) callconv(.C) void { gtk.Widget.disposeTemplate( self.as(gtk.Widget), @@ -47,6 +62,21 @@ pub const Window = extern struct { ); } + //--------------------------------------------------------------- + // Signal handlers + + fn surfaceCloseRequest( + surface: *Surface, + process_active: bool, + self: *Self, + ) callconv(.c) void { + // Todo + _ = process_active; + + assert(surface == self.private().surface); + self.as(gtk.Window).close(); + } + const C = Common(Self, Private); pub const as = C.as; pub const ref = C.ref; @@ -60,7 +90,6 @@ pub const Window = extern struct { fn init(class: *Class) callconv(.C) void { gobject.ext.ensureType(Surface); - gtk.Widget.Class.setTemplateFromResource( class.as(gtk.Widget.Class), comptime gresource.blueprint(.{ @@ -70,11 +99,14 @@ pub const Window = extern struct { }), ); + // Bindings + class.bindTemplateChildPrivate("surface", .{}); + + // Virtual methods gobject.Object.virtual_methods.dispose.implement(class, &dispose); } - pub fn as(class: *Class, comptime T: type) *T { - return gobject.ext.as(T, class); - } + pub const as = C.Class.as; + pub const bindTemplateChildPrivate = C.Class.bindTemplateChildPrivate; }; }; diff --git a/src/apprt/gtk-ng/ui/1.5/window.blp b/src/apprt/gtk-ng/ui/1.5/window.blp index 9f3a0c45f..f258c1bfd 100644 --- a/src/apprt/gtk-ng/ui/1.5/window.blp +++ b/src/apprt/gtk-ng/ui/1.5/window.blp @@ -2,5 +2,5 @@ using Gtk 4.0; using Adw 1; template $GhosttyWindow: Adw.ApplicationWindow { - content: $GhosttySurface {}; + content: $GhosttySurface surface {}; }