diff --git a/src/Surface.zig b/src/Surface.zig index 1442af8695..d7acd710d8 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -236,7 +236,7 @@ const DerivedConfig = struct { clipboard_paste_protection: bool, clipboard_paste_bracketed_safe: bool, copy_on_select: configpkg.CopyOnSelect, - confirm_close_surface: bool, + confirm_close_surface: configpkg.ConfirmCloseSurface, cursor_click_to_move: bool, desktop_notifications: bool, font: font.SharedGridSet.DerivedConfig, @@ -784,18 +784,27 @@ pub fn deactivateInspector(self: *Surface) void { /// True if the surface requires confirmation to quit. This should be called /// by apprt to determine if the surface should confirm before quitting. pub fn needsConfirmQuit(self: *Surface) bool { - // If the child has exited then our process is certainly not alive. + // If the child has exited, then our process is certainly not alive. // We check this first to avoid the locking overhead below. if (self.child_exited) return false; - // If we are configured to not hold open surfaces explicitly, just - // always say there is nothing alive. - if (!self.config.confirm_close_surface) return false; - - // We have to talk to the terminal. - self.renderer_state.mutex.lock(); - defer self.renderer_state.mutex.unlock(); - return !self.io.terminal.cursorIsAtPrompt(); + // Check the configuration for confirming close behavior. + switch (self.config.confirm_close_surface) { + .false => { + // No confirmation needed. + return false; + }, + .true => { + // Proceed with the standard check. + self.renderer_state.mutex.lock(); + defer self.renderer_state.mutex.unlock(); + return !self.io.terminal.cursorIsAtPrompt(); + }, + .always => { + // Always confirm, regardless of terminal state. + return true; + }, + } } /// Called from the app thread to handle mailbox messages to our specific diff --git a/src/config.zig b/src/config.zig index b7e818f8e1..75dbaae02b 100644 --- a/src/config.zig +++ b/src/config.zig @@ -14,6 +14,7 @@ pub const formatEntry = formatter.formatEntry; // Field types pub const ClipboardAccess = Config.ClipboardAccess; +pub const ConfirmCloseSurface = Config.ConfirmCloseSurface; pub const CopyOnSelect = Config.CopyOnSelect; pub const CustomShaderAnimation = Config.CustomShaderAnimation; pub const FontSyntheticStyle = Config.FontSyntheticStyle; diff --git a/src/config/Config.zig b/src/config/Config.zig index c6702bb742..b256747ca5 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -1305,8 +1305,11 @@ keybind: Keybinds = .{}, @"config-default-files": bool = true, /// Confirms that a surface should be closed before closing it. This defaults to -/// true. If set to false, surfaces will close without any confirmation. -@"confirm-close-surface": bool = true, +/// `true`. If set to `false`, surfaces will close without any confirmation. +/// +/// This can also be set to `always`, which will always confirm closing a +/// surface, even if shell integration says a process isn't running. +@"confirm-close-surface": ConfirmCloseSurface = .true, /// Whether or not to quit after the last surface is closed. /// @@ -3636,6 +3639,15 @@ const Replay = struct { } }; +/// Valid values for confirm-close-surface +/// c_int because it needs to be extern compatible +/// If this is changed, you must also update ghostty.h +pub const ConfirmCloseSurface = enum(c_int) { + false, + true, + always, +}; + /// Valid values for custom-shader-animation /// c_int because it needs to be extern compatible /// If this is changed, you must also update ghostty.h