use crate::{Bounds, DisplayId, Pixels, PlatformDisplay, px, size}; use anyhow::Result; use cocoa::{ appkit::NSScreen, base::{id, nil}, foundation::{NSDictionary, NSString}, }; use core_foundation::uuid::{CFUUIDGetUUIDBytes, CFUUIDRef}; use core_graphics::display::{CGDirectDisplayID, CGDisplayBounds, CGGetActiveDisplayList}; use objc::{msg_send, sel, sel_impl}; use uuid::Uuid; #[derive(Debug)] pub(crate) struct MacDisplay(pub(crate) CGDirectDisplayID); unsafe impl Send for MacDisplay {} impl MacDisplay { /// Get the screen with the given [`DisplayId`]. pub fn find_by_id(id: DisplayId) -> Option { Self::all().find(|screen| screen.id() == id) } /// Get the primary screen - the one with the menu bar, and whose bottom left /// corner is at the origin of the AppKit coordinate system. pub fn primary() -> Self { // 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. pub fn all() -> impl Iterator { unsafe { // We're assuming there aren't more than 32 displays connected to the system. let mut displays = Vec::with_capacity(32); let mut display_count = 0; let result = CGGetActiveDisplayList( displays.capacity() as u32, displays.as_mut_ptr(), &mut display_count, ); if result == 0 { displays.set_len(display_count as usize); displays.into_iter().map(MacDisplay) } else { panic!("Failed to get active display list. Result: {result}"); } } } } #[link(name = "ApplicationServices", kind = "framework")] unsafe extern "C" { fn CGDisplayCreateUUIDFromDisplayID(display: CGDirectDisplayID) -> CFUUIDRef; } impl PlatformDisplay for MacDisplay { fn id(&self) -> DisplayId { DisplayId(self.0) } fn uuid(&self) -> Result { let cfuuid = unsafe { CGDisplayCreateUUIDFromDisplayID(self.0 as CGDirectDisplayID) }; anyhow::ensure!( !cfuuid.is_null(), "AppKit returned a null from CGDisplayCreateUUIDFromDisplayID" ); let bytes = unsafe { CFUUIDGetUUIDBytes(cfuuid) }; Ok(Uuid::from_bytes([ bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, bytes.byte4, bytes.byte5, bytes.byte6, bytes.byte7, bytes.byte8, bytes.byte9, bytes.byte10, bytes.byte11, bytes.byte12, bytes.byte13, bytes.byte14, bytes.byte15, ])) } fn bounds(&self) -> Bounds { unsafe { // CGDisplayBounds is in "global display" coordinates, where 0 is // the top left of the primary display. let bounds = CGDisplayBounds(self.0); Bounds { origin: Default::default(), size: size(px(bounds.size.width as f32), px(bounds.size.height as f32)), } } } }