mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 06:47:33 +03:00
apprt/gtk-ng: close tab confirmation
This commit is contained in:
@ -57,6 +57,17 @@ pub const CloseConfirmationDialog = extern struct {
|
||||
void,
|
||||
);
|
||||
};
|
||||
|
||||
pub const cancel = struct {
|
||||
pub const name = "cancel";
|
||||
pub const connect = impl.connect;
|
||||
const impl = gobject.ext.defineSignal(
|
||||
name,
|
||||
Self,
|
||||
&.{},
|
||||
void,
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
const Private = struct {
|
||||
@ -72,14 +83,15 @@ pub const CloseConfirmationDialog = extern struct {
|
||||
|
||||
fn init(self: *Self, _: *Class) callconv(.C) void {
|
||||
gtk.Widget.initTemplate(self.as(gtk.Widget));
|
||||
}
|
||||
|
||||
pub fn present(self: *Self, parent: ?*gtk.Widget) void {
|
||||
// Setup our title/body text.
|
||||
const priv = self.private();
|
||||
self.as(Dialog.Parent).setHeading(priv.target.title());
|
||||
self.as(Dialog.Parent).setBody(priv.target.body());
|
||||
}
|
||||
|
||||
pub fn present(self: *Self, parent: ?*gtk.Widget) void {
|
||||
// Show it
|
||||
self.as(Dialog).present(parent);
|
||||
}
|
||||
|
||||
@ -91,13 +103,21 @@ pub const CloseConfirmationDialog = extern struct {
|
||||
self: *Self,
|
||||
response_id: [*:0]const u8,
|
||||
) callconv(.C) void {
|
||||
if (std.mem.orderZ(u8, response_id, "close") != .eq) return;
|
||||
signals.@"close-request".impl.emit(
|
||||
self,
|
||||
null,
|
||||
.{},
|
||||
null,
|
||||
);
|
||||
if (std.mem.orderZ(u8, response_id, "close") == .eq) {
|
||||
signals.@"close-request".impl.emit(
|
||||
self,
|
||||
null,
|
||||
.{},
|
||||
null,
|
||||
);
|
||||
} else {
|
||||
signals.cancel.impl.emit(
|
||||
self,
|
||||
null,
|
||||
.{},
|
||||
null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn dispose(self: *Self) callconv(.C) void {
|
||||
@ -141,6 +161,7 @@ pub const CloseConfirmationDialog = extern struct {
|
||||
|
||||
// Signals
|
||||
signals.@"close-request".impl.register(.{});
|
||||
signals.cancel.impl.register(.{});
|
||||
|
||||
// Virtual methods
|
||||
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
|
||||
@ -158,11 +179,13 @@ pub const CloseConfirmationDialog = extern struct {
|
||||
/// together into one struct that is the sole source of truth.
|
||||
pub const Target = enum(c_int) {
|
||||
app,
|
||||
tab,
|
||||
window,
|
||||
|
||||
pub fn title(self: Target) [*:0]const u8 {
|
||||
return switch (self) {
|
||||
.app => i18n._("Quit Ghostty?"),
|
||||
.tab => i18n._("Close Tab?"),
|
||||
.window => i18n._("Close Window?"),
|
||||
};
|
||||
}
|
||||
@ -170,6 +193,7 @@ pub const Target = enum(c_int) {
|
||||
pub fn body(self: Target) [*:0]const u8 {
|
||||
return switch (self) {
|
||||
.app => i18n._("All terminal sessions will be terminated."),
|
||||
.tab => i18n._("All terminal sessions in this tab will be terminated."),
|
||||
.window => i18n._("All terminal sessions in this window will be terminated."),
|
||||
};
|
||||
}
|
||||
|
@ -172,6 +172,14 @@ pub const Tab = extern struct {
|
||||
return priv.surface;
|
||||
}
|
||||
|
||||
/// Returns true if this tab needs confirmation before quitting based
|
||||
/// on the various Ghostty configurations.
|
||||
pub fn getNeedsConfirmQuit(self: *Self) bool {
|
||||
const surface = self.getActiveSurface();
|
||||
const core_surface = surface.core() orelse return false;
|
||||
return core_surface.needsConfirmQuit();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Virtual methods
|
||||
|
||||
|
@ -591,6 +591,81 @@ pub const Window = extern struct {
|
||||
self.as(gtk.Window).destroy();
|
||||
}
|
||||
|
||||
fn closeConfirmationCloseTab(
|
||||
_: *CloseConfirmationDialog,
|
||||
page: *adw.TabPage,
|
||||
) callconv(.c) void {
|
||||
const tab_view_widget = page
|
||||
.getChild()
|
||||
.as(gtk.Widget)
|
||||
.getAncestor(gobject.ext.typeFor(adw.TabView)) orelse {
|
||||
log.warn("close confirmation caled for non-existent page", .{});
|
||||
return;
|
||||
};
|
||||
const tab_view = gobject.ext.cast(
|
||||
adw.TabView,
|
||||
tab_view_widget,
|
||||
).?;
|
||||
tab_view.closePageFinish(page, @intFromBool(true));
|
||||
}
|
||||
|
||||
fn closeConfirmationCancelTab(
|
||||
_: *CloseConfirmationDialog,
|
||||
page: *adw.TabPage,
|
||||
) callconv(.c) void {
|
||||
const tab_view_widget = page
|
||||
.getChild()
|
||||
.as(gtk.Widget)
|
||||
.getAncestor(gobject.ext.typeFor(adw.TabView)) orelse {
|
||||
log.warn("close confirmation caled for non-existent page", .{});
|
||||
return;
|
||||
};
|
||||
const tab_view = gobject.ext.cast(
|
||||
adw.TabView,
|
||||
tab_view_widget,
|
||||
).?;
|
||||
tab_view.closePageFinish(page, @intFromBool(false));
|
||||
}
|
||||
|
||||
fn tabViewClosePage(
|
||||
_: *adw.TabView,
|
||||
page: *adw.TabPage,
|
||||
self: *Self,
|
||||
) callconv(.c) c_int {
|
||||
const priv = self.private();
|
||||
const child = page.getChild();
|
||||
const tab = gobject.ext.cast(Tab, child) orelse
|
||||
return @intFromBool(false);
|
||||
|
||||
// If the tab says it doesn't need confirmation then we go ahead
|
||||
// and close immediately.
|
||||
if (!tab.getNeedsConfirmQuit()) {
|
||||
priv.tab_view.closePageFinish(page, @intFromBool(true));
|
||||
return @intFromBool(true);
|
||||
}
|
||||
|
||||
// Show a confirmation dialog
|
||||
const dialog: *CloseConfirmationDialog = .new(.tab);
|
||||
_ = CloseConfirmationDialog.signals.@"close-request".connect(
|
||||
dialog,
|
||||
*adw.TabPage,
|
||||
closeConfirmationCloseTab,
|
||||
page,
|
||||
.{},
|
||||
);
|
||||
_ = CloseConfirmationDialog.signals.cancel.connect(
|
||||
dialog,
|
||||
*adw.TabPage,
|
||||
closeConfirmationCancelTab,
|
||||
page,
|
||||
.{},
|
||||
);
|
||||
|
||||
// Show it
|
||||
dialog.present(child);
|
||||
return @intFromBool(true);
|
||||
}
|
||||
|
||||
fn tabViewSelectedPage(
|
||||
_: *adw.TabView,
|
||||
_: *gobject.ParamSpec,
|
||||
@ -929,6 +1004,7 @@ pub const Window = extern struct {
|
||||
|
||||
// Template Callbacks
|
||||
class.bindTemplateCallback("close_request", &windowCloseRequest);
|
||||
class.bindTemplateCallback("close_page", &tabViewClosePage);
|
||||
class.bindTemplateCallback("selected_page", &tabViewSelectedPage);
|
||||
class.bindTemplateCallback("page_attached", &tabViewPageAttached);
|
||||
class.bindTemplateCallback("page_detached", &tabViewPageDetached);
|
||||
|
@ -79,6 +79,7 @@ template $GhosttyWindow: Adw.ApplicationWindow {
|
||||
Adw.ToastOverlay toast_overlay {
|
||||
Adw.TabView tab_view {
|
||||
notify::selected-page => $selected_page();
|
||||
close-page => $close_page();
|
||||
page-attached => $page_attached();
|
||||
page-detached => $page_detached();
|
||||
}
|
||||
|
Reference in New Issue
Block a user