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 { const Private = struct {
/// The configuration that this surface is using. /// The configuration that this surface is using.
config: ?*Config = null, 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. /// with the active surface but can be manually set to anything.
title: ?[:0]const u8 = null, title: ?[:0]const u8 = null,
@ -196,6 +210,27 @@ pub const Tab = extern struct {
//--------------------------------------------------------------- //---------------------------------------------------------------
// Signal handlers // 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); const C = Common(Self, Private);
pub const as = C.as; pub const as = C.as;
pub const ref = C.ref; pub const ref = C.ref;
@ -229,7 +264,10 @@ pub const Tab = extern struct {
class.bindTemplateChildPrivate("surface", .{}); class.bindTemplateChildPrivate("surface", .{});
// Template Callbacks // Template Callbacks
//class.bindTemplateCallback("close_request", &windowCloseRequest); class.bindTemplateCallback("surface_close_request", &surfaceCloseRequest);
// Signals
signals.@"close-request".impl.register(.{});
// Virtual methods // Virtual methods
gobject.Object.virtual_methods.dispose.implement(class, &dispose); gobject.Object.virtual_methods.dispose.implement(class, &dispose);

View File

@ -621,6 +621,15 @@ pub const Window = extern struct {
const child = page.getChild(); const child = page.getChild();
const tab = gobject.ext.cast(Tab, child) orelse return; 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. // Attach listeners for the surface.
// //
// Interesting behavior here that was previously undocumented but // 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. // We need to get the tab to disconnect the signals.
const child = page.getChild(); const child = page.getChild();
const tab = gobject.ext.cast(Tab, child) orelse return; 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. // Remove all the signals that have this window as the userdata.
const surface = tab.getActiveSurface(); 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( fn surfaceClipboardWrite(
_: *Surface, _: *Surface,
clipboard_type: apprt.Clipboard, clipboard_type: apprt.Clipboard,

View File

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