Skip to content

Commit

Permalink
feat: Add window-based constructor to macOS subclassing adapter (#253)
Browse files Browse the repository at this point in the history
  • Loading branch information
mwcampbell authored Jun 23, 2023
1 parent 424de4f commit 022ef04
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 2 deletions.
18 changes: 18 additions & 0 deletions bindings/c/src/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
8 changes: 7 additions & 1 deletion platforms/macos/src/appkit/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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<Id<NSView, Shared>> {
unsafe { msg_send_id![self, contentView] }
}
}
);
38 changes: 37 additions & 1 deletion platforms/macos/src/subclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Mutex<HashMap<&'static Class, &'static Class>>> =
SyncLazy::new(|| Mutex::new(HashMap::new()));
Expand Down Expand Up @@ -116,13 +120,22 @@ 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<NSView, Shared>,
source: impl 'static + FnOnce() -> TreeUpdate,
action_handler: Box<dyn ActionHandler>,
) -> Self {
let adapter: LazyAdapter = {
let retained_view = retained_view.clone();
Lazy::new(Box::new(move || {
let view = Id::as_ptr(&retained_view) as *mut c_void;
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.
Expand Down Expand Up @@ -171,6 +184,29 @@ impl SubclassingAdapter {
}
}

/// Create an adapter that dynamically subclasses the 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,
action_handler: Box<dyn ActionHandler>,
) -> 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.
///
Expand Down

0 comments on commit 022ef04

Please sign in to comment.