1 | // Copyright 2022 The AccessKit Authors. All rights reserved. |
2 | // Licensed under the Apache License, Version 2.0 (found in |
3 | // the LICENSE-APACHE file). |
4 | |
5 | /// ## Compatibility with async runtimes |
6 | /// |
7 | /// The following only applies on Linux/Unix: |
8 | /// |
9 | /// While this crate's API is purely blocking, it internally spawns asynchronous tasks on an executor. |
10 | /// |
11 | /// - If you use tokio, make sure to enable the `tokio` feature of this crate. |
12 | /// - If you use another async runtime or if you don't use one at all, the default feature will suit your needs. |
13 | |
14 | #[cfg (all( |
15 | feature = "accesskit_unix" , |
16 | any( |
17 | target_os = "linux" , |
18 | target_os = "dragonfly" , |
19 | target_os = "freebsd" , |
20 | target_os = "netbsd" , |
21 | target_os = "openbsd" |
22 | ), |
23 | not(feature = "async-io" ), |
24 | not(feature = "tokio" ) |
25 | ))] |
26 | compile_error!("Either \"async-io \" (default) or \"tokio \" feature must be enabled." ); |
27 | |
28 | #[cfg (all( |
29 | feature = "accesskit_unix" , |
30 | any( |
31 | target_os = "linux" , |
32 | target_os = "dragonfly" , |
33 | target_os = "freebsd" , |
34 | target_os = "netbsd" , |
35 | target_os = "openbsd" |
36 | ), |
37 | feature = "async-io" , |
38 | feature = "tokio" |
39 | ))] |
40 | compile_error!( |
41 | "Both \"async-io \" (default) and \"tokio \" features cannot be enabled at the same time." |
42 | ); |
43 | |
44 | #[cfg (all(not(feature = "rwh_05" ), not(feature = "rwh_06" )))] |
45 | compile_error!("Either \"rwh_06 \" (default) or \"rwh_05 \" feature must be enabled." ); |
46 | |
47 | #[cfg (all(feature = "rwh_05" , feature = "rwh_06" ))] |
48 | compile_error!( |
49 | "Both \"rwh_06 \" (default) and \"rwh_05 \" features cannot be enabled at the same time." |
50 | ); |
51 | |
52 | use accesskit::{ActionHandler, ActionRequest, ActivationHandler, DeactivationHandler, TreeUpdate}; |
53 | use winit::{ |
54 | event::WindowEvent as WinitWindowEvent, |
55 | event_loop::EventLoopProxy, |
56 | window::{Window, WindowId}, |
57 | }; |
58 | |
59 | #[cfg (feature = "rwh_05" )] |
60 | #[allow (unused)] |
61 | use rwh_05 as raw_window_handle; |
62 | #[cfg (feature = "rwh_06" )] |
63 | #[allow (unused)] |
64 | use rwh_06 as raw_window_handle; |
65 | |
66 | mod platform_impl; |
67 | |
68 | #[derive (Debug)] |
69 | pub struct Event { |
70 | pub window_id: WindowId, |
71 | pub window_event: WindowEvent, |
72 | } |
73 | |
74 | #[derive (Debug)] |
75 | pub enum WindowEvent { |
76 | InitialTreeRequested, |
77 | ActionRequested(ActionRequest), |
78 | AccessibilityDeactivated, |
79 | } |
80 | |
81 | struct WinitActivationHandler<T: From<Event> + Send + 'static> { |
82 | window_id: WindowId, |
83 | proxy: EventLoopProxy<T>, |
84 | } |
85 | |
86 | impl<T: From<Event> + Send + 'static> ActivationHandler for WinitActivationHandler<T> { |
87 | fn request_initial_tree(&mut self) -> Option<TreeUpdate> { |
88 | let event: Event = Event { |
89 | window_id: self.window_id, |
90 | window_event: WindowEvent::InitialTreeRequested, |
91 | }; |
92 | self.proxy.send_event(event.into()).ok(); |
93 | None |
94 | } |
95 | } |
96 | |
97 | struct WinitActionHandler<T: From<Event> + Send + 'static> { |
98 | window_id: WindowId, |
99 | proxy: EventLoopProxy<T>, |
100 | } |
101 | |
102 | impl<T: From<Event> + Send + 'static> ActionHandler for WinitActionHandler<T> { |
103 | fn do_action(&mut self, request: ActionRequest) { |
104 | let event: Event = Event { |
105 | window_id: self.window_id, |
106 | window_event: WindowEvent::ActionRequested(request), |
107 | }; |
108 | self.proxy.send_event(event.into()).ok(); |
109 | } |
110 | } |
111 | |
112 | struct WinitDeactivationHandler<T: From<Event> + Send + 'static> { |
113 | window_id: WindowId, |
114 | proxy: EventLoopProxy<T>, |
115 | } |
116 | |
117 | impl<T: From<Event> + Send + 'static> DeactivationHandler for WinitDeactivationHandler<T> { |
118 | fn deactivate_accessibility(&mut self) { |
119 | let event: Event = Event { |
120 | window_id: self.window_id, |
121 | window_event: WindowEvent::AccessibilityDeactivated, |
122 | }; |
123 | self.proxy.send_event(event.into()).ok(); |
124 | } |
125 | } |
126 | |
127 | pub struct Adapter { |
128 | inner: platform_impl::Adapter, |
129 | } |
130 | |
131 | impl Adapter { |
132 | /// Creates a new AccessKit adapter for a winit window. This must be done |
133 | /// before the window is shown for the first time. This means that you must |
134 | /// use [`winit::window::WindowAttributes::with_visible`] to make the window |
135 | /// initially invisible, then create the adapter, then show the window. |
136 | /// |
137 | /// This constructor uses a winit event loop proxy to deliver AccessKit |
138 | /// events to the main event loop. The primary disadvantage of this approach |
139 | /// is that it's not possible to synchronously return an initial tree |
140 | /// in response to the [`WindowEvent::InitialTreeRequested`] event, |
141 | /// so some platform adapters will have to use a temporary placeholder tree |
142 | /// until you send the first update. For an optimal implementation, |
143 | /// consider using [`Adapter::with_direct_handlers`] or |
144 | /// [`Adapter::with_mixed_handlers`] instead. |
145 | pub fn with_event_loop_proxy<T: From<Event> + Send + 'static>( |
146 | window: &Window, |
147 | proxy: EventLoopProxy<T>, |
148 | ) -> Self { |
149 | let window_id = window.id(); |
150 | let activation_handler = WinitActivationHandler { |
151 | window_id, |
152 | proxy: proxy.clone(), |
153 | }; |
154 | let action_handler = WinitActionHandler { |
155 | window_id, |
156 | proxy: proxy.clone(), |
157 | }; |
158 | let deactivation_handler = WinitDeactivationHandler { window_id, proxy }; |
159 | Self::with_direct_handlers( |
160 | window, |
161 | activation_handler, |
162 | action_handler, |
163 | deactivation_handler, |
164 | ) |
165 | } |
166 | |
167 | /// Creates a new AccessKit adapter for a winit window. This must be done |
168 | /// before the window is shown for the first time. This means that you must |
169 | /// use [`winit::window::WindowAttributes::with_visible`] to make the window |
170 | /// initially invisible, then create the adapter, then show the window. |
171 | /// |
172 | /// Use this if you want to provide your own AccessKit handler callbacks |
173 | /// rather than dispatching requests through the winit event loop. This is |
174 | /// especially useful for the activation handler, because depending on |
175 | /// your application's architecture, implementing the handler directly may |
176 | /// allow you to return an initial tree synchronously, rather than requiring |
177 | /// some platform adapters to use a placeholder tree until you send |
178 | /// the first update. However, remember that each of these handlers may be |
179 | /// called on any thread, depending on the underlying platform adapter. |
180 | pub fn with_direct_handlers( |
181 | window: &Window, |
182 | activation_handler: impl 'static + ActivationHandler + Send, |
183 | action_handler: impl 'static + ActionHandler + Send, |
184 | deactivation_handler: impl 'static + DeactivationHandler + Send, |
185 | ) -> Self { |
186 | let inner = platform_impl::Adapter::new( |
187 | window, |
188 | activation_handler, |
189 | action_handler, |
190 | deactivation_handler, |
191 | ); |
192 | Self { inner } |
193 | } |
194 | |
195 | /// Creates a new AccessKit adapter for a winit window. This must be done |
196 | /// before the window is shown for the first time. This means that you must |
197 | /// use [`winit::window::WindowAttributes::with_visible`] to make the window |
198 | /// initially invisible, then create the adapter, then show the window. |
199 | /// |
200 | /// This constructor provides a mix of the approaches used by |
201 | /// [`Adapter::with_event_loop_proxy`] and [`Adapter::with_direct_handlers`]. |
202 | /// It uses the event loop proxy for the action request and deactivation |
203 | /// events, which can be handled asynchronously with no drawback, |
204 | /// while using a direct, caller-provided activation handler that can |
205 | /// return the initial tree synchronously. Remember that the thread on which |
206 | /// the activation handler is called is platform-dependent. |
207 | pub fn with_mixed_handlers<T: From<Event> + Send + 'static>( |
208 | window: &Window, |
209 | activation_handler: impl 'static + ActivationHandler + Send, |
210 | proxy: EventLoopProxy<T>, |
211 | ) -> Self { |
212 | let window_id = window.id(); |
213 | let action_handler = WinitActionHandler { |
214 | window_id, |
215 | proxy: proxy.clone(), |
216 | }; |
217 | let deactivation_handler = WinitDeactivationHandler { window_id, proxy }; |
218 | Self::with_direct_handlers( |
219 | window, |
220 | activation_handler, |
221 | action_handler, |
222 | deactivation_handler, |
223 | ) |
224 | } |
225 | |
226 | /// Allows reacting to window events. |
227 | /// |
228 | /// This must be called whenever a new window event is received |
229 | /// and before it is handled by the application. |
230 | pub fn process_event(&mut self, window: &Window, event: &WinitWindowEvent) { |
231 | self.inner.process_event(window, event); |
232 | } |
233 | |
234 | /// If and only if the tree has been initialized, call the provided function |
235 | /// and apply the resulting update. Note: If the caller's implementation of |
236 | /// [`ActivationHandler::request_initial_tree`] initially returned `None`, |
237 | /// or if the caller created the adapter using [`EventLoopProxy`], then |
238 | /// the [`TreeUpdate`] returned by the provided function must contain |
239 | /// a full tree. |
240 | pub fn update_if_active(&mut self, updater: impl FnOnce() -> TreeUpdate) { |
241 | self.inner.update_if_active(updater); |
242 | } |
243 | } |
244 | |