From b916e1aca69d25b970c98351d5917bf1228af0ca Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Mon, 27 Jan 2025 10:24:14 -0600 Subject: [PATCH] gtk: move builder to separate file/struct --- src/apprt/gtk/Builder.zig | 37 +++++++++++++++++++++++++++++++++++++ src/apprt/gtk/menu.zig | 25 ++++--------------------- 2 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 src/apprt/gtk/Builder.zig diff --git a/src/apprt/gtk/Builder.zig b/src/apprt/gtk/Builder.zig new file mode 100644 index 000000000..d3df0b672 --- /dev/null +++ b/src/apprt/gtk/Builder.zig @@ -0,0 +1,37 @@ +/// Wrapper around GTK's builder APIs that perform some comptime checks. +const Builder = @This(); + +const std = @import("std"); +const c = @import("c.zig").c; + +builder: *c.GtkBuilder, + +pub fn init(comptime name: []const u8) Builder { + comptime { + // Use @embedFile to make sure that the file exists at compile + // time. Zig _should_ discard the data so that it doesn't end up + // in the final executable. At runtime we will load the data from + // a GResource. + _ = @embedFile("ui/" ++ name ++ ".ui"); + + // Check to make sure that our file is listed as a `ui_file` in + // `gresource.zig`. If it isn't Ghostty could crash at runtime + // when we try and load a nonexistent GResource. + const gresource = @import("gresource.zig"); + for (gresource.ui_files) |ui_file| { + if (std.mem.eql(u8, ui_file, name)) break; + } else @compileError("missing '" ++ name ++ "' in gresource.zig"); + } + + return .{ + .builder = c.gtk_builder_new_from_resource("/com/mitchellh/ghostty/ui/" ++ name ++ ".ui") orelse unreachable, + }; +} + +pub fn getObject(self: *const Builder, comptime T: type, name: [:0]const u8) *T { + return @ptrCast(@alignCast(c.gtk_builder_get_object(self.builder, name.ptr))); +} + +pub fn deinit(self: *const Builder) void { + c.g_object_unref(self.builder); +} diff --git a/src/apprt/gtk/menu.zig b/src/apprt/gtk/menu.zig index 1de895c19..fe4fb6764 100644 --- a/src/apprt/gtk/menu.zig +++ b/src/apprt/gtk/menu.zig @@ -5,6 +5,7 @@ const apprt = @import("../../apprt.zig"); const App = @import("App.zig"); const Window = @import("Window.zig"); const Surface = @import("Surface.zig"); +const Builder = @import("Builder.zig"); const log = std.log.scoped(.gtk_menu); @@ -31,28 +32,10 @@ pub fn Menu( }; const parent: *T = @alignCast(@fieldParentPtr(variant, self)); - const path = "ui/menu-" ++ name ++ "-" ++ variant ++ ".ui"; + const builder = Builder.init("menu-" ++ name ++ "-" ++ variant); + defer builder.deinit(); - comptime { - // Use @embedFile to make sure that the file exists at compile - // time. Zig _should_ discard the data so that it doesn't end up - // in the final executable. At runtime we will load the data from - // a GResource. - _ = @embedFile(path); - - // Check to make sure that our file is listed as a `ui_file` in - // `gresource.zig`. If it isn't Ghostty could crash at runtime - // when we try and load a nonexistent GResource. - const gresource = @import("gresource.zig"); - for (gresource.ui_files) |ui_file| { - if (std.mem.eql(u8, ui_file, "menu-" ++ name ++ "-" ++ variant)) break; - } else @compileError("missing 'menu-" ++ name ++ "-" ++ variant ++ "' in gresource.zig"); - } - - const builder = c.gtk_builder_new_from_resource("/com/mitchellh/ghostty/" ++ path); - defer c.g_object_unref(@ptrCast(builder)); - - const menu_model: *c.GMenuModel = @ptrCast(@alignCast(c.gtk_builder_get_object(builder, "menu"))); + const menu_model = builder.getObject(c.GMenuModel, "menu"); const menu_widget: *MenuWidget = switch (style) { .popover_menu => brk: {