Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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