1 | // Copyright 2023 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 | |
6 | use accesskit::{ActivationHandler, DeactivationHandler}; |
7 | use accesskit_atspi_common::{Adapter as AdapterImpl, AppContext, Event}; |
8 | #[cfg (not(feature = "tokio" ))] |
9 | use async_channel::{Receiver, Sender}; |
10 | use atspi::proxy::bus::StatusProxy; |
11 | #[cfg (not(feature = "tokio" ))] |
12 | use futures_util::{pin_mut as pin, select, StreamExt}; |
13 | use std::{ |
14 | sync::{Arc, Mutex, OnceLock, RwLock}, |
15 | thread, |
16 | }; |
17 | #[cfg (feature = "tokio" )] |
18 | use tokio::{ |
19 | pin, select, |
20 | sync::mpsc::{UnboundedReceiver as Receiver, UnboundedSender as Sender}, |
21 | }; |
22 | #[cfg (feature = "tokio" )] |
23 | use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; |
24 | use zbus::{Connection, ConnectionBuilder}; |
25 | |
26 | use crate::{ |
27 | adapter::{AdapterState, Callback, Message}, |
28 | atspi::{map_or_ignoring_broken_pipe, Bus}, |
29 | executor::Executor, |
30 | util::block_on, |
31 | }; |
32 | |
33 | static APP_CONTEXT: OnceLock<Arc<RwLock<AppContext>>> = OnceLock::new(); |
34 | static MESSAGES: OnceLock<Sender<Message>> = OnceLock::new(); |
35 | |
36 | pub(crate) fn get_or_init_app_context<'a>() -> &'a Arc<RwLock<AppContext>> { |
37 | APP_CONTEXT.get_or_init(AppContext::new) |
38 | } |
39 | |
40 | pub(crate) fn get_or_init_messages() -> Sender<Message> { |
41 | MESSAGES&Sender |
42 | .get_or_init(|| { |
43 | #[cfg (not(feature = "tokio" ))] |
44 | let (tx: Sender, rx: Receiver) = async_channel::unbounded(); |
45 | #[cfg (feature = "tokio" )] |
46 | let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); |
47 | |
48 | thread::spawn(|| { |
49 | let executor: Executor<'_> = Executor::new(); |
50 | block_on(future:executor.run(future:async { |
51 | if let Ok(session_bus: Builder<'_>) = ConnectionBuilder::session() { |
52 | if let Ok(session_bus: Connection) = session_bus.internal_executor(enabled:false).build().await |
53 | { |
54 | run_event_loop(&executor, session_bus, rx).await.unwrap(); |
55 | } |
56 | } |
57 | })) |
58 | }); |
59 | |
60 | tx |
61 | }) |
62 | .clone() |
63 | } |
64 | |
65 | struct AdapterEntry { |
66 | id: usize, |
67 | activation_handler: Box<dyn ActivationHandler>, |
68 | deactivation_handler: Box<dyn DeactivationHandler>, |
69 | state: Arc<Mutex<AdapterState>>, |
70 | } |
71 | |
72 | fn activate_adapter(entry: &mut AdapterEntry) { |
73 | let mut state = entry.state.lock().unwrap(); |
74 | if let AdapterState::Inactive { |
75 | is_window_focused, |
76 | root_window_bounds, |
77 | action_handler, |
78 | } = &*state |
79 | { |
80 | *state = match entry.activation_handler.request_initial_tree() { |
81 | Some(initial_state) => { |
82 | let r#impl = AdapterImpl::with_wrapped_action_handler( |
83 | entry.id, |
84 | get_or_init_app_context(), |
85 | Callback::new(), |
86 | initial_state, |
87 | *is_window_focused, |
88 | *root_window_bounds, |
89 | Arc::clone(action_handler), |
90 | ); |
91 | AdapterState::Active(r#impl) |
92 | } |
93 | None => AdapterState::Pending { |
94 | is_window_focused: *is_window_focused, |
95 | root_window_bounds: *root_window_bounds, |
96 | action_handler: Arc::clone(action_handler), |
97 | }, |
98 | }; |
99 | } |
100 | } |
101 | |
102 | fn deactivate_adapter(entry: &mut AdapterEntry) { |
103 | let mut state = entry.state.lock().unwrap(); |
104 | match &*state { |
105 | AdapterState::Inactive { .. } => (), |
106 | AdapterState::Pending { |
107 | is_window_focused, |
108 | root_window_bounds, |
109 | action_handler, |
110 | } => { |
111 | *state = AdapterState::Inactive { |
112 | is_window_focused: *is_window_focused, |
113 | root_window_bounds: *root_window_bounds, |
114 | action_handler: Arc::clone(action_handler), |
115 | }; |
116 | drop(state); |
117 | entry.deactivation_handler.deactivate_accessibility(); |
118 | } |
119 | AdapterState::Active(r#impl) => { |
120 | *state = AdapterState::Inactive { |
121 | is_window_focused: r#impl.is_window_focused(), |
122 | root_window_bounds: r#impl.root_window_bounds(), |
123 | action_handler: r#impl.wrapped_action_handler(), |
124 | }; |
125 | drop(state); |
126 | entry.deactivation_handler.deactivate_accessibility(); |
127 | } |
128 | } |
129 | } |
130 | |
131 | async fn run_event_loop( |
132 | executor: &Executor<'_>, |
133 | session_bus: Connection, |
134 | rx: Receiver<Message>, |
135 | ) -> zbus::Result<()> { |
136 | let session_bus_copy = session_bus.clone(); |
137 | let _session_bus_task = executor.spawn( |
138 | async move { |
139 | loop { |
140 | session_bus_copy.executor().tick().await; |
141 | } |
142 | }, |
143 | "accesskit_session_bus_task" , |
144 | ); |
145 | |
146 | let status = StatusProxy::new(&session_bus).await?; |
147 | let changes = status.receive_is_enabled_changed().await.fuse(); |
148 | pin!(changes); |
149 | |
150 | #[cfg (not(feature = "tokio" ))] |
151 | let messages = rx.fuse(); |
152 | #[cfg (feature = "tokio" )] |
153 | let messages = UnboundedReceiverStream::new(rx).fuse(); |
154 | pin!(messages); |
155 | |
156 | let mut atspi_bus = None; |
157 | let mut adapters: Vec<AdapterEntry> = Vec::new(); |
158 | |
159 | loop { |
160 | select! { |
161 | change = changes.next() => { |
162 | atspi_bus = None; |
163 | if let Some(change) = change { |
164 | if change.get().await? { |
165 | atspi_bus = map_or_ignoring_broken_pipe(Bus::new(&session_bus, executor).await, None, Some)?; |
166 | } |
167 | } |
168 | for entry in &mut adapters { |
169 | if atspi_bus.is_some() { |
170 | activate_adapter(entry); |
171 | } else { |
172 | deactivate_adapter(entry); |
173 | } |
174 | } |
175 | } |
176 | message = messages.next() => { |
177 | if let Some(message) = message { |
178 | process_adapter_message(&atspi_bus, &mut adapters, message).await?; |
179 | } |
180 | } |
181 | } |
182 | } |
183 | } |
184 | |
185 | async fn process_adapter_message( |
186 | atspi_bus: &Option<Bus>, |
187 | adapters: &mut Vec<AdapterEntry>, |
188 | message: Message, |
189 | ) -> zbus::Result<()> { |
190 | match message { |
191 | Message::AddAdapter { |
192 | id, |
193 | activation_handler, |
194 | deactivation_handler, |
195 | state, |
196 | } => { |
197 | adapters.push(AdapterEntry { |
198 | id, |
199 | activation_handler, |
200 | deactivation_handler, |
201 | state, |
202 | }); |
203 | if atspi_bus.is_some() { |
204 | let entry = adapters.last_mut().unwrap(); |
205 | activate_adapter(entry); |
206 | } |
207 | } |
208 | Message::RemoveAdapter { id } => { |
209 | if let Ok(index) = adapters.binary_search_by(|entry| entry.id.cmp(&id)) { |
210 | adapters.remove(index); |
211 | } |
212 | } |
213 | Message::RegisterInterfaces { node, interfaces } => { |
214 | if let Some(bus) = atspi_bus { |
215 | bus.register_interfaces(node, interfaces).await? |
216 | } |
217 | } |
218 | Message::UnregisterInterfaces { |
219 | adapter_id, |
220 | node_id, |
221 | interfaces, |
222 | } => { |
223 | if let Some(bus) = atspi_bus { |
224 | bus.unregister_interfaces(adapter_id, node_id, interfaces) |
225 | .await? |
226 | } |
227 | } |
228 | Message::EmitEvent { |
229 | adapter_id, |
230 | event: Event::Object { target, event }, |
231 | } => { |
232 | if let Some(bus) = atspi_bus { |
233 | bus.emit_object_event(adapter_id, target, event).await? |
234 | } |
235 | } |
236 | Message::EmitEvent { |
237 | adapter_id, |
238 | event: |
239 | Event::Window { |
240 | target, |
241 | name, |
242 | event, |
243 | }, |
244 | } => { |
245 | if let Some(bus) = atspi_bus { |
246 | bus.emit_window_event(adapter_id, target, name, event) |
247 | .await?; |
248 | } |
249 | } |
250 | } |
251 | |
252 | Ok(()) |
253 | } |
254 | |