Skip to content

Commit

Permalink
Update to objc2 v0.6 (#4092)
Browse files Browse the repository at this point in the history
* Use available! macro
* Use objc2-core-foundation and objc2-core-graphics
* Use MainThreadBound instead of StaticMainThreadBound hack
  • Loading branch information
madsmtm authored Jan 28, 2025
1 parent f5dcd2a commit 953d9b4
Show file tree
Hide file tree
Showing 25 changed files with 787 additions and 1,103 deletions.
60 changes: 49 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,15 @@ ndk = { version = "0.9.0", features = ["rwh_06"], default-features = false }

# AppKit or UIKit
[target.'cfg(target_vendor = "apple")'.dependencies]
block2 = "0.5.1"
core-foundation = "0.9.3"
objc2 = "0.5.2"
block2 = "0.6.0"
dispatch2 = { version = "0.2.0", default-features = false, features = ["std", "objc2"] }
objc2 = "0.6.0"

# AppKit
[target.'cfg(target_os = "macos")'.dependencies]
core-graphics = "0.23.1"
objc2-app-kit = { version = "0.2.2", features = [
objc2-app-kit = { version = "0.3.0", default-features = false, features = [
"std",
"objc2-core-foundation",
"NSAppearance",
"NSApplication",
"NSBitmapImageRep",
Expand Down Expand Up @@ -141,9 +142,37 @@ objc2-app-kit = { version = "0.2.2", features = [
"NSWindowScripting",
"NSWindowTabGroup",
] }
objc2-foundation = { version = "0.2.2", features = [
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",
"dispatch",
"objc2-core-foundation",
"NSArray",
"NSAttributedString",
"NSData",
Expand All @@ -165,20 +194,29 @@ objc2-foundation = { version = "0.2.2", features = [

# UIKit
[target.'cfg(all(target_vendor = "apple", not(target_os = "macos")))'.dependencies]
objc2-foundation = { version = "0.2.2", features = [
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",
"dispatch",
"objc2-core-foundation",
"NSArray",
"NSEnumerator",
"NSGeometry",
"NSObjCRuntime",
"NSOperation",
"NSString",
"NSProcessInfo",
"NSThread",
"NSSet",
] }
objc2-ui-kit = { version = "0.2.2", features = [
objc2-ui-kit = { version = "0.3.0", default-features = false, features = [
"std",
"objc2-core-foundation",
"UIApplication",
"UIDevice",
"UIEvent",
Expand Down
1 change: 1 addition & 0 deletions src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ changelog entry.
The `WindowEvent::DragMoved` event is entirely new, and is emitted whenever the pointer moves
whilst files are being dragged over the window. It doesn't contain any file paths, just the
pointer position.
- Updated `objc2` to `v0.6`.

### Removed

Expand Down
2 changes: 1 addition & 1 deletion src/platform/ios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ impl MonitorHandleExtIOS for MonitorHandle {
#[inline]
fn ui_screen(&self) -> *mut c_void {
// SAFETY: The marker is only used to get the pointer of the screen
let mtm = unsafe { objc2_foundation::MainThreadMarker::new_unchecked() };
let mtm = unsafe { objc2::MainThreadMarker::new_unchecked() };
objc2::rc::Retained::as_ptr(self.inner.ui_screen(mtm)) as *mut c_void
}

Expand Down
23 changes: 9 additions & 14 deletions src/platform/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,21 @@
#![cfg_attr(not(target_os = "macos"), doc = "```ignore")]
//! use objc2::rc::Retained;
//! use objc2::runtime::ProtocolObject;
//! use objc2::{declare_class, msg_send_id, mutability, ClassType, DeclaredClass};
//! use objc2::{define_class, msg_send, DefinedClass, MainThreadMarker, MainThreadOnly};
//! use objc2_app_kit::{NSApplication, NSApplicationDelegate};
//! use objc2_foundation::{NSArray, NSURL, MainThreadMarker, NSObject, NSObjectProtocol};
//! use objc2_foundation::{NSArray, NSURL, NSObject, NSObjectProtocol};
//! use winit::event_loop::EventLoop;
//!
//! declare_class!(
//! define_class!(
//! #[unsafe(super(NSObject))]
//! #[thread_kind = MainThreadOnly]
//! #[name = "AppDelegate"]
//! struct AppDelegate;
//!
//! unsafe impl ClassType for AppDelegate {
//! type Super = NSObject;
//! type Mutability = mutability::MainThreadOnly;
//! const NAME: &'static str = "MyAppDelegate";
//! }
//!
//! impl DeclaredClass for AppDelegate {}
//!
//! unsafe impl NSObjectProtocol for AppDelegate {}
//!
//! unsafe impl NSApplicationDelegate for AppDelegate {
//! #[method(application:openURLs:)]
//! #[unsafe(method(application:openURLs:))]
//! fn application_openURLs(&self, application: &NSApplication, urls: &NSArray<NSURL>) {
//! // Note: To specifically get `application:openURLs:` to work, you _might_
//! // have to bundle your application. This is not done in this example.
Expand All @@ -51,7 +46,7 @@
//!
//! impl AppDelegate {
//! fn new(mtm: MainThreadMarker) -> Retained<Self> {
//! unsafe { msg_send_id![super(mtm.alloc().set_ivars(())), init] }
//! unsafe { msg_send![super(Self::alloc(mtm).set_ivars(())), init] }
//! }
//! }
//!
Expand Down Expand Up @@ -518,7 +513,7 @@ impl MonitorHandleExtMacOS for MonitorHandle {

fn ns_screen(&self) -> Option<*mut c_void> {
// SAFETY: We only use the marker to get a pointer
let mtm = unsafe { objc2_foundation::MainThreadMarker::new_unchecked() };
let mtm = unsafe { objc2::MainThreadMarker::new_unchecked() };
self.inner.ns_screen(mtm).map(|s| objc2::rc::Retained::as_ptr(&s) as _)
}
}
Expand Down
23 changes: 8 additions & 15 deletions src/platform_impl/apple/appkit/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,31 @@

use std::rc::Rc;

use objc2::{declare_class, msg_send, mutability, ClassType, DeclaredClass};
use objc2::{define_class, msg_send, MainThreadMarker};
use objc2_app_kit::{NSApplication, NSEvent, NSEventModifierFlags, NSEventType, NSResponder};
use objc2_foundation::{MainThreadMarker, NSObject};
use objc2_foundation::NSObject;

use super::app_state::AppState;
use crate::event::{DeviceEvent, ElementState};

declare_class!(
define_class!(
#[unsafe(super(NSApplication, NSResponder, NSObject))]
#[name = "WinitApplication"]
pub(super) struct WinitApplication;

unsafe impl ClassType for WinitApplication {
#[inherits(NSResponder, NSObject)]
type Super = NSApplication;
type Mutability = mutability::MainThreadOnly;
const NAME: &'static str = "WinitApplication";
}

impl DeclaredClass for WinitApplication {}

unsafe impl WinitApplication {
impl WinitApplication {
// Normally, holding Cmd + any key never sends us a `keyUp` event for that key.
// Overriding `sendEvent:` like this fixes that. (https://stackoverflow.com/a/15294196)
// Fun fact: Firefox still has this bug! (https://bugzilla.mozilla.org/show_bug.cgi?id=1299553)
#[method(sendEvent:)]
#[unsafe(method(sendEvent:))]
fn send_event(&self, event: &NSEvent) {
// For posterity, there are some undocumented event types
// (https://github.com/servo/cocoa-rs/issues/155)
// but that doesn't really matter here.
let event_type = unsafe { event.r#type() };
let modifier_flags = unsafe { event.modifierFlags() };
if event_type == NSEventType::KeyUp
&& modifier_flags.contains(NSEventModifierFlags::NSEventModifierFlagCommand)
&& modifier_flags.contains(NSEventModifierFlags::Command)
{
if let Some(key_window) = self.keyWindow() {
key_window.sendEvent(event);
Expand Down
22 changes: 6 additions & 16 deletions src/platform_impl/apple/appkit/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ use std::sync::atomic::Ordering as AtomicOrdering;
use std::sync::Arc;
use std::time::Instant;

use dispatch2::MainThreadBound;
use objc2::MainThreadMarker;
use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy, NSRunningApplication};
use objc2_foundation::{MainThreadMarker, NSNotification};
use objc2_foundation::NSNotification;

use super::super::event_handler::EventHandler;
use super::event_loop::{stop_app_immediately, ActiveEventLoop, EventLoopProxy, PanicInfo};
Expand Down Expand Up @@ -45,22 +47,10 @@ pub(super) struct AppState {
// as such should be careful to not add fields that, in turn, strongly reference those.
}

// TODO(madsmtm): Use `MainThreadBound` once that is possible in `static`s.
struct StaticMainThreadBound<T>(T);

impl<T> StaticMainThreadBound<T> {
const fn get(&self, _mtm: MainThreadMarker) -> &T {
&self.0
}
}

unsafe impl<T> Send for StaticMainThreadBound<T> {}
unsafe impl<T> Sync for StaticMainThreadBound<T> {}

// SAFETY: Creating `StaticMainThreadBound` in a `const` context, where there is no concept of the
// SAFETY: Creating `MainThreadBound` in a `const` context, where there is no concept of the
// main thread.
static GLOBAL: StaticMainThreadBound<OnceCell<Rc<AppState>>> =
StaticMainThreadBound(OnceCell::new());
static GLOBAL: MainThreadBound<OnceCell<Rc<AppState>>> =
MainThreadBound::new(OnceCell::new(), unsafe { MainThreadMarker::new_unchecked() });

impl AppState {
pub(super) fn setup_global(
Expand Down
30 changes: 14 additions & 16 deletions src/platform_impl/apple/appkit/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ use std::sync::OnceLock;

use objc2::rc::Retained;
use objc2::runtime::Sel;
use objc2::{msg_send, msg_send_id, sel, ClassType};
use objc2::{available, msg_send, sel, AllocAnyThread, ClassType};
use objc2_app_kit::{NSBitmapImageRep, NSCursor, NSDeviceRGBColorSpace, NSImage};
use objc2_foundation::{
ns_string, NSData, NSDictionary, NSNumber, NSObject, NSObjectProtocol, NSPoint, NSSize,
NSString,
ns_string, NSData, NSDictionary, NSNumber, NSObject, NSPoint, NSSize, NSString,
};

use crate::cursor::{CursorImage, OnlyCursorImageSource};
Expand Down Expand Up @@ -67,8 +66,8 @@ pub(crate) fn default_cursor() -> Retained<NSCursor> {

unsafe fn try_cursor_from_selector(sel: Sel) -> Option<Retained<NSCursor>> {
let cls = NSCursor::class();
if msg_send![cls, respondsToSelector: sel] {
let cursor: Retained<NSCursor> = unsafe { msg_send_id![cls, performSelector: sel] };
if unsafe { msg_send![cls, respondsToSelector: sel] } {
let cursor: Retained<NSCursor> = unsafe { msg_send![cls, performSelector: sel] };
Some(cursor)
} else {
tracing::warn!("cursor `{sel}` appears to be invalid");
Expand Down Expand Up @@ -130,25 +129,21 @@ unsafe fn load_webkit_cursor(name: &NSString) -> Retained<NSCursor> {
// TODO: Handle PLists better
let info_path = cursor_path.stringByAppendingPathComponent(ns_string!("info.plist"));
let info: Retained<NSDictionary<NSObject, NSObject>> = unsafe {
msg_send_id![
msg_send![
<NSDictionary<NSObject, NSObject>>::class(),
dictionaryWithContentsOfFile: &*info_path,
]
};
let mut x = 0.0;
if let Some(n) = info.get(&*ns_string!("hotx")) {
if n.is_kind_of::<NSNumber>() {
let ptr: *const NSObject = n;
let ptr: *const NSNumber = ptr.cast();
x = unsafe { &*ptr }.as_cgfloat()
if let Some(n) = info.objectForKey(ns_string!("hotx")) {
if let Ok(n) = n.downcast::<NSNumber>() {
x = n.as_cgfloat();
}
}
let mut y = 0.0;
if let Some(n) = info.get(&*ns_string!("hotx")) {
if n.is_kind_of::<NSNumber>() {
let ptr: *const NSObject = n;
let ptr: *const NSNumber = ptr.cast();
y = unsafe { &*ptr }.as_cgfloat()
if let Some(n) = info.objectForKey(ns_string!("hoty")) {
if let Ok(n) = n.downcast::<NSNumber>() {
y = n.as_cgfloat();
}
}

Expand Down Expand Up @@ -188,6 +183,7 @@ pub(crate) fn invisible_cursor() -> Retained<NSCursor> {
CURSOR.get_or_init(|| CustomCursor(new_invisible())).0.clone()
}

#[allow(deprecated)]
pub(crate) fn cursor_from_icon(icon: CursorIcon) -> Retained<NSCursor> {
match icon {
CursorIcon::Default => default_cursor(),
Expand All @@ -208,7 +204,9 @@ pub(crate) fn cursor_from_icon(icon: CursorIcon) -> Retained<NSCursor> {
CursorIcon::EwResize | CursorIcon::ColResize => NSCursor::resizeLeftRightCursor(),
CursorIcon::NsResize | CursorIcon::RowResize => NSCursor::resizeUpDownCursor(),
CursorIcon::Help => _helpCursor(),
CursorIcon::ZoomIn if available!(macos = 15.0) => unsafe { NSCursor::zoomInCursor() },
CursorIcon::ZoomIn => _zoomInCursor(),
CursorIcon::ZoomOut if available!(macos = 15.0) => unsafe { NSCursor::zoomOutCursor() },
CursorIcon::ZoomOut => _zoomOutCursor(),
CursorIcon::NeResize => _windowResizeNorthEastCursor(),
CursorIcon::NwResize => _windowResizeNorthWestCursor(),
Expand Down
Loading

0 comments on commit 953d9b4

Please sign in to comment.