Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial transition to objc2 #2452

Merged
merged 4 commits into from
Sep 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre

# Unreleased

- macOS/iOS: Use `objc2` instead of `objc` internally.
- **Breaking:** Bump MSRV from `1.57` to `1.60`.
- **Breaking:** Split the `platform::unix` module into `platform::x11` and `platform::wayland`. The extension types are similarly renamed.
- **Breaking:**: Removed deprecated method `platform::unix::WindowExtUnix::is_ready`.
Expand Down
10 changes: 6 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,14 @@ ndk = "0.7.0"
ndk-glue = "0.7.0"

[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
objc = "0.2.7"
objc = { version = "=0.3.0-beta.3", package = "objc2" }

[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.24"
core-foundation = "0.9"
core-graphics = "0.22"
# Branch: objc2
# TODO: Use non-git versions before we release
cocoa = { git = "https://github.com/madsmtm/core-foundation-rs.git", rev = "c770e620ba0766fc1d2a9f83327b0fee905eb5cb" }
core-foundation = { git = "https://github.com/madsmtm/core-foundation-rs.git", rev = "c770e620ba0766fc1d2a9f83327b0fee905eb5cb" }
core-graphics = { git = "https://github.com/madsmtm/core-foundation-rs.git", rev = "c770e620ba0766fc1d2a9f83327b0fee905eb5cb" }
dispatch = "0.2.0"

[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
Expand Down
33 changes: 14 additions & 19 deletions src/platform_impl/ios/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use std::{
time::Instant,
};

use objc::runtime::{BOOL, YES};
use objc::foundation::{NSInteger, NSUInteger};
use objc::runtime::Object;
use once_cell::sync::Lazy;

use crate::{
Expand All @@ -21,8 +22,8 @@ use crate::{
ffi::{
id, kCFRunLoopCommonModes, CFAbsoluteTimeGetCurrent, CFRelease, CFRunLoopAddTimer,
CFRunLoopGetMain, CFRunLoopRef, CFRunLoopTimerCreate, CFRunLoopTimerInvalidate,
CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate, CGRect, CGSize, NSInteger,
NSOperatingSystemVersion, NSUInteger,
CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate, CGRect, CGSize,
NSOperatingSystemVersion,
},
},
window::WindowId as RootWindowId,
Expand Down Expand Up @@ -472,10 +473,7 @@ impl AppState {
// retains window
pub unsafe fn set_key_window(window: id) {
bug_assert!(
{
let is_window: BOOL = msg_send![window, isKindOfClass: class!(UIWindow)];
is_window == YES
},
msg_send![window, isKindOfClass: class!(UIWindow)],
"set_key_window called with an incorrect type"
);
let mut this = AppState::get_mut();
Expand All @@ -502,10 +500,7 @@ pub unsafe fn set_key_window(window: id) {
// retains window
pub unsafe fn queue_gl_or_metal_redraw(window: id) {
bug_assert!(
{
let is_window: BOOL = msg_send![window, isKindOfClass: class!(UIWindow)];
is_window == YES
},
msg_send![window, isKindOfClass: class!(UIWindow)],
"set_key_window called with an incorrect type"
);
let mut this = AppState::get_mut();
Expand Down Expand Up @@ -582,7 +577,7 @@ pub unsafe fn did_finish_launching() {
let _: () = msg_send![window, setScreen: screen];
let _: () = msg_send![screen, release];
let controller: id = msg_send![window, rootViewController];
let _: () = msg_send![window, setRootViewController:ptr::null::<()>()];
let _: () = msg_send![window, setRootViewController:ptr::null::<Object>()];
let _: () = msg_send![window, setRootViewController: controller];
let _: () = msg_send![window, makeKeyAndVisible];
}
Expand Down Expand Up @@ -886,8 +881,11 @@ fn get_view_and_screen_frame(window_id: id) -> (id, CGRect) {
let bounds: CGRect = msg_send![window_id, bounds];
let screen: id = msg_send![window_id, screen];
let screen_space: id = msg_send![screen, coordinateSpace];
let screen_frame: CGRect =
msg_send![window_id, convertRect:bounds toCoordinateSpace:screen_space];
let screen_frame: CGRect = msg_send![
window_id,
convertRect: bounds,
toCoordinateSpace: screen_space,
];
(view, screen_frame)
}
}
Expand Down Expand Up @@ -1019,7 +1017,7 @@ pub fn os_capabilities() -> OSCapabilities {
static OS_CAPABILITIES: Lazy<OSCapabilities> = Lazy::new(|| {
let version: NSOperatingSystemVersion = unsafe {
let process_info: id = msg_send![class!(NSProcessInfo), processInfo];
let atleast_ios_8: BOOL = msg_send![
let atleast_ios_8: bool = msg_send![
process_info,
respondsToSelector: sel!(operatingSystemVersion)
];
Expand All @@ -1030,10 +1028,7 @@ pub fn os_capabilities() -> OSCapabilities {
// has been tested to not even run on macOS 10.15 - Xcode 8 might?
//
// The minimum required iOS version is likely to grow in the future.
assert!(
atleast_ios_8 == YES,
"`winit` requires iOS version 8 or greater"
);
assert!(atleast_ios_8, "`winit` requires iOS version 8 or greater");
msg_send![process_info, operatingSystemVersion]
};
version.into()
Expand Down
3 changes: 2 additions & 1 deletion src/platform_impl/ios/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@ pub(crate) struct PlatformSpecificEventLoopAttributes {}

impl<T: 'static> EventLoop<T> {
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> EventLoop<T> {
assert_main_thread!("`EventLoop` can only be created on the main thread on iOS");

static mut SINGLETON_INIT: bool = false;
unsafe {
assert_main_thread!("`EventLoop` can only be created on the main thread on iOS");
assert!(
!SINGLETON_INIT,
"Only one `EventLoop` is supported on iOS. \
Expand Down
76 changes: 50 additions & 26 deletions src/platform_impl/ios/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::{convert::TryInto, ffi::CString, ops::BitOr, os::raw::*};

use objc::foundation::{NSInteger, NSUInteger};
use objc::{runtime::Object, Encode, Encoding};

use crate::{
Expand All @@ -17,9 +18,6 @@ pub type CGFloat = f32;
#[cfg(target_pointer_width = "64")]
pub type CGFloat = f64;

pub type NSInteger = isize;
pub type NSUInteger = usize;

#[repr(C)]
#[derive(Clone, Debug)]
pub struct NSOperatingSystemVersion {
Expand All @@ -28,13 +26,28 @@ pub struct NSOperatingSystemVersion {
pub patch: NSInteger,
}

unsafe impl Encode for NSOperatingSystemVersion {
const ENCODING: Encoding = Encoding::Struct(
"NSOperatingSystemVersion",
&[
NSInteger::ENCODING,
NSInteger::ENCODING,
NSInteger::ENCODING,
],
);
}

#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CGPoint {
pub x: CGFloat,
pub y: CGFloat,
}

unsafe impl Encode for CGPoint {
const ENCODING: Encoding = Encoding::Struct("CGPoint", &[CGFloat::ENCODING, CGFloat::ENCODING]);
}

#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CGSize {
Expand All @@ -51,6 +64,10 @@ impl CGSize {
}
}

unsafe impl Encode for CGSize {
const ENCODING: Encoding = Encoding::Struct("CGSize", &[CGFloat::ENCODING, CGFloat::ENCODING]);
}

#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CGRect {
Expand All @@ -65,18 +82,9 @@ impl CGRect {
}

unsafe impl Encode for CGRect {
fn encode() -> Encoding {
unsafe {
if cfg!(target_pointer_width = "32") {
Encoding::from_str("{CGRect={CGPoint=ff}{CGSize=ff}}")
} else if cfg!(target_pointer_width = "64") {
Encoding::from_str("{CGRect={CGPoint=dd}{CGSize=dd}}")
} else {
unimplemented!()
}
}
}
const ENCODING: Encoding = Encoding::Struct("CGRect", &[CGPoint::ENCODING, CGSize::ENCODING]);
}

#[derive(Debug)]
#[allow(dead_code)]
#[repr(isize)]
Expand All @@ -88,6 +96,10 @@ pub enum UITouchPhase {
Cancelled,
}

unsafe impl Encode for UITouchPhase {
const ENCODING: Encoding = NSInteger::ENCODING;
}

#[derive(Debug, PartialEq, Eq)]
#[allow(dead_code)]
#[repr(isize)]
Expand All @@ -97,6 +109,10 @@ pub enum UIForceTouchCapability {
Available,
}

unsafe impl Encode for UIForceTouchCapability {
const ENCODING: Encoding = NSInteger::ENCODING;
}

#[derive(Debug, PartialEq, Eq)]
#[allow(dead_code)]
#[repr(isize)]
Expand All @@ -106,6 +122,10 @@ pub enum UITouchType {
Pencil,
}

unsafe impl Encode for UITouchType {
const ENCODING: Encoding = NSInteger::ENCODING;
}

#[repr(C)]
#[derive(Debug, Clone)]
pub struct UIEdgeInsets {
Expand All @@ -115,14 +135,24 @@ pub struct UIEdgeInsets {
pub right: CGFloat,
}

unsafe impl Encode for UIEdgeInsets {
const ENCODING: Encoding = Encoding::Struct(
"UIEdgeInsets",
&[
CGFloat::ENCODING,
CGFloat::ENCODING,
CGFloat::ENCODING,
CGFloat::ENCODING,
],
);
}

#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct UIUserInterfaceIdiom(NSInteger);

unsafe impl Encode for UIUserInterfaceIdiom {
fn encode() -> Encoding {
NSInteger::encode()
}
const ENCODING: Encoding = NSInteger::ENCODING;
}

impl UIUserInterfaceIdiom {
Expand Down Expand Up @@ -162,9 +192,7 @@ impl From<UIUserInterfaceIdiom> for Idiom {
pub struct UIInterfaceOrientationMask(NSUInteger);

unsafe impl Encode for UIInterfaceOrientationMask {
fn encode() -> Encoding {
NSUInteger::encode()
}
const ENCODING: Encoding = NSUInteger::ENCODING;
}

impl UIInterfaceOrientationMask {
Expand Down Expand Up @@ -213,9 +241,7 @@ impl UIInterfaceOrientationMask {
pub struct UIRectEdge(NSUInteger);

unsafe impl Encode for UIRectEdge {
fn encode() -> Encoding {
NSUInteger::encode()
}
const ENCODING: Encoding = NSUInteger::ENCODING;
}

impl From<ScreenEdge> for UIRectEdge {
Expand All @@ -241,9 +267,7 @@ impl From<UIRectEdge> for ScreenEdge {
pub struct UIScreenOverscanCompensation(NSInteger);

unsafe impl Encode for UIScreenOverscanCompensation {
fn encode() -> Encoding {
NSInteger::encode()
}
const ENCODING: Encoding = NSInteger::ENCODING;
}

#[allow(dead_code)]
Expand Down
3 changes: 1 addition & 2 deletions src/platform_impl/ios/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@
// window size/position.
macro_rules! assert_main_thread {
($($t:tt)*) => {
let is_main_thread: ::objc::runtime::BOOL = msg_send!(class!(NSThread), isMainThread);
if is_main_thread == ::objc::runtime::NO {
if !::objc::foundation::is_main_thread() {
panic!($($t)*);
}
};
Expand Down
22 changes: 7 additions & 15 deletions src/platform_impl/ios/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ use std::{
ops::{Deref, DerefMut},
};

use objc::foundation::{NSInteger, NSUInteger};

use crate::{
dpi::{PhysicalPosition, PhysicalSize},
monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode},
platform_impl::platform::{
app_state,
ffi::{id, nil, CGFloat, CGRect, CGSize, NSInteger, NSUInteger},
ffi::{id, nil, CGFloat, CGRect, CGSize},
},
};

Expand Down Expand Up @@ -113,22 +115,14 @@ impl Deref for MonitorHandle {
type Target = Inner;

fn deref(&self) -> &Inner {
unsafe {
assert_main_thread!(
"`MonitorHandle` methods can only be run on the main thread on iOS"
);
}
assert_main_thread!("`MonitorHandle` methods can only be run on the main thread on iOS");
&self.inner
}
}

impl DerefMut for MonitorHandle {
fn deref_mut(&mut self) -> &mut Inner {
unsafe {
assert_main_thread!(
"`MonitorHandle` methods can only be run on the main thread on iOS"
);
}
assert_main_thread!("`MonitorHandle` methods can only be run on the main thread on iOS");
&mut self.inner
}
}
Expand All @@ -144,9 +138,7 @@ impl Clone for MonitorHandle {

impl Drop for MonitorHandle {
fn drop(&mut self) {
unsafe {
assert_main_thread!("`MonitorHandle` can only be dropped on the main thread on iOS");
}
assert_main_thread!("`MonitorHandle` can only be dropped on the main thread on iOS");
}
}

Expand Down Expand Up @@ -175,8 +167,8 @@ impl fmt::Debug for MonitorHandle {

impl MonitorHandle {
pub fn retained_new(uiscreen: id) -> MonitorHandle {
assert_main_thread!("`MonitorHandle` can only be cloned on the main thread on iOS");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has nothing to do with that PR, but could libdispatch used to drop from the main thread? So we won't have runtime panics like that? Though I think the issue that you can't use that from the other thread as well?

It just all looks wrong to me. We say that winit window is Send and you can get MonitorHandle from the Window(owning one iirc), but when you drop it you'll panic?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is so much thread-unsafety in our macOS (and probably also iOS, but less well-versed in that) implementation, really, you have no idea!

Anyway, to answer your question: Yes, we could and should use libdispatch to do things on the main thread, both here and in a lot of other places. I'm in the process of exploring solutions, have focused on objc2 stuff first though.

unsafe {
assert_main_thread!("`MonitorHandle` can only be cloned on the main thread on iOS");
let _: id = msg_send![uiscreen, retain];
}
MonitorHandle {
Expand Down