diff --git a/macos/Sources/Ghostty/Ghostty.SplitView.swift b/macos/Sources/Ghostty/Ghostty.SplitView.swift index 47a8be4f2..25113f8cf 100644 --- a/macos/Sources/Ghostty/Ghostty.SplitView.swift +++ b/macos/Sources/Ghostty/Ghostty.SplitView.swift @@ -7,10 +7,11 @@ extension Ghostty { /// split direction by splitting the terminal. struct TerminalSplit: View { @Environment(\.ghosttyApp) private var app - + let onClose: (() -> Void)? + var body: some View { if let app = app { - TerminalSplitRoot(app: app) + TerminalSplitRoot(app: app, onClose: onClose) } } } @@ -78,13 +79,13 @@ extension Ghostty { /// one of these in a split tree. private struct TerminalSplitRoot: View { @State private var node: SplitNode - - /// This is an ignored value because at the root we can't close. - @State private var ignoredRequestClose: Bool = false + @State private var requestClose: Bool = false + let onClose: (() -> Void)? @FocusedValue(\.ghosttySurfaceTitle) private var surfaceTitle: String? - init(app: ghostty_app_t) { + init(app: ghostty_app_t, onClose: (() ->Void)? = nil) { + self.onClose = onClose _node = State(wrappedValue: SplitNode.noSplit(.init(app))) } @@ -92,7 +93,12 @@ extension Ghostty { ZStack { switch (node) { case .noSplit(let leaf): - TerminalSplitLeaf(leaf: leaf, node: $node, requestClose: $ignoredRequestClose) + TerminalSplitLeaf(leaf: leaf, node: $node, requestClose: $requestClose) + .onChange(of: requestClose) { value in + guard value else { return } + guard let onClose = self.onClose else { return } + onClose() + } case .horizontal(let container): TerminalSplitContainer(direction: .horizontal, node: $node, container: container) diff --git a/macos/Sources/GhosttyApp.swift b/macos/Sources/GhosttyApp.swift index b41d6188c..f096f1028 100644 --- a/macos/Sources/GhosttyApp.swift +++ b/macos/Sources/GhosttyApp.swift @@ -24,15 +24,15 @@ struct GhosttyApp: App { case .error: ErrorView() case .ready: - Ghostty.TerminalSplit() + Ghostty.TerminalSplit(onClose: Self.closeWindow) .ghosttyApp(ghostty.app!) } }.commands { CommandGroup(after: .newItem) { - Button("New Tab", action: newTab).keyboardShortcut("t", modifiers: [.command]) + Button("New Tab", action: Self.newTab).keyboardShortcut("t", modifiers: [.command]) Divider() Button("Close", action: close).keyboardShortcut("w", modifiers: [.command]) - Button("Close Window", action: closeWindow).keyboardShortcut("w", modifiers: [.command, .shift]) + Button("Close Window", action: Self.closeWindow).keyboardShortcut("w", modifiers: [.command, .shift]) } } @@ -42,7 +42,7 @@ struct GhosttyApp: App { } // Create a new tab in the currently active window - func newTab() { + static func newTab() { guard let currentWindow = NSApp.keyWindow else { return } guard let windowController = currentWindow.windowController else { return } windowController.newWindowForTab(nil) @@ -51,16 +51,16 @@ struct GhosttyApp: App { } } + static func closeWindow() { + guard let currentWindow = NSApp.keyWindow else { return } + currentWindow.close() + } + func close() { guard let surfaceView = focusedSurface else { return } guard let surface = surfaceView.surface else { return } ghostty.requestClose(surface: surface) } - - func closeWindow() { - guard let currentWindow = NSApp.keyWindow else { return } - currentWindow.close() - } } class AppDelegate: NSObject, NSApplicationDelegate { diff --git a/src/config.zig b/src/config.zig index a9d74c27c..2b6b3766f 100644 --- a/src/config.zig +++ b/src/config.zig @@ -278,9 +278,14 @@ pub const Config = struct { ); try result.keybind.set.put( alloc, - .{ .key = .w, .mods = .{ .super = true, .shift = true } }, + .{ .key = .w, .mods = .{ .super = true } }, .{ .close_surface = {} }, ); + try result.keybind.set.put( + alloc, + .{ .key = .w, .mods = .{ .super = true, .shift = true } }, + .{ .close_window = {} }, + ); try result.keybind.set.put( alloc, .{ .key = .t, .mods = .{ .super = true } },