diff --git a/Cargo.toml b/Cargo.toml index e442c4027f3..dabdca35a36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,14 +108,9 @@ block2 = "0.6.0" core-foundation = "0.9.3" dispatch2 = { version = "0.2.0", default-features = false, features = ["std", "objc2"] } objc2 = "0.6.0" -objc2-core-foundation = { version = "0.3.0", default-features = false, features = [ - "std", - "CFCGTypes", -] } # AppKit [target.'cfg(target_os = "macos")'.dependencies] -core-graphics = "0.23.1" objc2-app-kit = { version = "0.3.0", default-features = false, features = [ "std", "objc2-core-foundation", @@ -148,6 +143,33 @@ objc2-app-kit = { version = "0.3.0", default-features = false, features = [ "NSWindowScripting", "NSWindowTabGroup", ] } +objc2-core-foundation = { version = "0.3.0", default-features = false, features = [ + "std", + "block2", + "CFBase", + "CFCGTypes", + "CFData", + "CFRunLoop", + "CFString", + "CFUUID", +] } +objc2-core-graphics = { version = "0.3.0", default-features = false, features = [ + "std", + "libc", + "CGDirectDisplay", + "CGDisplayConfiguration", + "CGDisplayFade", + "CGError", + "CGRemoteOperation", + "CGWindowLevel", +] } +objc2-core-video = { version = "0.3.0", default-features = false, features = [ + "std", + "objc2-core-graphics", + "CVBase", + "CVReturn", + "CVDisplayLink", +] } objc2-foundation = { version = "0.3.0", default-features = false, features = [ "std", "block2", @@ -173,6 +195,13 @@ objc2-foundation = { version = "0.3.0", default-features = false, features = [ # UIKit [target.'cfg(all(target_vendor = "apple", not(target_os = "macos")))'.dependencies] +objc2-core-foundation = { version = "0.3.0", default-features = false, features = [ + "std", + "CFCGTypes", + "CFBase", + "CFRunLoop", + "CFString", +] } objc2-foundation = { version = "0.3.0", default-features = false, features = [ "std", "block2", diff --git a/src/platform_impl/apple/appkit/event.rs b/src/platform_impl/apple/appkit/event.rs index 3f743dc3d4e..0405088cb08 100644 --- a/src/platform_impl/apple/appkit/event.rs +++ b/src/platform_impl/apple/appkit/event.rs @@ -1,10 +1,9 @@ -use std::ffi::c_void; +use std::ptr::NonNull; -use core_foundation::base::CFRelease; -use core_foundation::data::{CFDataGetBytePtr, CFDataRef}; use dispatch2::run_on_main; use objc2::rc::Retained; use objc2_app_kit::{NSEvent, NSEventModifierFlags, NSEventSubtype, NSEventType}; +use objc2_core_foundation::{CFData, CFDataGetBytePtr, CFRetained}; use objc2_foundation::NSPoint; use smol_str::SmolStr; @@ -23,29 +22,27 @@ pub struct KeyEventExtra { /// Ignores ALL modifiers. pub fn get_modifierless_char(scancode: u16) -> Key { - let mut string = [0; 16]; - let input_source; - let layout; - unsafe { - input_source = ffi::TISCopyCurrentKeyboardLayoutInputSource(); - if input_source.is_null() { - tracing::error!("`TISCopyCurrentKeyboardLayoutInputSource` returned null ptr"); - return Key::Unidentified(NativeKey::MacOS(scancode)); - } - let layout_data = - ffi::TISGetInputSourceProperty(input_source, ffi::kTISPropertyUnicodeKeyLayoutData); - if layout_data.is_null() { - CFRelease(input_source as *mut c_void); - tracing::error!("`TISGetInputSourceProperty` returned null ptr"); - return Key::Unidentified(NativeKey::MacOS(scancode)); - } - layout = CFDataGetBytePtr(layout_data as CFDataRef) as *const ffi::UCKeyboardLayout; - } + let Some(ptr) = NonNull::new(unsafe { ffi::TISCopyCurrentKeyboardLayoutInputSource() }) else { + tracing::error!("`TISCopyCurrentKeyboardLayoutInputSource` returned null ptr"); + return Key::Unidentified(NativeKey::MacOS(scancode)); + }; + let input_source = unsafe { CFRetained::from_raw(ptr) }; + + let layout_data = unsafe { + ffi::TISGetInputSourceProperty(&input_source, ffi::kTISPropertyUnicodeKeyLayoutData) + }; + let Some(layout_data) = (unsafe { layout_data.cast::().as_ref() }) else { + tracing::error!("`TISGetInputSourceProperty` returned null ptr"); + return Key::Unidentified(NativeKey::MacOS(scancode)); + }; + + let layout = unsafe { CFDataGetBytePtr(layout_data).cast() }; let keyboard_type = run_on_main(|_mtm| unsafe { ffi::LMGetKbdType() }); let mut result_len = 0; let mut dead_keys = 0; let modifiers = 0; + let mut string = [0; 16]; let translate_result = unsafe { ffi::UCKeyTranslate( layout, @@ -60,9 +57,6 @@ pub fn get_modifierless_char(scancode: u16) -> Key { string.as_mut_ptr(), ) }; - unsafe { - CFRelease(input_source as *mut c_void); - } if translate_result != 0 { tracing::error!("`UCKeyTranslate` returned with the non-zero value: {}", translate_result); return Key::Unidentified(NativeKey::MacOS(scancode)); diff --git a/src/platform_impl/apple/appkit/event_loop.rs b/src/platform_impl/apple/appkit/event_loop.rs index b65679482bc..2d5c80a3658 100644 --- a/src/platform_impl/apple/appkit/event_loop.rs +++ b/src/platform_impl/apple/appkit/event_loop.rs @@ -8,11 +8,6 @@ use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use std::sync::Arc; use std::time::{Duration, Instant}; -use core_foundation::base::{CFIndex, CFRelease}; -use core_foundation::runloop::{ - kCFRunLoopCommonModes, CFRunLoopAddSource, CFRunLoopGetMain, CFRunLoopSourceContext, - CFRunLoopSourceCreate, CFRunLoopSourceRef, CFRunLoopSourceSignal, CFRunLoopWakeUp, -}; use objc2::rc::{autoreleasepool, Retained}; use objc2::runtime::ProtocolObject; use objc2::{available, msg_send, ClassType}; @@ -20,6 +15,11 @@ use objc2_app_kit::{ NSApplication, NSApplicationActivationPolicy, NSApplicationDidFinishLaunchingNotification, NSApplicationWillTerminateNotification, NSWindow, }; +use objc2_core_foundation::{ + kCFRunLoopCommonModes, CFIndex, CFRetained, CFRunLoopAddSource, CFRunLoopGetMain, + CFRunLoopSource, CFRunLoopSourceContext, CFRunLoopSourceCreate, CFRunLoopSourceSignal, + CFRunLoopWakeUp, +}; use objc2_foundation::{MainThreadMarker, NSNotificationCenter, NSObjectProtocol}; use rwh_06::HasDisplayHandle; @@ -437,29 +437,21 @@ pub fn stop_app_on_panic R + UnwindSafe, R>( #[derive(Debug)] pub struct EventLoopProxy { pub(crate) wake_up: AtomicBool, - source: CFRunLoopSourceRef, + source: CFRetained, } unsafe impl Send for EventLoopProxy {} unsafe impl Sync for EventLoopProxy {} -impl Drop for EventLoopProxy { - fn drop(&mut self) { - unsafe { - CFRelease(self.source as _); - } - } -} - impl EventLoopProxy { pub(crate) fn new() -> Self { unsafe { // just wake up the eventloop - extern "C" fn event_loop_proxy_handler(_: *const c_void) {} + extern "C-unwind" fn event_loop_proxy_handler(_context: *mut c_void) {} // adding a Source to the main CFRunLoop lets us wake it up and // process user events through the normal OS EventLoop mechanisms. - let rl = CFRunLoopGetMain(); + let rl = CFRunLoopGetMain().unwrap(); let mut context = CFRunLoopSourceContext { version: 0, info: ptr::null_mut(), @@ -470,11 +462,11 @@ impl EventLoopProxy { hash: None, schedule: None, cancel: None, - perform: event_loop_proxy_handler, + perform: Some(event_loop_proxy_handler), }; - let source = CFRunLoopSourceCreate(ptr::null_mut(), CFIndex::MAX - 1, &mut context); - CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes); - CFRunLoopWakeUp(rl); + let source = CFRunLoopSourceCreate(None, CFIndex::MAX - 1, &mut context).unwrap(); + CFRunLoopAddSource(&rl, Some(&source), kCFRunLoopCommonModes); + CFRunLoopWakeUp(&rl); EventLoopProxy { wake_up: AtomicBool::new(false), source } } @@ -486,9 +478,9 @@ impl EventLoopProxyProvider for EventLoopProxy { self.wake_up.store(true, AtomicOrdering::Relaxed); unsafe { // Let the main thread know there's a new event. - CFRunLoopSourceSignal(self.source); - let rl = CFRunLoopGetMain(); - CFRunLoopWakeUp(rl); + CFRunLoopSourceSignal(&self.source); + let rl = CFRunLoopGetMain().unwrap(); + CFRunLoopWakeUp(&rl); } } } diff --git a/src/platform_impl/apple/appkit/ffi.rs b/src/platform_impl/apple/appkit/ffi.rs index 92d4874e4b1..21241c6062e 100644 --- a/src/platform_impl/apple/appkit/ffi.rs +++ b/src/platform_impl/apple/appkit/ffi.rs @@ -4,18 +4,10 @@ use std::ffi::c_void; -use core_foundation::array::CFArrayRef; -use core_foundation::dictionary::CFDictionaryRef; -use core_foundation::string::CFStringRef; -use core_foundation::uuid::CFUUIDRef; -use core_graphics::base::CGError; -use core_graphics::display::{CGDirectDisplayID, CGDisplayConfigRef}; use objc2::ffi::NSInteger; use objc2::runtime::AnyObject; - -pub type CGDisplayFadeInterval = f32; -pub type CGDisplayReservationInterval = f32; -pub type CGDisplayBlendFraction = f32; +use objc2_core_foundation::{cf_type, CFString, CFUUID}; +use objc2_core_graphics::CGDirectDisplayID; pub const kCGDisplayBlendNormal: f32 = 0.0; pub const kCGDisplayBlendSolidColor: f32 = 1.0; @@ -23,22 +15,6 @@ pub const kCGDisplayBlendSolidColor: f32 = 1.0; pub type CGDisplayFadeReservationToken = u32; pub const kCGDisplayFadeReservationInvalidToken: CGDisplayFadeReservationToken = 0; -pub type Boolean = u8; -pub const FALSE: Boolean = 0; -pub const TRUE: Boolean = 1; - -pub const kCGErrorSuccess: i32 = 0; -pub const kCGErrorFailure: i32 = 1000; -pub const kCGErrorIllegalArgument: i32 = 1001; -pub const kCGErrorInvalidConnection: i32 = 1002; -pub const kCGErrorInvalidContext: i32 = 1003; -pub const kCGErrorCannotComplete: i32 = 1004; -pub const kCGErrorNotImplemented: i32 = 1006; -pub const kCGErrorRangeCheck: i32 = 1007; -pub const kCGErrorTypeCheck: i32 = 1008; -pub const kCGErrorInvalidOperation: i32 = 1010; -pub const kCGErrorNoneAvailable: i32 = 1011; - pub const IO1BitIndexedPixels: &str = "P"; pub const IO2BitIndexedPixels: &str = "PP"; pub const IO4BitIndexedPixels: &str = "PPPP"; @@ -55,9 +31,6 @@ pub const kIO32BitFloatPixels: &str = "-32FR32FG32FB32"; pub const IOYUV422Pixels: &str = "Y4U2V2"; pub const IO8BitOverlayPixels: &str = "O8"; -pub type CGWindowLevel = i32; -pub type CGDisplayModeRef = *mut c_void; - // `CGDisplayCreateUUIDFromDisplayID` comes from the `ColorSync` framework. // However, that framework was only introduced "publicly" in macOS 10.13. // @@ -67,54 +40,11 @@ pub type CGDisplayModeRef = *mut c_void; // https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/OSX_Technology_Overview/SystemFrameworks/SystemFrameworks.html#//apple_ref/doc/uid/TP40001067-CH210-BBCFFIEG #[link(name = "ApplicationServices", kind = "framework")] extern "C" { - pub fn CGDisplayCreateUUIDFromDisplayID(display: CGDirectDisplayID) -> CFUUIDRef; + pub fn CGDisplayCreateUUIDFromDisplayID(display: CGDirectDisplayID) -> *mut CFUUID; } #[link(name = "CoreGraphics", kind = "framework")] extern "C" { - pub fn CGRestorePermanentDisplayConfiguration(); - pub fn CGDisplayCapture(display: CGDirectDisplayID) -> CGError; - pub fn CGDisplayRelease(display: CGDirectDisplayID) -> CGError; - pub fn CGConfigureDisplayFadeEffect( - config: CGDisplayConfigRef, - fadeOutSeconds: CGDisplayFadeInterval, - fadeInSeconds: CGDisplayFadeInterval, - fadeRed: f32, - fadeGreen: f32, - fadeBlue: f32, - ) -> CGError; - pub fn CGAcquireDisplayFadeReservation( - seconds: CGDisplayReservationInterval, - token: *mut CGDisplayFadeReservationToken, - ) -> CGError; - pub fn CGDisplayFade( - token: CGDisplayFadeReservationToken, - duration: CGDisplayFadeInterval, - startBlend: CGDisplayBlendFraction, - endBlend: CGDisplayBlendFraction, - redBlend: f32, - greenBlend: f32, - blueBlend: f32, - synchronous: Boolean, - ) -> CGError; - pub fn CGReleaseDisplayFadeReservation(token: CGDisplayFadeReservationToken) -> CGError; - pub fn CGShieldingWindowLevel() -> CGWindowLevel; - pub fn CGDisplaySetDisplayMode( - display: CGDirectDisplayID, - mode: CGDisplayModeRef, - options: CFDictionaryRef, - ) -> CGError; - pub fn CGDisplayCopyAllDisplayModes( - display: CGDirectDisplayID, - options: CFDictionaryRef, - ) -> CFArrayRef; - pub fn CGDisplayModeGetPixelWidth(mode: CGDisplayModeRef) -> usize; - pub fn CGDisplayModeGetPixelHeight(mode: CGDisplayModeRef) -> usize; - pub fn CGDisplayModeGetRefreshRate(mode: CGDisplayModeRef) -> f64; - pub fn CGDisplayModeCopyPixelEncoding(mode: CGDisplayModeRef) -> CFStringRef; - pub fn CGDisplayModeRetain(mode: CGDisplayModeRef); - pub fn CGDisplayModeRelease(mode: CGDisplayModeRef); - // Wildly used private APIs; Apple uses them for their Terminal.app. pub fn CGSMainConnectionID() -> *mut AnyObject; pub fn CGSSetWindowBackgroundBlurRadius( @@ -124,50 +54,13 @@ extern "C" { ) -> i32; } -mod core_video { - use super::*; - - #[link(name = "CoreVideo", kind = "framework")] - extern "C" {} - - // CVBase.h - - pub type CVTimeFlags = i32; // int32_t - pub const kCVTimeIsIndefinite: CVTimeFlags = 1 << 0; - - #[repr(C)] - #[derive(Debug, Clone)] - pub struct CVTime { - pub time_value: i64, // int64_t - pub time_scale: i32, // int32_t - pub flags: i32, // int32_t - } - - // CVReturn.h - - pub type CVReturn = i32; // int32_t - pub const kCVReturnSuccess: CVReturn = 0; - - // CVDisplayLink.h - - pub type CVDisplayLinkRef = *mut c_void; - - extern "C" { - pub fn CVDisplayLinkCreateWithCGDisplay( - displayID: CGDirectDisplayID, - displayLinkOut: *mut CVDisplayLinkRef, - ) -> CVReturn; - pub fn CVDisplayLinkGetNominalOutputVideoRefreshPeriod( - displayLink: CVDisplayLinkRef, - ) -> CVTime; - pub fn CVDisplayLinkRelease(displayLink: CVDisplayLinkRef); - } -} - -pub use core_video::*; #[repr(transparent)] pub struct TISInputSource(std::ffi::c_void); -pub type TISInputSourceRef = *mut TISInputSource; + +cf_type!( + #[encoding_name = "__TISInputSource"] + unsafe impl TISInputSource {} +); #[repr(transparent)] pub struct UCKeyboardLayout(std::ffi::c_void); @@ -184,15 +77,15 @@ pub const kUCKeyTranslateNoDeadKeysMask: OptionBits = 1; #[link(name = "Carbon", kind = "framework")] extern "C" { - pub static kTISPropertyUnicodeKeyLayoutData: CFStringRef; + pub static kTISPropertyUnicodeKeyLayoutData: &'static CFString; #[allow(non_snake_case)] pub fn TISGetInputSourceProperty( - inputSource: TISInputSourceRef, - propertyKey: CFStringRef, + inputSource: &TISInputSource, + propertyKey: &CFString, ) -> *mut c_void; - pub fn TISCopyCurrentKeyboardLayoutInputSource() -> TISInputSourceRef; + pub fn TISCopyCurrentKeyboardLayoutInputSource() -> *mut TISInputSource; pub fn LMGetKbdType() -> u8; diff --git a/src/platform_impl/apple/appkit/monitor.rs b/src/platform_impl/apple/appkit/monitor.rs index 0f337724736..fd516e3a29e 100644 --- a/src/platform_impl/apple/appkit/monitor.rs +++ b/src/platform_impl/apple/appkit/monitor.rs @@ -1,22 +1,32 @@ #![allow(clippy::unnecessary_cast)] use std::collections::VecDeque; -use std::fmt; use std::num::{NonZeroU16, NonZeroU32}; +use std::ptr::NonNull; +use std::{fmt, ptr}; -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, -}; use dispatch2::run_on_main; use objc2::rc::Retained; use objc2_app_kit::NSScreen; +use objc2_core_foundation::{ + CFArrayGetCount, CFArrayGetValueAtIndex, CFRetained, CFUUIDGetUUIDBytes, +}; +#[allow(deprecated)] +use objc2_core_graphics::{ + CGDirectDisplayID, CGDisplayBounds, CGDisplayCopyAllDisplayModes, CGDisplayCopyDisplayMode, + CGDisplayMode, CGDisplayModeCopyPixelEncoding, CGDisplayModeGetPixelHeight, + CGDisplayModeGetPixelWidth, CGDisplayModeGetRefreshRate, CGDisplayModelNumber, + CGGetActiveDisplayList, CGMainDisplayID, +}; +#[allow(deprecated)] +use objc2_core_video::{ + kCVReturnSuccess, CVDisplayLinkCreateWithCGDisplay, + CVDisplayLinkGetNominalOutputVideoRefreshPeriod, CVTimeFlags, +}; use objc2_foundation::{ns_string, MainThreadMarker, NSNumber, NSPoint, NSRect}; use super::ffi; +use super::util::cgerr; use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; use crate::monitor::VideoMode; @@ -50,28 +60,12 @@ impl std::fmt::Debug for VideoModeHandle { } } -pub struct NativeDisplayMode(pub ffi::CGDisplayModeRef); +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct NativeDisplayMode(pub CFRetained); unsafe impl Send for NativeDisplayMode {} unsafe impl Sync for NativeDisplayMode {} -impl Drop for NativeDisplayMode { - fn drop(&mut self) { - unsafe { - ffi::CGDisplayModeRelease(self.0); - } - } -} - -impl Clone for NativeDisplayMode { - fn clone(&self) -> Self { - unsafe { - ffi::CGDisplayModeRetain(self.0); - } - NativeDisplayMode(self.0) - } -} - impl VideoModeHandle { fn new( monitor: MonitorHandle, @@ -79,10 +73,9 @@ impl VideoModeHandle { refresh_rate_millihertz: Option, ) -> Self { unsafe { - let pixel_encoding = CFString::wrap_under_create_rule( - ffi::CGDisplayModeCopyPixelEncoding(native_mode.0), - ) - .to_string(); + #[allow(deprecated)] + let pixel_encoding = + CGDisplayModeCopyPixelEncoding(Some(&native_mode.0)).unwrap().to_string(); let bit_depth = if pixel_encoding.eq_ignore_ascii_case(ffi::IO32BitDirectPixels) { 32 } else if pixel_encoding.eq_ignore_ascii_case(ffi::IO16BitDirectPixels) { @@ -95,8 +88,8 @@ impl VideoModeHandle { let mode = VideoMode { size: PhysicalSize::new( - ffi::CGDisplayModeGetPixelWidth(native_mode.0) as u32, - ffi::CGDisplayModeGetPixelHeight(native_mode.0) as u32, + CGDisplayModeGetPixelWidth(Some(&native_mode.0)) as u32, + CGDisplayModeGetPixelHeight(Some(&native_mode.0)) as u32, ), refresh_rate_millihertz, bit_depth: NonZeroU16::new(bit_depth), @@ -110,33 +103,12 @@ 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, - ]) + fn uuid(&self) -> [u8; 16] { + let ptr = unsafe { ffi::CGDisplayCreateUUIDFromDisplayID(self.0) }; + let cf_uuid = unsafe { CFRetained::from_raw(NonNull::new(ptr).unwrap()) }; + unsafe { CFUUIDGetUUIDBytes(&cf_uuid) }.into() } } @@ -170,19 +142,32 @@ impl std::hash::Hash for MonitorHandle { } pub fn available_monitors() -> VecDeque { - if let Ok(displays) = CGDisplay::active_displays() { - let mut monitors = VecDeque::with_capacity(displays.len()); - for display in displays { - monitors.push_back(MonitorHandle(display)); - } - monitors - } else { - VecDeque::with_capacity(0) + let mut expected_count = 0; + let res = cgerr(unsafe { CGGetActiveDisplayList(0, ptr::null_mut(), &mut expected_count) }); + if res.is_err() { + return VecDeque::with_capacity(0); + } + + let mut displays: Vec = vec![0; expected_count as usize]; + let mut actual_count = 0; + let res = cgerr(unsafe { + CGGetActiveDisplayList(expected_count, displays.as_mut_ptr(), &mut actual_count) + }); + displays.truncate(actual_count as usize); + + if res.is_err() { + return VecDeque::with_capacity(0); + } + + let mut monitors = VecDeque::with_capacity(displays.len()); + for display in displays { + monitors.push_back(MonitorHandle(display)); } + monitors } pub fn primary_monitor() -> MonitorHandle { - MonitorHandle(CGDisplay::main().id) + MonitorHandle(unsafe { CGMainDisplayID() }) } impl fmt::Debug for MonitorHandle { @@ -204,8 +189,7 @@ impl MonitorHandle { // TODO: Be smarter about this: // pub fn name(&self) -> Option { - let MonitorHandle(display_id) = *self; - let screen_num = CGDisplay::new(display_id).model_number(); + let screen_num = unsafe { CGDisplayModelNumber(self.0) }; Some(format!("Monitor #{screen_num}")) } @@ -219,7 +203,7 @@ impl MonitorHandle { // This is already in screen coordinates. If we were using `NSScreen`, // then a conversion would've been needed: // flip_window_screen_coordinates(self.ns_screen(mtm)?.frame()) - let bounds = unsafe { CGDisplayBounds(self.native_identifier()) }; + let bounds = unsafe { CGDisplayBounds(self.0) }; let position = LogicalPosition::new(bounds.origin.x, bounds.origin.y); Some(position.to_physical(self.scale_factor())) } @@ -235,12 +219,12 @@ impl MonitorHandle { fn refresh_rate_millihertz(&self) -> Option { let current_display_mode = - NativeDisplayMode(unsafe { CGDisplayCopyDisplayMode(self.0) } as _); + NativeDisplayMode(unsafe { CGDisplayCopyDisplayMode(self.0) }.unwrap()); refresh_rate_millihertz(self.0, ¤t_display_mode) } pub fn current_video_mode(&self) -> Option { - let mode = NativeDisplayMode(unsafe { CGDisplayCopyDisplayMode(self.0) } as _); + let mode = NativeDisplayMode(unsafe { CGDisplayCopyDisplayMode(self.0) }.unwrap()); let refresh_rate_millihertz = refresh_rate_millihertz(self.0, &mode); Some(VideoModeHandle::new(self.clone(), mode, refresh_rate_millihertz).mode) } @@ -255,22 +239,20 @@ impl MonitorHandle { unsafe { let modes = { - let array = ffi::CGDisplayCopyAllDisplayModes(self.0, std::ptr::null()); - assert!(!array.is_null(), "failed to get list of display modes"); - let array_count = CFArrayGetCount(array); + let array = CGDisplayCopyAllDisplayModes(self.0, None) + .expect("failed to get list of display modes"); + let array_count = CFArrayGetCount(&array); let modes: Vec<_> = (0..array_count) .map(move |i| { - let mode = CFArrayGetValueAtIndex(array, i) as *mut _; - ffi::CGDisplayModeRetain(mode); - mode + let mode = CFArrayGetValueAtIndex(&array, i) as *mut CGDisplayMode; + CFRetained::from_raw(NonNull::new(mode).unwrap()) }) .collect(); - CFRelease(array as *const _); modes }; modes.into_iter().map(move |mode| { - let cg_refresh_rate_hertz = ffi::CGDisplayModeGetRefreshRate(mode).round() as i64; + let cg_refresh_rate_hertz = CGDisplayModeGetRefreshRate(Some(&mode)).round() as i64; // CGDisplayModeGetRefreshRate returns 0.0 for any display that // isn't a CRT @@ -335,7 +317,7 @@ pub(crate) fn flip_window_screen_coordinates(frame: NSRect) -> NSPoint { // It is intentional that we use `CGMainDisplayID` (as opposed to // `NSScreen::mainScreen`), because that's what the screen coordinates // are relative to, no matter which display the window is currently on. - let main_screen_height = CGDisplay::main().bounds().size.height; + let main_screen_height = unsafe { CGDisplayBounds(CGMainDisplayID()) }.size.height; let y = main_screen_height - frame.size.height - frame.origin.y; NSPoint::new(frame.origin.x, y) @@ -343,25 +325,29 @@ pub(crate) fn flip_window_screen_coordinates(frame: NSRect) -> NSPoint { fn refresh_rate_millihertz(id: CGDirectDisplayID, mode: &NativeDisplayMode) -> Option { unsafe { - let refresh_rate = ffi::CGDisplayModeGetRefreshRate(mode.0); + let refresh_rate = CGDisplayModeGetRefreshRate(Some(&mode.0)); if refresh_rate > 0.0 { return NonZeroU32::new((refresh_rate * 1000.0).round() as u32); } let mut display_link = std::ptr::null_mut(); - if ffi::CVDisplayLinkCreateWithCGDisplay(id, &mut display_link) != ffi::kCVReturnSuccess { + #[allow(deprecated)] + if CVDisplayLinkCreateWithCGDisplay(id, NonNull::from(&mut display_link)) + != kCVReturnSuccess + { return None; } - let time = ffi::CVDisplayLinkGetNominalOutputVideoRefreshPeriod(display_link); - ffi::CVDisplayLinkRelease(display_link); + let display_link = CFRetained::from_raw(NonNull::new(display_link).unwrap()); + #[allow(deprecated)] + let time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(&display_link); // This value is indefinite if an invalid display link was specified - if time.flags & ffi::kCVTimeIsIndefinite != 0 { + if time.flags & CVTimeFlags::IsIndefinite.0 != 0 { return None; } - (time.time_scale as i64) - .checked_div(time.time_value) + (time.timeScale as i64) + .checked_div(time.timeValue) .map(|v| (v * 1000) as u32) .and_then(NonZeroU32::new) } diff --git a/src/platform_impl/apple/appkit/observer.rs b/src/platform_impl/apple/appkit/observer.rs index 426b90bb960..f9bb1f944db 100644 --- a/src/platform_impl/apple/appkit/observer.rs +++ b/src/platform_impl/apple/appkit/observer.rs @@ -9,22 +9,18 @@ use std::ptr; use std::rc::Weak; use std::time::Instant; -use block2::Block; -use core_foundation::base::{CFIndex, CFOptionFlags, CFRelease, CFTypeRef}; -use core_foundation::date::CFAbsoluteTimeGetCurrent; -use core_foundation::runloop::{ - kCFRunLoopAfterWaiting, kCFRunLoopBeforeWaiting, kCFRunLoopCommonModes, kCFRunLoopDefaultMode, - kCFRunLoopExit, CFRunLoopActivity, CFRunLoopAddObserver, CFRunLoopAddTimer, CFRunLoopGetMain, - CFRunLoopObserverCallBack, CFRunLoopObserverContext, CFRunLoopObserverCreate, - CFRunLoopObserverRef, CFRunLoopRef, CFRunLoopTimerCreate, CFRunLoopTimerInvalidate, - CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate, CFRunLoopWakeUp, +use objc2_core_foundation::{ + kCFRunLoopCommonModes, kCFRunLoopDefaultMode, CFAbsoluteTimeGetCurrent, CFIndex, CFRetained, + CFRunLoop, CFRunLoopActivity, CFRunLoopAddObserver, CFRunLoopAddTimer, CFRunLoopGetMain, + CFRunLoopObserver, CFRunLoopObserverCallBack, CFRunLoopObserverContext, + CFRunLoopObserverCreate, CFRunLoopPerformBlock, CFRunLoopTimer, CFRunLoopTimerCreate, + CFRunLoopTimerInvalidate, CFRunLoopTimerSetNextFireDate, CFRunLoopWakeUp, }; use objc2_foundation::MainThreadMarker; use tracing::error; use super::app_state::AppState; use super::event_loop::{stop_app_on_panic, PanicInfo}; -use super::ffi; unsafe fn control_flow_handler(panic_info: *mut c_void, f: F) where @@ -48,8 +44,8 @@ where } // begin is queued with the highest priority to ensure it is processed before other observers -extern "C" fn control_flow_begin_handler( - _: CFRunLoopObserverRef, +extern "C-unwind" fn control_flow_begin_handler( + _: *mut CFRunLoopObserver, activity: CFRunLoopActivity, panic_info: *mut c_void, ) { @@ -57,7 +53,7 @@ extern "C" fn control_flow_begin_handler( control_flow_handler(panic_info, |panic_info| { #[allow(non_upper_case_globals)] match activity { - kCFRunLoopAfterWaiting => { + CFRunLoopActivity::AfterWaiting => { // trace!("Triggered `CFRunLoopAfterWaiting`"); AppState::get(MainThreadMarker::new().unwrap()).wakeup(panic_info); // trace!("Completed `CFRunLoopAfterWaiting`"); @@ -70,8 +66,8 @@ extern "C" fn control_flow_begin_handler( // end is queued with the lowest priority to ensure it is processed after other observers // without that, LoopExiting would get sent after AboutToWait -extern "C" fn control_flow_end_handler( - _: CFRunLoopObserverRef, +extern "C-unwind" fn control_flow_end_handler( + _: *mut CFRunLoopObserver, activity: CFRunLoopActivity, panic_info: *mut c_void, ) { @@ -79,12 +75,12 @@ extern "C" fn control_flow_end_handler( control_flow_handler(panic_info, |panic_info| { #[allow(non_upper_case_globals)] match activity { - kCFRunLoopBeforeWaiting => { + CFRunLoopActivity::BeforeWaiting => { // trace!("Triggered `CFRunLoopBeforeWaiting`"); AppState::get(MainThreadMarker::new().unwrap()).cleared(panic_info); // trace!("Completed `CFRunLoopBeforeWaiting`"); }, - kCFRunLoopExit => (), // unimplemented!(), // not expected to ever happen + CFRunLoopActivity::Exit => (), /* unimplemented!(), // not expected to ever happen */ _ => unreachable!(), } }); @@ -92,44 +88,33 @@ extern "C" fn control_flow_end_handler( } #[derive(Debug)] -pub struct RunLoop(CFRunLoopRef); - -impl Default for RunLoop { - fn default() -> Self { - Self(ptr::null_mut()) - } -} +pub struct RunLoop(CFRetained); impl RunLoop { pub fn main(mtm: MainThreadMarker) -> Self { // SAFETY: We have a MainThreadMarker here, which means we know we're on the main thread, so // scheduling (and scheduling a non-`Send` block) to that thread is allowed. let _ = mtm; - RunLoop(unsafe { CFRunLoopGetMain() }) + RunLoop(unsafe { CFRunLoopGetMain() }.unwrap()) } pub fn wakeup(&self) { - unsafe { CFRunLoopWakeUp(self.0) } + unsafe { CFRunLoopWakeUp(&self.0) } } unsafe fn add_observer( &self, - flags: CFOptionFlags, + flags: CFRunLoopActivity, + // The lower the value, the sooner this will run priority: CFIndex, handler: CFRunLoopObserverCallBack, context: *mut CFRunLoopObserverContext, ) { let observer = unsafe { - CFRunLoopObserverCreate( - ptr::null_mut(), - flags, - ffi::TRUE, // Indicates we want this to run repeatedly - priority, // The lower the value, the sooner this will run - handler, - context, - ) - }; - unsafe { CFRunLoopAddObserver(self.0, observer, kCFRunLoopCommonModes) }; + CFRunLoopObserverCreate(None, flags.0, true as _, priority, handler, context) + } + .unwrap(); + unsafe { CFRunLoopAddObserver(&self.0, Some(&observer), kCFRunLoopCommonModes) }; } /// Submit a closure to run on the main thread as the next step in the run loop, before other @@ -166,10 +151,6 @@ impl RunLoop { /// put the event at the very front of the queue, to be handled as soon as possible after /// handling whatever event it's currently handling. pub fn queue_closure(&self, closure: impl FnOnce() + 'static) { - extern "C" { - fn CFRunLoopPerformBlock(rl: CFRunLoopRef, mode: CFTypeRef, block: &Block); - } - // Convert `FnOnce()` to `Block`. let closure = Cell::new(Some(closure)); let block = block2::RcBlock::new(move || { @@ -195,10 +176,10 @@ impl RunLoop { // and be delivered to the application afterwards. // // [#1779]: https://github.com/rust-windowing/winit/issues/1779 - let mode = unsafe { kCFRunLoopDefaultMode as CFTypeRef }; + let mode = unsafe { kCFRunLoopDefaultMode.unwrap() }; // SAFETY: The runloop is valid, the mode is a `CFStringRef`, and the block is `'static`. - unsafe { CFRunLoopPerformBlock(self.0, mode, &block) } + unsafe { CFRunLoopPerformBlock(&self.0, Some(mode), Some(&block)) } } } @@ -213,15 +194,15 @@ pub fn setup_control_flow_observers(mtm: MainThreadMarker, panic_info: Weak, /// An arbitrary instant in the past, that will trigger an immediate wake /// We save this as the `next_fire_date` for consistency so we can @@ -244,30 +225,28 @@ pub struct EventLoopWaker { impl Drop for EventLoopWaker { fn drop(&mut self) { - unsafe { - CFRunLoopTimerInvalidate(self.timer); - CFRelease(self.timer as _); - } + unsafe { CFRunLoopTimerInvalidate(&self.timer) }; } } impl EventLoopWaker { pub(crate) fn new() -> Self { - extern "C" fn wakeup_main_loop(_timer: CFRunLoopTimerRef, _info: *mut c_void) {} + extern "C-unwind" fn wakeup_main_loop(_timer: *mut CFRunLoopTimer, _info: *mut c_void) {} unsafe { // Create a timer with a 0.1µs interval (1ns does not work) to mimic polling. // It is initially setup with a first fire time really far into the // future, but that gets changed to fire immediately in did_finish_launching let timer = CFRunLoopTimerCreate( - ptr::null_mut(), + None, f64::MAX, 0.000_000_1, 0, 0, - wakeup_main_loop, + Some(wakeup_main_loop), ptr::null_mut(), - ); - CFRunLoopAddTimer(CFRunLoopGetMain(), timer, kCFRunLoopCommonModes); + ) + .unwrap(); + CFRunLoopAddTimer(&CFRunLoopGetMain().unwrap(), Some(&timer), kCFRunLoopCommonModes); Self { timer, start_instant: Instant::now(), next_fire_date: None } } } @@ -275,14 +254,14 @@ impl EventLoopWaker { pub fn stop(&mut self) { if self.next_fire_date.is_some() { self.next_fire_date = None; - unsafe { CFRunLoopTimerSetNextFireDate(self.timer, f64::MAX) } + unsafe { CFRunLoopTimerSetNextFireDate(&self.timer, f64::MAX) }; } } pub fn start(&mut self) { if self.next_fire_date != Some(self.start_instant) { self.next_fire_date = Some(self.start_instant); - unsafe { CFRunLoopTimerSetNextFireDate(self.timer, f64::MIN) } + unsafe { CFRunLoopTimerSetNextFireDate(&self.timer, f64::MIN) }; } } @@ -300,7 +279,7 @@ impl EventLoopWaker { let duration = instant - now; let fsecs = duration.subsec_nanos() as f64 / 1_000_000_000.0 + duration.as_secs() as f64; - CFRunLoopTimerSetNextFireDate(self.timer, current + fsecs) + CFRunLoopTimerSetNextFireDate(&self.timer, current + fsecs); } } }, diff --git a/src/platform_impl/apple/appkit/util.rs b/src/platform_impl/apple/appkit/util.rs index ae78b532bdf..97ffca7f2d7 100644 --- a/src/platform_impl/apple/appkit/util.rs +++ b/src/platform_impl/apple/appkit/util.rs @@ -1,5 +1,8 @@ +use objc2_core_graphics::CGError; use tracing::trace; +use crate::error::OsError; + macro_rules! trace_scope { ($s:literal) => { let _crate = @@ -26,3 +29,12 @@ impl Drop for TraceGuard { trace!(target = self.module_path, "Completed `{}`", self.called_from_fn); } } + +#[track_caller] +pub(crate) fn cgerr(err: CGError) -> Result<(), OsError> { + if err == CGError::Success { + Ok(()) + } else { + Err(os_error!(format!("CGError {err:?}"))) + } +} diff --git a/src/platform_impl/apple/appkit/window_delegate.rs b/src/platform_impl/apple/appkit/window_delegate.rs index 018afe142b9..5106bf2f2ff 100644 --- a/src/platform_impl/apple/appkit/window_delegate.rs +++ b/src/platform_impl/apple/appkit/window_delegate.rs @@ -6,7 +6,6 @@ use std::ptr; use std::rc::Rc; use std::sync::{Arc, Mutex}; -use core_graphics::display::CGDisplay; use objc2::rc::{autoreleasepool, Retained}; use objc2::runtime::{AnyObject, ProtocolObject}; use objc2::{ @@ -21,7 +20,12 @@ use objc2_app_kit::{ NSWindowOcclusionState, NSWindowOrderingMode, NSWindowSharingType, NSWindowStyleMask, NSWindowTabbingMode, NSWindowTitleVisibility, NSWindowToolbarStyle, }; -use objc2_core_foundation::CGFloat; +use objc2_core_foundation::{CGFloat, CGPoint}; +use objc2_core_graphics::{ + CGAcquireDisplayFadeReservation, CGAssociateMouseAndMouseCursorPosition, CGDisplayCapture, + CGDisplayFade, CGDisplayRelease, CGDisplaySetDisplayMode, CGReleaseDisplayFadeReservation, + CGRestorePermanentDisplayConfiguration, CGShieldingWindowLevel, CGWarpMouseCursorPosition, +}; use objc2_foundation::{ ns_string, MainThreadMarker, NSArray, NSDictionary, NSEdgeInsets, NSKeyValueChangeKey, NSKeyValueChangeNewKey, NSKeyValueChangeOldKey, NSKeyValueObservingOptions, @@ -34,6 +38,7 @@ use super::app_state::AppState; use super::cursor::cursor_from_icon; use super::monitor::{self, flip_window_screen_coordinates, get_display_id}; use super::observer::RunLoop; +use super::util::cgerr; use super::view::WinitView; use super::window::{window_id, WinitPanel, WinitWindow}; use super::{ffi, Fullscreen, MonitorHandle}; @@ -1216,8 +1221,9 @@ impl WindowDelegate { }; // TODO: Do this for real https://stackoverflow.com/a/40922095/5435443 - CGDisplay::associate_mouse_and_mouse_cursor_position(associate_mouse_cursor) - .map_err(|status| os_error!(format!("CGError {status}")).into()) + cgerr(unsafe { CGAssociateMouseAndMouseCursorPosition(associate_mouse_cursor) })?; + + Ok(()) } #[inline] @@ -1239,14 +1245,12 @@ impl WindowDelegate { let content_rect = self.window().contentRectForFrameRect(self.window().frame()); let window_position = flip_window_screen_coordinates(content_rect); let cursor_position = cursor_position.to_logical::(self.scale_factor()); - let point = core_graphics::display::CGPoint { + let point = CGPoint { x: window_position.x + cursor_position.x, y: window_position.y + cursor_position.y, }; - CGDisplay::warp_mouse_cursor_position(point) - .map_err(|status| os_error!(format!("CGError {status}")))?; - CGDisplay::associate_mouse_and_mouse_cursor_position(true) - .map_err(|status| os_error!(format!("CGError {status}")))?; + cgerr(unsafe { CGWarpMouseCursorPosition(point) })?; + cgerr(unsafe { CGAssociateMouseAndMouseCursorPosition(true) })?; Ok(()) } @@ -1448,10 +1452,8 @@ impl WindowDelegate { unsafe { // Fade to black (and wait for the fade to complete) to hide the // flicker from capturing the display and switching display mode - if ffi::CGAcquireDisplayFadeReservation(5.0, &mut fade_token) - == ffi::kCGErrorSuccess - { - ffi::CGDisplayFade( + if cgerr(CGAcquireDisplayFadeReservation(5.0, &mut fade_token)).is_ok() { + CGDisplayFade( fade_token, 0.3, ffi::kCGDisplayBlendNormal, @@ -1459,11 +1461,11 @@ impl WindowDelegate { 0.0, 0.0, 0.0, - ffi::TRUE, + true, ); } - assert_eq!(ffi::CGDisplayCapture(display_id), ffi::kCGErrorSuccess); + cgerr(CGDisplayCapture(display_id)).unwrap(); } let video_mode = @@ -1473,17 +1475,13 @@ impl WindowDelegate { }; unsafe { - let result = ffi::CGDisplaySetDisplayMode( - display_id, - video_mode.native_mode.0, - std::ptr::null(), - ); - assert!(result == ffi::kCGErrorSuccess, "failed to set video mode"); + cgerr(CGDisplaySetDisplayMode(display_id, Some(&video_mode.native_mode.0), None)) + .expect("failed to set video mode"); // After the display has been configured, fade back in // asynchronously if fade_token != ffi::kCGDisplayFadeReservationInvalidToken { - ffi::CGDisplayFade( + CGDisplayFade( fade_token, 0.6, ffi::kCGDisplayBlendSolidColor, @@ -1491,9 +1489,9 @@ impl WindowDelegate { 0.0, 0.0, 0.0, - ffi::FALSE, + false, ); - ffi::CGReleaseDisplayFadeReservation(fade_token); + CGReleaseDisplayFadeReservation(fade_token); } } } @@ -1556,7 +1554,7 @@ impl WindowDelegate { | NSApplicationPresentationOptions::HideMenuBar; app.setPresentationOptions(presentation_options); - let window_level = unsafe { ffi::CGShieldingWindowLevel() } as NSWindowLevel + 1; + let window_level = unsafe { CGShieldingWindowLevel() } as NSWindowLevel + 1; self.window().setLevel(window_level); }, (Some(Fullscreen::Exclusive(ref monitor, _)), Some(Fullscreen::Borderless(_))) => { @@ -1770,8 +1768,8 @@ fn restore_and_release_display(monitor: &MonitorHandle) { let available_monitors = monitor::available_monitors(); if available_monitors.contains(monitor) { unsafe { - ffi::CGRestorePermanentDisplayConfiguration(); - assert_eq!(ffi::CGDisplayRelease(monitor.native_identifier()), ffi::kCGErrorSuccess); + CGRestorePermanentDisplayConfiguration(); + cgerr(CGDisplayRelease(monitor.native_identifier())).unwrap(); }; } else { warn!( diff --git a/src/platform_impl/apple/uikit/app_state.rs b/src/platform_impl/apple/uikit/app_state.rs index 4f2680a9d93..0266bbbad39 100644 --- a/src/platform_impl/apple/uikit/app_state.rs +++ b/src/platform_impl/apple/uikit/app_state.rs @@ -8,14 +8,12 @@ use std::sync::{Arc, Mutex}; use std::time::Instant; use std::{mem, ptr}; -use core_foundation::base::CFRelease; -use core_foundation::date::CFAbsoluteTimeGetCurrent; -use core_foundation::runloop::{ - kCFRunLoopCommonModes, CFRunLoopAddTimer, CFRunLoopGetMain, CFRunLoopRef, CFRunLoopTimerCreate, - CFRunLoopTimerInvalidate, CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate, -}; use objc2::rc::Retained; -use objc2_core_foundation::{CGRect, CGSize}; +use objc2_core_foundation::{ + kCFRunLoopCommonModes, CFAbsoluteTimeGetCurrent, CFRetained, CFRunLoop, CFRunLoopAddTimer, + CFRunLoopGetMain, CFRunLoopTimer, CFRunLoopTimerCreate, CFRunLoopTimerInvalidate, + CFRunLoopTimerSetNextFireDate, CGRect, CGSize, +}; use objc2_foundation::MainThreadMarker; use objc2_ui_kit::{UIApplication, UICoordinateSpace, UIView}; @@ -128,7 +126,7 @@ impl AppState { #[inline(never)] #[cold] fn init_guard(guard: &mut RefMut<'static, Option>) { - let waker = EventLoopWaker::new(unsafe { CFRunLoopGetMain() }); + let waker = EventLoopWaker::new(unsafe { CFRunLoopGetMain().unwrap() }); **guard = Some(AppState { app_state: Some(AppStateImpl::Initial { queued_gpu_redraws: HashSet::new() }), control_flow: ControlFlow::default(), @@ -554,46 +552,46 @@ fn get_view_and_screen_frame(window: &WinitUIWindow) -> (Retained, CGRec } struct EventLoopWaker { - timer: CFRunLoopTimerRef, + timer: CFRetained, } impl Drop for EventLoopWaker { fn drop(&mut self) { unsafe { - CFRunLoopTimerInvalidate(self.timer); - CFRelease(self.timer as _); + CFRunLoopTimerInvalidate(&self.timer); } } } impl EventLoopWaker { - fn new(rl: CFRunLoopRef) -> EventLoopWaker { - extern "C" fn wakeup_main_loop(_timer: CFRunLoopTimerRef, _info: *mut c_void) {} + fn new(rl: CFRetained) -> EventLoopWaker { + extern "C-unwind" fn wakeup_main_loop(_timer: *mut CFRunLoopTimer, _info: *mut c_void) {} unsafe { // Create a timer with a 0.1µs interval (1ns does not work) to mimic polling. // It is initially setup with a first fire time really far into the // future, but that gets changed to fire immediately in did_finish_launching let timer = CFRunLoopTimerCreate( - ptr::null_mut(), + None, f64::MAX, 0.000_000_1, 0, 0, - wakeup_main_loop, + Some(wakeup_main_loop), ptr::null_mut(), - ); - CFRunLoopAddTimer(rl, timer, kCFRunLoopCommonModes); + ) + .unwrap(); + CFRunLoopAddTimer(&rl, Some(&timer), kCFRunLoopCommonModes); EventLoopWaker { timer } } } fn stop(&mut self) { - unsafe { CFRunLoopTimerSetNextFireDate(self.timer, f64::MAX) } + unsafe { CFRunLoopTimerSetNextFireDate(&self.timer, f64::MAX) } } fn start(&mut self) { - unsafe { CFRunLoopTimerSetNextFireDate(self.timer, f64::MIN) } + unsafe { CFRunLoopTimerSetNextFireDate(&self.timer, f64::MIN) } } fn start_at(&mut self, instant: Instant) { @@ -606,7 +604,7 @@ impl EventLoopWaker { let duration = instant - now; let fsecs = duration.subsec_nanos() as f64 / 1_000_000_000.0 + duration.as_secs() as f64; - CFRunLoopTimerSetNextFireDate(self.timer, current + fsecs) + CFRunLoopTimerSetNextFireDate(&self.timer, current + fsecs); } } } diff --git a/src/platform_impl/apple/uikit/event_loop.rs b/src/platform_impl/apple/uikit/event_loop.rs index 9aa0d380967..fd1dfdbb420 100644 --- a/src/platform_impl/apple/uikit/event_loop.rs +++ b/src/platform_impl/apple/uikit/event_loop.rs @@ -3,16 +3,15 @@ use std::ptr::{self, NonNull}; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use std::sync::Arc; -use core_foundation::base::{CFIndex, CFRelease}; -use core_foundation::runloop::{ - kCFRunLoopAfterWaiting, kCFRunLoopBeforeWaiting, kCFRunLoopCommonModes, kCFRunLoopDefaultMode, - kCFRunLoopExit, CFRunLoopActivity, CFRunLoopAddObserver, CFRunLoopAddSource, CFRunLoopGetMain, - CFRunLoopObserverCreate, CFRunLoopObserverRef, CFRunLoopSourceContext, CFRunLoopSourceCreate, - CFRunLoopSourceInvalidate, CFRunLoopSourceRef, CFRunLoopSourceSignal, CFRunLoopWakeUp, -}; use objc2::rc::Retained; use objc2::runtime::ProtocolObject; use objc2::{msg_send, ClassType}; +use objc2_core_foundation::{ + kCFRunLoopCommonModes, kCFRunLoopDefaultMode, CFIndex, CFRetained, CFRunLoopActivity, + CFRunLoopAddObserver, CFRunLoopAddSource, CFRunLoopGetMain, CFRunLoopObserver, + CFRunLoopObserverCreate, CFRunLoopSource, CFRunLoopSourceContext, CFRunLoopSourceCreate, + CFRunLoopSourceInvalidate, CFRunLoopSourceSignal, CFRunLoopWakeUp, +}; use objc2_foundation::{MainThreadMarker, NSNotificationCenter, NSObjectProtocol}; use objc2_ui_kit::{ UIApplication, UIApplicationDidBecomeActiveNotification, @@ -280,7 +279,7 @@ impl EventLoop { pub struct EventLoopProxy { pub(crate) wake_up: AtomicBool, - source: CFRunLoopSourceRef, + source: CFRetained, } unsafe impl Send for EventLoopProxy {} @@ -288,10 +287,7 @@ unsafe impl Sync for EventLoopProxy {} impl Drop for EventLoopProxy { fn drop(&mut self) { - unsafe { - CFRunLoopSourceInvalidate(self.source); - CFRelease(self.source as _); - } + unsafe { CFRunLoopSourceInvalidate(&self.source) }; } } @@ -299,11 +295,11 @@ impl EventLoopProxy { pub(crate) fn new() -> EventLoopProxy { unsafe { // just wake up the eventloop - extern "C" fn event_loop_proxy_handler(_: *const c_void) {} + extern "C-unwind" fn event_loop_proxy_handler(_: *mut c_void) {} // adding a Source to the main CFRunLoop lets us wake it up and // process user events through the normal OS EventLoop mechanisms. - let rl = CFRunLoopGetMain(); + let rl = CFRunLoopGetMain().unwrap(); let mut context = CFRunLoopSourceContext { version: 0, info: ptr::null_mut(), @@ -314,11 +310,11 @@ impl EventLoopProxy { hash: None, schedule: None, cancel: None, - perform: event_loop_proxy_handler, + perform: Some(event_loop_proxy_handler), }; - let source = CFRunLoopSourceCreate(ptr::null_mut(), CFIndex::MAX - 1, &mut context); - CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes); - CFRunLoopWakeUp(rl); + let source = CFRunLoopSourceCreate(None, CFIndex::MAX - 1, &mut context).unwrap(); + CFRunLoopAddSource(&rl, Some(&source), kCFRunLoopCommonModes); + CFRunLoopWakeUp(&rl); EventLoopProxy { wake_up: AtomicBool::new(false), source } } @@ -330,9 +326,9 @@ impl EventLoopProxyProvider for EventLoopProxy { self.wake_up.store(true, AtomicOrdering::Relaxed); unsafe { // let the main thread know there's a new event - CFRunLoopSourceSignal(self.source); - let rl = CFRunLoopGetMain(); - CFRunLoopWakeUp(rl); + CFRunLoopSourceSignal(&self.source); + let rl = CFRunLoopGetMain().unwrap(); + CFRunLoopWakeUp(&rl); } } } @@ -341,15 +337,15 @@ fn setup_control_flow_observers() { unsafe { // begin is queued with the highest priority to ensure it is processed before other // observers - extern "C" fn control_flow_begin_handler( - _: CFRunLoopObserverRef, + extern "C-unwind" fn control_flow_begin_handler( + _: *mut CFRunLoopObserver, activity: CFRunLoopActivity, _: *mut c_void, ) { let mtm = MainThreadMarker::new().unwrap(); #[allow(non_upper_case_globals)] match activity { - kCFRunLoopAfterWaiting => app_state::handle_wakeup_transition(mtm), + CFRunLoopActivity::AfterWaiting => app_state::handle_wakeup_transition(mtm), _ => unreachable!(), } } @@ -365,65 +361,68 @@ fn setup_control_flow_observers() { // registers for every `CFRunLoopAddObserver` call on an iPad Air 2 running iOS 11.4. // // Also tested to be `0x1e8480` on iPhone 8, iOS 13 beta 4. - extern "C" fn control_flow_main_end_handler( - _: CFRunLoopObserverRef, + extern "C-unwind" fn control_flow_main_end_handler( + _: *mut CFRunLoopObserver, activity: CFRunLoopActivity, _: *mut c_void, ) { let mtm = MainThreadMarker::new().unwrap(); #[allow(non_upper_case_globals)] match activity { - kCFRunLoopBeforeWaiting => app_state::handle_main_events_cleared(mtm), - kCFRunLoopExit => {}, // may happen when running on macOS + CFRunLoopActivity::BeforeWaiting => app_state::handle_main_events_cleared(mtm), + CFRunLoopActivity::Exit => {}, // may happen when running on macOS _ => unreachable!(), } } // end is queued with the lowest priority to ensure it is processed after other observers - extern "C" fn control_flow_end_handler( - _: CFRunLoopObserverRef, + extern "C-unwind" fn control_flow_end_handler( + _: *mut CFRunLoopObserver, activity: CFRunLoopActivity, _: *mut c_void, ) { let mtm = MainThreadMarker::new().unwrap(); #[allow(non_upper_case_globals)] match activity { - kCFRunLoopBeforeWaiting => app_state::handle_events_cleared(mtm), - kCFRunLoopExit => {}, // may happen when running on macOS + CFRunLoopActivity::BeforeWaiting => app_state::handle_events_cleared(mtm), + CFRunLoopActivity::Exit => {}, // may happen when running on macOS _ => unreachable!(), } } - let main_loop = CFRunLoopGetMain(); + let main_loop = CFRunLoopGetMain().unwrap(); let begin_observer = CFRunLoopObserverCreate( - ptr::null_mut(), - kCFRunLoopAfterWaiting, - 1, // repeat = true + None, + CFRunLoopActivity::AfterWaiting.0, + true, CFIndex::MIN, - control_flow_begin_handler, + Some(control_flow_begin_handler), ptr::null_mut(), - ); - CFRunLoopAddObserver(main_loop, begin_observer, kCFRunLoopDefaultMode); + ) + .unwrap(); + CFRunLoopAddObserver(&main_loop, Some(&begin_observer), kCFRunLoopDefaultMode); let main_end_observer = CFRunLoopObserverCreate( - ptr::null_mut(), - kCFRunLoopExit | kCFRunLoopBeforeWaiting, - 1, // repeat = true + None, + (CFRunLoopActivity::Exit | CFRunLoopActivity::BeforeWaiting).0, + true, 0, // see comment on `control_flow_main_end_handler` - control_flow_main_end_handler, + Some(control_flow_main_end_handler), ptr::null_mut(), - ); - CFRunLoopAddObserver(main_loop, main_end_observer, kCFRunLoopDefaultMode); + ) + .unwrap(); + CFRunLoopAddObserver(&main_loop, Some(&main_end_observer), kCFRunLoopDefaultMode); let end_observer = CFRunLoopObserverCreate( - ptr::null_mut(), - kCFRunLoopExit | kCFRunLoopBeforeWaiting, - 1, // repeat = true + None, + (CFRunLoopActivity::Exit | CFRunLoopActivity::BeforeWaiting).0, + true, CFIndex::MAX, - control_flow_end_handler, + Some(control_flow_end_handler), ptr::null_mut(), - ); - CFRunLoopAddObserver(main_loop, end_observer, kCFRunLoopDefaultMode); + ) + .unwrap(); + CFRunLoopAddObserver(&main_loop, Some(&end_observer), kCFRunLoopDefaultMode); } }