apprt/gtk-ng: active surface hookups

pull/8207/head
Mitchell Hashimoto 2025-08-09 13:49:25 -07:00
parent 8232cf33b4
commit ec293c1fd0
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
4 changed files with 29 additions and 55 deletions

View File

@ -49,8 +49,6 @@ pub const SplitTree = extern struct {
Self, Self,
?*Surface, ?*Surface,
.{ .{
.nick = "Active Surface",
.blurb = "The currently active surface.",
.accessor = gobject.ext.typedAccessor( .accessor = gobject.ext.typedAccessor(
Self, Self,
?*Surface, ?*Surface,
@ -481,6 +479,7 @@ pub const SplitTree = extern struct {
// Remove the surface from the tree. // Remove the surface from the tree.
.surface => { .surface => {
// TODO: close confirmation // TODO: close confirmation
// TODO: invalid free on final close
// Find the surface in the tree. // Find the surface in the tree.
const tree = self.getTree() orelse return; const tree = self.getTree() orelse return;
@ -517,6 +516,9 @@ pub const SplitTree = extern struct {
// the surface is destroyed. // the surface is destroyed.
if (!surface.getFocused()) return; if (!surface.getFocused()) return;
self.private().last_focused.set(surface); self.private().last_focused.set(surface);
// Our active surface probably changed
self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec);
} }
fn propTree( fn propTree(
@ -566,6 +568,9 @@ pub const SplitTree = extern struct {
v.grabFocus(); v.grabFocus();
} }
// Our active surface may have changed
self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec);
return 0; return 0;
} }
@ -616,6 +621,7 @@ pub const SplitTree = extern struct {
// Properties // Properties
gobject.ext.registerProperties(class, &.{ gobject.ext.registerProperties(class, &.{
properties.@"active-surface".impl,
properties.@"has-surfaces".impl, properties.@"has-surfaces".impl,
properties.tree.impl, properties.tree.impl,
}); });

View File

@ -175,42 +175,6 @@ pub const Tab = extern struct {
}; };
} }
fn connectSurfaceHandlers(
self: *Self,
tree: *const Surface.Tree,
) void {
var it = tree.iterator();
while (it.next()) |entry| {
const surface = entry.view;
_ = gobject.Object.signals.notify.connect(
surface,
*Self,
propSurfaceFocused,
self,
.{ .detail = "focused" },
);
}
}
fn disconnectSurfaceHandlers(
self: *Self,
tree: *const Surface.Tree,
) void {
var it = tree.iterator();
while (it.next()) |entry| {
const surface = entry.view;
_ = gobject.signalHandlersDisconnectMatched(
surface.as(gobject.Object),
.{ .data = true },
0,
0,
null,
null,
self,
);
}
}
//--------------------------------------------------------------- //---------------------------------------------------------------
// Properties // Properties
@ -280,14 +244,10 @@ pub const Tab = extern struct {
fn splitTreeChanged( fn splitTreeChanged(
_: *SplitTree, _: *SplitTree,
old_tree: ?*const Surface.Tree, _: ?*const Surface.Tree,
new_tree: ?*const Surface.Tree, new_tree: ?*const Surface.Tree,
self: *Self, self: *Self,
) callconv(.c) void { ) callconv(.c) void {
if (old_tree) |tree| {
self.disconnectSurfaceHandlers(tree);
}
// If our tree is empty we close the tab. // If our tree is empty we close the tab.
const tree: *const Surface.Tree = new_tree orelse &.empty; const tree: *const Surface.Tree = new_tree orelse &.empty;
if (tree.isEmpty()) { if (tree.isEmpty()) {
@ -299,9 +259,6 @@ pub const Tab = extern struct {
); );
return; return;
} }
// Non-empty tree, connect handlers we care about.
self.connectSurfaceHandlers(tree);
} }
fn propSplitTree( fn propSplitTree(
@ -313,7 +270,7 @@ pub const Tab = extern struct {
} }
fn propActiveSurface( fn propActiveSurface(
_: *Self, _: *SplitTree,
_: *gobject.ParamSpec, _: *gobject.ParamSpec,
self: *Self, self: *Self,
) callconv(.c) void { ) callconv(.c) void {
@ -322,14 +279,7 @@ pub const Tab = extern struct {
if (self.getActiveSurface()) |surface| { if (self.getActiveSurface()) |surface| {
priv.surface_bindings.setSource(surface.as(gobject.Object)); priv.surface_bindings.setSource(surface.as(gobject.Object));
} }
}
fn propSurfaceFocused(
surface: *Surface,
_: *gobject.ParamSpec,
self: *Self,
) callconv(.c) void {
if (!surface.getFocused()) return;
self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec); self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec);
} }

View File

@ -5,12 +5,12 @@ template $GhosttyTab: Box {
"tab", "tab",
] ]
notify::active-surface => $notify_active_surface();
orientation: vertical; orientation: vertical;
hexpand: true; hexpand: true;
vexpand: true; vexpand: true;
$GhosttySplitTree split_tree { $GhosttySplitTree split_tree {
notify::active-surface => $notify_active_surface();
notify::tree => $notify_tree(); notify::tree => $notify_tree();
changed => $tree_changed(); changed => $tree_changed();
} }

View File

@ -1151,3 +1151,21 @@ test "SplitTree: split twice, remove intermediary" {
t.deinit(); t.deinit();
} }
} }
test "SplitTree: clone empty tree" {
const testing = std.testing;
const alloc = testing.allocator;
var t: TestTree = .empty;
defer t.deinit();
var t2 = try t.clone(alloc);
defer t2.deinit();
{
const str = try std.fmt.allocPrint(alloc, "{}", .{t2});
defer alloc.free(str);
try testing.expectEqualStrings(str,
\\empty
);
}
}