mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
apprt/gtk-ng: hook up window close confirmation
This commit is contained in:
@ -418,10 +418,16 @@ pub const Application = extern struct {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the parent for our dialog
|
||||
const parent: ?*gtk.Widget = parent: {
|
||||
const list = gtk.Window.listToplevels();
|
||||
defer list.free();
|
||||
const focused = list.findCustom(null, findActiveWindow);
|
||||
break :parent @ptrCast(@alignCast(focused.f_data));
|
||||
};
|
||||
|
||||
// Show a confirmation dialog
|
||||
const dialog: *CloseConfirmationDialog = .new(.app);
|
||||
|
||||
// Connect to the reload signal so we know to reload our config.
|
||||
_ = CloseConfirmationDialog.signals.@"close-request".connect(
|
||||
dialog,
|
||||
*Application,
|
||||
@ -431,7 +437,7 @@ pub const Application = extern struct {
|
||||
);
|
||||
|
||||
// Show it
|
||||
dialog.present();
|
||||
dialog.present(parent);
|
||||
}
|
||||
|
||||
fn quitNow(self: *Self) void {
|
||||
@ -1359,3 +1365,12 @@ fn setGtkEnv(config: *const CoreConfig) error{NoSpaceLeft}!void {
|
||||
_ = internal_os.setenv("GDK_DISABLE", value[0 .. value.len - 1 :0]);
|
||||
}
|
||||
}
|
||||
|
||||
fn findActiveWindow(data: ?*const anyopaque, _: ?*const anyopaque) callconv(.c) c_int {
|
||||
const window: *gtk.Window = @ptrCast(@alignCast(@constCast(data orelse return -1)));
|
||||
|
||||
// Confusingly, `isActive` returns 1 when active,
|
||||
// but we want to return 0 to indicate equality.
|
||||
// Abusing integers to be enums and booleans is a terrible idea, C.
|
||||
return if (window.isActive() != 0) 0 else -1;
|
||||
}
|
||||
|
@ -79,9 +79,8 @@ pub const CloseConfirmationDialog = extern struct {
|
||||
self.as(Dialog.Parent).setBody(priv.target.body());
|
||||
}
|
||||
|
||||
pub fn present(self: *Self) void {
|
||||
const priv = self.private();
|
||||
self.as(Dialog).present(priv.target.dialogParent());
|
||||
pub fn present(self: *Self, parent: ?*gtk.Widget) void {
|
||||
self.as(Dialog).present(parent);
|
||||
}
|
||||
|
||||
pub fn close(self: *Self) void {
|
||||
@ -159,28 +158,19 @@ pub const CloseConfirmationDialog = extern struct {
|
||||
/// together into one struct that is the sole source of truth.
|
||||
pub const Target = enum(c_int) {
|
||||
app,
|
||||
window,
|
||||
|
||||
pub fn title(self: Target) [*:0]const u8 {
|
||||
return switch (self) {
|
||||
.app => i18n._("Quit Ghostty?"),
|
||||
.window => i18n._("Close Window?"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn body(self: Target) [*:0]const u8 {
|
||||
return switch (self) {
|
||||
.app => i18n._("All terminal sessions will be terminated."),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn dialogParent(self: Target) ?*gtk.Widget {
|
||||
return switch (self) {
|
||||
.app => {
|
||||
// Find the currently focused window.
|
||||
const list = gtk.Window.listToplevels();
|
||||
defer list.free();
|
||||
const focused = list.findCustom(null, findActiveWindow);
|
||||
return @ptrCast(@alignCast(focused.f_data));
|
||||
},
|
||||
.window => i18n._("All terminal sessions in this window will be terminated."),
|
||||
};
|
||||
}
|
||||
|
||||
@ -189,12 +179,3 @@ pub const Target = enum(c_int) {
|
||||
.{ .name = "GhosttyCloseConfirmationDialogTarget" },
|
||||
);
|
||||
};
|
||||
|
||||
fn findActiveWindow(data: ?*const anyopaque, _: ?*const anyopaque) callconv(.c) c_int {
|
||||
const window: *gtk.Window = @ptrCast(@alignCast(@constCast(data orelse return -1)));
|
||||
|
||||
// Confusingly, `isActive` returns 1 when active,
|
||||
// but we want to return 0 to indicate equality.
|
||||
// Abusing integers to be enums and booleans is a terrible idea, C.
|
||||
return if (window.isActive() != 0) 0 else -1;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ const gresource = @import("../build/gresource.zig");
|
||||
const Common = @import("../class.zig").Common;
|
||||
const Config = @import("config.zig").Config;
|
||||
const Application = @import("application.zig").Application;
|
||||
const CloseConfirmationDialog = @import("close_confirmation_dialog.zig").CloseConfirmationDialog;
|
||||
const Surface = @import("surface.zig").Surface;
|
||||
const DebugWarning = @import("debug_warning.zig").DebugWarning;
|
||||
|
||||
@ -337,6 +338,44 @@ pub const Window = extern struct {
|
||||
//---------------------------------------------------------------
|
||||
// Signal handlers
|
||||
|
||||
fn windowCloseRequest(
|
||||
_: *gtk.Window,
|
||||
self: *Self,
|
||||
) callconv(.c) c_int {
|
||||
// If our surface needs confirmation then we show confirmation.
|
||||
// This will have to be expanded to a list when we have tabs
|
||||
// or splits.
|
||||
confirm: {
|
||||
const surface = self.getActiveSurface() orelse break :confirm;
|
||||
const core_surface = surface.core() orelse break :confirm;
|
||||
if (!core_surface.needsConfirmQuit()) break :confirm;
|
||||
|
||||
// Show a confirmation dialog
|
||||
const dialog: *CloseConfirmationDialog = .new(.app);
|
||||
_ = CloseConfirmationDialog.signals.@"close-request".connect(
|
||||
dialog,
|
||||
*Self,
|
||||
closeConfirmationClose,
|
||||
self,
|
||||
.{},
|
||||
);
|
||||
|
||||
// Show it
|
||||
dialog.present(self.as(gtk.Widget));
|
||||
return @intFromBool(true);
|
||||
}
|
||||
|
||||
self.as(gtk.Window).destroy();
|
||||
return @intFromBool(false);
|
||||
}
|
||||
|
||||
fn closeConfirmationClose(
|
||||
_: *CloseConfirmationDialog,
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
self.as(gtk.Window).destroy();
|
||||
}
|
||||
|
||||
fn surfaceCloseRequest(
|
||||
surface: *Surface,
|
||||
scope: *const Surface.CloseScope,
|
||||
@ -426,8 +465,7 @@ pub const Window = extern struct {
|
||||
_: ?*glib.Variant,
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
// TODO: Confirmation
|
||||
self.as(gtk.Window).destroy();
|
||||
self.as(gtk.Window).close();
|
||||
}
|
||||
|
||||
fn actionCopy(
|
||||
@ -497,6 +535,7 @@ pub const Window = extern struct {
|
||||
class.bindTemplateChildPrivate("surface", .{});
|
||||
|
||||
// Template Callbacks
|
||||
class.bindTemplateCallback("close_request", &windowCloseRequest);
|
||||
class.bindTemplateCallback("surface_close_request", &surfaceCloseRequest);
|
||||
class.bindTemplateCallback("surface_toggle_fullscreen", &surfaceToggleFullscreen);
|
||||
class.bindTemplateCallback("surface_toggle_maximize", &surfaceToggleMaximize);
|
||||
|
@ -6,6 +6,7 @@ template $GhosttyWindow: Adw.ApplicationWindow {
|
||||
"window",
|
||||
]
|
||||
|
||||
close-request => $close_request();
|
||||
notify::config => $notify_config();
|
||||
notify::fullscreened => $notify_fullscreened();
|
||||
notify::maximized => $notify_maximized();
|
||||
|
Reference in New Issue
Block a user