mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-10-14 13:56:08 +00:00
gtk/TabView: do not closeTab within close-page signal handler
`TabView` assumes to be the sole owner of all `Tab`s within a Window. As such, it could close the managed `Window` once all tabs are removed from its widget. However, during `AdwTabView::close-page` signal triggered by libadwaita, the `Tab` to be closed will gain an another reference for the duration of the signal, breaking `TabView.closeTab` (called via `Tab.closeWithConfirmation`) assumptions that having no tabs meant they are all destroyed. This commit solves the issue by scheduling `Tab.closeWithConfirmation` to be run after `AdwTabView::close-page` signal has finished processing.
This commit is contained in:
@@ -7,6 +7,7 @@ const std = @import("std");
|
|||||||
const gtk = @import("gtk");
|
const gtk = @import("gtk");
|
||||||
const adw = @import("adw");
|
const adw = @import("adw");
|
||||||
const gobject = @import("gobject");
|
const gobject = @import("gobject");
|
||||||
|
const glib = @import("glib");
|
||||||
|
|
||||||
const Window = @import("Window.zig");
|
const Window = @import("Window.zig");
|
||||||
const Tab = @import("Tab.zig");
|
const Tab = @import("Tab.zig");
|
||||||
@@ -243,7 +244,14 @@ fn adwClosePage(
|
|||||||
const child = page.getChild().as(gobject.Object);
|
const child = page.getChild().as(gobject.Object);
|
||||||
const tab: *Tab = @ptrCast(@alignCast(child.getData(Tab.GHOSTTY_TAB) orelse return 0));
|
const tab: *Tab = @ptrCast(@alignCast(child.getData(Tab.GHOSTTY_TAB) orelse return 0));
|
||||||
self.tab_view.closePageFinish(page, @intFromBool(self.forcing_close));
|
self.tab_view.closePageFinish(page, @intFromBool(self.forcing_close));
|
||||||
if (!self.forcing_close) tab.closeWithConfirmation();
|
if (!self.forcing_close) {
|
||||||
|
// We cannot trigger a close directly in here as the page will stay
|
||||||
|
// alive until this handler returns, breaking the assumption where
|
||||||
|
// no pages means they are all destroyed.
|
||||||
|
//
|
||||||
|
// Schedule the close request to happen in the next event cycle.
|
||||||
|
_ = glib.idleAddOnce(glibIdleOnceCloseTab, tab);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -269,3 +277,8 @@ fn adwSelectPage(_: *adw.TabView, _: *gobject.ParamSpec, self: *TabView) callcon
|
|||||||
const title = page.getTitle();
|
const title = page.getTitle();
|
||||||
self.window.setTitle(std.mem.span(title));
|
self.window.setTitle(std.mem.span(title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn glibIdleOnceCloseTab(data: ?*anyopaque) callconv(.c) void {
|
||||||
|
const tab: *Tab = @ptrCast(@alignCast(data orelse return));
|
||||||
|
tab.closeWithConfirmation();
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user