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            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}