From 02e6ef7e9b03f5e67e3b4c5c705f8125498811ad Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 25 Jul 2025 11:20:39 -0700 Subject: [PATCH] apprt/gtk-ng: setup action maps in app and window --- src/apprt/gtk-ng/class/application.zig | 39 ++++++++++++++ src/apprt/gtk-ng/class/window.zig | 74 ++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/src/apprt/gtk-ng/class/application.zig b/src/apprt/gtk-ng/class/application.zig index 385749c04..4847b1283 100644 --- a/src/apprt/gtk-ng/class/application.zig +++ b/src/apprt/gtk-ng/class/application.zig @@ -10,6 +10,7 @@ const gobject = @import("gobject"); const gtk = @import("gtk"); const build_config = @import("../../../build_config.zig"); +const i18n = @import("../../../os/main.zig").i18n; const apprt = @import("../../../apprt.zig"); const cgroup = @import("../cgroup.zig"); const CoreApp = @import("../../../App.zig"); @@ -677,6 +678,9 @@ pub const Application = extern struct { // Setup our style manager (light/dark mode) self.startupStyleManager(); + // Setup our action map + self.startupActionMap(); + // Setup our cgroup for the application. self.startupCgroup() catch |err| { log.warn("cgroup initialization failed err={}", .{err}); @@ -762,6 +766,30 @@ pub const Application = extern struct { ); } + /// Setup our action map. + fn startupActionMap(self: *Self) void { + const actions = .{ + .{ "quit", actionQuit, null }, + }; + + const action_map = self.as(gio.ActionMap); + inline for (actions) |entry| { + const action = gio.SimpleAction.new( + entry[0], + entry[2], + ); + defer action.unref(); + _ = gio.SimpleAction.signals.activate.connect( + action, + *Self, + entry[1], + self, + .{}, + ); + action_map.addAction(action.as(gio.Action)); + } + } + const CgroupError = error{ DbusConnectionFailed, CgroupInitFailed, @@ -961,6 +989,17 @@ pub const Application = extern struct { dialog.present(null); } + fn actionQuit( + _: *gio.SimpleAction, + _: ?*glib.Variant, + self: *Self, + ) callconv(.c) void { + const priv = self.private(); + priv.core_app.performAction(self.rt(), .quit) catch |err| { + log.warn("error quitting err={}", .{err}); + }; + } + //---------------------------------------------------------------- // Boilerplate/Noise diff --git a/src/apprt/gtk-ng/class/window.zig b/src/apprt/gtk-ng/class/window.zig index 9e72b2827..6e906b149 100644 --- a/src/apprt/gtk-ng/class/window.zig +++ b/src/apprt/gtk-ng/class/window.zig @@ -2,10 +2,14 @@ const std = @import("std"); const build_config = @import("../../../build_config.zig"); const assert = std.debug.assert; const adw = @import("adw"); +const gio = @import("gio"); +const glib = @import("glib"); const gobject = @import("gobject"); const gtk = @import("gtk"); +const i18n = @import("../../../os/main.zig").i18n; const CoreSurface = @import("../../../Surface.zig"); +const adw_version = @import("../adw_version.zig"); const gresource = @import("../build/gresource.zig"); const Common = @import("../class.zig").Common; const Application = @import("application.zig").Application; @@ -80,6 +84,32 @@ pub const Window = extern struct { // Set our window icon. We can't set this in the blueprint file // because its dependent on the build config. self.as(gtk.Window).setIconName(build_config.bundle_id); + + self.initActionMap(); + } + + /// Setup our action map. + fn initActionMap(self: *Self) void { + const actions = .{ + .{ "about", actionAbout, null }, + }; + + const action_map = self.as(gio.ActionMap); + inline for (actions) |entry| { + const action = gio.SimpleAction.new( + entry[0], + entry[2], + ); + defer action.unref(); + _ = gio.SimpleAction.signals.activate.connect( + action, + *Self, + entry[1], + self, + .{}, + ); + action_map.addAction(action.as(gio.Action)); + } } //--------------------------------------------------------------- @@ -112,6 +142,50 @@ pub const Window = extern struct { self.as(gtk.Window).close(); } + fn actionAbout( + _: *gio.SimpleAction, + _: ?*glib.Variant, + self: *Self, + ) callconv(.c) void { + const name = "Ghostty"; + const icon = "com.mitchellh.ghostty"; + const website = "https://ghostty.org"; + + if (adw_version.supportsDialogs()) { + adw.showAboutDialog( + self.as(gtk.Widget), + "application-name", + name, + "developer-name", + i18n._("Ghostty Developers"), + "application-icon", + icon, + "version", + build_config.version_string.ptr, + "issue-url", + "https://github.com/ghostty-org/ghostty/issues", + "website", + website, + @as(?*anyopaque, null), + ); + } else { + gtk.showAboutDialog( + self.as(gtk.Window), + "program-name", + name, + "logo-icon-name", + icon, + "title", + i18n._("About Ghostty"), + "version", + build_config.version_string.ptr, + "website", + website, + @as(?*anyopaque, null), + ); + } + } + const C = Common(Self, Private); pub const as = C.as; pub const ref = C.ref;