macos: change key window detection

This commit is contained in:
Mitchell Hashimoto
2023-03-06 21:53:22 -08:00
parent 1a3cd852f9
commit 1faca5972f
4 changed files with 4 additions and 97 deletions

View File

@ -7,7 +7,6 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
A518502629A1A45100E4CC4F /* WindowTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A518502529A1A45100E4CC4F /* WindowTracker.swift */; };
A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A535B9D9299C569B0017E2E4 /* ErrorView.swift */; }; A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A535B9D9299C569B0017E2E4 /* ErrorView.swift */; };
A55685E029A03A9F004303CE /* AppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55685DF29A03A9F004303CE /* AppError.swift */; }; A55685E029A03A9F004303CE /* AppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55685DF29A03A9F004303CE /* AppError.swift */; };
A55B7BB629B6F47F0055DE60 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55B7BB529B6F47F0055DE60 /* AppState.swift */; }; A55B7BB629B6F47F0055DE60 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55B7BB529B6F47F0055DE60 /* AppState.swift */; };
@ -21,7 +20,6 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
A518502529A1A45100E4CC4F /* WindowTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowTracker.swift; sourceTree = "<group>"; };
A535B9D9299C569B0017E2E4 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = "<group>"; }; A535B9D9299C569B0017E2E4 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = "<group>"; };
A55685DF29A03A9F004303CE /* AppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppError.swift; sourceTree = "<group>"; }; A55685DF29A03A9F004303CE /* AppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppError.swift; sourceTree = "<group>"; };
A55B7BB529B6F47F0055DE60 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; }; A55B7BB529B6F47F0055DE60 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
@ -57,7 +55,6 @@
A535B9D9299C569B0017E2E4 /* ErrorView.swift */, A535B9D9299C569B0017E2E4 /* ErrorView.swift */,
A55685DF29A03A9F004303CE /* AppError.swift */, A55685DF29A03A9F004303CE /* AppError.swift */,
A59444F629A2ED5200725BBA /* SettingsView.swift */, A59444F629A2ED5200725BBA /* SettingsView.swift */,
A518502529A1A45100E4CC4F /* WindowTracker.swift */,
); );
path = Sources; path = Sources;
sourceTree = "<group>"; sourceTree = "<group>";
@ -178,7 +175,6 @@
files = ( files = (
A55B7BBC29B6FC330055DE60 /* SurfaceView.swift in Sources */, A55B7BBC29B6FC330055DE60 /* SurfaceView.swift in Sources */,
A59444F729A2ED5200725BBA /* SettingsView.swift in Sources */, A59444F729A2ED5200725BBA /* SettingsView.swift in Sources */,
A518502629A1A45100E4CC4F /* WindowTracker.swift in Sources */,
A55B7BB829B6F53A0055DE60 /* Package.swift in Sources */, A55B7BB829B6F53A0055DE60 /* Package.swift in Sources */,
A55B7BBE29B701360055DE60 /* SplitView.swift in Sources */, A55B7BBE29B701360055DE60 /* SplitView.swift in Sources */,
A55B7BB629B6F47F0055DE60 /* AppState.swift in Sources */, A55B7BB629B6F47F0055DE60 /* AppState.swift in Sources */,

View File

@ -31,11 +31,13 @@ extension Ghostty {
@ObservedObject var surfaceView: SurfaceView @ObservedObject var surfaceView: SurfaceView
@FocusState private var surfaceFocus: Bool @FocusState private var surfaceFocus: Bool
@Environment(\.isKeyWindow) private var isKeyWindow: Bool
// https://nilcoalescing.com/blog/DetectFocusedWindowOnMacOS/
@Environment(\.controlActiveState) var controlActiveState
// 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 && isKeyWindow } private var hasFocus: Bool { surfaceFocus && controlActiveState == .key }
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

View File

@ -23,7 +23,6 @@ struct GhosttyApp: App {
case .ready: case .ready:
Ghostty.TerminalSplitView() Ghostty.TerminalSplitView()
.ghosttyApp(ghostty.app!) .ghosttyApp(ghostty.app!)
.modifier(WindowObservationModifier())
} }
}.commands { }.commands {
CommandGroup(after: .newItem) { CommandGroup(after: .newItem) {

View File

@ -1,90 +0,0 @@
import SwiftUI
/// This modifier tracks whether the window is the key window in the isKeyWindow environment value.
struct WindowObservationModifier: ViewModifier {
@StateObject var windowObserver: WindowObserver = WindowObserver()
func body(content: Content) -> some View {
content.background(
HostingWindowFinder { [weak windowObserver] window in
windowObserver?.window = window
}
).environment(\.isKeyWindow, windowObserver.isKeyWindow)
}
}
extension EnvironmentValues {
struct IsKeyWindowKey: EnvironmentKey {
static var defaultValue: Bool = false
typealias Value = Bool
}
fileprivate(set) var isKeyWindow: Bool {
get {
self[IsKeyWindowKey.self]
}
set {
self[IsKeyWindowKey.self] = newValue
}
}
}
class WindowObserver: ObservableObject {
@Published public private(set) var isKeyWindow: Bool = false
private var becomeKeyobserver: NSObjectProtocol?
private var resignKeyobserver: NSObjectProtocol?
weak var window: NSWindow? {
didSet {
// Always remove our previous observers if we have any
if let previous = self.becomeKeyobserver {
NotificationCenter.default.removeObserver(previous)
self.becomeKeyobserver = nil
}
if let previous = self.resignKeyobserver {
NotificationCenter.default.removeObserver(previous)
self.resignKeyobserver = nil
}
// If our window is becoming nil then we clear everything
guard let window = window else {
self.isKeyWindow = false
return
}
self.isKeyWindow = window.isKeyWindow
self.becomeKeyobserver = NotificationCenter.default.addObserver(
forName: NSWindow.didBecomeKeyNotification,
object: window,
queue: .main
) { (n) in
self.isKeyWindow = true
}
self.resignKeyobserver = NotificationCenter.default.addObserver(
forName: NSWindow.didResignKeyNotification,
object: window,
queue: .main
) { (n) in
self.isKeyWindow = false
}
}
}
}
/// This view calls the callback with the window value that hosts the view.
struct HostingWindowFinder: NSViewRepresentable {
var callback: (NSWindow?) -> ()
func makeNSView(context: Self.Context) -> NSView {
let view = NSView()
view.translatesAutoresizingMaskIntoConstraints = false
DispatchQueue.main.async { [weak view] in
self.callback(view?.window)
}
return view
}
func updateNSView(_ nsView: NSView, context: Context) {}
}