From 5e5dbed44548927ef2164021e3cf0841555a885b Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 22 Feb 2024 22:29:27 +0100 Subject: [PATCH] Improve documentation for UIKit and AppKit handles (#160) * Document that Apple handles are main thread only * Add example usage to AppKitWindowHandle and UiKitWindowHandle --- src/appkit.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/uikit.rs | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/src/appkit.rs b/src/appkit.rs index 5bdbf5b..20eb68b 100644 --- a/src/appkit.rs +++ b/src/appkit.rs @@ -44,6 +44,45 @@ impl DisplayHandle<'static> { } /// Raw window handle for AppKit. +/// +/// Note that `NSView` can only be accessed from the main thread of the +/// application. This struct is `!Send` and `!Sync` to help with ensuring +/// that. +/// +/// # Example +/// +/// Getting the view from a [`WindowHandle`][crate::WindowHandle]. +/// +/// ```no_run +/// # fn inner() { +/// #![cfg(target_os = "macos")] +/// # #[cfg(requires_objc2)] +/// use icrate::AppKit::NSView; +/// # #[cfg(requires_objc2)] +/// use icrate::Foundation::is_main_thread; +/// # #[cfg(requires_objc2)] +/// use objc2::rc::Id; +/// use raw_window_handle::{WindowHandle, RawWindowHandle}; +/// +/// let handle: WindowHandle<'_>; // Get the window handle from somewhere else +/// # handle = unimplemented!(); +/// match handle.as_raw() { +/// # #[cfg(requires_objc2)] +/// RawWindowHandle::AppKit(handle) => { +/// assert!(is_main_thread(), "can only access AppKit handles on the main thread"); +/// let ns_view = handle.ns_view.as_ptr(); +/// // SAFETY: The pointer came from `WindowHandle`, which ensures +/// // that the `AppKitWindowHandle` contains a valid pointer to an +/// // `NSView`. +/// // Unwrap is fine, since the pointer came from `NonNull`. +/// let ns_view: Id = unsafe { Id::retain(ns_view.cast()) }.unwrap(); +/// // Do something with the NSView here, like getting the `NSWindow` +/// let ns_window = ns_view.window().expect("view was not installed in a window"); +/// } +/// handle => unreachable!("unknown handle {handle:?} for platform"), +/// } +/// # } +/// ``` #[non_exhaustive] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct AppKitWindowHandle { diff --git a/src/uikit.rs b/src/uikit.rs index 3759bc2..db628fe 100644 --- a/src/uikit.rs +++ b/src/uikit.rs @@ -44,6 +44,45 @@ impl DisplayHandle<'static> { } /// Raw window handle for UIKit. +/// +/// Note that `UIView` can only be accessed from the main thread of the +/// application. This struct is `!Send` and `!Sync` to help with ensuring +/// that. +/// +/// # Example +/// +/// Getting the view from a [`WindowHandle`][crate::WindowHandle]. +/// +/// ```no_run +/// # fn inner() { +/// #![cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "xros"))] +/// # #[cfg(requires_objc2)] +/// use icrate::Foundation::is_main_thread; +/// # #[cfg(requires_objc2)] +/// use objc2::rc::Id; +/// // TODO: Use `icrate::UIKit::UIView` when available +/// # #[cfg(requires_objc2)] +/// use objc2::runtime::NSObject; +/// use raw_window_handle::{WindowHandle, RawWindowHandle}; +/// +/// let handle: WindowHandle<'_>; // Get the window handle from somewhere else +/// # handle = unimplemented!(); +/// match handle.as_raw() { +/// # #[cfg(requires_objc2)] +/// RawWindowHandle::UIKit(handle) => { +/// assert!(is_main_thread(), "can only access UIKit handles on the main thread"); +/// let ui_view = handle.ui_view.as_ptr(); +/// // SAFETY: The pointer came from `WindowHandle`, which ensures +/// // that the `UiKitWindowHandle` contains a valid pointer to an +/// // `UIView`. +/// // Unwrap is fine, since the pointer came from `NonNull`. +/// let ui_view: Id = unsafe { Id::retain(ui_view.cast()) }.unwrap(); +/// // Do something with the UIView here. +/// } +/// handle => unreachable!("unknown handle {handle:?} for platform"), +/// } +/// # } +/// ``` #[non_exhaustive] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct UiKitWindowHandle {