diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 9c904725c..4c9b9aa80 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -61,3 +61,4 @@ changelog entry. - On X11, creating windows while passing `with_x11_screen(non_default_screen)` works again. - On X11, fix XInput handling that prevented a new window from getting the focus in some cases. - On macOS, fix crash when pressing Caps Lock in certain configurations. +- On iOS, fixed `MonitorHandle`'s `PartialEq` and `Hash` implementations. diff --git a/src/platform_impl/ios/monitor.rs b/src/platform_impl/ios/monitor.rs index 1c707a3ac..9f017a246 100644 --- a/src/platform_impl/ios/monitor.rs +++ b/src/platform_impl/ios/monitor.rs @@ -102,13 +102,20 @@ impl Clone for MonitorHandle { impl hash::Hash for MonitorHandle { fn hash(&self, state: &mut H) { - (self as *const Self).hash(state); + // SAFETY: Only getting the pointer. + let mtm = unsafe { MainThreadMarker::new_unchecked() }; + Retained::as_ptr(self.ui_screen.get(mtm)).hash(state); } } impl PartialEq for MonitorHandle { fn eq(&self, other: &Self) -> bool { - ptr::eq(self, other) + // SAFETY: Only getting the pointer. + let mtm = unsafe { MainThreadMarker::new_unchecked() }; + ptr::eq( + Retained::as_ptr(self.ui_screen.get(mtm)), + Retained::as_ptr(other.ui_screen.get(mtm)), + ) } } @@ -122,8 +129,10 @@ impl PartialOrd for MonitorHandle { impl Ord for MonitorHandle { fn cmp(&self, other: &Self) -> std::cmp::Ordering { + // SAFETY: Only getting the pointer. // TODO: Make a better ordering - (self as *const Self).cmp(&(other as *const Self)) + let mtm = unsafe { MainThreadMarker::new_unchecked() }; + Retained::as_ptr(self.ui_screen.get(mtm)).cmp(&Retained::as_ptr(other.ui_screen.get(mtm))) } } @@ -242,3 +251,27 @@ pub fn uiscreens(mtm: MainThreadMarker) -> VecDeque { #[allow(deprecated)] UIScreen::screens(mtm).into_iter().map(MonitorHandle::new).collect() } + +#[cfg(test)] +mod tests { + use objc2_foundation::NSSet; + + use super::*; + + // Test that UIScreen pointer comparisons are correct. + #[test] + #[allow(deprecated)] + fn screen_comparisons() { + // Test code, doesn't matter that it's not thread safe + let mtm = unsafe { MainThreadMarker::new_unchecked() }; + + assert!(ptr::eq(&*UIScreen::mainScreen(mtm), &*UIScreen::mainScreen(mtm))); + + let main = UIScreen::mainScreen(mtm); + assert!(UIScreen::screens(mtm).iter().any(|screen| ptr::eq(screen, &*main))); + + assert!(unsafe { + NSSet::setWithArray(&UIScreen::screens(mtm)).containsObject(&UIScreen::mainScreen(mtm)) + }); + } +}