Use NSScreen to fetch primary display

According to Chromium source, `NSScreen::screens` should always get us
one display.

We made this change because we ran into panics caused by the previous
`unwrap()` when `CGGetActiveDisplayList` might return an empty list.
This commit is contained in:
Thorsten Ball 2024-01-16 14:23:10 +01:00
parent 03bfe3ef80
commit f938bae0a2
2 changed files with 23 additions and 2 deletions

View file

@ -1,10 +1,16 @@
use crate::{point, size, Bounds, DisplayId, GlobalPixels, PlatformDisplay}; use crate::{point, size, Bounds, DisplayId, GlobalPixels, PlatformDisplay};
use anyhow::Result; use anyhow::Result;
use cocoa::{
appkit::NSScreen,
base::{id, nil},
foundation::{NSDictionary, NSString},
};
use core_foundation::uuid::{CFUUIDGetUUIDBytes, CFUUIDRef}; use core_foundation::uuid::{CFUUIDGetUUIDBytes, CFUUIDRef};
use core_graphics::{ use core_graphics::{
display::{CGDirectDisplayID, CGDisplayBounds, CGGetActiveDisplayList}, display::{CGDirectDisplayID, CGDisplayBounds, CGGetActiveDisplayList},
geometry::{CGPoint, CGRect, CGSize}, geometry::{CGPoint, CGRect, CGSize},
}; };
use objc::{msg_send, sel, sel_impl};
use std::any::Any; use std::any::Any;
use uuid::Uuid; use uuid::Uuid;
@ -27,7 +33,22 @@ impl MacDisplay {
/// Get the primary screen - the one with the menu bar, and whose bottom left /// Get the primary screen - the one with the menu bar, and whose bottom left
/// corner is at the origin of the AppKit coordinate system. /// corner is at the origin of the AppKit coordinate system.
pub fn primary() -> Self { pub fn primary() -> Self {
Self::all().next().unwrap() // Instead of iterating through all active systems displays via `all()` we use the first
// NSScreen and gets its CGDirectDisplayID, because we can't be sure that `CGGetActiveDisplayList`
// will always return a list of active displays (machine might be sleeping).
//
// The following is what Chromium does too:
//
// https://chromium.googlesource.com/chromium/src/+/66.0.3359.158/ui/display/mac/screen_mac.mm#56
unsafe {
let screens = NSScreen::screens(nil);
let screen = cocoa::foundation::NSArray::objectAtIndex(screens, 0);
let device_description = NSScreen::deviceDescription(screen);
let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber");
let screen_number = device_description.objectForKey_(screen_number_key);
let screen_number: CGDirectDisplayID = msg_send![screen_number, unsignedIntegerValue];
Self(screen_number)
}
} }
/// Obtains an iterator over all currently active system displays. /// Obtains an iterator over all currently active system displays.

View file

@ -484,7 +484,7 @@ impl MacWindow {
let display = options let display = options
.display_id .display_id
.and_then(|display_id| MacDisplay::all().find(|display| display.id() == display_id)) .and_then(MacDisplay::find_by_id)
.unwrap_or_else(MacDisplay::primary); .unwrap_or_else(MacDisplay::primary);
let mut target_screen = nil; let mut target_screen = nil;