mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
apprt/gtk-ng: close tab confirmation
This commit is contained in:
@ -57,6 +57,17 @@ pub const CloseConfirmationDialog = extern struct {
|
|||||||
void,
|
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 {
|
const Private = struct {
|
||||||
@ -72,14 +83,15 @@ pub const CloseConfirmationDialog = extern struct {
|
|||||||
|
|
||||||
fn init(self: *Self, _: *Class) callconv(.C) void {
|
fn init(self: *Self, _: *Class) callconv(.C) void {
|
||||||
gtk.Widget.initTemplate(self.as(gtk.Widget));
|
gtk.Widget.initTemplate(self.as(gtk.Widget));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn present(self: *Self, parent: ?*gtk.Widget) void {
|
||||||
// Setup our title/body text.
|
// Setup our title/body text.
|
||||||
const priv = self.private();
|
const priv = self.private();
|
||||||
self.as(Dialog.Parent).setHeading(priv.target.title());
|
self.as(Dialog.Parent).setHeading(priv.target.title());
|
||||||
self.as(Dialog.Parent).setBody(priv.target.body());
|
self.as(Dialog.Parent).setBody(priv.target.body());
|
||||||
}
|
|
||||||
|
|
||||||
pub fn present(self: *Self, parent: ?*gtk.Widget) void {
|
// Show it
|
||||||
self.as(Dialog).present(parent);
|
self.as(Dialog).present(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,13 +103,21 @@ pub const CloseConfirmationDialog = extern struct {
|
|||||||
self: *Self,
|
self: *Self,
|
||||||
response_id: [*:0]const u8,
|
response_id: [*:0]const u8,
|
||||||
) callconv(.C) void {
|
) callconv(.C) void {
|
||||||
if (std.mem.orderZ(u8, response_id, "close") != .eq) return;
|
if (std.mem.orderZ(u8, response_id, "close") == .eq) {
|
||||||
signals.@"close-request".impl.emit(
|
signals.@"close-request".impl.emit(
|
||||||
self,
|
self,
|
||||||
null,
|
null,
|
||||||
.{},
|
.{},
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
signals.cancel.impl.emit(
|
||||||
|
self,
|
||||||
|
null,
|
||||||
|
.{},
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dispose(self: *Self) callconv(.C) void {
|
fn dispose(self: *Self) callconv(.C) void {
|
||||||
@ -141,6 +161,7 @@ pub const CloseConfirmationDialog = extern struct {
|
|||||||
|
|
||||||
// Signals
|
// Signals
|
||||||
signals.@"close-request".impl.register(.{});
|
signals.@"close-request".impl.register(.{});
|
||||||
|
signals.cancel.impl.register(.{});
|
||||||
|
|
||||||
// Virtual methods
|
// Virtual methods
|
||||||
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
|
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.
|
/// together into one struct that is the sole source of truth.
|
||||||
pub const Target = enum(c_int) {
|
pub const Target = enum(c_int) {
|
||||||
app,
|
app,
|
||||||
|
tab,
|
||||||
window,
|
window,
|
||||||
|
|
||||||
pub fn title(self: Target) [*:0]const u8 {
|
pub fn title(self: Target) [*:0]const u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.app => i18n._("Quit Ghostty?"),
|
.app => i18n._("Quit Ghostty?"),
|
||||||
|
.tab => i18n._("Close Tab?"),
|
||||||
.window => i18n._("Close Window?"),
|
.window => i18n._("Close Window?"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -170,6 +193,7 @@ pub const Target = enum(c_int) {
|
|||||||
pub fn body(self: Target) [*:0]const u8 {
|
pub fn body(self: Target) [*:0]const u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.app => i18n._("All terminal sessions will be terminated."),
|
.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."),
|
.window => i18n._("All terminal sessions in this window will be terminated."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -172,6 +172,14 @@ pub const Tab = extern struct {
|
|||||||
return priv.surface;
|
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
|
// Virtual methods
|
||||||
|
|
||||||
|
@ -591,6 +591,81 @@ pub const Window = extern struct {
|
|||||||
self.as(gtk.Window).destroy();
|
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(
|
fn tabViewSelectedPage(
|
||||||
_: *adw.TabView,
|
_: *adw.TabView,
|
||||||
_: *gobject.ParamSpec,
|
_: *gobject.ParamSpec,
|
||||||
@ -929,6 +1004,7 @@ pub const Window = extern struct {
|
|||||||
|
|
||||||
// Template Callbacks
|
// Template Callbacks
|
||||||
class.bindTemplateCallback("close_request", &windowCloseRequest);
|
class.bindTemplateCallback("close_request", &windowCloseRequest);
|
||||||
|
class.bindTemplateCallback("close_page", &tabViewClosePage);
|
||||||
class.bindTemplateCallback("selected_page", &tabViewSelectedPage);
|
class.bindTemplateCallback("selected_page", &tabViewSelectedPage);
|
||||||
class.bindTemplateCallback("page_attached", &tabViewPageAttached);
|
class.bindTemplateCallback("page_attached", &tabViewPageAttached);
|
||||||
class.bindTemplateCallback("page_detached", &tabViewPageDetached);
|
class.bindTemplateCallback("page_detached", &tabViewPageDetached);
|
||||||
|
@ -79,6 +79,7 @@ template $GhosttyWindow: Adw.ApplicationWindow {
|
|||||||
Adw.ToastOverlay toast_overlay {
|
Adw.ToastOverlay toast_overlay {
|
||||||
Adw.TabView tab_view {
|
Adw.TabView tab_view {
|
||||||
notify::selected-page => $selected_page();
|
notify::selected-page => $selected_page();
|
||||||
|
close-page => $close_page();
|
||||||
page-attached => $page_attached();
|
page-attached => $page_attached();
|
||||||
page-detached => $page_detached();
|
page-detached => $page_detached();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user