accesskit_windows/
subclass.rs1use accesskit::{ActionHandler, ActivationHandler, TreeUpdate};
7use std::{
8 cell::{Cell, RefCell},
9 ffi::c_void,
10 mem::transmute,
11};
12use windows::{
13 core::*,
14 Win32::{Foundation::*, UI::WindowsAndMessaging::*},
15};
16
17use crate::{Adapter, QueuedEvents};
18
19fn win32_error() -> ! {
20 panic!("{}", Error::from_thread())
21}
22
23#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
26type LongPtr = isize;
27#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
28type LongPtr = i32;
29
30const PROP_NAME: PCWSTR = w!("AccessKitAdapter");
31
32struct SubclassState {
33 adapter: Adapter,
34 activation_handler: Box<dyn ActivationHandler>,
35}
36
37struct SubclassImpl {
38 hwnd: HWND,
39 state: RefCell<SubclassState>,
40 prev_wnd_proc: WNDPROC,
41 window_destroyed: Cell<bool>,
42}
43
44extern "system" fn wnd_proc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
45 let handle = unsafe { GetPropW(window, PROP_NAME) };
46 let impl_ptr = handle.0 as *const SubclassImpl;
47 assert!(!impl_ptr.is_null());
48 let r#impl = unsafe { &*impl_ptr };
49 match message {
50 WM_GETOBJECT => {
51 let mut state = r#impl.state.borrow_mut();
52 let state_mut = &mut *state;
53 if let Some(result) = state_mut.adapter.handle_wm_getobject(
54 wparam,
55 lparam,
56 &mut *state_mut.activation_handler,
57 ) {
58 drop(state);
59 return result.into();
60 }
61 }
62 WM_SETFOCUS | WM_EXITMENULOOP | WM_EXITSIZEMOVE => {
63 r#impl.update_window_focus_state(true);
64 }
65 WM_KILLFOCUS | WM_ENTERMENULOOP | WM_ENTERSIZEMOVE => {
66 r#impl.update_window_focus_state(false);
67 }
68 WM_NCDESTROY => {
69 r#impl.window_destroyed.set(true);
70 }
71 _ => (),
72 }
73 unsafe { CallWindowProcW(r#impl.prev_wnd_proc, window, message, wparam, lparam) }
74}
75
76impl SubclassImpl {
77 fn new(
78 hwnd: HWND,
79 activation_handler: impl 'static + ActivationHandler,
80 action_handler: impl 'static + ActionHandler + Send,
81 ) -> Box<Self> {
82 let adapter = Adapter::new(hwnd, false, action_handler);
83 let state = RefCell::new(SubclassState {
84 adapter,
85 activation_handler: Box::new(activation_handler),
86 });
87 Box::new(Self {
88 hwnd,
89 state,
90 prev_wnd_proc: None,
91 window_destroyed: Cell::new(false),
92 })
93 }
94
95 fn install(&mut self) {
96 if !unsafe { GetPropW(self.hwnd, PROP_NAME) }.0.is_null() {
97 panic!(
98 "subclassing adapter already instantiated on window {:?}",
99 self.hwnd.0
100 );
101 }
102 unsafe {
103 SetPropW(
104 self.hwnd,
105 PROP_NAME,
106 Some(HANDLE(self as *const SubclassImpl as _)),
107 )
108 }
109 .unwrap();
110 let result =
111 unsafe { SetWindowLongPtrW(self.hwnd, GWLP_WNDPROC, wnd_proc as *const c_void as _) };
112 if result == 0 {
113 win32_error();
114 }
115 self.prev_wnd_proc = unsafe { transmute::<LongPtr, WNDPROC>(result) };
116 }
117
118 fn update_window_focus_state(&self, is_focused: bool) {
119 let mut state = self.state.borrow_mut();
120 if let Some(events) = state.adapter.update_window_focus_state(is_focused) {
121 drop(state);
122 events.raise();
123 }
124 }
125
126 fn uninstall(&self) {
127 if self.window_destroyed.get() {
128 return;
129 }
130 let result = unsafe {
131 SetWindowLongPtrW(
132 self.hwnd,
133 GWLP_WNDPROC,
134 transmute::<WNDPROC, LongPtr>(self.prev_wnd_proc),
135 )
136 };
137 if result == 0 {
138 win32_error();
139 }
140 unsafe { RemovePropW(self.hwnd, PROP_NAME) }.unwrap();
141 }
142}
143
144pub struct SubclassingAdapter(Box<SubclassImpl>);
149
150impl SubclassingAdapter {
151 pub fn new(
163 hwnd: HWND,
164 activation_handler: impl 'static + ActivationHandler,
165 action_handler: impl 'static + ActionHandler + Send,
166 ) -> Self {
167 if unsafe { IsWindowVisible(hwnd) }.into() {
168 panic!("The AccessKit Windows subclassing adapter must be created before the window is shown (made visible) for the first time.");
169 }
170
171 let mut r#impl = SubclassImpl::new(hwnd, activation_handler, action_handler);
172 r#impl.install();
173 Self(r#impl)
174 }
175
176 pub fn update_if_active(
185 &mut self,
186 update_factory: impl FnOnce() -> TreeUpdate,
187 ) -> Option<QueuedEvents> {
188 let mut state = self.0.state.borrow_mut();
194 state.adapter.update_if_active(update_factory)
195 }
196}
197
198impl Drop for SubclassingAdapter {
199 fn drop(&mut self) {
200 self.0.uninstall();
201 }
202}