accesskit_unix/atspi/
bus.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 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}