macOS:ios: use next objc2 version
A lot of CoreFoundation methods have been marked safe, and converted into methods. Note that the old functions are still available, just deprecated.
This commit is contained in:
parent
ed4d70fdd4
commit
24e2c6914a
9 changed files with 125 additions and 217 deletions
|
|
@ -3,7 +3,7 @@ use std::ptr::NonNull;
|
|||
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_core_foundation::{CFData, CFRetained};
|
||||
use objc2_foundation::NSPoint;
|
||||
use smol_str::SmolStr;
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ pub fn get_modifierless_char(scancode: u16) -> Key {
|
|||
return Key::Unidentified(NativeKey::MacOS(scancode));
|
||||
};
|
||||
|
||||
let layout = unsafe { CFDataGetBytePtr(layout_data).cast() };
|
||||
let layout = layout_data.byte_ptr().cast();
|
||||
let keyboard_type = run_on_main(|_mtm| unsafe { ffi::LMGetKbdType() });
|
||||
|
||||
let mut result_len = 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// TODO: Upstream these
|
||||
|
||||
#![allow(dead_code, non_snake_case, non_upper_case_globals)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use std::ffi::c_void;
|
||||
|
||||
|
|
@ -9,27 +9,10 @@ use objc2::runtime::AnyObject;
|
|||
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;
|
||||
|
||||
pub type CGDisplayFadeReservationToken = u32;
|
||||
pub const kCGDisplayFadeReservationInvalidToken: CGDisplayFadeReservationToken = 0;
|
||||
|
||||
pub const IO1BitIndexedPixels: &str = "P";
|
||||
pub const IO2BitIndexedPixels: &str = "PP";
|
||||
pub const IO4BitIndexedPixels: &str = "PPPP";
|
||||
pub const IO8BitIndexedPixels: &str = "PPPPPPPP";
|
||||
pub const IO16BitDirectPixels: &str = "-RRRRRGGGGGBBBBB";
|
||||
pub const IO32BitDirectPixels: &str = "--------RRRRRRRRGGGGGGGGBBBBBBBB";
|
||||
|
||||
pub const kIO30BitDirectPixels: &str = "--RRRRRRRRRRGGGGGGGGGGBBBBBBBBBB";
|
||||
pub const kIO64BitDirectPixels: &str = "-16R16G16B16";
|
||||
|
||||
pub const kIO16BitFloatPixels: &str = "-16FR16FG16FB16";
|
||||
pub const kIO32BitFloatPixels: &str = "-32FR32FG32FB32";
|
||||
|
||||
pub const IOYUV422Pixels: &str = "Y4U2V2";
|
||||
pub const IO8BitOverlayPixels: &str = "O8";
|
||||
|
||||
// `CGDisplayCreateUUIDFromDisplayID` comes from the `ColorSync` framework.
|
||||
// However, that framework was only introduced "publicly" in macOS 10.13.
|
||||
|
|
@ -58,7 +41,6 @@ extern "C" {
|
|||
pub struct TISInputSource(std::ffi::c_void);
|
||||
|
||||
cf_type!(
|
||||
#[encoding_name = "__TISInputSource"]
|
||||
unsafe impl TISInputSource {}
|
||||
);
|
||||
|
||||
|
|
@ -103,45 +85,3 @@ extern "C" {
|
|||
unicodeString: *mut UniChar,
|
||||
) -> OSStatus;
|
||||
}
|
||||
|
||||
// CGWindowLevel.h
|
||||
//
|
||||
// Note: There are two different things at play in this header:
|
||||
// `CGWindowLevel` and `CGWindowLevelKey`.
|
||||
//
|
||||
// It seems like there was a push towards using "key" values instead of the
|
||||
// raw window level values, and then you were supposed to use
|
||||
// `CGWindowLevelForKey` to get the actual level.
|
||||
//
|
||||
// But the values that `NSWindowLevel` has are compiled in, and as such has
|
||||
// to remain ABI compatible, so they're safe for us to hardcode as well.
|
||||
#[allow(dead_code, non_upper_case_globals)]
|
||||
mod window_level {
|
||||
const kCGNumReservedWindowLevels: i32 = 16;
|
||||
const kCGNumReservedBaseWindowLevels: i32 = 5;
|
||||
|
||||
pub const kCGBaseWindowLevel: i32 = i32::MIN;
|
||||
pub const kCGMinimumWindowLevel: i32 = kCGBaseWindowLevel + kCGNumReservedBaseWindowLevels;
|
||||
pub const kCGMaximumWindowLevel: i32 = i32::MAX - kCGNumReservedWindowLevels;
|
||||
|
||||
pub const kCGDesktopWindowLevel: i32 = kCGMinimumWindowLevel + 20;
|
||||
pub const kCGDesktopIconWindowLevel: i32 = kCGDesktopWindowLevel + 20;
|
||||
pub const kCGBackstopMenuLevel: i32 = -20;
|
||||
pub const kCGNormalWindowLevel: i32 = 0;
|
||||
pub const kCGFloatingWindowLevel: i32 = 3;
|
||||
pub const kCGTornOffMenuWindowLevel: i32 = 3;
|
||||
pub const kCGModalPanelWindowLevel: i32 = 8;
|
||||
pub const kCGUtilityWindowLevel: i32 = 19;
|
||||
pub const kCGDockWindowLevel: i32 = 20;
|
||||
pub const kCGMainMenuWindowLevel: i32 = 24;
|
||||
pub const kCGStatusWindowLevel: i32 = 25;
|
||||
pub const kCGPopUpMenuWindowLevel: i32 = 101;
|
||||
pub const kCGOverlayWindowLevel: i32 = 102;
|
||||
pub const kCGHelpWindowLevel: i32 = 200;
|
||||
pub const kCGDraggingWindowLevel: i32 = 500;
|
||||
pub const kCGScreenSaverWindowLevel: i32 = 1000;
|
||||
pub const kCGAssistiveTechHighWindowLevel: i32 = 1500;
|
||||
pub const kCGCursorWindowLevel: i32 = kCGMaximumWindowLevel - 1;
|
||||
}
|
||||
|
||||
pub use window_level::*;
|
||||
|
|
|
|||
|
|
@ -9,21 +9,12 @@ use dispatch2::run_on_main;
|
|||
use objc2::rc::Retained;
|
||||
use objc2::MainThreadMarker;
|
||||
use objc2_app_kit::NSScreen;
|
||||
use objc2_core_foundation::{
|
||||
CFArrayGetCount, CFArrayGetValueAtIndex, CFRetained, CFUUIDGetUUIDBytes,
|
||||
};
|
||||
#[allow(deprecated)]
|
||||
use objc2_core_foundation::{CFArray, CFRetained};
|
||||
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,
|
||||
CGDisplayMode, CGDisplayModelNumber, CGGetActiveDisplayList, CGMainDisplayID,
|
||||
};
|
||||
use objc2_core_video::{kCVReturnSuccess, CVDisplayLink, CVTimeFlags};
|
||||
use objc2_foundation::{ns_string, NSNumber, NSPoint, NSRect};
|
||||
|
||||
use super::ffi;
|
||||
|
|
@ -76,7 +67,7 @@ impl VideoModeHandle {
|
|||
unsafe {
|
||||
#[allow(deprecated)]
|
||||
let pixel_encoding =
|
||||
CGDisplayModeCopyPixelEncoding(Some(&native_mode.0)).unwrap().to_string();
|
||||
CGDisplayMode::pixel_encoding(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) {
|
||||
|
|
@ -89,8 +80,8 @@ impl VideoModeHandle {
|
|||
|
||||
let mode = VideoMode {
|
||||
size: PhysicalSize::new(
|
||||
CGDisplayModeGetPixelWidth(Some(&native_mode.0)) as u32,
|
||||
CGDisplayModeGetPixelHeight(Some(&native_mode.0)) as u32,
|
||||
CGDisplayMode::pixel_width(Some(&native_mode.0)) as u32,
|
||||
CGDisplayMode::pixel_height(Some(&native_mode.0)) as u32,
|
||||
),
|
||||
refresh_rate_millihertz,
|
||||
bit_depth: NonZeroU16::new(bit_depth),
|
||||
|
|
@ -107,9 +98,12 @@ pub struct MonitorHandle(CGDirectDisplayID);
|
|||
impl MonitorHandle {
|
||||
/// Internal comparisons of [`MonitorHandle`]s are done first requesting a UUID for the handle.
|
||||
fn uuid(&self) -> u128 {
|
||||
// SAFETY: Valid to call.
|
||||
let ptr = unsafe { ffi::CGDisplayCreateUUIDFromDisplayID(self.0) };
|
||||
// SAFETY: `CGDisplayCreateUUIDFromDisplayID` is a "create" function, so the pointer has
|
||||
// +1 retain count.
|
||||
let cf_uuid = unsafe { CFRetained::from_raw(NonNull::new(ptr).unwrap()) };
|
||||
u128::from_ne_bytes(unsafe { CFUUIDGetUUIDBytes(&cf_uuid) }.into())
|
||||
u128::from_ne_bytes(cf_uuid.uuid_bytes().into())
|
||||
}
|
||||
|
||||
pub fn new(id: CGDirectDisplayID) -> Self {
|
||||
|
|
@ -126,38 +120,25 @@ impl MonitorHandle {
|
|||
let refresh_rate_millihertz = self.refresh_rate_millihertz();
|
||||
let monitor = self.clone();
|
||||
|
||||
unsafe {
|
||||
let modes = {
|
||||
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 CGDisplayMode;
|
||||
CFRetained::retain(NonNull::new(mode).unwrap())
|
||||
})
|
||||
.collect();
|
||||
modes
|
||||
let array = unsafe { CGDisplayCopyAllDisplayModes(self.0, None) }
|
||||
.expect("failed to get list of display modes");
|
||||
// SAFETY: `CGDisplayCopyAllDisplayModes` is documented to return an array of display modes.
|
||||
let modes = unsafe { CFRetained::cast_unchecked::<CFArray<CGDisplayMode>>(array) };
|
||||
|
||||
modes.into_iter().map(move |mode| {
|
||||
let cg_refresh_rate_hertz =
|
||||
unsafe { CGDisplayMode::refresh_rate(Some(&mode)) }.round() as i64;
|
||||
|
||||
// CGDisplayModeGetRefreshRate returns 0.0 for any display that
|
||||
// isn't a CRT
|
||||
let refresh_rate_millihertz = if cg_refresh_rate_hertz > 0 {
|
||||
NonZeroU32::new((cg_refresh_rate_hertz * 1000) as u32)
|
||||
} else {
|
||||
refresh_rate_millihertz
|
||||
};
|
||||
|
||||
modes.into_iter().map(move |mode| {
|
||||
let cg_refresh_rate_hertz = CGDisplayModeGetRefreshRate(Some(&mode)).round() as i64;
|
||||
|
||||
// CGDisplayModeGetRefreshRate returns 0.0 for any display that
|
||||
// isn't a CRT
|
||||
let refresh_rate_millihertz = if cg_refresh_rate_hertz > 0 {
|
||||
NonZeroU32::new((cg_refresh_rate_hertz * 1000) as u32)
|
||||
} else {
|
||||
refresh_rate_millihertz
|
||||
};
|
||||
|
||||
VideoModeHandle::new(
|
||||
monitor.clone(),
|
||||
NativeDisplayMode(mode),
|
||||
refresh_rate_millihertz,
|
||||
)
|
||||
})
|
||||
}
|
||||
VideoModeHandle::new(monitor.clone(), NativeDisplayMode(mode), refresh_rate_millihertz)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn ns_screen(&self, mtm: MainThreadMarker) -> Option<Retained<NSScreen>> {
|
||||
|
|
@ -329,21 +310,21 @@ pub(crate) fn flip_window_screen_coordinates(frame: NSRect) -> NSPoint {
|
|||
|
||||
fn refresh_rate_millihertz(id: CGDirectDisplayID, mode: &NativeDisplayMode) -> Option<NonZeroU32> {
|
||||
unsafe {
|
||||
let refresh_rate = CGDisplayModeGetRefreshRate(Some(&mode.0));
|
||||
let refresh_rate = CGDisplayMode::refresh_rate(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();
|
||||
#[allow(deprecated)]
|
||||
if CVDisplayLinkCreateWithCGDisplay(id, NonNull::from(&mut display_link))
|
||||
if CVDisplayLink::create_with_cg_display(id, NonNull::from(&mut display_link))
|
||||
!= kCVReturnSuccess
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let display_link = CFRetained::from_raw(NonNull::new(display_link).unwrap());
|
||||
#[allow(deprecated)]
|
||||
let time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(&display_link);
|
||||
let time = display_link.nominal_output_video_refresh_period();
|
||||
|
||||
// This value is indefinite if an invalid display link was specified
|
||||
if time.flags & CVTimeFlags::IsIndefinite.0 != 0 {
|
||||
|
|
|
|||
|
|
@ -12,10 +12,8 @@ use std::time::Instant;
|
|||
use objc2::MainThreadMarker;
|
||||
use objc2_core_foundation::{
|
||||
kCFRunLoopCommonModes, kCFRunLoopDefaultMode, CFAbsoluteTimeGetCurrent, CFIndex, CFRetained,
|
||||
CFRunLoop, CFRunLoopActivity, CFRunLoopAddObserver, CFRunLoopAddTimer, CFRunLoopGetMain,
|
||||
CFRunLoopObserver, CFRunLoopObserverCallBack, CFRunLoopObserverContext,
|
||||
CFRunLoopObserverCreate, CFRunLoopPerformBlock, CFRunLoopTimer, CFRunLoopTimerCreate,
|
||||
CFRunLoopTimerInvalidate, CFRunLoopTimerSetNextFireDate, CFRunLoopWakeUp,
|
||||
CFRunLoop, CFRunLoopActivity, CFRunLoopObserver, CFRunLoopObserverCallBack,
|
||||
CFRunLoopObserverContext, CFRunLoopTimer,
|
||||
};
|
||||
use tracing::error;
|
||||
|
||||
|
|
@ -95,11 +93,11 @@ impl RunLoop {
|
|||
// 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() }.unwrap())
|
||||
RunLoop(CFRunLoop::main().unwrap())
|
||||
}
|
||||
|
||||
pub fn wakeup(&self) {
|
||||
unsafe { CFRunLoopWakeUp(&self.0) }
|
||||
self.0.wake_up();
|
||||
}
|
||||
|
||||
unsafe fn add_observer(
|
||||
|
|
@ -111,9 +109,9 @@ impl RunLoop {
|
|||
context: *mut CFRunLoopObserverContext,
|
||||
) {
|
||||
let observer =
|
||||
unsafe { CFRunLoopObserverCreate(None, flags.0, true, priority, handler, context) }
|
||||
unsafe { CFRunLoopObserver::new(None, flags.0, true, priority, handler, context) }
|
||||
.unwrap();
|
||||
unsafe { CFRunLoopAddObserver(&self.0, Some(&observer), kCFRunLoopCommonModes) };
|
||||
self.0.add_observer(Some(&observer), unsafe { kCFRunLoopCommonModes });
|
||||
}
|
||||
|
||||
/// Submit a closure to run on the main thread as the next step in the run loop, before other
|
||||
|
|
@ -178,7 +176,7 @@ impl RunLoop {
|
|||
let mode = unsafe { kCFRunLoopDefaultMode.unwrap() };
|
||||
|
||||
// SAFETY: The runloop is valid, the mode is a `CFStringRef`, and the block is `'static`.
|
||||
unsafe { CFRunLoopPerformBlock(&self.0, Some(mode), Some(&block)) }
|
||||
unsafe { self.0.perform_block(Some(mode), Some(&block)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +222,7 @@ pub struct EventLoopWaker {
|
|||
|
||||
impl Drop for EventLoopWaker {
|
||||
fn drop(&mut self) {
|
||||
unsafe { CFRunLoopTimerInvalidate(&self.timer) };
|
||||
self.timer.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -235,7 +233,7 @@ impl EventLoopWaker {
|
|||
// 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(
|
||||
let timer = CFRunLoopTimer::new(
|
||||
None,
|
||||
f64::MAX,
|
||||
0.000_000_1,
|
||||
|
|
@ -245,7 +243,7 @@ impl EventLoopWaker {
|
|||
ptr::null_mut(),
|
||||
)
|
||||
.unwrap();
|
||||
CFRunLoopAddTimer(&CFRunLoopGetMain().unwrap(), Some(&timer), kCFRunLoopCommonModes);
|
||||
CFRunLoop::main().unwrap().add_timer(Some(&timer), kCFRunLoopCommonModes);
|
||||
Self { timer, start_instant: Instant::now(), next_fire_date: None }
|
||||
}
|
||||
}
|
||||
|
|
@ -253,14 +251,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) };
|
||||
self.timer.set_next_fire_date(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) };
|
||||
self.timer.set_next_fire_date(f64::MIN);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -273,13 +271,11 @@ impl EventLoopWaker {
|
|||
Some(instant) => {
|
||||
if self.next_fire_date != Some(instant) {
|
||||
self.next_fire_date = Some(instant);
|
||||
unsafe {
|
||||
let current = CFAbsoluteTimeGetCurrent();
|
||||
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);
|
||||
}
|
||||
let current = CFAbsoluteTimeGetCurrent();
|
||||
let duration = instant - now;
|
||||
let fsecs = duration.subsec_nanos() as f64 / 1_000_000_000.0
|
||||
+ duration.as_secs() as f64;
|
||||
self.timer.set_next_fire_date(current + fsecs);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
|
|
|
|||
|
|
@ -23,8 +23,10 @@ use objc2_app_kit::{
|
|||
};
|
||||
use objc2_core_foundation::{CGFloat, CGPoint};
|
||||
use objc2_core_graphics::{
|
||||
CGAcquireDisplayFadeReservation, CGAssociateMouseAndMouseCursorPosition, CGDisplayCapture,
|
||||
CGDisplayFade, CGDisplayRelease, CGDisplaySetDisplayMode, CGReleaseDisplayFadeReservation,
|
||||
kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, kCGDisplayFadeReservationInvalidToken,
|
||||
kCGFloatingWindowLevel, kCGNormalWindowLevel, CGAcquireDisplayFadeReservation,
|
||||
CGAssociateMouseAndMouseCursorPosition, CGDisplayCapture, CGDisplayFade, CGDisplayRelease,
|
||||
CGDisplaySetDisplayMode, CGReleaseDisplayFadeReservation,
|
||||
CGRestorePermanentDisplayConfiguration, CGShieldingWindowLevel, CGWarpMouseCursorPosition,
|
||||
};
|
||||
use objc2_foundation::{
|
||||
|
|
@ -1500,7 +1502,7 @@ impl WindowDelegate {
|
|||
|
||||
let display_id = monitor.native_id() as _;
|
||||
|
||||
let mut fade_token = ffi::kCGDisplayFadeReservationInvalidToken;
|
||||
let mut fade_token = kCGDisplayFadeReservationInvalidToken;
|
||||
|
||||
if matches!(old_fullscreen, Some(Fullscreen::Borderless(_))) {
|
||||
self.ivars().save_presentation_opts.replace(Some(app.presentationOptions()));
|
||||
|
|
@ -1513,8 +1515,8 @@ impl WindowDelegate {
|
|||
CGDisplayFade(
|
||||
fade_token,
|
||||
0.3,
|
||||
ffi::kCGDisplayBlendNormal,
|
||||
ffi::kCGDisplayBlendSolidColor,
|
||||
kCGDisplayBlendNormal,
|
||||
kCGDisplayBlendSolidColor,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
|
|
@ -1538,12 +1540,12 @@ impl WindowDelegate {
|
|||
|
||||
// After the display has been configured, fade back in
|
||||
// asynchronously
|
||||
if fade_token != ffi::kCGDisplayFadeReservationInvalidToken {
|
||||
if fade_token != kCGDisplayFadeReservationInvalidToken {
|
||||
CGDisplayFade(
|
||||
fade_token,
|
||||
0.6,
|
||||
ffi::kCGDisplayBlendSolidColor,
|
||||
ffi::kCGDisplayBlendNormal,
|
||||
kCGDisplayBlendSolidColor,
|
||||
kCGDisplayBlendNormal,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
|
|
@ -1560,7 +1562,7 @@ impl WindowDelegate {
|
|||
// Window level must be restored from `CGShieldingWindowLevel()
|
||||
// + 1` back to normal in order for `toggleFullScreen` to do
|
||||
// anything
|
||||
window.setLevel(ffi::kCGNormalWindowLevel as NSWindowLevel);
|
||||
window.setLevel(kCGNormalWindowLevel as NSWindowLevel);
|
||||
window.toggleFullScreen(None);
|
||||
}
|
||||
|
||||
|
|
@ -1629,7 +1631,7 @@ impl WindowDelegate {
|
|||
|
||||
// Restore the normal window level following the Borderless fullscreen
|
||||
// `CGShieldingWindowLevel() + 1` hack.
|
||||
self.window().setLevel(ffi::kCGNormalWindowLevel as NSWindowLevel);
|
||||
self.window().setLevel(kCGNormalWindowLevel as NSWindowLevel);
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
|
|
@ -1676,10 +1678,19 @@ impl WindowDelegate {
|
|||
|
||||
#[inline]
|
||||
pub fn set_window_level(&self, level: WindowLevel) {
|
||||
// Note: There are two different things at play here:
|
||||
// `CGWindowLevel` and `CGWindowLevelKey`.
|
||||
//
|
||||
// It seems like there was a push towards using "key" values instead of the
|
||||
// raw window level values, and then you were supposed to use
|
||||
// `CGWindowLevelForKey` to get the actual level.
|
||||
//
|
||||
// But the values that `NSWindowLevel` has are compiled in, and as such has
|
||||
// to remain ABI compatible, so they're safe for us to hardcode as well.
|
||||
let level = match level {
|
||||
WindowLevel::AlwaysOnTop => ffi::kCGFloatingWindowLevel as NSWindowLevel,
|
||||
WindowLevel::AlwaysOnBottom => (ffi::kCGNormalWindowLevel - 1) as NSWindowLevel,
|
||||
WindowLevel::Normal => ffi::kCGNormalWindowLevel as NSWindowLevel,
|
||||
WindowLevel::AlwaysOnTop => kCGFloatingWindowLevel as NSWindowLevel,
|
||||
WindowLevel::AlwaysOnBottom => (kCGNormalWindowLevel - 1) as NSWindowLevel,
|
||||
WindowLevel::Normal => kCGNormalWindowLevel as NSWindowLevel,
|
||||
};
|
||||
self.window().setLevel(level);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ use std::sync::Arc;
|
|||
|
||||
use objc2::MainThreadMarker;
|
||||
use objc2_core_foundation::{
|
||||
kCFRunLoopCommonModes, CFIndex, CFRetained, CFRunLoop, CFRunLoopAddSource, CFRunLoopGetMain,
|
||||
CFRunLoopSource, CFRunLoopSourceContext, CFRunLoopSourceCreate, CFRunLoopSourceInvalidate,
|
||||
CFRunLoopSourceSignal, CFRunLoopWakeUp,
|
||||
kCFRunLoopCommonModes, CFIndex, CFRetained, CFRunLoop, CFRunLoopSource, CFRunLoopSourceContext,
|
||||
};
|
||||
|
||||
use crate::event_loop::EventLoopProxyProvider;
|
||||
|
|
@ -90,12 +88,12 @@ impl EventLoopProxy {
|
|||
// Keeping the closure alive beyond this scope is fine, because `F: 'static`.
|
||||
let source = unsafe {
|
||||
let _ = mtm;
|
||||
CFRunLoopSourceCreate(None, order, &mut context).unwrap()
|
||||
CFRunLoopSource::new(None, order, &mut context).unwrap()
|
||||
};
|
||||
|
||||
// Register the source to be performed on the main thread.
|
||||
let main_loop = unsafe { CFRunLoopGetMain() }.unwrap();
|
||||
unsafe { CFRunLoopAddSource(&main_loop, Some(&source), kCFRunLoopCommonModes) };
|
||||
let main_loop = CFRunLoop::main().unwrap();
|
||||
unsafe { main_loop.add_source(Some(&source), kCFRunLoopCommonModes) };
|
||||
|
||||
Self { source, main_loop }
|
||||
}
|
||||
|
|
@ -106,7 +104,7 @@ impl EventLoopProxy {
|
|||
pub(crate) fn invalidate(&self) {
|
||||
// NOTE: We do NOT fire this on `Drop`, since we want the proxy to be cloneable, such that
|
||||
// we only need to register a single source even if there's multiple proxies in use.
|
||||
unsafe { CFRunLoopSourceInvalidate(&self.source) };
|
||||
self.source.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,12 +113,12 @@ impl EventLoopProxyProvider for EventLoopProxy {
|
|||
// Signal the source, which ends up later invoking `perform` on the main thread.
|
||||
//
|
||||
// Multiple signals in quick succession are automatically coalesced into a single signal.
|
||||
unsafe { CFRunLoopSourceSignal(&self.source) };
|
||||
self.source.signal();
|
||||
|
||||
// Let the main thread know there's a new event.
|
||||
//
|
||||
// This is required since we may be (probably are) running on a different thread, and the
|
||||
// main loop may be sleeping (and `CFRunLoopSourceSignal` won't wake it).
|
||||
unsafe { CFRunLoopWakeUp(&self.main_loop) };
|
||||
self.main_loop.wake_up();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,8 @@ use dispatch2::MainThreadBound;
|
|||
use objc2::rc::Retained;
|
||||
use objc2::MainThreadMarker;
|
||||
use objc2_core_foundation::{
|
||||
kCFRunLoopCommonModes, CFAbsoluteTimeGetCurrent, CFRetained, CFRunLoop, CFRunLoopAddTimer,
|
||||
CFRunLoopGetMain, CFRunLoopTimer, CFRunLoopTimerCreate, CFRunLoopTimerInvalidate,
|
||||
CFRunLoopTimerSetNextFireDate, CGRect, CGSize,
|
||||
kCFRunLoopCommonModes, CFAbsoluteTimeGetCurrent, CFRetained, CFRunLoop, CFRunLoopTimer, CGRect,
|
||||
CGSize,
|
||||
};
|
||||
use objc2_ui_kit::{UIApplication, UICoordinateSpace, UIView};
|
||||
|
||||
|
|
@ -115,7 +114,7 @@ impl AppState {
|
|||
#[inline(never)]
|
||||
#[cold]
|
||||
fn init_guard(guard: &mut RefMut<'static, Option<AppState>>, mtm: MainThreadMarker) {
|
||||
let waker = EventLoopWaker::new(unsafe { CFRunLoopGetMain().unwrap() });
|
||||
let waker = EventLoopWaker::new(CFRunLoop::main().unwrap());
|
||||
let event_loop_proxy = Arc::new(EventLoopProxy::new(mtm, move || {
|
||||
get_handler(mtm).handle(|app| app.proxy_wake_up(&ActiveEventLoop { mtm }));
|
||||
}));
|
||||
|
|
@ -305,7 +304,11 @@ pub(crate) fn queue_gl_or_metal_redraw(mtm: MainThreadMarker, window: Retained<W
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn launch(mtm: MainThreadMarker, app: impl ApplicationHandler, run: impl FnOnce()) {
|
||||
pub(crate) fn launch<R>(
|
||||
mtm: MainThreadMarker,
|
||||
app: impl ApplicationHandler,
|
||||
run: impl FnOnce() -> R,
|
||||
) -> R {
|
||||
get_handler(mtm).set(Box::new(app), run)
|
||||
}
|
||||
|
||||
|
|
@ -544,9 +547,7 @@ struct EventLoopWaker {
|
|||
|
||||
impl Drop for EventLoopWaker {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
CFRunLoopTimerInvalidate(&self.timer);
|
||||
}
|
||||
self.timer.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +558,7 @@ impl EventLoopWaker {
|
|||
// 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(
|
||||
let timer = CFRunLoopTimer::new(
|
||||
None,
|
||||
f64::MAX,
|
||||
0.000_000_1,
|
||||
|
|
@ -567,18 +568,18 @@ impl EventLoopWaker {
|
|||
ptr::null_mut(),
|
||||
)
|
||||
.unwrap();
|
||||
CFRunLoopAddTimer(&rl, Some(&timer), kCFRunLoopCommonModes);
|
||||
rl.add_timer(Some(&timer), kCFRunLoopCommonModes);
|
||||
|
||||
EventLoopWaker { timer }
|
||||
}
|
||||
}
|
||||
|
||||
fn stop(&mut self) {
|
||||
unsafe { CFRunLoopTimerSetNextFireDate(&self.timer, f64::MAX) }
|
||||
self.timer.set_next_fire_date(f64::MAX);
|
||||
}
|
||||
|
||||
fn start(&mut self) {
|
||||
unsafe { CFRunLoopTimerSetNextFireDate(&self.timer, f64::MIN) }
|
||||
self.timer.set_next_fire_date(f64::MIN);
|
||||
}
|
||||
|
||||
fn start_at(&mut self, instant: Instant) {
|
||||
|
|
@ -586,13 +587,11 @@ impl EventLoopWaker {
|
|||
if now >= instant {
|
||||
self.start();
|
||||
} else {
|
||||
unsafe {
|
||||
let current = CFAbsoluteTimeGetCurrent();
|
||||
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);
|
||||
}
|
||||
let current = CFAbsoluteTimeGetCurrent();
|
||||
let duration = instant - now;
|
||||
let fsecs =
|
||||
duration.subsec_nanos() as f64 / 1_000_000_000.0 + duration.as_secs() as f64;
|
||||
self.timer.set_next_fire_date(current + fsecs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,19 @@
|
|||
use std::ffi::{c_char, c_int, c_void};
|
||||
use std::ptr::{self, NonNull};
|
||||
use std::ffi::c_void;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use objc2::rc::Retained;
|
||||
use objc2::runtime::ProtocolObject;
|
||||
use objc2::{msg_send, ClassType, MainThreadMarker};
|
||||
use objc2_core_foundation::{
|
||||
kCFRunLoopDefaultMode, CFIndex, CFRunLoopActivity, CFRunLoopAddObserver, CFRunLoopGetMain,
|
||||
CFRunLoopObserver, CFRunLoopObserverCreate,
|
||||
kCFRunLoopDefaultMode, CFIndex, CFRunLoop, CFRunLoopActivity, CFRunLoopObserver,
|
||||
};
|
||||
use objc2_foundation::{NSNotificationCenter, NSObjectProtocol};
|
||||
use objc2_ui_kit::{
|
||||
UIApplication, UIApplicationDidBecomeActiveNotification,
|
||||
UIApplicationDidEnterBackgroundNotification, UIApplicationDidFinishLaunchingNotification,
|
||||
UIApplicationDidReceiveMemoryWarningNotification, UIApplicationMain,
|
||||
UIApplicationWillEnterForegroundNotification, UIApplicationWillResignActiveNotification,
|
||||
UIApplicationWillTerminateNotification, UIScreen,
|
||||
UIApplicationDidReceiveMemoryWarningNotification, UIApplicationWillEnterForegroundNotification,
|
||||
UIApplicationWillResignActiveNotification, UIApplicationWillTerminateNotification, UIScreen,
|
||||
};
|
||||
use rwh_06::HasDisplayHandle;
|
||||
|
||||
|
|
@ -253,24 +251,9 @@ impl EventLoop {
|
|||
`EventLoop::run_app` calls `UIApplicationMain` on iOS",
|
||||
);
|
||||
|
||||
extern "C" {
|
||||
// These functions are in crt_externs.h.
|
||||
fn _NSGetArgc() -> *mut c_int;
|
||||
fn _NSGetArgv() -> *mut *mut *mut c_char;
|
||||
}
|
||||
|
||||
app_state::launch(self.mtm, app, || unsafe {
|
||||
UIApplicationMain(
|
||||
*_NSGetArgc(),
|
||||
NonNull::new(*_NSGetArgv()).unwrap(),
|
||||
// We intentionally override neither the application nor the delegate, to allow
|
||||
// the user to do so themselves!
|
||||
None,
|
||||
None,
|
||||
);
|
||||
});
|
||||
|
||||
unreachable!()
|
||||
// We intentionally override neither the application nor the delegate,
|
||||
// to allow the user to do so themselves!
|
||||
app_state::launch(self.mtm, app, || UIApplication::main(None, None, self.mtm))
|
||||
}
|
||||
|
||||
pub fn window_target(&self) -> &dyn RootActiveEventLoop {
|
||||
|
|
@ -335,9 +318,9 @@ fn setup_control_flow_observers() {
|
|||
}
|
||||
}
|
||||
|
||||
let main_loop = CFRunLoopGetMain().unwrap();
|
||||
let main_loop = CFRunLoop::main().unwrap();
|
||||
|
||||
let begin_observer = CFRunLoopObserverCreate(
|
||||
let begin_observer = CFRunLoopObserver::new(
|
||||
None,
|
||||
CFRunLoopActivity::AfterWaiting.0,
|
||||
true,
|
||||
|
|
@ -346,9 +329,9 @@ fn setup_control_flow_observers() {
|
|||
ptr::null_mut(),
|
||||
)
|
||||
.unwrap();
|
||||
CFRunLoopAddObserver(&main_loop, Some(&begin_observer), kCFRunLoopDefaultMode);
|
||||
main_loop.add_observer(Some(&begin_observer), kCFRunLoopDefaultMode);
|
||||
|
||||
let main_end_observer = CFRunLoopObserverCreate(
|
||||
let main_end_observer = CFRunLoopObserver::new(
|
||||
None,
|
||||
(CFRunLoopActivity::Exit | CFRunLoopActivity::BeforeWaiting).0,
|
||||
true,
|
||||
|
|
@ -357,9 +340,9 @@ fn setup_control_flow_observers() {
|
|||
ptr::null_mut(),
|
||||
)
|
||||
.unwrap();
|
||||
CFRunLoopAddObserver(&main_loop, Some(&main_end_observer), kCFRunLoopDefaultMode);
|
||||
main_loop.add_observer(Some(&main_end_observer), kCFRunLoopDefaultMode);
|
||||
|
||||
let end_observer = CFRunLoopObserverCreate(
|
||||
let end_observer = CFRunLoopObserver::new(
|
||||
None,
|
||||
(CFRunLoopActivity::Exit | CFRunLoopActivity::BeforeWaiting).0,
|
||||
true,
|
||||
|
|
@ -368,6 +351,6 @@ fn setup_control_flow_observers() {
|
|||
ptr::null_mut(),
|
||||
)
|
||||
.unwrap();
|
||||
CFRunLoopAddObserver(&main_loop, Some(&end_observer), kCFRunLoopDefaultMode);
|
||||
main_loop.add_observer(Some(&end_observer), kCFRunLoopDefaultMode);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue