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::{ActiveEventLoop, 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        event_loop: &ActiveEventLoop,
147        window: &Window,
148        proxy: EventLoopProxy<T>,
149    ) -> Self {
150        let window_id = window.id();
151        let activation_handler = WinitActivationHandler {
152            window_id,
153            proxy: proxy.clone(),
154        };
155        let action_handler = WinitActionHandler {
156            window_id,
157            proxy: proxy.clone(),
158        };
159        let deactivation_handler = WinitDeactivationHandler { window_id, proxy };
160        Self::with_direct_handlers(
161            event_loop,
162            window,
163            activation_handler,
164            action_handler,
165            deactivation_handler,
166        )
167    }
168
169    /// Creates a new AccessKit adapter for a winit window. This must be done
170    /// before the window is shown for the first time. This means that you must
171    /// use [`winit::window::WindowAttributes::with_visible`] to make the window
172    /// initially invisible, then create the adapter, then show the window.
173    ///
174    /// Use this if you want to provide your own AccessKit handler callbacks
175    /// rather than dispatching requests through the winit event loop. This is
176    /// especially useful for the activation handler, because depending on
177    /// your application's architecture, implementing the handler directly may
178    /// allow you to return an initial tree synchronously, rather than requiring
179    /// some platform adapters to use a placeholder tree until you send
180    /// the first update. However, remember that each of these handlers may be
181    /// called on any thread, depending on the underlying platform adapter.
182    pub fn with_direct_handlers(
183        event_loop: &ActiveEventLoop,
184        window: &Window,
185        activation_handler: impl 'static + ActivationHandler + Send,
186        action_handler: impl 'static + ActionHandler + Send,
187        deactivation_handler: impl 'static + DeactivationHandler + Send,
188    ) -> Self {
189        let inner = platform_impl::Adapter::new(
190            event_loop,
191            window,
192            activation_handler,
193            action_handler,
194            deactivation_handler,
195        );
196        Self { inner }
197    }
198
199    /// Creates a new AccessKit adapter for a winit window. This must be done
200    /// before the window is shown for the first time. This means that you must
201    /// use [`winit::window::WindowAttributes::with_visible`] to make the window
202    /// initially invisible, then create the adapter, then show the window.
203    ///
204    /// This constructor provides a mix of the approaches used by
205    /// [`Adapter::with_event_loop_proxy`] and [`Adapter::with_direct_handlers`].
206    /// It uses the event loop proxy for the action request and deactivation
207    /// events, which can be handled asynchronously with no drawback,
208    /// while using a direct, caller-provided activation handler that can
209    /// return the initial tree synchronously. Remember that the thread on which
210    /// the activation handler is called is platform-dependent.
211    pub fn with_mixed_handlers<T: From<Event> + Send + 'static>(
212        event_loop: &ActiveEventLoop,
213        window: &Window,
214        activation_handler: impl 'static + ActivationHandler + Send,
215        proxy: EventLoopProxy<T>,
216    ) -> Self {
217        let window_id = window.id();
218        let action_handler = WinitActionHandler {
219            window_id,
220            proxy: proxy.clone(),
221        };
222        let deactivation_handler = WinitDeactivationHandler { window_id, proxy };
223        Self::with_direct_handlers(
224            event_loop,
225            window,
226            activation_handler,
227            action_handler,
228            deactivation_handler,
229        )
230    }
231
232    /// Allows reacting to window events.
233    ///
234    /// This must be called whenever a new window event is received
235    /// and before it is handled by the application.
236    pub fn process_event(&mut self, window: &Window, event: &WinitWindowEvent) {
237        self.inner.process_event(window, event);
238    }
239
240    /// If and only if the tree has been initialized, call the provided function
241    /// and apply the resulting update. Note: If the caller's implementation of
242    /// [`ActivationHandler::request_initial_tree`] initially returned `None`,
243    /// or if the caller created the adapter using [`EventLoopProxy`], then
244    /// the [`TreeUpdate`] returned by the provided function must contain
245    /// a full tree.
246    pub fn update_if_active(&mut self, updater: impl FnOnce() -> TreeUpdate) {
247        self.inner.update_if_active(updater);
248    }
249}