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