accesskit_unix/
adapter.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) or the MIT license (found in
4// the LICENSE-MIT file), at your option.
5
6use accesskit::{ActionHandler, ActivationHandler, DeactivationHandler, NodeId, Rect, TreeUpdate};
7use accesskit_atspi_common::{
8    next_adapter_id, ActionHandlerNoMut, ActionHandlerWrapper, Adapter as AdapterImpl,
9    AdapterCallback, Event, PlatformNode, WindowBounds,
10};
11#[cfg(not(feature = "tokio"))]
12use async_channel::Sender;
13use atspi::InterfaceSet;
14use std::fmt::{Debug, Formatter};
15use std::sync::{Arc, Mutex};
16#[cfg(feature = "tokio")]
17use tokio::sync::mpsc::UnboundedSender as Sender;
18
19use crate::context::{get_or_init_app_context, get_or_init_messages};
20
21pub(crate) struct Callback {
22    messages: Sender<Message>,
23}
24
25impl Callback {
26    pub(crate) fn new() -> Self {
27        let messages = get_or_init_messages();
28        Self { messages }
29    }
30
31    fn send_message(&self, message: Message) {
32        #[cfg(not(feature = "tokio"))]
33        let _ = self.messages.try_send(message);
34        #[cfg(feature = "tokio")]
35        let _ = self.messages.send(message);
36    }
37}
38
39impl AdapterCallback for Callback {
40    fn register_interfaces(&self, adapter: &AdapterImpl, id: NodeId, interfaces: InterfaceSet) {
41        let node = adapter.platform_node(id);
42        self.send_message(Message::RegisterInterfaces { node, interfaces });
43    }
44
45    fn unregister_interfaces(&self, adapter: &AdapterImpl, id: NodeId, interfaces: InterfaceSet) {
46        self.send_message(Message::UnregisterInterfaces {
47            adapter_id: adapter.id(),
48            node_id: id,
49            interfaces,
50        })
51    }
52
53    fn emit_event(&self, adapter: &AdapterImpl, event: Event) {
54        self.send_message(Message::EmitEvent {
55            adapter_id: adapter.id(),
56            event,
57        });
58    }
59}
60
61pub(crate) enum AdapterState {
62    Inactive {
63        is_window_focused: bool,
64        root_window_bounds: WindowBounds,
65        action_handler: Arc<dyn ActionHandlerNoMut + Send + Sync>,
66    },
67    Pending {
68        is_window_focused: bool,
69        root_window_bounds: WindowBounds,
70        action_handler: Arc<dyn ActionHandlerNoMut + Send + Sync>,
71    },
72    Active(AdapterImpl),
73}
74
75impl Debug for AdapterState {
76    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
77        match self {
78            AdapterState::Inactive {
79                is_window_focused,
80                root_window_bounds,
81                action_handler: _,
82            } => f
83                .debug_struct("Inactive")
84                .field("is_window_focused", is_window_focused)
85                .field("root_window_bounds", root_window_bounds)
86                .field("action_handler", &"ActionHandler")
87                .finish(),
88            AdapterState::Pending {
89                is_window_focused,
90                root_window_bounds,
91                action_handler: _,
92            } => f
93                .debug_struct("Pending")
94                .field("is_window_focused", is_window_focused)
95                .field("root_window_bounds", root_window_bounds)
96                .field("action_handler", &"ActionHandler")
97                .finish(),
98            AdapterState::Active(r#impl) => f.debug_tuple("Active").field(r#impl).finish(),
99        }
100    }
101}
102
103#[derive(Debug)]
104pub struct Adapter {
105    messages: Sender<Message>,
106    id: usize,
107    state: Arc<Mutex<AdapterState>>,
108}
109
110impl Adapter {
111    /// Create a new Unix adapter.
112    ///
113    /// All of the handlers will always be called from another thread.
114    pub fn new(
115        activation_handler: impl 'static + ActivationHandler + Send,
116        action_handler: impl 'static + ActionHandler + Send,
117        deactivation_handler: impl 'static + DeactivationHandler + Send,
118    ) -> Self {
119        let id = next_adapter_id();
120        let messages = get_or_init_messages();
121        let state = Arc::new(Mutex::new(AdapterState::Inactive {
122            is_window_focused: false,
123            root_window_bounds: Default::default(),
124            action_handler: Arc::new(ActionHandlerWrapper::new(action_handler)),
125        }));
126        let adapter = Self {
127            id,
128            messages,
129            state: Arc::clone(&state),
130        };
131        adapter.send_message(Message::AddAdapter {
132            id,
133            activation_handler: Box::new(activation_handler),
134            deactivation_handler: Box::new(deactivation_handler),
135            state,
136        });
137        adapter
138    }
139
140    pub(crate) fn send_message(&self, message: Message) {
141        #[cfg(not(feature = "tokio"))]
142        let _ = self.messages.try_send(message);
143        #[cfg(feature = "tokio")]
144        let _ = self.messages.send(message);
145    }
146
147    /// Set the bounds of the top-level window. The outer bounds contain any
148    /// window decoration and borders.
149    ///
150    /// # Caveats
151    ///
152    /// Since an application can not get the position of its window under
153    /// Wayland, calling this method only makes sense under X11.
154    pub fn set_root_window_bounds(&mut self, outer: Rect, inner: Rect) {
155        let new_bounds = WindowBounds::new(outer, inner);
156        let mut state = self.state.lock().unwrap();
157        match &mut *state {
158            AdapterState::Inactive {
159                root_window_bounds, ..
160            } => {
161                *root_window_bounds = new_bounds;
162            }
163            AdapterState::Pending {
164                root_window_bounds, ..
165            } => {
166                *root_window_bounds = new_bounds;
167            }
168            AdapterState::Active(r#impl) => r#impl.set_root_window_bounds(new_bounds),
169        }
170    }
171
172    /// If and only if the tree has been initialized, call the provided function
173    /// and apply the resulting update. Note: If the caller's implementation of
174    /// [`ActivationHandler::request_initial_tree`] initially returned `None`,
175    /// the [`TreeUpdate`] returned by the provided function must contain
176    /// a full tree.
177    pub fn update_if_active(&mut self, update_factory: impl FnOnce() -> TreeUpdate) {
178        let mut state = self.state.lock().unwrap();
179        match &mut *state {
180            AdapterState::Inactive { .. } => (),
181            AdapterState::Pending {
182                is_window_focused,
183                root_window_bounds,
184                action_handler,
185            } => {
186                let initial_state = update_factory();
187                let r#impl = AdapterImpl::with_wrapped_action_handler(
188                    self.id,
189                    get_or_init_app_context(),
190                    Callback::new(),
191                    initial_state,
192                    *is_window_focused,
193                    *root_window_bounds,
194                    Arc::clone(action_handler),
195                );
196                *state = AdapterState::Active(r#impl);
197            }
198            AdapterState::Active(r#impl) => r#impl.update(update_factory()),
199        }
200    }
201
202    /// Update the tree state based on whether the window is focused.
203    pub fn update_window_focus_state(&mut self, is_focused: bool) {
204        let mut state = self.state.lock().unwrap();
205        match &mut *state {
206            AdapterState::Inactive {
207                is_window_focused, ..
208            } => {
209                *is_window_focused = is_focused;
210            }
211            AdapterState::Pending {
212                is_window_focused, ..
213            } => {
214                *is_window_focused = is_focused;
215            }
216            AdapterState::Active(r#impl) => r#impl.update_window_focus_state(is_focused),
217        }
218    }
219}
220
221impl Drop for Adapter {
222    fn drop(&mut self) {
223        self.send_message(Message::RemoveAdapter { id: self.id });
224    }
225}
226
227pub(crate) enum Message {
228    AddAdapter {
229        id: usize,
230        activation_handler: Box<dyn ActivationHandler + Send>,
231        deactivation_handler: Box<dyn DeactivationHandler + Send>,
232        state: Arc<Mutex<AdapterState>>,
233    },
234    RemoveAdapter {
235        id: usize,
236    },
237    RegisterInterfaces {
238        node: PlatformNode,
239        interfaces: InterfaceSet,
240    },
241    UnregisterInterfaces {
242        adapter_id: usize,
243        node_id: NodeId,
244        interfaces: InterfaceSet,
245    },
246    EmitEvent {
247        adapter_id: usize,
248        event: Event,
249    },
250}