mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: reliable window focus tracking for surface
This commit is contained in:
@ -38,24 +38,42 @@ extension Ghostty {
|
|||||||
// remains the same, the surface that is being rendered remains the same.
|
// remains the same, the surface that is being rendered remains the same.
|
||||||
@ObservedObject var surfaceView: SurfaceView
|
@ObservedObject var surfaceView: SurfaceView
|
||||||
|
|
||||||
|
// Maintain whether our view has focus or not
|
||||||
@FocusState private var surfaceFocus: Bool
|
@FocusState private var surfaceFocus: Bool
|
||||||
|
|
||||||
// https://nilcoalescing.com/blog/DetectFocusedWindowOnMacOS/
|
// Maintain whether our window has focus (is key) or not
|
||||||
@Environment(\.controlActiveState) var controlActiveState
|
@State private var windowFocus: Bool = false
|
||||||
|
|
||||||
// This is true if the terminal is considered "focused". The terminal is focused if
|
// This is true if the terminal is considered "focused". The terminal is focused if
|
||||||
// it is both individually focused and the containing window is key.
|
// it is both individually focused and the containing window is key.
|
||||||
private var hasFocus: Bool { surfaceFocus && controlActiveState == .key }
|
private var hasFocus: Bool { surfaceFocus && windowFocus }
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
// We use a GeometryReader to get the frame bounds so that our metal surface
|
// We use a GeometryReader to get the frame bounds so that our metal surface
|
||||||
// is up to date. See TerminalSurfaceView for why we don't use the NSView
|
// is up to date. See TerminalSurfaceView for why we don't use the NSView
|
||||||
// resize callback.
|
// resize callback.
|
||||||
GeometryReader { geo in
|
GeometryReader { geo in
|
||||||
|
// We use these notifications to determine when the window our surface is
|
||||||
|
// attached to is or is not focused.
|
||||||
|
let pubBecomeKey = NotificationCenter.default.publisher(for: NSWindow.didBecomeKeyNotification)
|
||||||
|
let pubResign = NotificationCenter.default.publisher(for: NSWindow.didResignKeyNotification)
|
||||||
|
|
||||||
Surface(view: surfaceView, hasFocus: hasFocus, size: geo.size)
|
Surface(view: surfaceView, hasFocus: hasFocus, size: geo.size)
|
||||||
.focused($surfaceFocus)
|
.focused($surfaceFocus)
|
||||||
.focusedValue(\.ghosttySurfaceTitle, surfaceView.title)
|
.focusedValue(\.ghosttySurfaceTitle, surfaceView.title)
|
||||||
.focusedValue(\.ghosttySurfaceView, surfaceView)
|
.focusedValue(\.ghosttySurfaceView, surfaceView)
|
||||||
|
.onReceive(pubBecomeKey) { notification in
|
||||||
|
guard let window = notification.object as? NSWindow else { return }
|
||||||
|
guard let surfaceWindow = surfaceView.window else { return }
|
||||||
|
windowFocus = surfaceWindow == window
|
||||||
|
}
|
||||||
|
.onReceive(pubResign) { notification in
|
||||||
|
guard let window = notification.object as? NSWindow else { return }
|
||||||
|
guard let surfaceWindow = surfaceView.window else { return }
|
||||||
|
if (surfaceWindow == window) {
|
||||||
|
windowFocus = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.ghosttySurfaceView(surfaceView)
|
.ghosttySurfaceView(surfaceView)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user