Move AppKit (macOS) backend to winit-appkit (#4248)

This commit is contained in:
Mads Marquart 2025-05-25 17:37:40 +02:00 committed by GitHub
parent 256bbe949e
commit 5f2c7350e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 232 additions and 203 deletions

3
.github/CODEOWNERS vendored
View file

@ -2,9 +2,8 @@
/winit-android @MarijnS95
# Apple (AppKit + UIKit)
/winit-appkit @madsmtm
/winit-uikit @madsmtm
/src/platform/macos.rs @madsmtm
/src/platform_impl/apple @madsmtm
/winit-common/src/core_foundation @madsmtm
/winit-common/src/event_handler.rs @madsmtm

View file

@ -197,6 +197,10 @@ jobs:
if: contains(matrix.platform.target, 'linux-gnu')
run: cargo $CMD test -p winit-common --features xkb,x11,wayland --no-run
- name: Test winit AppKit
if: contains(matrix.platform.target, 'macos')
run: cargo $CMD test -p winit-appkit --target=${{ matrix.platform.target }}
- name: Test winit Orbital
if: contains(matrix.platform.target, 'redox')
run: cargo test -p winit-orbital

View file

@ -13,6 +13,7 @@ rust-version = "1.80"
# `winit` has no version here to allow using it in dev deps for docs.
winit = { path = "." }
winit-android = { version = "0.0.0", path = "winit-android" }
winit-appkit = { version = "0.0.0", path = "winit-appkit" }
winit-common = { version = "0.0.0", path = "winit-common" }
winit-core = { version = "0.0.0", path = "winit-core" }
winit-orbital = { version = "0.0.0", path = "winit-orbital" }
@ -200,96 +201,8 @@ softbuffer.workspace = true
[target.'cfg(target_os = "android")'.dependencies]
winit-android.workspace = true
# AppKit or UIKit
[target.'cfg(target_vendor = "apple")'.dependencies]
block2.workspace = true
dispatch2.workspace = true
objc2.workspace = true
winit-common = { workspace = true, features = ["core-foundation", "event-handler"] }
# AppKit
[target.'cfg(target_os = "macos")'.dependencies]
objc2-app-kit = { workspace = true, features = [
"std",
"objc2-core-foundation",
"NSAppearance",
"NSApplication",
"NSBitmapImageRep",
"NSButton",
"NSColor",
"NSControl",
"NSCursor",
"NSDragging",
"NSEvent",
"NSGraphics",
"NSGraphicsContext",
"NSImage",
"NSImageRep",
"NSMenu",
"NSMenuItem",
"NSOpenGLView",
"NSPanel",
"NSPasteboard",
"NSResponder",
"NSRunningApplication",
"NSScreen",
"NSTextInputClient",
"NSTextInputContext",
"NSToolbar",
"NSView",
"NSWindow",
"NSWindowScripting",
"NSWindowTabGroup",
] }
objc2-core-foundation = { workspace = true, features = [
"std",
"block2",
"CFBase",
"CFCGTypes",
"CFData",
"CFRunLoop",
"CFString",
"CFUUID",
] }
objc2-core-graphics = { workspace = true, features = [
"std",
"libc",
"CGDirectDisplay",
"CGDisplayConfiguration",
"CGDisplayFade",
"CGError",
"CGRemoteOperation",
"CGWindowLevel",
] }
objc2-core-video = { workspace = true, features = [
"std",
"objc2-core-graphics",
"CVBase",
"CVReturn",
"CVDisplayLink",
] }
objc2-foundation = { workspace = true, features = [
"std",
"block2",
"objc2-core-foundation",
"NSArray",
"NSAttributedString",
"NSData",
"NSDictionary",
"NSDistributedNotificationCenter",
"NSEnumerator",
"NSGeometry",
"NSKeyValueObserving",
"NSNotification",
"NSObjCRuntime",
"NSOperation",
"NSPathUtilities",
"NSProcessInfo",
"NSRunLoop",
"NSString",
"NSThread",
"NSValue",
] }
winit-appkit.workspace = true
[target.'cfg(all(target_vendor = "apple", not(target_os = "macos")))'.dependencies]
winit-uikit.workspace = true

View file

@ -348,6 +348,30 @@ impl winit_android::EventLoopBuilderExtAndroid for EventLoopBuilder {
}
}
#[cfg(macos_platform)]
impl winit_appkit::EventLoopBuilderExtMacOS for EventLoopBuilder {
#[inline]
fn with_activation_policy(
&mut self,
activation_policy: winit_appkit::ActivationPolicy,
) -> &mut Self {
self.platform_specific.activation_policy = Some(activation_policy);
self
}
#[inline]
fn with_default_menu(&mut self, enable: bool) -> &mut Self {
self.platform_specific.default_menu = enable;
self
}
#[inline]
fn with_activate_ignoring_other_apps(&mut self, ignore: bool) -> &mut Self {
self.platform_specific.activate_ignoring_other_apps = ignore;
self
}
}
#[cfg(wayland_platform)]
impl winit_wayland::EventLoopExtWayland for EventLoop {
#[inline]

View file

@ -4,12 +4,12 @@
#[cfg(android_platform)]
pub use winit_android as android;
#[cfg(ios_platform)]
pub use winit_uikit as ios;
#[cfg(macos_platform)]
pub mod macos;
pub use winit_appkit as macos;
#[cfg(orbital_platform)]
pub use winit_orbital as orbital;
#[cfg(ios_platform)]
pub use winit_uikit as ios;
#[cfg(any(x11_platform, wayland_platform))]
pub mod startup_notify;
#[cfg(wayland_platform)]

View file

@ -1,23 +0,0 @@
#[macro_use]
mod util;
mod app;
mod app_state;
mod cursor;
mod event;
mod event_loop;
mod ffi;
mod menu;
mod monitor;
mod notification_center;
mod observer;
mod view;
mod window;
mod window_delegate;
pub(crate) use self::event::{physicalkey_to_scancode, scancode_to_physicalkey};
pub(crate) use self::event_loop::{
ActiveEventLoop, EventLoop, PlatformSpecificEventLoopAttributes,
};
pub(crate) use self::monitor::MonitorHandle;
pub(crate) use self::window::Window;

View file

@ -1,6 +0,0 @@
#[cfg(target_os = "macos")]
mod appkit;
#[allow(unused_imports)]
#[cfg(target_os = "macos")]
pub use self::appkit::*;

View file

@ -1,7 +1,7 @@
#[cfg(android_platform)]
pub(crate) use winit_android as platform;
#[cfg(macos_platform)]
mod apple;
pub(crate) use winit_appkit as platform;
#[cfg(any(x11_platform, wayland_platform))]
mod linux;
#[cfg(orbital_platform)]
@ -13,8 +13,6 @@ mod web;
#[cfg(windows_platform)]
pub(crate) use winit_win32 as platform;
#[cfg(macos_platform)]
use self::apple as platform;
#[cfg(any(x11_platform, wayland_platform))]
use self::linux as platform;
#[allow(unused_imports)]

116
winit-appkit/Cargo.toml Normal file
View file

@ -0,0 +1,116 @@
[package]
description = "Winit's Appkit / macOS backend"
documentation = "https://docs.rs/winit-appkit"
edition.workspace = true
license.workspace = true
name = "winit-appkit"
repository.workspace = true
rust-version.workspace = true
version = "0.0.0"
[features]
serde = ["dep:serde", "bitflags/serde", "smol_str/serde", "dpi/serde"]
[dependencies]
bitflags.workspace = true
dpi.workspace = true
rwh_06.workspace = true
serde = { workspace = true, optional = true }
smol_str.workspace = true
tracing.workspace = true
winit-common = { workspace = true, features = ["core-foundation", "event-handler"] }
winit-core.workspace = true
# Platform-specific
[target.'cfg(target_vendor = "apple")'.dependencies]
block2.workspace = true
dispatch2 = { workspace = true, features = ["std", "objc2"] }
objc2.workspace = true
objc2-app-kit = { workspace = true, features = [
"std",
"objc2-core-foundation",
"NSAppearance",
"NSApplication",
"NSBitmapImageRep",
"NSButton",
"NSColor",
"NSControl",
"NSCursor",
"NSDragging",
"NSEvent",
"NSGraphics",
"NSGraphicsContext",
"NSImage",
"NSImageRep",
"NSMenu",
"NSMenuItem",
"NSOpenGLView",
"NSPanel",
"NSPasteboard",
"NSResponder",
"NSRunningApplication",
"NSScreen",
"NSTextInputClient",
"NSTextInputContext",
"NSToolbar",
"NSView",
"NSWindow",
"NSWindowScripting",
"NSWindowTabGroup",
] }
objc2-core-foundation = { workspace = true, features = [
"std",
"block2",
"CFBase",
"CFCGTypes",
"CFData",
"CFRunLoop",
"CFString",
"CFUUID",
] }
objc2-core-graphics = { workspace = true, features = [
"std",
"libc",
"CGDirectDisplay",
"CGDisplayConfiguration",
"CGDisplayFade",
"CGError",
"CGRemoteOperation",
"CGWindowLevel",
] }
objc2-core-video = { workspace = true, features = [
"std",
"objc2-core-graphics",
"CVBase",
"CVReturn",
"CVDisplayLink",
] }
objc2-foundation = { workspace = true, features = [
"std",
"block2",
"objc2-core-foundation",
"NSArray",
"NSAttributedString",
"NSData",
"NSDictionary",
"NSDistributedNotificationCenter",
"NSEnumerator",
"NSGeometry",
"NSKeyValueObserving",
"NSNotification",
"NSObjCRuntime",
"NSOperation",
"NSPathUtilities",
"NSProcessInfo",
"NSRunLoop",
"NSString",
"NSThread",
"NSValue",
] }
[dev-dependencies]
winit.workspace = true
[package.metadata.docs.rs]
all-features = true
targets = ["aarch64-apple-darwin", "x86_64-apple-darwin"]

1
winit-appkit/README.md Symbolic link
View file

@ -0,0 +1 @@
../README.md

View file

@ -349,7 +349,7 @@ pub(super) fn dummy_event() -> Option<Retained<NSEvent>> {
}
}
pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32> {
pub fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32> {
let code = match physical_key {
PhysicalKey::Code(code) => code,
PhysicalKey::Unidentified(_) => return None,
@ -481,7 +481,7 @@ pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32>
}
}
pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
pub fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
// Follows what Chromium and Firefox do:
// https://chromium.googlesource.com/chromium/src.git/+/3e1a26c44c024d97dc9a4c09bbc6a2365398ca2c/ui/events/keycodes/dom/dom_code_data.inc
// https://searchfox.org/mozilla-central/rev/c597e9c789ad36af84a0370d395be066b7dc94f4/widget/NativeKeyToDOMCodeName.h

View file

@ -29,8 +29,8 @@ use super::event::dummy_event;
use super::monitor;
use super::notification_center::create_observer;
use super::observer::setup_control_flow_observers;
use crate::platform::macos::ActivationPolicy;
use crate::platform_impl::Window;
use crate::window::Window;
use crate::ActivationPolicy;
#[derive(Debug)]
pub struct ActiveEventLoop {
@ -153,10 +153,10 @@ pub struct EventLoop {
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) struct PlatformSpecificEventLoopAttributes {
pub(crate) activation_policy: Option<ActivationPolicy>,
pub(crate) default_menu: bool,
pub(crate) activate_ignoring_other_apps: bool,
pub struct PlatformSpecificEventLoopAttributes {
pub activation_policy: Option<ActivationPolicy>,
pub default_menu: bool,
pub activate_ignoring_other_apps: bool,
}
impl Default for PlatformSpecificEventLoopAttributes {
@ -166,9 +166,7 @@ impl Default for PlatformSpecificEventLoopAttributes {
}
impl EventLoop {
pub(crate) fn new(
attributes: &PlatformSpecificEventLoopAttributes,
) -> Result<Self, EventLoopError> {
pub fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
let mtm = MainThreadMarker::new()
.expect("on macOS, `EventLoop` must be created on the main thread!");

View file

@ -17,13 +17,12 @@
//! Instead, Winit guarantees that it will not register an application delegate, so the solution is
//! to register your own application delegate, as outlined in the following example (see
//! `objc2-app-kit` for more detailed information).
#![cfg_attr(target_os = "macos", doc = "```")]
#![cfg_attr(not(target_os = "macos"), doc = "```ignore")]
//! ```
//! use objc2::rc::Retained;
//! use objc2::runtime::ProtocolObject;
//! use objc2::{define_class, msg_send, DefinedClass, MainThreadMarker, MainThreadOnly};
//! use objc2_app_kit::{NSApplication, NSApplicationDelegate};
//! use objc2_foundation::{NSArray, NSURL, NSObject, NSObjectProtocol};
//! use objc2_foundation::{NSArray, NSObject, NSObjectProtocol, NSURL};
//! use winit::event_loop::EventLoop;
//!
//! define_class!(
@ -64,6 +63,24 @@
//! Ok(())
//! }
//! ```
#![cfg(target_vendor = "apple")] // TODO: Remove once `objc2` allows compiling on all platforms
#[macro_use]
mod util;
mod app;
mod app_state;
mod cursor;
mod event;
mod event_loop;
mod ffi;
mod menu;
mod monitor;
mod notification_center;
mod observer;
mod view;
mod window;
mod window_delegate;
use std::os::raw::c_void;
@ -71,12 +88,15 @@ use std::os::raw::c_void;
use serde::{Deserialize, Serialize};
#[doc(inline)]
pub use winit_core::application::macos::ApplicationHandlerExtMacOS;
use winit_core::window::PlatformWindowAttributes;
use winit_core::event_loop::ActiveEventLoop;
use winit_core::monitor::MonitorHandle;
use winit_core::window::{PlatformWindowAttributes, Window};
use crate::event_loop::{ActiveEventLoop, EventLoopBuilder};
use crate::monitor::MonitorHandle;
use crate::platform_impl::MonitorHandle as MacOsMonitorHandle;
use crate::window::Window;
pub use self::event::{physicalkey_to_scancode, scancode_to_physicalkey};
use self::event_loop::ActiveEventLoop as AppKitActiveEventLoop;
pub use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes};
use self::monitor::MonitorHandle as AppKitMonitorHandle;
use self::window::Window as AppKitWindow;
/// Additional methods on [`Window`] that are specific to MacOS.
pub trait WindowExtMacOS {
@ -172,109 +192,109 @@ pub trait WindowExtMacOS {
impl WindowExtMacOS for dyn Window + '_ {
#[inline]
fn simple_fullscreen(&self) -> bool {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.simple_fullscreen())
}
#[inline]
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(move |w| w.set_simple_fullscreen(fullscreen))
}
#[inline]
fn has_shadow(&self) -> bool {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.has_shadow())
}
#[inline]
fn set_has_shadow(&self, has_shadow: bool) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(move |w| w.set_has_shadow(has_shadow));
}
#[inline]
fn set_tabbing_identifier(&self, identifier: &str) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.set_tabbing_identifier(identifier))
}
#[inline]
fn tabbing_identifier(&self) -> String {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.tabbing_identifier())
}
#[inline]
fn select_next_tab(&self) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.select_next_tab());
}
#[inline]
fn select_previous_tab(&self) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.select_previous_tab());
}
#[inline]
fn select_tab_at_index(&self, index: usize) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(move |w| w.select_tab_at_index(index));
}
#[inline]
fn num_tabs(&self) -> usize {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.num_tabs())
}
#[inline]
fn is_document_edited(&self) -> bool {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.is_document_edited())
}
#[inline]
fn set_document_edited(&self, edited: bool) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(move |w| w.set_document_edited(edited));
}
#[inline]
fn set_option_as_alt(&self, option_as_alt: OptionAsAlt) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(move |w| w.set_option_as_alt(option_as_alt));
}
#[inline]
fn option_as_alt(&self) -> OptionAsAlt {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.option_as_alt())
}
#[inline]
fn set_borderless_game(&self, borderless_game: bool) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.set_borderless_game(borderless_game))
}
#[inline]
fn is_borderless_game(&self) -> bool {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.is_borderless_game())
}
#[inline]
fn set_unified_titlebar(&self, unified_titlebar: bool) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.set_unified_titlebar(unified_titlebar))
}
#[inline]
fn unified_titlebar(&self) -> bool {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<AppKitWindow>().unwrap();
window.maybe_wait_on_main(|w| w.unified_titlebar())
}
}
@ -513,26 +533,6 @@ pub trait EventLoopBuilderExtMacOS {
fn with_activate_ignoring_other_apps(&mut self, ignore: bool) -> &mut Self;
}
impl EventLoopBuilderExtMacOS for EventLoopBuilder {
#[inline]
fn with_activation_policy(&mut self, activation_policy: ActivationPolicy) -> &mut Self {
self.platform_specific.activation_policy = Some(activation_policy);
self
}
#[inline]
fn with_default_menu(&mut self, enable: bool) -> &mut Self {
self.platform_specific.default_menu = enable;
self
}
#[inline]
fn with_activate_ignoring_other_apps(&mut self, ignore: bool) -> &mut Self {
self.platform_specific.activate_ignoring_other_apps = ignore;
self
}
}
/// Additional methods on [`MonitorHandle`] that are specific to MacOS.
pub trait MonitorHandleExtMacOS {
/// Returns a pointer to the NSScreen representing this monitor.
@ -541,7 +541,7 @@ pub trait MonitorHandleExtMacOS {
impl MonitorHandleExtMacOS for MonitorHandle {
fn ns_screen(&self) -> Option<*mut c_void> {
let monitor = self.cast_ref::<MacOsMonitorHandle>().unwrap();
let monitor = self.cast_ref::<AppKitMonitorHandle>().unwrap();
// SAFETY: We only use the marker to get a pointer
let mtm = unsafe { objc2::MainThreadMarker::new_unchecked() };
monitor.ns_screen(mtm).map(|s| objc2::rc::Retained::as_ptr(&s) as _)
@ -566,30 +566,26 @@ pub trait ActiveEventLoopExtMacOS {
impl ActiveEventLoopExtMacOS for dyn ActiveEventLoop + '_ {
fn hide_application(&self) {
let event_loop = self
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non macOS event loop on macOS");
let event_loop =
self.cast_ref::<AppKitActiveEventLoop>().expect("non macOS event loop on macOS");
event_loop.hide_application()
}
fn hide_other_applications(&self) {
let event_loop = self
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non macOS event loop on macOS");
let event_loop =
self.cast_ref::<AppKitActiveEventLoop>().expect("non macOS event loop on macOS");
event_loop.hide_other_applications()
}
fn set_allows_automatic_window_tabbing(&self, enabled: bool) {
let event_loop = self
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non macOS event loop on macOS");
let event_loop =
self.cast_ref::<AppKitActiveEventLoop>().expect("non macOS event loop on macOS");
event_loop.set_allows_automatic_window_tabbing(enabled);
}
fn allows_automatic_window_tabbing(&self) -> bool {
let event_loop = self
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non macOS event loop on macOS");
let event_loop =
self.cast_ref::<AppKitActiveEventLoop>().expect("non macOS event loop on macOS");
event_loop.allows_automatic_window_tabbing()
}
}

View file

@ -2,10 +2,15 @@ use objc2_core_graphics::CGError;
use tracing::trace;
use winit_core::error::OsError;
macro_rules! os_error {
($error:expr) => {{
winit_core::error::OsError::new(line!(), file!(), $error)
}};
}
macro_rules! trace_scope {
($s:literal) => {
let _crate =
$crate::platform_impl::platform::appkit::util::TraceGuard::new(module_path!(), $s);
let _crate = $crate::util::TraceGuard::new(module_path!(), $s);
};
}

View file

@ -29,7 +29,7 @@ use super::event::{
scancode_to_physicalkey,
};
use super::window::window_id;
use crate::platform::macos::OptionAsAlt;
use crate::OptionAsAlt;
#[derive(Debug)]
struct CursorState {

View file

@ -52,13 +52,13 @@ use winit_core::window::{
use super::app_state::AppState;
use super::cursor::{cursor_from_icon, CustomCursor};
use super::monitor::{self, flip_window_screen_coordinates, get_display_id};
use super::ffi;
use super::monitor::{self, flip_window_screen_coordinates, get_display_id, MonitorHandle};
use super::observer::RunLoop;
use super::util::cgerr;
use super::view::WinitView;
use super::window::{window_id, WinitPanel, WinitWindow};
use super::{ffi, MonitorHandle};
use crate::platform::macos::{OptionAsAlt, WindowAttributesMacOS, WindowExtMacOS};
use crate::{OptionAsAlt, WindowAttributesMacOS, WindowExtMacOS};
#[derive(Debug)]
pub(crate) struct State {

View file

@ -70,3 +70,7 @@ objc2-ui-kit = { workspace = true, features = [
"UIViewController",
"UIWindow",
] }
[package.metadata.docs.rs]
all-features = true
targets = ["aarch64-apple-ios", "aarch64-apple-ios-macabi"]

View file

@ -1 +1 @@
../../src/platform_impl/apple/appkit/notification_center.rs
../../winit-appkit/src/notification_center.rs