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).
45/// ## 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.
1314#[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))]
26compile_error!("Either \"async-io\" (default) or \"tokio\" feature must be enabled.");
2728#[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))]
40compile_error!(
41"Both \"async-io\" (default) and \"tokio\" features cannot be enabled at the same time."
42);
4344#[cfg(all(not(feature = "rwh_05"), not(feature = "rwh_06")))]
45compile_error!("Either \"rwh_06\" (default) or \"rwh_05\" feature must be enabled.");
4647#[cfg(all(feature = "rwh_05", feature = "rwh_06"))]
48compile_error!(
49"Both \"rwh_06\" (default) and \"rwh_05\" features cannot be enabled at the same time."
50);
5152use accesskit::{ActionHandler, ActionRequest, ActivationHandler, DeactivationHandler, TreeUpdate};
53use winit::{
54 event::WindowEvent as WinitWindowEvent,
55 event_loop::EventLoopProxy,
56 window::{Window, WindowId},
57};
5859#[cfg(feature = "rwh_05")]
60#[allow(unused)]
61use rwh_05 as raw_window_handle;
62#[cfg(feature = "rwh_06")]
63#[allow(unused)]
64use rwh_06 as raw_window_handle;
6566mod platform_impl;
6768#[derive(Debug)]
69pub struct Event {
70pub window_id: WindowId,
71pub window_event: WindowEvent,
72}
7374#[derive(Debug)]
75pub enum WindowEvent {
76 InitialTreeRequested,
77 ActionRequested(ActionRequest),
78 AccessibilityDeactivated,
79}
8081struct WinitActivationHandler<T: From<Event> + Send + 'static> {
82 window_id: WindowId,
83 proxy: EventLoopProxy<T>,
84}
8586impl<T: From<Event> + Send + 'static> ActivationHandler for WinitActivationHandler<T> {
87fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
88let event = Event {
89 window_id: self.window_id,
90 window_event: WindowEvent::InitialTreeRequested,
91 };
92self.proxy.send_event(event.into()).ok();
93None
94}
95}
9697struct WinitActionHandler<T: From<Event> + Send + 'static> {
98 window_id: WindowId,
99 proxy: EventLoopProxy<T>,
100}
101102impl<T: From<Event> + Send + 'static> ActionHandler for WinitActionHandler<T> {
103fn do_action(&mut self, request: ActionRequest) {
104let event = Event {
105 window_id: self.window_id,
106 window_event: WindowEvent::ActionRequested(request),
107 };
108self.proxy.send_event(event.into()).ok();
109 }
110}
111112struct WinitDeactivationHandler<T: From<Event> + Send + 'static> {
113 window_id: WindowId,
114 proxy: EventLoopProxy<T>,
115}
116117impl<T: From<Event> + Send + 'static> DeactivationHandler for WinitDeactivationHandler<T> {
118fn deactivate_accessibility(&mut self) {
119let event = Event {
120 window_id: self.window_id,
121 window_event: WindowEvent::AccessibilityDeactivated,
122 };
123self.proxy.send_event(event.into()).ok();
124 }
125}
126127pub struct Adapter {
128 inner: platform_impl::Adapter,
129}
130131impl 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.
145pub fn with_event_loop_proxy<T: From<Event> + Send + 'static>(
146 window: &Window,
147 proxy: EventLoopProxy<T>,
148 ) -> Self {
149let window_id = window.id();
150let activation_handler = WinitActivationHandler {
151 window_id,
152 proxy: proxy.clone(),
153 };
154let action_handler = WinitActionHandler {
155 window_id,
156 proxy: proxy.clone(),
157 };
158let deactivation_handler = WinitDeactivationHandler { window_id, proxy };
159Self::with_direct_handlers(
160 window,
161 activation_handler,
162 action_handler,
163 deactivation_handler,
164 )
165 }
166167/// 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.
180pub 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 {
186let inner = platform_impl::Adapter::new(
187 window,
188 activation_handler,
189 action_handler,
190 deactivation_handler,
191 );
192Self { inner }
193 }
194195/// 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.
207pub 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 {
212let window_id = window.id();
213let action_handler = WinitActionHandler {
214 window_id,
215 proxy: proxy.clone(),
216 };
217let deactivation_handler = WinitDeactivationHandler { window_id, proxy };
218Self::with_direct_handlers(
219 window,
220 activation_handler,
221 action_handler,
222 deactivation_handler,
223 )
224 }
225226/// 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.
230pub fn process_event(&mut self, window: &Window, event: &WinitWindowEvent) {
231self.inner.process_event(window, event);
232 }
233234/// 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.
240pub fn update_if_active(&mut self, updater: impl FnOnce() -> TreeUpdate) {
241self.inner.update_if_active(updater);
242 }
243}