1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
//! # `AccessibleProxy`
//!
//! A handle for a remote object implementing the `org.a11y.atspi.Accessible`
//! interface.
//!
//! Accessible is the interface which is implemented by all accessible objects.
//!

use crate::common::{InterfaceSet, ObjectRef, RelationType, Role, StateSet};
use crate::AtspiError;

/// # `AccessibleProxy`
///
/// A handle for a remote object implementing the `org.a11y.atspi.Accessible`
/// interface.
///
/// Accessible is the interface which is implemented by all accessible objects.
///
#[zbus::proxy(interface = "org.a11y.atspi.Accessible", assume_defaults = true)]
trait Accessible {
	/// Returns an [`ObjectRef`] which refers to the `Application` object of the application.
	/// This object will have [`Application`] interface implemented.
	///
	/// The application object is the root of the accessibility hierarchy for the application.
	/// It is the only object in the hierarchy that does not have a parent.
	///
	/// ## Notes
	/// The application object is the only object in the accessibility hierarchy that is
	/// guaranteed to be persistent for the lifetime of the application.
	/// All other objects in the accessibility hierarchy may be created and destroyed dynamically.
	///
	/// [`ObjectRef`]: ../crate::common::events::ObjectRef
	/// [`Application`]: crate::application::ApplicationProxy
	fn get_application(&self) -> zbus::Result<ObjectRef>;

	/// Gets a list of name/value pairs of attributes or annotations for this object.
	///
	/// ## Disambiguation
	/// For	typographic, textual, or textually-semantic attributes,
	/// see [`TextProxy`]'s [`get_attributes`] method instead.
	///
	/// [`TextProxy`]: crate::text::TextProxy
	/// [`get_attributes`]: crate::text::TextProxy#method.get_attributes
	fn get_attributes(&self) -> zbus::Result<std::collections::HashMap<String, String>>;

	/// Retrieve child by index (starting from 0),
	///
	/// Queries the N-th accessible child of `self`. It is expected that this
	/// will correspond to the order that the [`get_children`] method would return.
	///
	/// ## Notes
	/// Implementations vary in their behavior when the index is out of range.
	/// GTK4 returns an error, while atk-adaptor (e.g. Gtk3) returns the
	/// null object path "/org/a11y/atspi/null".
	///
	/// Documentation advises implementors to return a DBus Error when the index is
	/// out of range, to "keep the type system gods happy".
	///
	/// [`get_children`]: #method.get_children
	fn get_child_at_index(&self, index: i32) -> zbus::Result<ObjectRef>;

	/// Retrieves a list of the object's accessible children.
	///
	/// Each array element is an [`Accessible`] representing the accessible child object.
	///
	/// ## Registry
	///
	/// On the [`Accessible`] interface of `org.a11y.atspi.Registry`, the registry daemon, this method retrieves a list
	/// of all accessible applications' root objects on the bus.
	///
	/// [`Accessible`]: crate::accessible::AccessibleProxy
	fn get_children(&self) -> zbus::Result<Vec<ObjectRef>>;

	/// This object resides in its parent's list of children.
	/// This returns its position in this list of children, starting from 0.
	///
	/// The function returns -1 if the object does not have a parent or
	/// if an exception occurs.
	fn get_index_in_parent(&self) -> zbus::Result<i32>;

	/// Returns an [`InterfaceSet`] accessible interface names supported by the `self` object.
	/// [`InterfaceSet`]: crate::common::InterfaceSet
	fn get_interfaces(&self) -> zbus::Result<InterfaceSet>;

	/// Gets a `String` corresponding to the name of the role played by an object,
	/// translated to the current locale.
	///
	/// ## Notes
	///
	/// This method will return useful values for roles that fall outside the
	/// enumeration used in the [`get_role`] method.
	///
	/// For applications, implementing this method is optional, and it may be removed
	/// in a future version of the API.
	///
	/// For example, [`libatspi`] will only call it in the event of an unknown role.
	///
	/// [`libatspi`]: <https://gitlab.gnome.org/GNOME/at-spi2-core/main/atspi>
	/// [`get_role`]: #method.get_role
	fn get_localized_role_name(&self) -> zbus::Result<String>;

	/// Returns a set of relationships between the this `self` object and others.
	///
	/// This vector of tuples contains a [`RelationType`] and a vector of [`Accessible`]'s to which that
	/// relationship applies.
	/// These relationships allow for better identification of how objects are associated with one another.
	///
	/// For example, the relationship [`RelationType::LabelledBy`] can be used to identify labeling information
	/// that should accompany the accessible [`name`] property when presenting an object's content or identity
	/// to the end user.
	///
	/// Similarly, [`RelationType::ControllerFor`] can be used to specify the context in which a valuator is useful
	/// and/or the other UI components that are directly affected by user interactions with the valuator.
	/// Common examples include the association of scrollbars with the viewport or panel that they control.
	///
	/// [`RelationType`]: crate::common::RelationType
	/// [`RelationType::LabelledBy`]: crate::common::RelationType::LabelledBy
	/// [`RelationType::ControllerFor`]: crate::common::RelationType::ControllerFor
	/// [`name`]: #method.name
	/// [`Accessible`]: ../crate::common::events::Accessible
	fn get_relation_set(&self) -> zbus::Result<Vec<(RelationType, Vec<ObjectRef>)>>;

	/// Gets the [`Role`] that the current accessible object represents.
	///
	/// Roles make it possible for various UI toolkits to expose their controls to
	/// assistive technologies (ATs) with a standard interface, regardless of toolkit.
	///
	/// For example, a widget that acts like a conventional push button
	/// (appears unpressed; presses	when acted upon; invokes a certain action
	/// when pressed) can expose an	[`Role::PushButton`] role.
	///
	/// [`Role::PushButton`]: crate::common::Role::PushButton
	/// [`Role`]: crate::common::Role
	fn get_role(&self) -> zbus::Result<Role>;

	/// Gets a `String` corresponding to the name of the role played by an object,
	/// translated to the current locale.
	///
	/// ## Notes
	///
	/// This method will return useful values for roles that fall outside the
	/// enumeration used in the `get_role` method.
	///
	/// For applications, implementing this method is optional, and it may be removed
	/// in a future version of the API.
	///
	/// [`libatspi`]: <https://gitlab.gnome.org/GNOME/at-spi2-core/main/atspi>
	/// [`libatspi`]: <https://gitlab.gnome.org/GNOME/at-spi2-core/>
	fn get_role_name(&self) -> zbus::Result<String>;

	/// Method to retrieve the [`StateSet`] of states currently held by `self`.
	/// [`StateSet`]: crate::common::StateSet
	fn get_state(&self) -> zbus::Result<StateSet>;

	/// Application-specific identifier for the current object.
	///
	/// A special id given to an object.
	/// Accessible application developers can use this to give a special id to an object
	/// to use in tests, for example, "my_widget".
	///
	/// Note that there is no way to directly find an object by its id;
	/// a test program may have to recursively get the children to find a specific id.
	/// This is because accessible objects can be created dynamically, and they do not always
	/// correspond to a static view of an application's data.
	#[zbus(property)]
	fn accessible_id(&self) -> zbus::Result<String>;

	/// Number of accessible children for the current object.
	#[zbus(property)]
	fn child_count(&self) -> zbus::Result<i32>;

	/// Human-readable, localized description of `self` in more detail.
	///
	/// This is a longer description than the [`Name`][name] property.
	///
	/// For example, a button might have a name of "OK", but a description of "OK button".
	///
	/// While the Name property is meant to be a short string that screen readers say
	/// during normal navigation, the Description property is for when the user asks for
	/// more detail.
	///
	/// [name]: #method.name
	#[zbus(property)]
	fn description(&self) -> zbus::Result<String>;

	/// Unix locale for the current object.
	///
	/// This is a string in the form of "language_territory.codeset".
	/// For example, "en_US.UTF-8" or "de_DE.UTF-8".
	///
	/// For an application, this may be the locale for the language that the application
	/// shows in its user interface.
	///
	/// For a document being shown in an application, or a paragraph within a document,
	/// the locale may refer to that object exclusively. For example:
	/// an application may be showing itself in English ("en"), but it may be used to
	/// display a document in Spanish ("es").
	/// In the latter case, a screen reader will want to know that it should switch to
	/// Spanish while reading the document.
	#[zbus(property)]
	fn locale(&self) -> zbus::Result<String>;

	/// Human-readable, localized, short name for the object.
	///
	/// Applications should have this set for objects which do not
	/// have a [`RelationType::LabelledBy`] relation.
	///
	/// Consider a widget to select RGB colors by setting three sliders.
	/// The	names for the sliders would be "Red", "Green", "Blue", respectively, or
	/// their translations to application's locale.  The names would be unnecessary if each
	/// slider had a `LabeledBy` relation to corresponding labels visible in the user
	/// interface.
	///
	/// [`RelationType::LabelledBy`]: crate::common::RelationType::LabelledBy
	#[zbus(property)]
	fn name(&self) -> zbus::Result<String>;

	/// ObjectRef parent object of the current object.
	///
	/// Null parent:
	/// If the object has no parent (e.g. the application's root object is being queried),
	/// The application should return "" for the application name name and "/org/a11y/atspi/null"
	/// for the object path.
	///
	/// Root object:
	/// An application must have a single root object, called "/org/a11y/atspi/accessible/root".
	/// All other objects should have that one as their highest-level ancestor.
	#[zbus(property)]
	fn parent(&self) -> zbus::Result<ObjectRef>;
}

impl TryFrom<AccessibleProxy<'_>> for ObjectRef {
	type Error = AtspiError;
	fn try_from(proxy: AccessibleProxy<'_>) -> Result<ObjectRef, Self::Error> {
		Ok(ObjectRef {
			name: proxy.inner().destination().as_str().try_into()?,
			path: proxy.inner().path().to_string().try_into()?,
		})
	}
}

impl TryFrom<&AccessibleProxy<'_>> for ObjectRef {
	type Error = AtspiError;
	fn try_from(proxy: &AccessibleProxy<'_>) -> Result<ObjectRef, Self::Error> {
		Ok(ObjectRef {
			name: proxy.inner().destination().as_str().try_into()?,
			path: proxy.inner().path().to_string().try_into()?,
		})
	}
}

pub trait ObjectRefExt {
	/// Returns an [`AccessibleProxy`], the handle to the object's  `Accessible` interface.
	///
	/// # Errors  
	///
	/// `UniqueName` or `ObjectPath` are assumed to be valid because they are obtained from a valid `ObjectRef`.
	/// If the builder is lacking the necessary parameters to build a proxy. See [`zbus::ProxyBuilder::build`].
	/// If this method fails, you may want to check the `AccessibleProxy` default values for missing / invalid parameters.
	fn as_accessible_proxy(
		&self,
		conn: &zbus::Connection,
	) -> impl std::future::Future<Output = Result<AccessibleProxy<'_>, zbus::Error>> + Send;
}

impl ObjectRefExt for ObjectRef {
	async fn as_accessible_proxy(
		&self,
		conn: &zbus::Connection,
	) -> Result<AccessibleProxy<'_>, zbus::Error> {
		let builder = AccessibleProxy::builder(conn).destination(self.name.as_str());
		let Ok(builder) = builder else {
			return Err(builder.unwrap_err());
		};

		let builder = builder.path(self.path.as_str());
		let Ok(builder) = builder else {
			return Err(builder.unwrap_err());
		};

		builder
			.cache_properties(zbus::proxy::CacheProperties::No)
			.build()
			.await
	}
}

impl PartialEq for AccessibleProxy<'_> {
	fn eq<'a>(&self, other: &Self) -> bool {
		self.inner().path() == other.inner().path()
	}
}
impl Eq for AccessibleProxy<'_> {}

#[cfg(test)]
mod tests {
	use crate::accessible::Role;

	#[test]
	fn test_output_of_role_name() {
		assert_eq!(Role::Invalid.name(), "invalid");
		assert_eq!(Role::PushButtonMenu.name(), "push button menu");
	}
}