accesskit_winit/
lib.rs

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))]
26compile_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))]
40compile_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")))]
45compile_error!("Either \"rwh_06\" (default) or \"rwh_05\" feature must be enabled.");
46
47#[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);
51
52use accesskit::{ActionHandler, ActionRequest, ActivationHandler, DeactivationHandler, TreeUpdate};
53use winit::{
54    event::WindowEvent as WinitWindowEvent,
55    event_loop::EventLoopProxy,
56    window::{Window, WindowId},
57};
58
59#[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;
65
66mod platform_impl;
67
68#[derive(Debug)]
69pub struct Event {
70    pub window_id: WindowId,
71    pub window_event: WindowEvent,
72}
73
74#[derive(Debug)]
75pub enum WindowEvent {
76    InitialTreeRequested,
77    ActionRequested(ActionRequest),
78    AccessibilityDeactivated,
79}
80
81struct WinitActivationHandler<T: From<Event> + Send + 'static> {
82    window_id: WindowId,
83    proxy: EventLoopProxy<T>,
84}
85
86impl<T: From<Event> + Send + 'static> ActivationHandler for WinitActivationHandler<T> {
87    fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
88        let 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
97struct WinitActionHandler<T: From<Event> + Send + 'static> {
98    window_id: WindowId,
99    proxy: EventLoopProxy<T>,
100}
101
102impl<T: From<Event> + Send + 'static> ActionHandler for WinitActionHandler<T> {
103    fn do_action(&mut self, request: ActionRequest) {
104        let 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
112struct WinitDeactivationHandler<T: From<Event> + Send + 'static> {
113    window_id: WindowId,
114    proxy: EventLoopProxy<T>,
115}
116
117impl<T: From<Event> + Send + 'static> DeactivationHandler for WinitDeactivationHandler<T> {
118    fn deactivate_accessibility(&mut self) {
119        let 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
127pub struct Adapter {
128    inner: platform_impl::Adapter,
129}
130
131impl 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}