From 7ca3f41f6f25e13e5da065700eaad0c5798a9ddb Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 23 Dec 2025 10:31:53 -0800 Subject: [PATCH] apprt/gtk: key state overlay take bindings from surface --- src/apprt/gtk/class/key_state_overlay.zig | 111 ++++++++++++++-------- src/apprt/gtk/ext/slice.zig | 5 + src/apprt/gtk/ui/1.2/surface.blp | 5 +- 3 files changed, 83 insertions(+), 38 deletions(-) diff --git a/src/apprt/gtk/class/key_state_overlay.zig b/src/apprt/gtk/class/key_state_overlay.zig index 15dc0d502..20c0a8ab8 100644 --- a/src/apprt/gtk/class/key_state_overlay.zig +++ b/src/apprt/gtk/class/key_state_overlay.zig @@ -1,10 +1,9 @@ const std = @import("std"); const adw = @import("adw"); -const glib = @import("glib"); const gobject = @import("gobject"); -const gdk = @import("gdk"); const gtk = @import("gtk"); +const ext = @import("../ext.zig"); const gresource = @import("../build/gresource.zig"); const Common = @import("../class.zig").Common; @@ -39,15 +38,23 @@ pub const KeyStateOverlay = extern struct { ); }; - pub const @"tables-text" = struct { - pub const name = "tables-text"; + pub const tables = struct { + pub const name = "tables"; const impl = gobject.ext.defineProperty( name, Self, - ?[:0]const u8, + ?*ext.StringList, .{ - .default = null, - .accessor = C.privateStringFieldAccessor("tables_text"), + .accessor = gobject.ext.typedAccessor( + Self, + ?*ext.StringList, + .{ + .getter = getTables, + .getter_transfer = .full, + .setter = setTables, + .setter_transfer = .full, + }, + ), }, ); }; @@ -69,15 +76,23 @@ pub const KeyStateOverlay = extern struct { ); }; - pub const @"sequence-text" = struct { - pub const name = "sequence-text"; + pub const sequence = struct { + pub const name = "sequence"; const impl = gobject.ext.defineProperty( name, Self, - ?[:0]const u8, + ?*ext.StringList, .{ - .default = null, - .accessor = C.privateStringFieldAccessor("sequence_text"), + .accessor = gobject.ext.typedAccessor( + Self, + ?*ext.StringList, + .{ + .getter = getSequence, + .getter_transfer = .full, + .setter = setSequence, + .setter_transfer = .full, + }, + ), }, ); }; @@ -130,11 +145,11 @@ pub const KeyStateOverlay = extern struct { /// Whether the overlay is active/visible. active: bool = false, - /// The formatted key table stack text (e.g., "default › vim"). - tables_text: ?[:0]const u8 = null, + /// The key table stack. + tables: ?*ext.StringList = null, - /// The formatted key sequence text (e.g., "Ctrl+A B"). - sequence_text: ?[:0]const u8 = null, + /// The key sequence. + sequence: ?*ext.StringList = null, /// Whether we're waiting for more keys in a sequence. pending: bool = false, @@ -147,30 +162,52 @@ pub const KeyStateOverlay = extern struct { fn init(self: *Self, _: *Class) callconv(.c) void { gtk.Widget.initTemplate(self.as(gtk.Widget)); + } - // Set dummy data for UI iteration + fn getTables(self: *Self) ?*ext.StringList { const priv = self.private(); - priv.active = true; - priv.tables_text = glib.ext.dupeZ(u8, "default › vim"); - priv.sequence_text = glib.ext.dupeZ(u8, "Ctrl+A"); - priv.pending = true; + if (priv.tables) |tables| { + return ext.StringList.create(tables.allocator(), tables.strings) catch null; + } + return null; + } - // Notify property changes so bindings update - const obj = self.as(gobject.Object); - obj.notifyByPspec(properties.active.impl.param_spec); - obj.notifyByPspec(properties.@"tables-text".impl.param_spec); - obj.notifyByPspec(properties.@"has-tables".impl.param_spec); - obj.notifyByPspec(properties.@"sequence-text".impl.param_spec); - obj.notifyByPspec(properties.@"has-sequence".impl.param_spec); - obj.notifyByPspec(properties.pending.impl.param_spec); + fn getSequence(self: *Self) ?*ext.StringList { + const priv = self.private(); + if (priv.sequence) |sequence| { + return ext.StringList.create(sequence.allocator(), sequence.strings) catch null; + } + return null; + } + + fn setTables(self: *Self, value: ?*ext.StringList) void { + const priv = self.private(); + if (priv.tables) |old| { + old.destroy(); + priv.tables = null; + } + + priv.tables = value; + self.as(gobject.Object).notifyByPspec(properties.@"has-tables".impl.param_spec); + } + + fn setSequence(self: *Self, value: ?*ext.StringList) void { + const priv = self.private(); + if (priv.sequence) |old| { + old.destroy(); + priv.sequence = null; + } + + priv.sequence = value; + self.as(gobject.Object).notifyByPspec(properties.@"has-sequence".impl.param_spec); } fn getHasTables(self: *Self) bool { - return self.private().tables_text != null; + return self.private().tables != null; } fn getHasSequence(self: *Self) bool { - return self.private().sequence_text != null; + return self.private().sequence != null; } fn closureShowChevron( @@ -229,11 +266,11 @@ pub const KeyStateOverlay = extern struct { fn finalize(self: *Self) callconv(.c) void { const priv = self.private(); - if (priv.tables_text) |v| { - glib.free(@ptrCast(@constCast(v))); + if (priv.tables) |v| { + v.destroy(); } - if (priv.sequence_text) |v| { - glib.free(@ptrCast(@constCast(v))); + if (priv.sequence) |v| { + v.destroy(); } gobject.Object.virtual_methods.finalize.call( @@ -270,9 +307,9 @@ pub const KeyStateOverlay = extern struct { // Properties gobject.ext.registerProperties(class, &.{ properties.active.impl, - properties.@"tables-text".impl, + properties.tables.impl, properties.@"has-tables".impl, - properties.@"sequence-text".impl, + properties.sequence.impl, properties.@"has-sequence".impl, properties.pending.impl, properties.@"valign-target".impl, diff --git a/src/apprt/gtk/ext/slice.zig b/src/apprt/gtk/ext/slice.zig index a746d8045..49ad63d85 100644 --- a/src/apprt/gtk/ext/slice.zig +++ b/src/apprt/gtk/ext/slice.zig @@ -36,6 +36,11 @@ pub const StringList = struct { alloc.destroy(self); } + /// Returns the general-purpose allocator used by this StringList. + pub fn allocator(self: *const StringList) Allocator { + return self.arena.child_allocator; + } + pub const getGObjectType = gobject.ext.defineBoxed( StringList, .{ diff --git a/src/apprt/gtk/ui/1.2/surface.blp b/src/apprt/gtk/ui/1.2/surface.blp index e9db4208e..a594ba98f 100644 --- a/src/apprt/gtk/ui/1.2/surface.blp +++ b/src/apprt/gtk/ui/1.2/surface.blp @@ -156,7 +156,10 @@ Overlay terminal_page { } [overlay] - $GhosttyKeyStateOverlay key_state_overlay {} + $GhosttyKeyStateOverlay key_state_overlay { + tables: bind template.key-table; + sequence: bind template.key-sequence; + } [overlay] // Apply unfocused-split-fill and unfocused-split-opacity to current surface