From 1ae93229593194dc1e5a4c7a6d29fd02cfa93930 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 5 Oct 2024 06:19:07 -1000 Subject: [PATCH] macos: non-native fs keeps track of screen number for change screen comp Fixes #2370 Comparing NSScreens directly was fragile. It appears that AppKit/Cocoa can return different instances of NSScreen for the same screen for unknown reasons between calls to windowDidChangeScreen. I don't fully understand why this happens. In any case, our comparison was not safe. Instad, we now keep track of of the CGDirectDisplayID for each screen and compare those instead. --- macos/Sources/Ghostty/SurfaceView_AppKit.swift | 3 +-- macos/Sources/Helpers/Fullscreen.swift | 6 +++--- macos/Sources/Helpers/NSScreen+Extension.swift | 5 +++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/macos/Sources/Ghostty/SurfaceView_AppKit.swift b/macos/Sources/Ghostty/SurfaceView_AppKit.swift index a5e6b2f04..ead898bdd 100644 --- a/macos/Sources/Ghostty/SurfaceView_AppKit.swift +++ b/macos/Sources/Ghostty/SurfaceView_AppKit.swift @@ -325,8 +325,7 @@ extension Ghostty { // When the window changes screens, we need to update libghostty with the screen // ID. If vsync is enabled, this will be used with the CVDisplayLink to ensure // the proper refresh rate is going. - let id = (screen.deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as! NSNumber).uint32Value - ghostty_surface_set_display_id(surface, id) + ghostty_surface_set_display_id(surface, screen.displayID ?? 0) } // MARK: - NSView diff --git a/macos/Sources/Helpers/Fullscreen.swift b/macos/Sources/Helpers/Fullscreen.swift index 65de2f627..f5df43ec2 100644 --- a/macos/Sources/Helpers/Fullscreen.swift +++ b/macos/Sources/Helpers/Fullscreen.swift @@ -269,7 +269,7 @@ class NonNativeFullscreen: FullscreenStyle { object == window else { return } // Our screens must have changed - guard savedState.screen != window.screen else { return } + guard savedState.screenID != window.screen?.displayID else { return } // When we change screens, we simply exit fullscreen. Changing // screens shouldn't naturally be possible, it can only happen @@ -337,7 +337,7 @@ class NonNativeFullscreen: FullscreenStyle { /// The state that must be saved for non-native fullscreen to exit fullscreen. class SavedState { - weak var screen: NSScreen? + let screenID: UInt32? let tabGroup: NSWindowTabGroup? let tabGroupIndex: Int? let contentFrame: NSRect @@ -347,7 +347,7 @@ class NonNativeFullscreen: FullscreenStyle { init?(_ window: NSWindow) { guard let contentView = window.contentView else { return nil } - self.screen = window.screen + self.screenID = window.screen?.displayID self.tabGroup = window.tabGroup self.tabGroupIndex = window.tabGroup?.windows.firstIndex(of: window) self.contentFrame = window.convertToScreen(contentView.frame) diff --git a/macos/Sources/Helpers/NSScreen+Extension.swift b/macos/Sources/Helpers/NSScreen+Extension.swift index f5a08b524..1091436dd 100644 --- a/macos/Sources/Helpers/NSScreen+Extension.swift +++ b/macos/Sources/Helpers/NSScreen+Extension.swift @@ -1,6 +1,11 @@ import Cocoa extension NSScreen { + /// The unique CoreGraphics display ID for this screen. + var displayID: UInt32? { + deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as? UInt32 + } + // Returns true if the given screen has a visible dock. This isn't // point-in-time visible, this is true if the dock is always visible // AND present on this screen.