From cd82a610c3a482dbcb6d2c8c74089ddcf046e786 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 21 Jul 2025 06:52:23 -0700 Subject: [PATCH] apprt/gtk-ng: abstract helper for private string fields --- src/apprt/gtk-ng/class.zig | 42 +++++++++++++++++++ src/apprt/gtk-ng/class/surface.zig | 67 +++++------------------------- 2 files changed, 52 insertions(+), 57 deletions(-) diff --git a/src/apprt/gtk-ng/class.zig b/src/apprt/gtk-ng/class.zig index 5d64cb903..7c8cfbc06 100644 --- a/src/apprt/gtk-ng/class.zig +++ b/src/apprt/gtk-ng/class.zig @@ -46,6 +46,48 @@ pub fn Common( } }).private else {}; + /// A helper that can be used to create a property that reads and + /// writes a private `?[:0]const u8` field type. + /// + /// This helper helps properly manage the memory to avoid memory leaks. + /// + /// The object class (Self) must still free the private field + /// in finalize! + pub fn privateStringFieldAccessor( + comptime name: []const u8, + ) gobject.ext.Accessor( + Self, + @FieldType(Private.?, name), + ) { + const S = struct { + fn getter(self: *Self) ?[:0]const u8 { + return @field(private(self), name); + } + + fn setter(self: *Self, value: ?[:0]const u8) void { + const priv = private(self); + if (@field(priv, name)) |v| { + glib.free(@constCast(@ptrCast(v))); + } + + // We don't need to copy this because it was already + // copied by the typedAccessor. + @field(priv, name) = value; + } + }; + + return gobject.ext.typedAccessor( + Self, + ?[:0]const u8, + .{ + .getter = S.getter, + .getter_transfer = .none, + .setter = S.setter, + .setter_transfer = .full, + }, + ); + } + /// Common class functions. pub const Class = struct { pub fn as(class: *Self.Class, comptime T: type) *T { diff --git a/src/apprt/gtk-ng/class/surface.zig b/src/apprt/gtk-ng/class/surface.zig index 353a1babb..211deebfb 100644 --- a/src/apprt/gtk-ng/class/surface.zig +++ b/src/apprt/gtk-ng/class/surface.zig @@ -96,6 +96,8 @@ pub const Surface = extern struct { pub const pwd = struct { pub const name = "pwd"; + pub const get = impl.get; + pub const set = impl.set; const impl = gobject.ext.defineProperty( name, Self, @@ -104,22 +106,15 @@ pub const Surface = extern struct { .nick = "Working Directory", .blurb = "The current working directory as reported by core.", .default = null, - .accessor = gobject.ext.typedAccessor( - Self, - ?[:0]const u8, - .{ - .getter = getPwd, - .getter_transfer = .none, - .setter = setPwd, - .setter_transfer = .full, - }, - ), + .accessor = C.privateStringFieldAccessor("pwd"), }, ); }; pub const title = struct { pub const name = "title"; + pub const get = impl.get; + pub const set = impl.set; const impl = gobject.ext.defineProperty( name, Self, @@ -128,16 +123,7 @@ pub const Surface = extern struct { .nick = "Title", .blurb = "The title of the surface.", .default = null, - .accessor = gobject.ext.typedAccessor( - Self, - ?[:0]const u8, - .{ - .getter = getTitle, - .getter_transfer = .none, - .setter = setTitle, - .setter_transfer = .full, - }, - ), + .accessor = C.privateStringFieldAccessor("title"), }, ); }; @@ -876,8 +862,10 @@ pub const Surface = extern struct { priv.core_surface = null; } - if (priv.pwd != null) self.setPwd(null); - if (priv.title != null) self.setTitle(null); + + var @"null": gobject.Value = undefined; + if (priv.pwd != null) properties.pwd.set(self, &@"null"); + if (priv.title != null) properties.pwd.set(self, &@"null"); gobject.Object.virtual_methods.finalize.call( Class.parent, @@ -888,41 +876,6 @@ pub const Surface = extern struct { //--------------------------------------------------------------- // Properties - fn getPwd( - self: *Self, - ) ?[:0]const u8 { - return self.private().pwd; - } - - fn setPwd( - self: *Self, - value: ?[:0]const u8, - ) void { - const priv = self.private(); - - // Free the previous value - if (priv.pwd) |v| glib.free(@constCast(@ptrCast(v.ptr))); - - // Set the new value, which is already copied since we - // set our setter_transfer value to full. - priv.pwd = value; - } - - fn getTitle( - self: *Self, - ) ?[:0]const u8 { - return self.private().title; - } - - fn setTitle( - self: *Self, - value: ?[:0]const u8, - ) void { - const priv = self.private(); - if (priv.title) |v| glib.free(@constCast(@ptrCast(v.ptr))); - priv.title = value; - } - fn propMouseHidden( self: *Self, _: *gobject.ParamSpec,