From 508277f823e11213efb07c6cc89dfd50d00d3e86 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 7 Mar 2023 21:37:36 -0800 Subject: [PATCH] macos: fix focus on split change --- macos/Sources/Ghostty/Ghostty.SplitView.swift | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/macos/Sources/Ghostty/Ghostty.SplitView.swift b/macos/Sources/Ghostty/Ghostty.SplitView.swift index e0fd35ec9..3e6397f7e 100644 --- a/macos/Sources/Ghostty/Ghostty.SplitView.swift +++ b/macos/Sources/Ghostty/Ghostty.SplitView.swift @@ -52,7 +52,6 @@ extension Ghostty { let app: ghostty_app_t @StateObject private var state: ViewState - @FocusState private var focusedSide: Side? init(_ app: ghostty_app_t) { self.app = app @@ -73,6 +72,9 @@ extension Ghostty { // Create the new split which always goes to the bottom right. state.bottomRight = Ghostty.SurfaceView(app) + + // See fixFocus comment, we have to run this whenever split changes. + fixFocus() } func closeTopLeft() { @@ -80,7 +82,9 @@ extension Ghostty { assert(state.bottomRight != nil) state.topLeft = state.bottomRight! state.direction = .none - focusedSide = .TopLeft + + // See fixFocus comment, we have to run this whenever split changes. + fixFocus() } func closeBottomRight() { @@ -88,7 +92,26 @@ extension Ghostty { assert(state.bottomRight != nil) state.bottomRight = nil state.direction = .none - focusedSide = .TopLeft + + // See fixFocus comment, we have to run this whenever split changes. + fixFocus() + } + + /// There is a bug I can't figure out where when changing the split state, the terminal view + /// will lose focus. There has to be some nice SwiftUI-native way to fix this but I can't + /// figure it out so we're going to do this hacky thing to bring focus back to the terminal + /// that should have it. + private func fixFocus() { + DispatchQueue.main.async { + // If the callback runs before the surface is attached to a view + // then the window will be nil. We just reschedule in that case. + guard let window = state.topLeft.window else { + self.fixFocus() + return + } + + window.makeFirstResponder(state.topLeft) + } } var body: some View { @@ -97,11 +120,12 @@ extension Ghostty { VStack { HStack { Button("Split Horizontal") { split(to: .horizontal) } + .keyboardShortcut("d", modifiers: .command) Button("Split Vertical") { split(to: .vertical) } + .keyboardShortcut("d", modifiers: [.command, .shift]) } SurfaceWrapper(surfaceView: state.topLeft) - .focused($focusedSide, equals: .TopLeft) } case .horizontal: VStack { @@ -112,10 +136,8 @@ extension Ghostty { SplitView(.horizontal, left: { TerminalSplitChild(app, topLeft: state.topLeft) - .focused($focusedSide, equals: .TopLeft) }, right: { TerminalSplitChild(app, topLeft: state.bottomRight!) - .focused($focusedSide, equals: .BottomRight) }) } case .vertical: @@ -127,10 +149,8 @@ extension Ghostty { SplitView(.vertical, left: { TerminalSplitChild(app, topLeft: state.topLeft) - .focused($focusedSide, equals: .TopLeft) }, right: { TerminalSplitChild(app, topLeft: state.bottomRight!) - .focused($focusedSide, equals: .BottomRight) }) } }