From e293cf3356518cffeb39e12e317755481c2ded32 Mon Sep 17 00:00:00 2001 From: Matt Campbell Date: Tue, 20 Jun 2023 08:53:42 -0500 Subject: [PATCH 1/2] feat: Add window-based constructor to macOS subclassing adapter --- bindings/c/src/macos.rs | 18 +++++++++++++++ platforms/macos/src/appkit/window.rs | 8 ++++++- platforms/macos/src/subclass.rs | 34 +++++++++++++++++++++++++++- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/bindings/c/src/macos.rs b/bindings/c/src/macos.rs index fe953f563..7d6fa6e8a 100644 --- a/bindings/c/src/macos.rs +++ b/bindings/c/src/macos.rs @@ -128,6 +128,24 @@ impl macos_subclassing_adapter { BoxCastPtr::to_mut_ptr(adapter) } + /// This function takes ownership of `handler`. + #[no_mangle] + pub unsafe extern "C" fn accesskit_macos_subclassing_adapter_for_window( + window: *mut c_void, + source: tree_update_factory, + source_userdata: *mut c_void, + handler: *mut action_handler, + ) -> *mut macos_subclassing_adapter { + let source = source.unwrap(); + let handler = box_from_ptr(handler); + let adapter = SubclassingAdapter::for_window( + window, + move || box_from_ptr(source(source_userdata)).into(), + handler, + ); + BoxCastPtr::to_mut_ptr(adapter) + } + #[no_mangle] pub extern "C" fn accesskit_macos_subclassing_adapter_free( adapter: *mut macos_subclassing_adapter, diff --git a/platforms/macos/src/appkit/window.rs b/platforms/macos/src/appkit/window.rs index 35407626b..a58712ace 100644 --- a/platforms/macos/src/appkit/window.rs +++ b/platforms/macos/src/appkit/window.rs @@ -6,10 +6,12 @@ use objc2::{ extern_class, extern_methods, foundation::{NSObject, NSPoint, NSRect}, + msg_send_id, + rc::{Id, Shared}, ClassType, }; -use super::NSResponder; +use super::{NSResponder, NSView}; extern_class!( #[derive(Debug)] @@ -28,5 +30,9 @@ extern_methods!( #[sel(convertPointFromScreen:)] pub(crate) fn convert_point_from_screen(&self, point: NSPoint) -> NSPoint; + + pub(crate) fn content_view(&self) -> Option> { + unsafe { msg_send_id![self, contentView] } + } } ); diff --git a/platforms/macos/src/subclass.rs b/platforms/macos/src/subclass.rs index d137009db..4b240036b 100644 --- a/platforms/macos/src/subclass.rs +++ b/platforms/macos/src/subclass.rs @@ -20,7 +20,11 @@ use objc2::{ use once_cell::{sync::Lazy as SyncLazy, unsync::Lazy}; use std::{collections::HashMap, ffi::c_void, sync::Mutex}; -use crate::{appkit::NSView, event::QueuedEvents, Adapter}; +use crate::{ + appkit::{NSView, NSWindow}, + event::QueuedEvents, + Adapter, +}; static SUBCLASSES: SyncLazy>> = SyncLazy::new(|| Mutex::new(HashMap::new())); @@ -116,6 +120,14 @@ impl SubclassingAdapter { ) -> Self { let view = view as *mut NSView; let retained_view = unsafe { Id::retain(view) }.unwrap(); + Self::new_internal(retained_view, source, action_handler) + } + + fn new_internal( + retained_view: Id, + source: impl 'static + FnOnce() -> TreeUpdate, + action_handler: Box, + ) -> Self { let adapter: LazyAdapter = { let retained_view = retained_view.clone(); Lazy::new(Box::new(move || { @@ -123,6 +135,7 @@ impl SubclassingAdapter { unsafe { Adapter::new(view, source(), action_handler) } })) }; + let view = Id::as_ptr(&retained_view) as *mut NSView; // Cast to a pointer and back to force the lifetime to 'static // SAFETY: We know the class will live as long as the instance, // and we only use this reference while the instance is alive. @@ -171,6 +184,25 @@ impl SubclassingAdapter { } } + /// Create an adapter that dynamically subclasses the content view + /// of the specified window. Panics if the specified window doesn't + /// currently have a content view. + /// + /// The action handler will always be called on the main thread. + /// + /// # Safety + /// + /// `window` must be a valid, unreleased pointer to an `NSWindow`. + pub unsafe fn for_window( + window: *mut c_void, + source: impl 'static + FnOnce() -> TreeUpdate, + action_handler: Box, + ) -> Self { + let window = unsafe { &*(window as *const NSWindow) }; + let retained_view = window.content_view().unwrap(); + Self::new_internal(retained_view, source, action_handler) + } + /// Initialize the tree if it hasn't been initialized already, then apply /// the provided update. /// From 92ea24e75a7491e9f9ed72f656d5ffb8501473ed Mon Sep 17 00:00:00 2001 From: Matt Campbell Date: Fri, 23 Jun 2023 06:11:44 -0500 Subject: [PATCH 2/2] Move note on panic to 'Panics' section --- platforms/macos/src/subclass.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/platforms/macos/src/subclass.rs b/platforms/macos/src/subclass.rs index 4b240036b..744f78ea0 100644 --- a/platforms/macos/src/subclass.rs +++ b/platforms/macos/src/subclass.rs @@ -185,14 +185,18 @@ impl SubclassingAdapter { } /// Create an adapter that dynamically subclasses the content view - /// of the specified window. Panics if the specified window doesn't - /// currently have a content view. + /// of the specified window. /// /// The action handler will always be called on the main thread. /// /// # Safety /// /// `window` must be a valid, unreleased pointer to an `NSWindow`. + /// + /// # Panics + /// + /// This function panics if the specified window doesn't currently have + /// a content view. pub unsafe fn for_window( window: *mut c_void, source: impl 'static + FnOnce() -> TreeUpdate,