atspi_proxies/accessible.rs
1//! # `AccessibleProxy`
2//!
3//! A handle for a remote object implementing the `org.a11y.atspi.Accessible`
4//! interface.
5//!
6//! Accessible is the interface which is implemented by all accessible objects.
7//!
8
9use crate::common::{InterfaceSet, ObjectRef, RelationType, Role, StateSet};
10use crate::AtspiError;
11use atspi_common::object_ref::ObjectRefOwned;
12use zbus::names::BusName;
13
14/// # `AccessibleProxy`
15///
16/// A handle for a remote object implementing the `org.a11y.atspi.Accessible`
17/// interface.
18///
19/// Accessible is the interface which is implemented by all accessible objects.
20///
21#[zbus::proxy(
22 interface = "org.a11y.atspi.Accessible",
23 default_path = "/org/a11y/atspi/accessible/root",
24 assume_defaults = true
25)]
26pub trait Accessible {
27 /// Returns an [`ObjectRef`] which refers to the `Application` object of the application.
28 /// This object will have [`Application`] interface implemented.
29 ///
30 /// The application object is the root of the accessibility hierarchy for the application.
31 /// It is the only object in the hierarchy that does not have a parent.
32 ///
33 /// ## Notes
34 /// The application object is the only object in the accessibility hierarchy that is
35 /// guaranteed to be persistent for the lifetime of the application.
36 /// All other objects in the accessibility hierarchy may be created and destroyed dynamically.
37 ///
38 /// [`ObjectRef`]: [`crate::common::events::ObjectRef`]
39 /// [`Application`]: [`crate::application::ApplicationProxy`]
40 fn get_application(&self) -> zbus::Result<ObjectRefOwned>;
41
42 /// Gets a list of name/value pairs of attributes or annotations for this object.
43 ///
44 /// ## Disambiguation
45 /// For typographic, textual, or textually-semantic attributes,
46 /// see [`TextProxy`]'s [`get_attributes`] method instead.
47 ///
48 /// [`TextProxy`]: [`crate::text::TextProxy`]
49 /// [`get_attributes`]: [`crate::text::TextProxy#method.get_attributes`]
50 fn get_attributes(&self) -> zbus::Result<std::collections::HashMap<String, String>>;
51
52 /// Retrieve child by index (starting from 0),
53 ///
54 /// Queries the N-th accessible child of `self`. It is expected that this
55 /// will correspond to the order that the [`get_children`] method would return.
56 ///
57 /// ## Notes
58 /// Implementations vary in their behavior when the index is out of range.
59 /// GTK4 returns an error, while atk-adaptor (e.g. Gtk3) returns the
60 /// null object path "/org/a11y/atspi/null".
61 ///
62 /// Documentation advises implementors to return a `DBus` Error when the index is
63 /// out of range, to "keep the type system gods happy".
64 ///
65 /// [`get_children`]: #method.get_children
66 fn get_child_at_index(&self, index: i32) -> zbus::Result<ObjectRefOwned>;
67
68 /// Retrieves a list of the object's accessible children.
69 ///
70 /// Each array element is an [`Accessible`] representing the accessible child object.
71 ///
72 /// ## Registry
73 ///
74 /// On the [`Accessible`] interface of `org.a11y.atspi.Registry`, the registry daemon, this method retrieves a list
75 /// of all accessible applications' root objects on the bus.
76 ///
77 /// [`Accessible`]: [`crate::accessible::AccessibleProxy`]
78 fn get_children(&self) -> zbus::Result<Vec<ObjectRefOwned>>;
79
80 /// This object resides in its parent's list of children.
81 /// This returns its position in this list of children, starting from 0.
82 ///
83 /// The function returns -1 if the object does not have a parent or
84 /// if an exception occurs.
85 fn get_index_in_parent(&self) -> zbus::Result<i32>;
86
87 /// Returns an [`InterfaceSet`] accessible interface names supported by the `self` object.
88 /// [`InterfaceSet`]: [`crate::common::InterfaceSet`]
89 fn get_interfaces(&self) -> zbus::Result<InterfaceSet>;
90
91 /// Gets a `String` corresponding to the name of the role played by an object,
92 /// translated to the current locale.
93 ///
94 /// ## Notes
95 ///
96 /// This method will return useful values for roles that fall outside the
97 /// enumeration used in the [`get_role`] method.
98 ///
99 /// For applications, implementing this method is optional, and it may be removed
100 /// in a future version of the API.
101 ///
102 /// For example, [`libatspi`] will only call it in the event of an unknown role.
103 ///
104 /// [`libatspi`]: <https://gitlab.gnome.org/GNOME/at-spi2-core/main/atspi>
105 /// [`get_role`]: #method.get_role
106 fn get_localized_role_name(&self) -> zbus::Result<String>;
107
108 /// Returns a set of relationships between the this `self` object and others.
109 ///
110 /// This vector of tuples contains a [`RelationType`] and a vector of [`Accessible`]'s to which that
111 /// relationship applies.
112 /// These relationships allow for better identification of how objects are associated with one another.
113 ///
114 /// For example, the relationship [`RelationType::LabelledBy`] can be used to identify labeling information
115 /// that should accompany the accessible [`name`] property when presenting an object's content or identity
116 /// to the end user.
117 ///
118 /// Similarly, [`RelationType::ControllerFor`] can be used to specify the context in which a valuator is useful
119 /// and/or the other UI components that are directly affected by user interactions with the valuator.
120 /// Common examples include the association of scrollbars with the viewport or panel that they control.
121 ///
122 /// [`RelationType`]: [`crate::common::RelationType`]
123 /// [`RelationType::LabelledBy`]: [`crate::common::RelationType::LabelledBy`]
124 /// [`RelationType::ControllerFor`]: [`crate::common::RelationType::ControllerFor`]
125 /// [`name`]: #method.name
126 /// [`Accessible`]: [`crate::common::events::Accessible`]
127 fn get_relation_set(&self) -> zbus::Result<Vec<(RelationType, Vec<ObjectRefOwned>)>>;
128
129 /// Gets the [`Role`] that the current accessible object represents.
130 ///
131 /// Roles make it possible for various UI toolkits to expose their controls to
132 /// assistive technologies (ATs) with a standard interface, regardless of toolkit.
133 ///
134 /// For example, a widget that acts like a conventional push button
135 /// (appears unpressed; presses when acted upon; invokes a certain action
136 /// when pressed) can expose an [`Role::Button`] role.
137 ///
138 /// [`Role::Button`]: [`crate::common::Role::Button`]
139 /// [`Role`]: [`crate::common::Role`]
140 fn get_role(&self) -> zbus::Result<Role>;
141
142 /// Gets a `String` corresponding to the name of the role played by an object,
143 /// translated to the current locale.
144 ///
145 /// ## Notes
146 ///
147 /// This method will return useful values for roles that fall outside the
148 /// enumeration used in the `get_role` method.
149 ///
150 /// For applications, implementing this method is optional, and it may be removed
151 /// in a future version of the API.
152 ///
153 /// [`libatspi`]: <https://gitlab.gnome.org/GNOME/at-spi2-core/main/atspi>
154 /// [`libatspi`]: <https://gitlab.gnome.org/GNOME/at-spi2-core/>
155 fn get_role_name(&self) -> zbus::Result<String>;
156
157 /// Method to retrieve the [`StateSet`] of states currently held by `self`.
158 /// [`StateSet`]: [`crate::common::StateSet`]
159 fn get_state(&self) -> zbus::Result<StateSet>;
160
161 /// Application-specific identifier for the current object.
162 ///
163 /// A special id given to an object.
164 /// Accessible application developers can use this to give a special id to an object
165 /// to use in tests, for example, "`my_widget`".
166 ///
167 /// Note that there is no way to directly find an object by its id;
168 /// a test program may have to recursively get the children to find a specific id.
169 /// This is because accessible objects can be created dynamically, and they do not always
170 /// correspond to a static view of an application's data.
171 #[zbus(property)]
172 fn accessible_id(&self) -> zbus::Result<String>;
173
174 /// Number of accessible children for the current object.
175 #[zbus(property)]
176 fn child_count(&self) -> zbus::Result<i32>;
177
178 /// Human-readable, localized description of `self` in more detail.
179 ///
180 /// This is a longer description than the [`Name`][name] property.
181 ///
182 /// For example, a button might have a name of "OK", but a description of "OK button".
183 ///
184 /// While the Name property is meant to be a short string that screen readers say
185 /// during normal navigation, the Description property is for when the user asks for
186 /// more detail.
187 ///
188 /// [name]: #method.name
189 #[zbus(property)]
190 fn description(&self) -> zbus::Result<String>;
191
192 /// Unix locale for the current object.
193 ///
194 /// This is a string in the form of "`language_territory.codeset`".
195 /// For example, "en_US.UTF-8" or "de_DE.UTF-8".
196 ///
197 /// For an application, this may be the locale for the language that the application
198 /// shows in its user interface.
199 ///
200 /// For a document being shown in an application, or a paragraph within a document,
201 /// the locale may refer to that object exclusively. For example:
202 /// an application may be showing itself in English ("en"), but it may be used to
203 /// display a document in Spanish ("es").
204 /// In the latter case, a screen reader will want to know that it should switch to
205 /// Spanish while reading the document.
206 #[zbus(property)]
207 fn locale(&self) -> zbus::Result<String>;
208
209 /// Human-readable, localized, short name for the object.
210 ///
211 /// Applications should have this set for objects which do not
212 /// have a [`RelationType::LabelledBy`] relation.
213 ///
214 /// Consider a widget to select RGB colors by setting three sliders.
215 /// The names for the sliders would be "Red", "Green", "Blue", respectively, or
216 /// their translations to application's locale. The names would be unnecessary if each
217 /// slider had a `LabeledBy` relation to corresponding labels visible in the user
218 /// interface.
219 ///
220 /// [`RelationType::LabelledBy`]: [`crate::common::RelationType::LabelledBy`]
221 #[zbus(property)]
222 fn name(&self) -> zbus::Result<String>;
223
224 /// `ObjectRef` parent object of the current object.
225 ///
226 /// Null parent:
227 /// If the object has no parent (e.g. the application's root object is being queried),
228 /// The application should return "" for the application name name and "/org/a11y/atspi/null"
229 /// for the object path.
230 ///
231 /// Root object:
232 /// An application must have a single root object, called "/org/a11y/atspi/accessible/root".
233 /// All other objects should have that one as their highest-level ancestor.
234 #[zbus(property)]
235 fn parent(&self) -> zbus::Result<ObjectRefOwned>;
236
237 /// Help text for the current object.
238 #[zbus(property)]
239 fn help_text(&self) -> zbus::Result<String>;
240}
241
242impl TryFrom<AccessibleProxy<'_>> for ObjectRefOwned {
243 type Error = AtspiError;
244 fn try_from(proxy: AccessibleProxy<'_>) -> Result<ObjectRefOwned, Self::Error> {
245 let sender = proxy.inner().destination();
246 let path = proxy.inner().path();
247 let object_ref = ObjectRef::try_from_bus_name_and_path(sender.into(), path.into())?;
248 Ok(ObjectRefOwned::from(object_ref))
249 }
250}
251
252impl TryFrom<&AccessibleProxy<'_>> for ObjectRefOwned {
253 type Error = AtspiError;
254 fn try_from(proxy: &AccessibleProxy<'_>) -> Result<ObjectRefOwned, Self::Error> {
255 let sender = proxy.inner().destination().clone();
256 let path = proxy.inner().path().clone();
257 let object_ref = ObjectRef::try_from_bus_name_and_path(sender, path)?;
258 Ok(ObjectRefOwned::from(object_ref))
259 }
260}
261
262pub trait ObjectRefExt {
263 /// Returns an [`AccessibleProxy`], the handle to the object's `Accessible` interface.
264 ///
265 /// # Errors
266 /// If the `ObjectRef` is null, this method returns an error.
267 /// Users are advised to check if the `ObjectRef` is null before calling this method.
268 fn as_accessible_proxy(
269 &self,
270 conn: &zbus::Connection,
271 ) -> impl std::future::Future<Output = Result<AccessibleProxy<'_>, AtspiError>> + Send;
272
273 /// Returns an [`AccessibleProxy`], the handle to the object's `Accessible` interface.
274 ///
275 /// # Errors
276 /// If the `ObjectRef` is null, this method returns an error.
277 /// Users are advised to check if the `ObjectRef` is null before calling this method.
278 fn into_accessible_proxy(
279 self,
280 conn: &zbus::Connection,
281 ) -> impl std::future::Future<Output = Result<AccessibleProxy<'_>, AtspiError>> + Send;
282}
283
284impl ObjectRefExt for ObjectRefOwned {
285 async fn as_accessible_proxy(
286 &self,
287 conn: &zbus::Connection,
288 ) -> Result<AccessibleProxy<'_>, AtspiError> {
289 if self.is_null() {
290 return Err(AtspiError::NullRef(
291 "`as_accessible_proxy` called on null-reference ObjectRef",
292 ));
293 }
294
295 let name: BusName = self.name().ok_or(AtspiError::MissingName)?.clone().into();
296 let path = self.path();
297
298 AccessibleProxy::builder(conn)
299 .destination(name)?
300 .path(path)?
301 .cache_properties(zbus::proxy::CacheProperties::No)
302 .build()
303 .await
304 .map_err(AtspiError::from)
305 }
306
307 async fn into_accessible_proxy(
308 self,
309 conn: &zbus::Connection,
310 ) -> Result<AccessibleProxy<'_>, AtspiError> {
311 if self.is_null() {
312 return Err(AtspiError::NullRef(
313 "`into_accessible_proxy` called on null-reference ObjectRef",
314 ));
315 }
316
317 let name: BusName = self.name().ok_or(AtspiError::MissingName)?.clone().into();
318 let path = self.path();
319
320 AccessibleProxy::builder(conn)
321 .destination(name)?
322 .path(path)?
323 .cache_properties(zbus::proxy::CacheProperties::No)
324 .build()
325 .await
326 .map_err(AtspiError::from)
327 }
328}
329
330#[cfg(test)]
331mod tests {
332 use crate::accessible::Role;
333
334 #[test]
335 fn test_output_of_role_name() {
336 assert_eq!(Role::Invalid.name(), "invalid");
337 assert_eq!(Role::PushButtonMenu.name(), "push button menu");
338 }
339}