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