Use wrapper type for CFUUID (#4032)

This no longer exposes `CGDisplayCreateUUIDFromDisplayID` and instead
uses `CFUUID` to avoid a leak.

Monitor comparisons should also be more stable now.
This commit is contained in:
Pascal Hertleif 2025-01-17 12:38:42 +01:00 committed by GitHub
parent 69382fda9a
commit 24c226416e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -7,6 +7,7 @@ use std::num::{NonZeroU16, NonZeroU32};
use core_foundation::array::{CFArrayGetCount, CFArrayGetValueAtIndex};
use core_foundation::base::{CFRelease, TCFType};
use core_foundation::string::CFString;
use core_foundation::uuid::{CFUUIDGetUUIDBytes, CFUUID};
use core_graphics::display::{
CGDirectDisplayID, CGDisplay, CGDisplayBounds, CGDisplayCopyDisplayMode,
};
@ -109,15 +110,42 @@ impl VideoModeHandle {
#[derive(Clone)]
pub struct MonitorHandle(CGDirectDisplayID);
type MonitorUuid = [u8; 16];
impl MonitorHandle {
/// Internal comparisons of [`MonitorHandle`]s are done first requesting a UUID for the handle.
fn uuid(&self) -> MonitorUuid {
let cf_uuid = unsafe {
CFUUID::wrap_under_create_rule(ffi::CGDisplayCreateUUIDFromDisplayID(self.0))
};
let uuid = unsafe { CFUUIDGetUUIDBytes(cf_uuid.as_concrete_TypeRef()) };
MonitorUuid::from([
uuid.byte0,
uuid.byte1,
uuid.byte2,
uuid.byte3,
uuid.byte4,
uuid.byte5,
uuid.byte6,
uuid.byte7,
uuid.byte8,
uuid.byte9,
uuid.byte10,
uuid.byte11,
uuid.byte12,
uuid.byte13,
uuid.byte14,
uuid.byte15,
])
}
}
// `CGDirectDisplayID` changes on video mode change, so we cannot rely on that
// for comparisons, but we can use `CGDisplayCreateUUIDFromDisplayID` to get an
// unique identifier that persists even across system reboots
impl PartialEq for MonitorHandle {
fn eq(&self, other: &Self) -> bool {
unsafe {
ffi::CGDisplayCreateUUIDFromDisplayID(self.0)
== ffi::CGDisplayCreateUUIDFromDisplayID(other.0)
}
self.uuid() == other.uuid()
}
}
@ -131,18 +159,13 @@ impl PartialOrd for MonitorHandle {
impl Ord for MonitorHandle {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
unsafe {
ffi::CGDisplayCreateUUIDFromDisplayID(self.0)
.cmp(&ffi::CGDisplayCreateUUIDFromDisplayID(other.0))
}
self.uuid().cmp(&other.uuid())
}
}
impl std::hash::Hash for MonitorHandle {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
unsafe {
ffi::CGDisplayCreateUUIDFromDisplayID(self.0).hash(state);
}
self.uuid().hash(state);
}
}
@ -267,13 +290,11 @@ impl MonitorHandle {
}
pub(crate) fn ns_screen(&self, mtm: MainThreadMarker) -> Option<Retained<NSScreen>> {
let uuid = unsafe { ffi::CGDisplayCreateUUIDFromDisplayID(self.0) };
let uuid = self.uuid();
NSScreen::screens(mtm).into_iter().find(|screen| {
let other_native_id = get_display_id(screen);
let other_uuid = unsafe {
ffi::CGDisplayCreateUUIDFromDisplayID(other_native_id as CGDirectDisplayID)
};
uuid == other_uuid
let other = MonitorHandle::new(other_native_id);
uuid == other.uuid()
})
}
}