From b7b5b9bbf5f570f4669c92e61322469a825d0b33 Mon Sep 17 00:00:00 2001 From: Leigh Oliver Date: Tue, 31 Dec 2024 23:40:49 +0000 Subject: [PATCH] fix(gtk): add close confirmation for tabs --- src/apprt/gtk/Tab.zig | 67 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/src/apprt/gtk/Tab.zig b/src/apprt/gtk/Tab.zig index ed0804fd3..1a3b44136 100644 --- a/src/apprt/gtk/Tab.zig +++ b/src/apprt/gtk/Tab.zig @@ -121,10 +121,71 @@ pub fn remove(self: *Tab) void { self.window.closeTab(self); } +/// Helper function to check if any surface in the split hierarchy needs close confirmation +const needsConfirm = struct { + fn check(elem: Surface.Container.Elem) bool { + return switch (elem) { + .surface => |s| s.core_surface.needsConfirmQuit(), + .split => |s| check(s.top_left) or check(s.bottom_right), + }; + } +}.check; + +/// Close the tab, asking for confirmation if any surface requests it. +fn closeWithConfirmation(tab: *Tab) void { + switch (tab.elem) { + .surface => |s| s.close(s.core_surface.needsConfirmQuit()), + .split => |s| { + if (needsConfirm(s.top_left) or needsConfirm(s.bottom_right)) { + const alert = c.gtk_message_dialog_new( + tab.window.window, + c.GTK_DIALOG_MODAL, + c.GTK_MESSAGE_QUESTION, + c.GTK_BUTTONS_YES_NO, + "Close this tab?", + ); + c.gtk_message_dialog_format_secondary_text( + @ptrCast(alert), + "All terminal sessions in this tab will be terminated.", + ); + + // We want the "yes" to appear destructive. + const yes_widget = c.gtk_dialog_get_widget_for_response( + @ptrCast(alert), + c.GTK_RESPONSE_YES, + ); + c.gtk_widget_add_css_class(yes_widget, "destructive-action"); + + // We want the "no" to be the default action + c.gtk_dialog_set_default_response( + @ptrCast(alert), + c.GTK_RESPONSE_NO, + ); + + _ = c.g_signal_connect_data(alert, "response", c.G_CALLBACK(>kTabCloseConfirmation), tab, null, c.G_CONNECT_DEFAULT); + c.gtk_widget_show(alert); + return; + } + tab.remove(); + }, + } +} + pub fn gtkTabCloseClick(_: *c.GtkButton, ud: ?*anyopaque) callconv(.C) void { const tab: *Tab = @ptrCast(@alignCast(ud)); - const window = tab.window; - window.closeTab(tab); + tab.closeWithConfirmation(); +} + +fn gtkTabCloseConfirmation( + alert: *c.GtkMessageDialog, + response: c.gint, + ud: ?*anyopaque, +) callconv(.C) void { + c.gtk_window_destroy(@ptrCast(alert)); + if (response == c.GTK_RESPONSE_YES) { + const tab: *Tab = @ptrCast(@alignCast(ud)); + tab.remove(); + } } fn gtkDestroy(v: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void { @@ -146,6 +207,6 @@ pub fn gtkTabClick( const self: *Tab = @ptrCast(@alignCast(ud)); const gtk_button = c.gtk_gesture_single_get_current_button(@ptrCast(gesture)); if (gtk_button == c.GDK_BUTTON_MIDDLE) { - self.remove(); + self.closeWithConfirmation(); } }