apprt/gtk-ng: handle surface close request

This commit is contained in:
Mitchell Hashimoto
2025-07-28 21:37:32 -07:00
parent ed25a57d08
commit 431a6328dc
3 changed files with 69 additions and 3 deletions

View File

@ -91,11 +91,25 @@ pub const Tab = extern struct {
};
};
pub const signals = struct {
/// Emitted whenever the tab would like to be closed.
pub const @"close-request" = struct {
pub const name = "close-request";
pub const connect = impl.connect;
const impl = gobject.ext.defineSignal(
name,
Self,
&.{},
void,
);
};
};
const Private = struct {
/// The configuration that this surface is using.
config: ?*Config = null,
/// The title to show for this tab. This is usally set to a binding
/// The title to show for this tab. This is usually set to a binding
/// with the active surface but can be manually set to anything.
title: ?[:0]const u8 = null,
@ -196,6 +210,27 @@ pub const Tab = extern struct {
//---------------------------------------------------------------
// Signal handlers
fn surfaceCloseRequest(
_: *Surface,
scope: *const Surface.CloseScope,
self: *Self,
) callconv(.c) void {
switch (scope.*) {
// Handled upstream... we don't control our window close.
.window => return,
// Presently both the same, results in the tab closing.
.surface, .tab => {
signals.@"close-request".impl.emit(
self,
null,
.{},
null,
);
},
}
}
const C = Common(Self, Private);
pub const as = C.as;
pub const ref = C.ref;
@ -229,7 +264,10 @@ pub const Tab = extern struct {
class.bindTemplateChildPrivate("surface", .{});
// Template Callbacks
//class.bindTemplateCallback("close_request", &windowCloseRequest);
class.bindTemplateCallback("surface_close_request", &surfaceCloseRequest);
// Signals
signals.@"close-request".impl.register(.{});
// Virtual methods
gobject.Object.virtual_methods.dispose.implement(class, &dispose);

View File

@ -621,6 +621,15 @@ pub const Window = extern struct {
const child = page.getChild();
const tab = gobject.ext.cast(Tab, child) orelse return;
// Attach listeners for the tab.
_ = Tab.signals.@"close-request".connect(
tab,
*Self,
tabCloseRequest,
self,
.{},
);
// Attach listeners for the surface.
//
// Interesting behavior here that was previously undocumented but
@ -682,6 +691,15 @@ pub const Window = extern struct {
// We need to get the tab to disconnect the signals.
const child = page.getChild();
const tab = gobject.ext.cast(Tab, child) orelse return;
_ = gobject.signalHandlersDisconnectMatched(
tab.as(gobject.Object),
.{ .data = true },
0,
0,
null,
null,
self,
);
// Remove all the signals that have this window as the userdata.
const surface = tab.getActiveSurface();
@ -696,6 +714,16 @@ pub const Window = extern struct {
);
}
fn tabCloseRequest(
tab: *Tab,
self: *Self,
) callconv(.c) void {
const priv = self.private();
const page = priv.tab_view.getPage(tab.as(gtk.Widget));
// TODO: connect close page handler to tab to check for confirmation
priv.tab_view.closePage(page);
}
fn surfaceClipboardWrite(
_: *Surface,
clipboard_type: apprt.Clipboard,

View File

@ -10,6 +10,6 @@ template $GhosttyTab: Box {
// A tab currently just contains a surface directly. When we introduce
// splits we probably want to replace this with the split widget type.
$GhosttySurface surface {
// close-request => $surface_close_request();
close-request => $surface_close_request();
}
}