1use crate::{
7 atspi::{interfaces::*, ObjectId},
8 context::get_or_init_app_context,
9 executor::{Executor, Task},
10};
11use accesskit::NodeId;
12use accesskit_atspi_common::{
13 NodeIdOrRoot, ObjectEvent, PlatformNode, PlatformRoot, Property, WindowEvent,
14};
15use atspi::{
16 events::EventBody,
17 proxy::{bus::BusProxy, socket::SocketProxy},
18 Interface, InterfaceSet,
19};
20use serde::Serialize;
21use std::{collections::HashMap, env::var, io};
22use zbus::{
23 names::{BusName, InterfaceName, MemberName, OwnedUniqueName},
24 zvariant::{Str, Value},
25 Address, Connection, ConnectionBuilder, Result,
26};
27
28pub(crate) struct Bus {
29 conn: Connection,
30 _task: Task<()>,
31 socket_proxy: SocketProxy<'static>,
32}
33
34impl Bus {
35 pub(crate) async fn new(
36 session_bus: &Connection,
37 executor: &Executor<'_>,
38 ) -> zbus::Result<Self> {
39 let address = match var("AT_SPI_BUS_ADDRESS") {
40 Ok(address) if !address.is_empty() => address,
41 _ => BusProxy::new(session_bus).await?.get_address().await?,
42 };
43 let address: Address = address.as_str().try_into()?;
44 let conn = ConnectionBuilder::address(address)?
45 .internal_executor(false)
46 .build()
47 .await?;
48 let conn_copy = conn.clone();
49 let _task = executor.spawn(
50 async move {
51 loop {
52 conn_copy.executor().tick().await;
53 }
54 },
55 "accesskit_atspi_bus_task",
56 );
57 let socket_proxy = SocketProxy::new(&conn).await?;
58 let mut bus = Bus {
59 conn,
60 _task,
61 socket_proxy,
62 };
63 bus.register_root_node().await?;
64 Ok(bus)
65 }
66
67 fn unique_name(&self) -> &OwnedUniqueName {
68 self.conn.unique_name().unwrap()
69 }
70
71 async fn register_root_node(&mut self) -> Result<()> {
72 let node = PlatformRoot::new(get_or_init_app_context());
73 let path = ObjectId::Root.path();
74
75 if self
76 .conn
77 .object_server()
78 .at(path.clone(), ApplicationInterface(node.clone()))
79 .await?
80 {
81 self.socket_proxy
82 .embed(&(self.unique_name().as_str(), ObjectId::Root.path().into()))
83 .await?;
84
85 self.conn
86 .object_server()
87 .at(
88 path,
89 RootAccessibleInterface::new(self.unique_name().to_owned(), node),
90 )
91 .await?;
92 }
93
94 Ok(())
95 }
96
97 pub(crate) async fn register_interfaces(
98 &self,
99 node: PlatformNode,
100 new_interfaces: InterfaceSet,
101 ) -> zbus::Result<()> {
102 let path = ObjectId::from(&node).path();
103 let bus_name = self.unique_name().to_owned();
104 if new_interfaces.contains(Interface::Accessible) {
105 self.register_interface(
106 &path,
107 NodeAccessibleInterface::new(bus_name.clone(), node.clone()),
108 )
109 .await?;
110 }
111 if new_interfaces.contains(Interface::Action) {
112 self.register_interface(&path, ActionInterface::new(node.clone()))
113 .await?;
114 }
115 if new_interfaces.contains(Interface::Component) {
116 self.register_interface(
117 &path,
118 ComponentInterface::new(bus_name.clone(), node.clone()),
119 )
120 .await?;
121 }
122 if new_interfaces.contains(Interface::Text) {
123 self.register_interface(&path, TextInterface::new(node.clone()))
124 .await?;
125 }
126 if new_interfaces.contains(Interface::Value) {
127 self.register_interface(&path, ValueInterface::new(node.clone()))
128 .await?;
129 }
130
131 Ok(())
132 }
133
134 async fn register_interface<T>(&self, path: &str, interface: T) -> Result<bool>
135 where
136 T: zbus::Interface,
137 {
138 map_or_ignoring_broken_pipe(
139 self.conn.object_server().at(path, interface).await,
140 false,
141 |result| result,
142 )
143 }
144
145 pub(crate) async fn unregister_interfaces(
146 &self,
147 adapter_id: usize,
148 node_id: NodeId,
149 old_interfaces: InterfaceSet,
150 ) -> zbus::Result<()> {
151 let path = ObjectId::Node {
152 adapter: adapter_id,
153 node: node_id,
154 }
155 .path();
156 if old_interfaces.contains(Interface::Accessible) {
157 self.unregister_interface::<NodeAccessibleInterface>(&path)
158 .await?;
159 }
160 if old_interfaces.contains(Interface::Action) {
161 self.unregister_interface::<ActionInterface>(&path).await?;
162 }
163 if old_interfaces.contains(Interface::Component) {
164 self.unregister_interface::<ComponentInterface>(&path)
165 .await?;
166 }
167 if old_interfaces.contains(Interface::Text) {
168 self.unregister_interface::<TextInterface>(&path).await?;
169 }
170 if old_interfaces.contains(Interface::Value) {
171 self.unregister_interface::<ValueInterface>(&path).await?;
172 }
173
174 Ok(())
175 }
176
177 async fn unregister_interface<T>(&self, path: &str) -> Result<bool>
178 where
179 T: zbus::Interface,
180 {
181 map_or_ignoring_broken_pipe(
182 self.conn.object_server().remove::<T, _>(path).await,
183 false,
184 |result| result,
185 )
186 }
187
188 pub(crate) async fn emit_object_event(
189 &self,
190 adapter_id: usize,
191 target: NodeIdOrRoot,
192 event: ObjectEvent,
193 ) -> Result<()> {
194 let target = match target {
195 NodeIdOrRoot::Node(node) => ObjectId::Node {
196 adapter: adapter_id,
197 node,
198 },
199 NodeIdOrRoot::Root => ObjectId::Root,
200 };
201 let interface = "org.a11y.atspi.Event.Object";
202 let signal = match event {
203 ObjectEvent::ActiveDescendantChanged(_) => "ActiveDescendantChanged",
204 ObjectEvent::Announcement(_, _) => "Announcement",
205 ObjectEvent::BoundsChanged(_) => "BoundsChanged",
206 ObjectEvent::CaretMoved(_) => "TextCaretMoved",
207 ObjectEvent::ChildAdded(_, _) | ObjectEvent::ChildRemoved(_) => "ChildrenChanged",
208 ObjectEvent::PropertyChanged(_) => "PropertyChange",
209 ObjectEvent::StateChanged(_, _) => "StateChanged",
210 ObjectEvent::TextInserted { .. } | ObjectEvent::TextRemoved { .. } => "TextChanged",
211 ObjectEvent::TextSelectionChanged => "TextSelectionChanged",
212 };
213 let properties = HashMap::new();
214 match event {
215 ObjectEvent::ActiveDescendantChanged(child) => {
216 let child = ObjectId::Node {
217 adapter: adapter_id,
218 node: child,
219 };
220 self.emit_event(
221 target,
222 interface,
223 signal,
224 EventBody {
225 kind: "",
226 detail1: 0,
227 detail2: 0,
228 any_data: child.to_address(self.unique_name().inner()).into(),
229 properties,
230 },
231 )
232 .await
233 }
234 ObjectEvent::Announcement(message, politeness) => {
235 self.emit_event(
236 target,
237 interface,
238 signal,
239 EventBody {
240 kind: "",
241 detail1: politeness as i32,
242 detail2: 0,
243 any_data: message.into(),
244 properties,
245 },
246 )
247 .await
248 }
249 ObjectEvent::BoundsChanged(bounds) => {
250 self.emit_event(
251 target,
252 interface,
253 signal,
254 EventBody {
255 kind: "",
256 detail1: 0,
257 detail2: 0,
258 any_data: Value::from(bounds),
259 properties,
260 },
261 )
262 .await
263 }
264 ObjectEvent::CaretMoved(offset) => {
265 self.emit_event(
266 target,
267 interface,
268 signal,
269 EventBody {
270 kind: "",
271 detail1: offset,
272 detail2: 0,
273 any_data: "".into(),
274 properties,
275 },
276 )
277 .await
278 }
279 ObjectEvent::ChildAdded(index, child) => {
280 let child = ObjectId::Node {
281 adapter: adapter_id,
282 node: child,
283 };
284 self.emit_event(
285 target,
286 interface,
287 signal,
288 EventBody {
289 kind: "add",
290 detail1: index as i32,
291 detail2: 0,
292 any_data: child.to_address(self.unique_name().inner()).into(),
293 properties,
294 },
295 )
296 .await
297 }
298 ObjectEvent::ChildRemoved(child) => {
299 let child = ObjectId::Node {
300 adapter: adapter_id,
301 node: child,
302 };
303 self.emit_event(
304 target,
305 interface,
306 signal,
307 EventBody {
308 kind: "remove",
309 detail1: -1,
310 detail2: 0,
311 any_data: child.to_address(self.unique_name().inner()).into(),
312 properties,
313 },
314 )
315 .await
316 }
317 ObjectEvent::PropertyChanged(property) => {
318 self.emit_event(
319 target,
320 interface,
321 signal,
322 EventBody {
323 kind: match property {
324 Property::Name(_) => "accessible-name",
325 Property::Description(_) => "accessible-description",
326 Property::Parent(_) => "accessible-parent",
327 Property::Role(_) => "accessible-role",
328 Property::Value(_) => "accessible-value",
329 },
330 detail1: 0,
331 detail2: 0,
332 any_data: match property {
333 Property::Name(value) => Str::from(value).into(),
334 Property::Description(value) => Str::from(value).into(),
335 Property::Parent(parent) => {
336 let parent = match parent {
337 NodeIdOrRoot::Node(node) => ObjectId::Node {
338 adapter: adapter_id,
339 node,
340 },
341 NodeIdOrRoot::Root => ObjectId::Root,
342 };
343 parent.to_address(self.unique_name().inner()).into()
344 }
345 Property::Role(value) => Value::U32(value as u32),
346 Property::Value(value) => Value::F64(value),
347 },
348 properties,
349 },
350 )
351 .await
352 }
353 ObjectEvent::StateChanged(state, value) => {
354 self.emit_event(
355 target,
356 interface,
357 signal,
358 EventBody {
359 kind: state,
360 detail1: value as i32,
361 detail2: 0,
362 any_data: 0i32.into(),
363 properties,
364 },
365 )
366 .await
367 }
368 ObjectEvent::TextInserted {
369 start_index,
370 length,
371 content,
372 } => {
373 self.emit_event(
374 target,
375 interface,
376 signal,
377 EventBody {
378 kind: "insert",
379 detail1: start_index,
380 detail2: length,
381 any_data: content.into(),
382 properties,
383 },
384 )
385 .await
386 }
387 ObjectEvent::TextRemoved {
388 start_index,
389 length,
390 content,
391 } => {
392 self.emit_event(
393 target,
394 interface,
395 signal,
396 EventBody {
397 kind: "delete",
398 detail1: start_index,
399 detail2: length,
400 any_data: content.into(),
401 properties,
402 },
403 )
404 .await
405 }
406 ObjectEvent::TextSelectionChanged => {
407 self.emit_event(
408 target,
409 interface,
410 signal,
411 EventBody {
412 kind: "",
413 detail1: 0,
414 detail2: 0,
415 any_data: "".into(),
416 properties,
417 },
418 )
419 .await
420 }
421 }
422 }
423
424 pub(crate) async fn emit_window_event(
425 &self,
426 adapter_id: usize,
427 target: NodeId,
428 window_name: String,
429 event: WindowEvent,
430 ) -> Result<()> {
431 let target = ObjectId::Node {
432 adapter: adapter_id,
433 node: target,
434 };
435 let signal = match event {
436 WindowEvent::Activated => "Activate",
437 WindowEvent::Deactivated => "Deactivate",
438 };
439 self.emit_event(
440 target,
441 "org.a11y.atspi.Event.Window",
442 signal,
443 EventBody {
444 kind: "",
445 detail1: 0,
446 detail2: 0,
447 any_data: window_name.into(),
448 properties: HashMap::new(),
449 },
450 )
451 .await
452 }
453
454 async fn emit_event<T: Serialize>(
455 &self,
456 target: ObjectId,
457 interface: &str,
458 signal_name: &str,
459 body: EventBody<'_, T>,
460 ) -> Result<()> {
461 map_or_ignoring_broken_pipe(
462 self.conn
463 .emit_signal(
464 Option::<BusName>::None,
465 target.path(),
466 InterfaceName::from_str_unchecked(interface),
467 MemberName::from_str_unchecked(signal_name),
468 &body,
469 )
470 .await,
471 (),
472 |_| (),
473 )
474 }
475}
476
477pub(crate) fn map_or_ignoring_broken_pipe<T, U, F>(
478 result: zbus::Result<T>,
479 default: U,
480 f: F,
481) -> zbus::Result<U>
482where
483 F: FnOnce(T) -> U,
484{
485 match result {
486 Ok(result) => Ok(f(result)),
487 Err(zbus::Error::InputOutput(error)) if error.kind() == io::ErrorKind::BrokenPipe => {
488 Ok(default)
489 }
490 Err(error) => Err(error),
491 }
492}