Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(platforms/windows)!: Simplify the adapter API by always boxi… #119

Merged
merged 1 commit into from
Jul 21, 2022
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
21 changes: 11 additions & 10 deletions platforms/windows/examples/hello_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,17 +216,18 @@ extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: L
is_window_focused: false,
}));
let inner_state_for_tree_init = inner_state.clone();
let adapter = accesskit_windows::Adapter::new(
window,
Box::new(move || {
let mut result = initial_state;
let state = inner_state_for_tree_init.borrow();
result.focus = state.is_window_focused.then(|| state.focus);
result
}),
Box::new(SimpleActionHandler { window }),
);
let state = Box::new(WindowState {
adapter: accesskit_windows::Adapter::new(
window,
Box::new(move || {
let mut result = initial_state;
let state = inner_state_for_tree_init.borrow();
result.focus = state.is_window_focused.then(|| state.focus);
result
}),
Box::new(SimpleActionHandler { window }),
),
adapter,
inner_state,
});
unsafe { SetWindowLongPtrW(window, GWLP_USERDATA, Box::into_raw(state) as _) };
Expand Down
2 changes: 1 addition & 1 deletion platforms/windows/examples/winit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ fn main() {
.build(&event_loop)
.unwrap();

let adapter: Arc<Adapter> = {
let adapter = {
let state = Arc::clone(&state);
let proxy = Mutex::new(event_loop.create_proxy());
Arc::new(Adapter::new(
Expand Down
33 changes: 23 additions & 10 deletions platforms/windows/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,22 @@ use crate::{
util::QueuedEvent,
};

pub struct Adapter<Source = Box<dyn FnOnce() -> TreeUpdate>>
where
Source: Into<TreeUpdate>,
{
struct UninitializedTree {
source: Box<dyn FnOnce() -> TreeUpdate>,
action_handler: Box<dyn ActionHandler>,
}

pub struct Adapter {
hwnd: HWND,
tree: LazyTransform<(Source, Box<dyn ActionHandler>), Arc<Tree>>,
tree: LazyTransform<UninitializedTree, Arc<Tree>>,
}

impl<Source: Into<TreeUpdate>> Adapter<Source> {
pub fn new(hwnd: HWND, source: Source, action_handler: Box<dyn ActionHandler>) -> Self {
impl Adapter {
pub fn new(
hwnd: HWND,
source: Box<dyn FnOnce() -> TreeUpdate>,
action_handler: Box<dyn ActionHandler>,
) -> Self {
// It's unfortunate that we have to force UIA to initialize early;
// it would be more optimal to let UIA lazily initialize itself
// when we receive the first `WM_GETOBJECT`. But if we don't do this,
Expand All @@ -38,7 +44,10 @@ impl<Source: Into<TreeUpdate>> Adapter<Source> {

Self {
hwnd,
tree: LazyTransform::new((source, action_handler)),
tree: LazyTransform::new(UninitializedTree {
source,
action_handler,
}),
}
}

Expand All @@ -47,8 +56,12 @@ impl<Source: Into<TreeUpdate>> Adapter<Source> {
}

fn get_or_create_tree(&self) -> &Arc<Tree> {
self.tree
.get_or_create(|(source, action_handler)| Tree::new(source.into(), action_handler))
self.tree.get_or_create(
|UninitializedTree {
source,
action_handler,
}| Tree::new(source.into(), action_handler),
)
}

/// Initialize the tree if it hasn't been initialized already, then apply
Expand Down
38 changes: 11 additions & 27 deletions platforms/windows/src/subclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// the LICENSE-APACHE file) or the MIT license (found in
// the LICENSE-MIT file), at your option.

use accesskit::TreeUpdate;
use std::{cell::Cell, ffi::c_void, mem::transmute};
use windows::{
core::*,
Expand All @@ -14,20 +13,15 @@ use crate::Adapter;

const PROP_NAME: &str = "AccessKitAdapter";

struct SubclassData<'a, Source: Into<TreeUpdate>> {
adapter: &'a Adapter<Source>,
struct SubclassData<'a> {
adapter: &'a Adapter,
prev_wnd_proc: WNDPROC,
window_destroyed: Cell<bool>,
}

extern "system" fn wnd_proc<Source: Into<TreeUpdate>>(
window: HWND,
message: u32,
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
extern "system" fn wnd_proc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
let handle = unsafe { GetPropW(window, PROP_NAME) };
let data_ptr = handle.0 as *const SubclassData<'_, Source>;
let data_ptr = handle.0 as *const SubclassData;
assert!(!data_ptr.is_null());
let data = unsafe { &*data_ptr };
if message == WM_GETOBJECT {
Expand All @@ -46,29 +40,19 @@ extern "system" fn wnd_proc<Source: Into<TreeUpdate>>(
///
/// [Win32 subclassing]: https://docs.microsoft.com/en-us/windows/win32/controls/subclassing-overview
#[repr(transparent)]
pub struct WindowSubclass<'a, Source: Into<TreeUpdate> = Box<dyn FnOnce() -> TreeUpdate>>(
Box<SubclassData<'a, Source>>,
);
pub struct WindowSubclass<'a>(Box<SubclassData<'a>>);

impl<'a, Source: Into<TreeUpdate>> WindowSubclass<'a, Source> {
pub fn new(adapter: &'a Adapter<Source>) -> Self {
impl<'a> WindowSubclass<'a> {
pub fn new(adapter: &'a Adapter) -> Self {
let hwnd = adapter.window_handle();
let mut data = Box::new(SubclassData {
adapter,
prev_wnd_proc: None,
window_destroyed: Cell::new(false),
});
unsafe {
SetPropW(
hwnd,
PROP_NAME,
HANDLE(&*data as *const SubclassData<'_, Source> as _),
)
}
.unwrap();
let result = unsafe {
SetWindowLongPtrW(hwnd, GWLP_WNDPROC, wnd_proc::<Source> as *const c_void as _)
};
unsafe { SetPropW(hwnd, PROP_NAME, HANDLE(&*data as *const SubclassData as _)) }.unwrap();
let result =
unsafe { SetWindowLongPtrW(hwnd, GWLP_WNDPROC, wnd_proc as *const c_void as _) };
if result == 0 {
let result: Result<()> = Err(Error::from_win32());
result.unwrap();
Expand All @@ -78,7 +62,7 @@ impl<'a, Source: Into<TreeUpdate>> WindowSubclass<'a, Source> {
}
}

impl<Source: Into<TreeUpdate>> Drop for WindowSubclass<'_, Source> {
impl Drop for WindowSubclass<'_> {
fn drop(&mut self) {
if !self.0.window_destroyed.get() {
let hwnd = self.0.adapter.window_handle();
Expand Down
6 changes: 5 additions & 1 deletion platforms/windows/src/tests/subclassed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ fn has_native_uia() {
.unwrap();
let hwnd = HWND(window.hwnd() as _);
assert!(!unsafe { UiaHasServerSideProvider(hwnd) }.as_bool());
let adapter = Adapter::new(hwnd, get_initial_state(), Box::new(NullActionHandler {}));
let adapter = Adapter::new(
hwnd,
Box::new(get_initial_state),
Box::new(NullActionHandler {}),
);
let subclass = WindowSubclass::new(&adapter);
assert!(unsafe { UiaHasServerSideProvider(hwnd) }.as_bool());
drop(subclass);
Expand Down