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.
This commit is contained in:
Mitchell Hashimoto
2024-10-05 06:19:07 -10:00
parent 9971d7a93d
commit 1ae9322959
3 changed files with 9 additions and 5 deletions

View File

@ -325,8 +325,7 @@ extension Ghostty {
// When the window changes screens, we need to update libghostty with the screen // 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 // ID. If vsync is enabled, this will be used with the CVDisplayLink to ensure
// the proper refresh rate is going. // the proper refresh rate is going.
let id = (screen.deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as! NSNumber).uint32Value ghostty_surface_set_display_id(surface, screen.displayID ?? 0)
ghostty_surface_set_display_id(surface, id)
} }
// MARK: - NSView // MARK: - NSView

View File

@ -269,7 +269,7 @@ class NonNativeFullscreen: FullscreenStyle {
object == window else { return } object == window else { return }
// Our screens must have changed // 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 // When we change screens, we simply exit fullscreen. Changing
// screens shouldn't naturally be possible, it can only happen // 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. /// The state that must be saved for non-native fullscreen to exit fullscreen.
class SavedState { class SavedState {
weak var screen: NSScreen? let screenID: UInt32?
let tabGroup: NSWindowTabGroup? let tabGroup: NSWindowTabGroup?
let tabGroupIndex: Int? let tabGroupIndex: Int?
let contentFrame: NSRect let contentFrame: NSRect
@ -347,7 +347,7 @@ class NonNativeFullscreen: FullscreenStyle {
init?(_ window: NSWindow) { init?(_ window: NSWindow) {
guard let contentView = window.contentView else { return nil } guard let contentView = window.contentView else { return nil }
self.screen = window.screen self.screenID = window.screen?.displayID
self.tabGroup = window.tabGroup self.tabGroup = window.tabGroup
self.tabGroupIndex = window.tabGroup?.windows.firstIndex(of: window) self.tabGroupIndex = window.tabGroup?.windows.firstIndex(of: window)
self.contentFrame = window.convertToScreen(contentView.frame) self.contentFrame = window.convertToScreen(contentView.frame)

View File

@ -1,6 +1,11 @@
import Cocoa import Cocoa
extension NSScreen { 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 // 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 // point-in-time visible, this is true if the dock is always visible
// AND present on this screen. // AND present on this screen.