From 693fbec03e484bf19f9813d05abf9f5ae9850fb3 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sat, 22 Jun 2024 18:43:21 +0200 Subject: [PATCH 01/30] Prepare collection proxy - Move from `MatchArgs` to `ObjectMatchRule` (note the "Object" prefix to avoid confusion with `zbus::MatchRule`) - Remove comment block on "Role fields" which are now a proper type `ObjectMatchRule` - Place the clippy suppression on the item that violates the rule. ToDo: - [ ] Document the methods properly This probably requires some digging in sources to find out what all arguments actually (were meant to) mean. --- atspi-proxies/src/collection.rs | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/atspi-proxies/src/collection.rs b/atspi-proxies/src/collection.rs index 2a030d05..3f8f6a54 100644 --- a/atspi-proxies/src/collection.rs +++ b/atspi-proxies/src/collection.rs @@ -9,31 +9,19 @@ //! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html) //! section of the zbus documentation. //! -#![allow(clippy::too_many_arguments)] -// this allow zbus to change the number of parameters in a function without setting off clippy +use atspi_common::ObjectMatchRule; -use crate::common::{MatchArgs, ObjectRef, SortOrder, TreeTraversalType}; +use crate::common::{ObjectRef, SortOrder, TreeTraversalType}; #[zbus::proxy(interface = "org.a11y.atspi.Collection", assume_defaults = true)] trait Collection { - /// GetActiveDescendant method + /// Get the active child-objects to the current object. fn get_active_descendant(&self) -> zbus::Result; - /* ROLE fields: - &[i32]: AtspiStateSet, - i32: AtspiCollectionMatchType, - HashMap<&str, &str>: attributes, - i32: AtspiCollectionMatchType (attribute match type), - &[i32]: roles, - i32: AtspiCollectionMatchType (role match type), - &[&str]: interfaces, - i32: AtspiCollectionMatchType (interface match type), - bool: invert - */ /// GetMatches method fn get_matches( &self, - rule: &MatchArgs<'_>, + rule: ObjectMatchRule, sortby: SortOrder, count: i32, traverse: bool, @@ -43,7 +31,7 @@ trait Collection { fn get_matches_from( &self, current_object: &zbus::zvariant::ObjectPath<'_>, - rule: &MatchArgs<'_>, + rule: ObjectMatchRule, sortby: SortOrder, tree: TreeTraversalType, count: i32, @@ -51,10 +39,11 @@ trait Collection { ) -> zbus::Result>; /// GetMatchesTo method + #[allow(clippy::too_many_arguments)] fn get_matches_to( &self, current_object: &zbus::zvariant::ObjectPath<'_>, - rule: &MatchArgs<'_>, + rule: ObjectMatchRule, sortby: SortOrder, tree: TreeTraversalType, limit_scope: bool, From fb8276a84459ac3bbf1a867d36803fe4eda1c6b6 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sat, 22 Jun 2024 18:52:07 +0200 Subject: [PATCH 02/30] Update type validation table - `Live` is now known as `Politeness` - `ObjectMatchRule` not verifiable --- type_validation.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/type_validation.md b/type_validation.md index 5edc8cea..6d69d19f 100644 --- a/type_validation.md +++ b/type_validation.md @@ -30,4 +30,5 @@ We leverage [zbus-lockstep](https://github.com/luukvanderduim/zbus-lockstep/) to | `Granularity` | ✓ | `Text::GetStringAtOffset` argument `granularity`| | `Layer` | ✓ | `Component::GetLayer` return type.| | `ScrollType` | ✓ | `Component::ScrollTo` argument `type`| -| `Live` | ✓ | `Event.Object::Announcement` argument `politeness`| +| `Politeness` | ✓ | `Event.Object::Announcement` argument `politeness`| +| `ObjectMatchRule` | ⚠ | `Collection::GetMatches` argument 'rule' contains `Vec` and `StateSet` which are defined as "ai", but `Role` and `StateSet` are not.| From a664693920f1b7841935d0471cd570e5b60007f4 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sat, 22 Jun 2024 18:57:20 +0200 Subject: [PATCH 03/30] Implement `Default` and `FromIterator` on `InterfaceSet` `FromIterator` allows us to `.collect()` into an `InterfaceSet` `Default` impl returns an empty set. --- atspi-common/src/interface.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/atspi-common/src/interface.rs b/atspi-common/src/interface.rs index f9c7d3fd..5d20008c 100644 --- a/atspi-common/src/interface.rs +++ b/atspi-common/src/interface.rs @@ -116,6 +116,12 @@ impl InterfaceSet { } } +impl Default for InterfaceSet { + fn default() -> Self { + Self::empty() + } +} + impl<'de> de::Deserialize<'de> for InterfaceSet { fn deserialize(deserializer: D) -> Result where @@ -161,6 +167,12 @@ impl Type for InterfaceSet { } } +impl FromIterator for InterfaceSet { + fn from_iter>(iter: T) -> Self { + Self(BitFlags::from_iter(iter)) + } +} + impl From for InterfaceSet { fn from(value: Interface) -> Self { Self(value.into()) From 7e6368e9812d608c706502e651daf3b821ab231d Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sat, 22 Jun 2024 19:03:32 +0200 Subject: [PATCH 04/30] Introduce `object_match` module - Remove `MatchArgs` - Move over `MatchType`, `TreeTraversalType` to `object_match.rs` - Introduce `ObjectMatchRule` with builder pattern - Move over / create tests --- atspi-common/src/lib.rs | 45 +----- atspi-common/src/object_match.rs | 236 +++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+), 43 deletions(-) create mode 100644 atspi-common/src/object_match.rs diff --git a/atspi-common/src/lib.rs b/atspi-common/src/lib.rs index 0411c2e4..f0516285 100644 --- a/atspi-common/src/lib.rs +++ b/atspi-common/src/lib.rs @@ -14,6 +14,8 @@ extern crate static_assertions; #[macro_use] pub(crate) mod macros; +pub mod object_match; +pub use object_match::{MatchType, ObjectMatchRule, TreeTraversalType}; pub mod object_ref; pub use object_ref::ObjectRef; pub mod interface; @@ -36,18 +38,6 @@ use zvariant::Type; pub type Result = std::result::Result; -pub type MatchArgs<'a> = ( - &'a [i32], - MatchType, - std::collections::HashMap<&'a str, &'a str>, - MatchType, - &'a [i32], - MatchType, - &'a [&'a str], - MatchType, - bool, -); - pub type TextSelection = (ObjectRef, i32, ObjectRef, i32, bool); #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Type)] @@ -73,37 +63,6 @@ pub enum SortOrder { ReverseTab, } -/// Method of traversing a tree in the `CollectionProxy`. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Type)] -#[repr(u32)] -pub enum TreeTraversalType { - /// Restrict children tree traversal - RestrictChildren, - /// Restrict sibling tree traversal - RestrictSibling, - /// In-order tree traversal. - Inorder, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Type)] -#[repr(i32)] -/// Enumeration used by [`MatchArgs`] to specify how to interpret [`ObjectRef`] objects. -/// -/// [`ObjectRef`]: crate::object_ref::ObjectRef -pub enum MatchType { - /// Invalid match type - Invalid, - /// true if all of the criteria are met. - All, - /// true if any of the criteria are met. - Any, - /// true if none of the criteria are met. - NA, - /// Same as [`Self::All`] if the criteria is non-empty; - /// for empty criteria this rule requires returned value to also have empty set. - Empty, -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Type)] #[repr(u32)] /// The coordinate type encodes the frame of reference. diff --git a/atspi-common/src/object_match.rs b/atspi-common/src/object_match.rs new file mode 100644 index 00000000..e903445b --- /dev/null +++ b/atspi-common/src/object_match.rs @@ -0,0 +1,236 @@ +use std::{collections::HashMap, marker::PhantomData}; + +use serde::{Deserialize, Serialize}; +use zvariant::{Signature, Type}; + +use crate::{Interface, InterfaceSet, Role, StateSet}; + +/// Defines how an object-tree is to be traversed. +/// Used in `CollectionProxy`. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, Type)] +#[repr(u32)] +pub enum TreeTraversalType { + /// When traversing the tree, restrict to children of the current object. + RestrictChildren, + + /// When traversing the tree, restrict to siblings of the current object. + RestrictSibling, + + /// Traverse the tree in order of appearance. + #[default] + Inorder, +} + +/// Definition of match rules for accessible objects. +/// Rule(s) against which we can match an object or a collection thereof. +/// +/// # Examples +/// ```Rust +/// let builder = MatchRule::builder(); +/// ``` +/// +#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)] +pub struct ObjectMatchRule { + pub states: StateSet, + pub states_mt: MatchType, + pub attr: HashMap, + pub attr_mt: MatchType, + pub roles: Vec, + pub roles_mt: MatchType, + pub ifaces: InterfaceSet, + pub ifaces_mt: MatchType, + pub invert: bool, + // Private phantom, gets compiled away. + // Here to ensure the builder is the only route to obtain a `MatchRule` + #[serde(skip)] + phantom: std::marker::PhantomData<()>, +} + +// !!! WARNING !!! : +// +// State and Role are defined as u32 in Accessible.xml but as i32 in Collection.xml +// +// The signature on StateSet is defined inconsistently in the XMLs +// Accessible.xml: GetState type="au" +// Collection.xml: GetMatches argument name="rule" type="(aiia{ss}iaiiasib)" +// The latter starts with ai, which is a signature for an array of signed ints i32. +// +// https://gitlab.gnome.org/federico/at-spi2-core/-/commit/4885efedeef71e0df8210622771a0b1bb10e194d +impl Type for ObjectMatchRule { + fn signature() -> Signature<'static> { + Signature::from_str_unchecked("(aiia{ss}iaiiasib)") + } +} + +impl ObjectMatchRule { + /// Create a new `MatchRuleBuilder` + #[must_use] + pub fn builder() -> ObjectMatchRuleBuilder { + ObjectMatchRuleBuilder::default() + } +} + +/// The 'builder' type for `MatchRule`. +/// Use its methods to set match criteria. +#[derive(Debug, Clone, Default)] +pub struct ObjectMatchRuleBuilder { + states: StateSet, + states_mt: MatchType, + attr: HashMap, + attr_mt: MatchType, + roles: Vec, + roles_mt: MatchType, + ifaces: InterfaceSet, + ifaces_mt: MatchType, + invert: bool, +} + +impl ObjectMatchRuleBuilder { + /// Insert a `StateSet` to the builder + #[must_use] + pub fn states(mut self, state_set: StateSet, mt: MatchType) -> Self { + self.states = state_set; + self.states_mt = mt; + self + } + + /// Insert a map of attributes + #[must_use] + pub fn attributes(mut self, attributes: HashMap, mt: MatchType) -> Self { + self.attr = attributes; + self.attr_mt = mt; + self + } + + /// Insert a slice of `Role`s + #[must_use] + pub fn roles(mut self, roles: &[Role], mt: MatchType) -> Self { + self.roles = roles.into(); + self.roles_mt = mt; + self + } + + /// Insert a slice of `Interface`s + #[must_use] + pub fn interfaces(mut self, interfaces: &[Interface], mt: MatchType) -> Self { + self.ifaces = interfaces.iter().copied().collect::(); + self.ifaces_mt = mt; + self + } + + /// Sets the inversion of the `MatchRule`, defaults to `false`, no inversion. + #[must_use] + pub fn invert(mut self, invert: bool) -> Self { + self.invert = invert; + self + } + + /// Builds the [`ObjectMatchRule`] + /// + /// [`ObjectMatchRule``]: crate::object_match::ObjectMatchRule + #[must_use] + pub fn build(self) -> ObjectMatchRule { + ObjectMatchRule { + states: self.states, + states_mt: self.states_mt, + attr: self.attr, + attr_mt: self.attr_mt, + roles: self.roles, + roles_mt: self.roles_mt, + ifaces: self.ifaces, + ifaces_mt: self.ifaces_mt, + invert: self.invert, + phantom: PhantomData, + } + } +} + +/// Enumeration used by [`MatchArgs`] to specify how to interpret [`ObjectRef`] objects. +/// +/// [`ObjectRef`]: crate::object_ref::ObjectRef +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Type, Default)] +#[repr(i32)] +pub enum MatchType { + #[default] + /// Invalidates match criterion. + Invalid, + + /// All of the criteria must be met. + All, + + /// Any of the criteria must criteria must be met. + Any, + + /// None of the criteria must be met. + NA, + + /// Same as [`Self::All`] if the criterion item is non-empty - All of the criteria must be met. + /// For empty criteria this rule requires the returned value to also have empty set. + Empty, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{SortOrder, State}; + use zbus_lockstep::method_args_signature; + + #[test] + fn validate_match_rule_signature() { + let signature = method_args_signature!(member: "GetMatchesTo", interface: "org.a11y.atspi.Collection", argument: "rule"); + assert_eq!(ObjectMatchRule::signature(), signature); + } + + #[test] + fn validate_match_type_signature() { + let rule_signature = method_args_signature!(member: "GetMatchesTo", interface: "org.a11y.atspi.Collection", argument: "rule"); + let match_type_signature = rule_signature.slice(3..4); + assert_eq!(MatchType::signature(), match_type_signature); + } + + #[test] + fn validate_tree_traversal_type_signature() { + let signature = method_args_signature!(member: "GetMatchesTo", interface: "org.a11y.atspi.Collection", argument: "tree"); + assert_eq!(TreeTraversalType::signature(), signature); + } + + #[test] + fn validate_sort_order_signature() { + let signature = method_args_signature!(member: "GetMatches", interface: "org.a11y.atspi.Collection", argument: "sortby"); + assert_eq!(SortOrder::signature(), signature); + } + + #[test] + fn create_empty_object_match_rule() { + let rule = ObjectMatchRule::builder().build(); + + assert_eq!(rule.states, StateSet::default()); + assert_eq!(rule.attr, HashMap::new()); + assert_eq!(rule.roles, Vec::new()); + assert_eq!(rule.ifaces, InterfaceSet::default()); + assert!(!rule.invert); + } + + #[test] + fn create_object_match_rule() { + let rule = ObjectMatchRule::builder() + .states(StateSet::new(State::Active), MatchType::All) + .attributes( + [("name".to_string(), "value".to_string())].iter().cloned().collect(), + MatchType::Any, + ) + .roles(&[Role::Alert], MatchType::All) + .interfaces(&[Interface::Action], MatchType::Any) + .invert(true) + .build(); + + assert_eq!(rule.states, StateSet::new(State::Active)); + assert_eq!( + rule.attr, + [("name".to_string(), "value".to_string())].iter().cloned().collect() + ); + assert_eq!(rule.roles, vec![Role::Alert]); + assert_eq!(rule.ifaces, InterfaceSet::new(Interface::Action)); + assert!(rule.invert); + } +} From fe8d1dca6cdde07b6d37651ede45560cd19d61c4 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sun, 23 Jun 2024 14:50:48 +0200 Subject: [PATCH 05/30] Fix Clippy lint on doc Missing item fixed. --- atspi-common/src/object_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atspi-common/src/object_match.rs b/atspi-common/src/object_match.rs index e903445b..6fbc678b 100644 --- a/atspi-common/src/object_match.rs +++ b/atspi-common/src/object_match.rs @@ -145,7 +145,7 @@ impl ObjectMatchRuleBuilder { } } -/// Enumeration used by [`MatchArgs`] to specify how to interpret [`ObjectRef`] objects. +/// Enumeration used by [`ObjectMatchRule`] to specify how to interpret [`ObjectRef`] objects. /// /// [`ObjectRef`]: crate::object_ref::ObjectRef #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Type, Default)] From 3aa32c34b15f001df223aa9bf1fc74e34864f643 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sun, 23 Jun 2024 15:50:42 +0200 Subject: [PATCH 06/30] Fix docs on `SortOrder` Only `SortOrder::Canonical` and `SortOrder::ReverseCanonical` seem implemented. [upstream issue 140](Are all the AtspiCollectionSortOrder types really a thing?) --- atspi-common/src/object_match.rs | 45 ++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/atspi-common/src/object_match.rs b/atspi-common/src/object_match.rs index 6fbc678b..3d80a6ec 100644 --- a/atspi-common/src/object_match.rs +++ b/atspi-common/src/object_match.rs @@ -169,6 +169,51 @@ pub enum MatchType { Empty, } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Type)] +#[repr(u32)] +/// Enumeration used by interface `CollectionProxy` to specify the way [`ObjectRef`] +/// objects should be sorted. +/// +/// # Note +/// +/// Only `Canonical` and `ReverseCanonical` are currently implemented. +/// +/// see: [issue 140. "Are all the AtspiCollectionSortOrder types really a thing?"](https://gitlab.gnome.org/GNOME/at-spi2-core/-/issues/140) +/// +/// [`ObjectRef`]: crate::object_ref::ObjectRef +pub enum SortOrder { + /// Invalid sort order + /// + /// Unimplemented + Invalid, + + /// Canonical sort order + Canonical, + + /// Flow sort order + /// + /// Unimplemented + Flow, + + /// Tab sort order + /// + /// Unimplemented + Tab, + + /// Reverse canonical sort order + ReverseCanonical, + + /// Reverse flow sort order + /// + /// Unimplemented + ReverseFlow, + + /// Reverse tab sort order + /// + /// Unimplemented + ReverseTab, +} + #[cfg(test)] mod tests { use super::*; From 86708f887c7dbf67b7df88abeebc467ea68d7a93 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sun, 23 Jun 2024 16:12:43 +0200 Subject: [PATCH 07/30] Add module level docs to CollectionProxy --- atspi-proxies/src/collection.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/atspi-proxies/src/collection.rs b/atspi-proxies/src/collection.rs index 3f8f6a54..06200e85 100644 --- a/atspi-proxies/src/collection.rs +++ b/atspi-proxies/src/collection.rs @@ -1,15 +1,14 @@ -//! # `DBus` interface proxy for: `org.a11y.atspi.Collection` +//! # [`CollectionProxy`] //! -//! This code was generated by `zbus-xmlgen` `2.0.1` from `DBus` introspection data. -//! Source: `Collection.xml`. +//! A handle to a remote object implementing the `org.a11y.atspi.Collection` +//! interface. //! -//! You may prefer to adapt it, instead of using it verbatim. +//! `Collection` is the interface which is implemented by objects that contain +//! other objects, such as a window or a table. //! -//! More information can be found in the -//! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html) -//! section of the zbus documentation. +//! See the documentation on the individual methods for details. //! -use atspi_common::ObjectMatchRule; +//! [`CollectionProxy`]: crate::collection::CollectionProxy use crate::common::{ObjectRef, SortOrder, TreeTraversalType}; From 6386203944fa59e95357e2d8ba18fb2bb25a4cb9 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sun, 23 Jun 2024 16:14:50 +0200 Subject: [PATCH 08/30] Document `get_active_descendant` Seems to be unimplemented as our upstream libatspi peers say it is. --- atspi-proxies/src/collection.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/atspi-proxies/src/collection.rs b/atspi-proxies/src/collection.rs index 06200e85..50b4ee69 100644 --- a/atspi-proxies/src/collection.rs +++ b/atspi-proxies/src/collection.rs @@ -14,8 +14,13 @@ use crate::common::{ObjectRef, SortOrder, TreeTraversalType}; #[zbus::proxy(interface = "org.a11y.atspi.Collection", assume_defaults = true)] trait Collection { - /// Get the active child-objects to the current object. - fn get_active_descendant(&self) -> zbus::Result; + // The active descendant of the given object. + // + // Looks like this is unimplemented. + // + // See [atspi/collection.c](https://gitlab.gnome.org/GNOME/at-spi2-core/-/blob/main/atspi/atspi-collection.c?ref_type=heads#L272) + // + // fn get_active_descendant(&self) -> zbus::Result; /// GetMatches method fn get_matches( From 39819ed41660a16fc090a5c1634e1c578bad0994 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sun, 23 Jun 2024 16:15:30 +0200 Subject: [PATCH 09/30] Document `get_matches` --- atspi-proxies/src/collection.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/atspi-proxies/src/collection.rs b/atspi-proxies/src/collection.rs index 50b4ee69..e7617e64 100644 --- a/atspi-proxies/src/collection.rs +++ b/atspi-proxies/src/collection.rs @@ -22,7 +22,21 @@ trait Collection { // // fn get_active_descendant(&self) -> zbus::Result; - /// GetMatches method + /// Retrieves a list of objects that match the specified ObjectMatchRule, ordered according to SortOrder and limited by the count parameter. + /// + /// # Arguments + /// + /// * `rule` - An [`ObjectMatchRule`] describing the match criteria. + /// * `sortby` - A [`SortOrder`] specifying the way the results are to be sorted. + /// * `count` - The maximum number of results to return, or 0 for no limit. + /// * `traverse` - Not supported. + /// + /// # Maximum number of objects + /// + /// This method will never return more than 65536 objects. + /// + /// [`ObjectMatchRule`]: atspi_common::object_match::ObjectMatchRule + /// [`SortOrder`]: atspi_common::SortOrder fn get_matches( &self, rule: ObjectMatchRule, From 3c6541091752c24c65112ffa7454a4ffe13ad93c Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sun, 23 Jun 2024 16:15:58 +0200 Subject: [PATCH 10/30] Document `get_matches_from` --- atspi-proxies/src/collection.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/atspi-proxies/src/collection.rs b/atspi-proxies/src/collection.rs index e7617e64..74d7ad8e 100644 --- a/atspi-proxies/src/collection.rs +++ b/atspi-proxies/src/collection.rs @@ -45,7 +45,25 @@ trait Collection { traverse: bool, ) -> zbus::Result>; - /// GetMatchesFrom method + /// Retrieves objects from the collection, after `current_object`, matching a given `rule`. + /// + /// # Arguments + /// + /// * `current_object` - The object at which to start searching. + /// * `rule` - An [`ObjectMatchRule`] describing the match criteria. + /// * `sortby` - A [`SortOrder`] specifying the way the results are to be sorted. + /// * `tree` - A [`TreeTraversalType`] specifying restrictions on the objects to be traversed. + /// * `limit_scope` - If `true`, only descendants of `current_object`'s parent will be returned. Otherwise (if `false`), any accessible may be returned if it would preceed `current_object` in a flattened hierarchy. + /// * `count` - The maximum number of results to return, or 0 for no limit. + /// * `traverse` - Not supported. + /// + /// # Maximum number of objects + /// + /// This method will never return more than 65536 objects. + /// + /// [`ObjectMatchRule`]: atspi_common::object_match::ObjectMatchRule + /// [`SortOrder`]: atspi_common::SortOrder + /// [`TreeTraversalType`]: atspi_common::TreeTraversalType fn get_matches_from( &self, current_object: &zbus::zvariant::ObjectPath<'_>, From 54753325247d789cb77560b439db9a2aa0300ecd Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sun, 23 Jun 2024 16:16:28 +0200 Subject: [PATCH 11/30] Document `get_matches_to` --- atspi-proxies/src/collection.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/atspi-proxies/src/collection.rs b/atspi-proxies/src/collection.rs index 74d7ad8e..70a630b5 100644 --- a/atspi-proxies/src/collection.rs +++ b/atspi-proxies/src/collection.rs @@ -74,7 +74,25 @@ trait Collection { traverse: bool, ) -> zbus::Result>; - /// GetMatchesTo method + /// Retrieves objects from the collection, before `current_object`, matching a given `rule`. + /// + /// # Arguments + /// + /// * `current_object` - The object at which to start searching. + /// * `rule` - An [`ObjectMatchRule`] describing the match criteria. + /// * `sortby` - A [`SortOrder`] specifying the way the results are to be sorted. + /// * `tree` - A [`TreeTraversalType`] specifying restrictions on the objects to be traversed. + /// * `limit_scope` - If `true`, only descendants of `current_object`'s parent will be returned. Otherwise (if `false`), any accessible may be returned if it would preceed `current_object` in a flattened hierarchy. + /// * `count` - The maximum number of results to return, or 0 for no limit. + /// * `traverse` - Not supported. + /// + /// # Maximum number of objects + /// + /// This method will never return more than 65536 objects. + /// + /// [`ObjectMatchRule`]: atspi_common::object_match::ObjectMatchRule + /// [`SortOrder`]: atspi_common::SortOrder + /// [`TreeTraversalType`]: atspi_common::TreeTraversalType #[allow(clippy::too_many_arguments)] fn get_matches_to( &self, From 7f5dcd7f161eb2d3a9efcb443df32e2e63e7fdb3 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sun, 23 Jun 2024 16:18:55 +0200 Subject: [PATCH 12/30] Move `SortOrder` to object_match module Move `SortOrder` to object_match module Delete duplicate tests. --- atspi-common/src/lib.rs | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/atspi-common/src/lib.rs b/atspi-common/src/lib.rs index f0516285..edbdede9 100644 --- a/atspi-common/src/lib.rs +++ b/atspi-common/src/lib.rs @@ -15,7 +15,7 @@ extern crate static_assertions; pub(crate) mod macros; pub mod object_match; -pub use object_match::{MatchType, ObjectMatchRule, TreeTraversalType}; +pub use object_match::{MatchType, ObjectMatchRule, SortOrder, TreeTraversalType}; pub mod object_ref; pub use object_ref::ObjectRef; pub mod interface; @@ -40,29 +40,6 @@ pub type Result = std::result::Result; pub type TextSelection = (ObjectRef, i32, ObjectRef, i32, bool); -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Type)] -#[repr(u32)] -/// Enumeration used by interface `CollectionProxy` to specify the way [`ObjectRef`] -/// objects should be sorted. -/// -/// [`ObjectRef`]: crate::object_ref::ObjectRef -pub enum SortOrder { - /// Invalid sort order - Invalid, - /// Canonical sort order - Canonical, - /// Flow sort order - Flow, - /// Tab sort order - Tab, - /// Reverse canonical sort order - ReverseCanonical, - /// Reverse flow sort order - ReverseFlow, - /// Reverse tab sort order - ReverseTab, -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Type)] #[repr(u32)] /// The coordinate type encodes the frame of reference. @@ -252,16 +229,4 @@ mod tests { let match_type_signature = rule_signature.slice(3..4); assert_eq!(MatchType::signature(), match_type_signature); } - - #[test] - fn validate_tree_traversal_type_signature() { - let signature = method_args_signature!(member: "GetMatchesTo", interface: "org.a11y.atspi.Collection", argument: "tree"); - assert_eq!(TreeTraversalType::signature(), signature); - } - - #[test] - fn validate_sort_order_signature() { - let signature = method_args_signature!(member: "GetMatches", interface: "org.a11y.atspi.Collection", argument: "sortby"); - assert_eq!(SortOrder::signature(), signature); - } } From 511637c6f09af20a8a67c29f5be42841b46d71b6 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sun, 23 Jun 2024 16:21:43 +0200 Subject: [PATCH 13/30] Fix imports --- atspi-proxies/src/collection.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atspi-proxies/src/collection.rs b/atspi-proxies/src/collection.rs index 70a630b5..cc713855 100644 --- a/atspi-proxies/src/collection.rs +++ b/atspi-proxies/src/collection.rs @@ -10,7 +10,7 @@ //! //! [`CollectionProxy`]: crate::collection::CollectionProxy -use crate::common::{ObjectRef, SortOrder, TreeTraversalType}; +use crate::common::{ObjectMatchRule, ObjectRef, SortOrder, TreeTraversalType}; #[zbus::proxy(interface = "org.a11y.atspi.Collection", assume_defaults = true)] trait Collection { From 6edc91621fd5cc842995c1a5d967f03a7bd7f6fd Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sun, 23 Jun 2024 23:01:43 +0200 Subject: [PATCH 14/30] Docs: Remove max object number Remove maximum object number from documentation. Even though atk-adaptor implements the maximum as of present, they may not always have and it may not be the only implementation on the bus either. --- atspi-proxies/src/collection.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/atspi-proxies/src/collection.rs b/atspi-proxies/src/collection.rs index cc713855..0fe4ff44 100644 --- a/atspi-proxies/src/collection.rs +++ b/atspi-proxies/src/collection.rs @@ -31,10 +31,6 @@ trait Collection { /// * `count` - The maximum number of results to return, or 0 for no limit. /// * `traverse` - Not supported. /// - /// # Maximum number of objects - /// - /// This method will never return more than 65536 objects. - /// /// [`ObjectMatchRule`]: atspi_common::object_match::ObjectMatchRule /// [`SortOrder`]: atspi_common::SortOrder fn get_matches( @@ -57,10 +53,6 @@ trait Collection { /// * `count` - The maximum number of results to return, or 0 for no limit. /// * `traverse` - Not supported. /// - /// # Maximum number of objects - /// - /// This method will never return more than 65536 objects. - /// /// [`ObjectMatchRule`]: atspi_common::object_match::ObjectMatchRule /// [`SortOrder`]: atspi_common::SortOrder /// [`TreeTraversalType`]: atspi_common::TreeTraversalType @@ -82,10 +74,6 @@ trait Collection { /// * `rule` - An [`ObjectMatchRule`] describing the match criteria. /// * `sortby` - A [`SortOrder`] specifying the way the results are to be sorted. /// * `tree` - A [`TreeTraversalType`] specifying restrictions on the objects to be traversed. - /// * `limit_scope` - If `true`, only descendants of `current_object`'s parent will be returned. Otherwise (if `false`), any accessible may be returned if it would preceed `current_object` in a flattened hierarchy. - /// * `count` - The maximum number of results to return, or 0 for no limit. - /// * `traverse` - Not supported. - /// /// # Maximum number of objects /// /// This method will never return more than 65536 objects. From 779a6c97ae5f4fb251e1f16bc356d3821522fa34 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Sun, 23 Jun 2024 23:03:00 +0200 Subject: [PATCH 15/30] Provide links to methods in module level docs --- atspi-proxies/src/collection.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/atspi-proxies/src/collection.rs b/atspi-proxies/src/collection.rs index 0fe4ff44..c68fd7d6 100644 --- a/atspi-proxies/src/collection.rs +++ b/atspi-proxies/src/collection.rs @@ -6,7 +6,11 @@ //! `Collection` is the interface which is implemented by objects that contain //! other objects, such as a window or a table. //! -//! See the documentation on the individual methods for details. +//! See the documentation on the individual methods for details: +//! +//! * [`get_matches`](struct.CollectionProxy.html#method.get_matches) +//! * [`get_matches_from`](struct.CollectionProxy.html#method.get_matches_from) +//! * [`get_matches_to`](struct.CollectionProxy.html#method.get_matches_to) //! //! [`CollectionProxy`]: crate::collection::CollectionProxy From d6e2f03682404e9a712fa2feca7a78ca700008f1 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Mon, 24 Jun 2024 11:30:55 +0200 Subject: [PATCH 16/30] Rename 'phantom' field to '_marker' --- atspi-common/src/object_match.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atspi-common/src/object_match.rs b/atspi-common/src/object_match.rs index 3d80a6ec..b41ae8db 100644 --- a/atspi-common/src/object_match.rs +++ b/atspi-common/src/object_match.rs @@ -43,7 +43,7 @@ pub struct ObjectMatchRule { // Private phantom, gets compiled away. // Here to ensure the builder is the only route to obtain a `MatchRule` #[serde(skip)] - phantom: std::marker::PhantomData<()>, + _marker: std::marker::PhantomData<()>, } // !!! WARNING !!! : @@ -140,7 +140,7 @@ impl ObjectMatchRuleBuilder { ifaces: self.ifaces, ifaces_mt: self.ifaces_mt, invert: self.invert, - phantom: PhantomData, + _marker: PhantomData, } } } From 728e724a1dfa2cb83f8fd0de077bb067173491a6 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Mon, 24 Jun 2024 14:15:15 +0200 Subject: [PATCH 17/30] `MatchType` now defaults to `All` --- atspi-common/src/object_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atspi-common/src/object_match.rs b/atspi-common/src/object_match.rs index b41ae8db..600e983a 100644 --- a/atspi-common/src/object_match.rs +++ b/atspi-common/src/object_match.rs @@ -151,10 +151,10 @@ impl ObjectMatchRuleBuilder { #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Type, Default)] #[repr(i32)] pub enum MatchType { - #[default] /// Invalidates match criterion. Invalid, + #[default] /// All of the criteria must be met. All, From e79d185224600ff466940ba316ea766c8f189327 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Mon, 24 Jun 2024 14:21:47 +0200 Subject: [PATCH 18/30] We know of only one implementation Only `Canonical` and `ReverseCanonical` are in use in atk-adaptor. Other or future implementation might use other variants. (but this is unlikely at this point in time.) --- atspi-common/src/object_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atspi-common/src/object_match.rs b/atspi-common/src/object_match.rs index 600e983a..ce60d34f 100644 --- a/atspi-common/src/object_match.rs +++ b/atspi-common/src/object_match.rs @@ -176,7 +176,7 @@ pub enum MatchType { /// /// # Note /// -/// Only `Canonical` and `ReverseCanonical` are currently implemented. +/// Only `Canonical` and `ReverseCanonical` are currently implemented in the known implementation of `Collection`. /// /// see: [issue 140. "Are all the AtspiCollectionSortOrder types really a thing?"](https://gitlab.gnome.org/GNOME/at-spi2-core/-/issues/140) /// From eb6b351fa1f6270835f76fa78fb83e5293eb325e Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Tue, 25 Jun 2024 00:10:11 +0200 Subject: [PATCH 19/30] Implement IntoIterator for InterfaceSet and &InterfaceSet --- atspi-common/src/interface.rs | 42 ++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/atspi-common/src/interface.rs b/atspi-common/src/interface.rs index 5d20008c..09ee4eed 100644 --- a/atspi-common/src/interface.rs +++ b/atspi-common/src/interface.rs @@ -111,11 +111,30 @@ impl InterfaceSet { self.0.insert(other); } - pub fn iter(self) -> impl Iterator { + #[must_use] + pub fn iter(&self) -> enumflags2::Iter { self.0.iter() } } +impl IntoIterator for InterfaceSet { + type IntoIter = enumflags2::Iter; + type Item = Interface; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for &InterfaceSet { + type IntoIter = enumflags2::Iter; + type Item = Interface; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + impl Default for InterfaceSet { fn default() -> Self { Self::empty() @@ -261,4 +280,25 @@ mod tests { let (decoded, _) = encoded.deserialize::().unwrap(); assert!(object == decoded); } + + // The order of appearance of the interfaces is equal to the order in the enum. + #[test] + fn iterator_on_interface_set() { + let set = + InterfaceSet::new(Interface::Accessible | Interface::Action | Interface::Component); + let mut iter = set.into_iter(); + assert_eq!(iter.next(), Some(Interface::Accessible)); + assert_eq!(iter.next(), Some(Interface::Action)); + assert_eq!(iter.next(), Some(Interface::Component)); + assert_eq!(iter.next(), None); + } + + #[test] + fn iterator_on_interface_set_ref() { + let set = InterfaceSet::new(Interface::Text | Interface::Collection | Interface::Component); + let mut iter = (&set).into_iter(); + assert_eq!(iter.next(), Some(Interface::Collection)); + assert_eq!(iter.next(), Some(Interface::Component)); + assert_eq!(iter.next(), Some(Interface::Text)); + } } From 9eea366633f895a6fadc72f5a8c96b6dcb0e030c Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Tue, 25 Jun 2024 00:17:56 +0200 Subject: [PATCH 20/30] Accept implementations of IntoIterator in `interfaces` method Items may be either &Interface or Interface --- atspi-common/src/object_match.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/atspi-common/src/object_match.rs b/atspi-common/src/object_match.rs index ce60d34f..e6017b1f 100644 --- a/atspi-common/src/object_match.rs +++ b/atspi-common/src/object_match.rs @@ -110,10 +110,14 @@ impl ObjectMatchRuleBuilder { self } - /// Insert a slice of `Interface`s + /// Insert an `InterfaceSet` from a collection of `Interface`s #[must_use] - pub fn interfaces(mut self, interfaces: &[Interface], mt: MatchType) -> Self { - self.ifaces = interfaces.iter().copied().collect::(); + pub fn interfaces(mut self, interfaces: I, mt: MatchType) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + self.ifaces = interfaces.into_iter().map(|iface| *iface.borrow()).collect(); self.ifaces_mt = mt; self } @@ -265,7 +269,7 @@ mod tests { MatchType::Any, ) .roles(&[Role::Alert], MatchType::All) - .interfaces(&[Interface::Action], MatchType::Any) + .interfaces([Interface::Action], MatchType::Any) .invert(true) .build(); From f723bfe7636584bb11d537a67befd95c611b13b6 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Tue, 25 Jun 2024 00:19:12 +0200 Subject: [PATCH 21/30] Update imports, add `Borrow` --- atspi-common/src/object_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atspi-common/src/object_match.rs b/atspi-common/src/object_match.rs index e6017b1f..5b939bab 100644 --- a/atspi-common/src/object_match.rs +++ b/atspi-common/src/object_match.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, marker::PhantomData}; +use std::{borrow::Borrow, collections::HashMap, marker::PhantomData}; use serde::{Deserialize, Serialize}; use zvariant::{Signature, Type}; From 6e5fbde81a719ec6b54bfcbfcc5d26ff8326475e Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Tue, 25 Jun 2024 11:21:50 +0200 Subject: [PATCH 22/30] Clippy requests us to be more concise. --- atspi-common/src/state.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/atspi-common/src/state.rs b/atspi-common/src/state.rs index 92661174..16ad1038 100644 --- a/atspi-common/src/state.rs +++ b/atspi-common/src/state.rs @@ -606,9 +606,8 @@ mod tests { #[test] fn convert_state_direct_string() { - for state in StateSet::from_bits(0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111) - .unwrap() - .iter() + for state in + StateSet::from_bits(0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111).unwrap() { let state_str: String = state.into(); let state_two: State = state_str.clone().into(); @@ -620,9 +619,8 @@ mod tests { } #[test] fn convert_state_direct_string_is_equal_to_serde_output() { - for state in StateSet::from_bits(0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111) - .unwrap() - .iter() + for state in + StateSet::from_bits(0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111).unwrap() { let serde_state_str: String = serde_plain::to_string(&state).unwrap(); let state_str: String = state.into(); From 1aaf7e05462c6e750d70a9d84d14d5cab056b60e Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Tue, 25 Jun 2024 12:21:59 +0200 Subject: [PATCH 23/30] Add `IntoIterator` for `StateSet` `IntoIterator` uses `StateSet`s own iter, which returned `impl Iterator`, The `IntoIterator` implementation does not accept the opaque type, it needs the specific type to coincide with its own type, so the return type on `StateSet::iter` is adjusted to enumflags2::Iter`. --- atspi-common/src/state.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atspi-common/src/state.rs b/atspi-common/src/state.rs index 16ad1038..0602d9ed 100644 --- a/atspi-common/src/state.rs +++ b/atspi-common/src/state.rs @@ -385,7 +385,8 @@ impl StateSet { } /// Returns an iterator that yields each set [`State`]. - pub fn iter(self) -> impl Iterator { + #[must_use] + pub fn iter(self) -> enumflags2::Iter { self.0.iter() } From 3e1ba08a9d63ea37740c9dd3d44c2a6fcccdef31 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Tue, 25 Jun 2024 12:49:54 +0200 Subject: [PATCH 24/30] Add FromIterator that allows to collect from iterators that yield &Interface too --- atspi-common/src/interface.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/atspi-common/src/interface.rs b/atspi-common/src/interface.rs index 09ee4eed..c5b81573 100644 --- a/atspi-common/src/interface.rs +++ b/atspi-common/src/interface.rs @@ -192,6 +192,12 @@ impl FromIterator for InterfaceSet { } } +impl<'a> FromIterator<&'a Interface> for InterfaceSet { + fn from_iter>(iter: I) -> Self { + InterfaceSet(iter.into_iter().copied().collect()) + } +} + impl From for InterfaceSet { fn from(value: Interface) -> Self { Self(value.into()) From 87117b8d3e15ad8aabd8c1707659ca08c82cf284 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Tue, 25 Jun 2024 12:53:10 +0200 Subject: [PATCH 25/30] impl `FromIterator` and `IntoIterator` for `StateSet` --- atspi-common/src/state.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/atspi-common/src/state.rs b/atspi-common/src/state.rs index 0602d9ed..9031b783 100644 --- a/atspi-common/src/state.rs +++ b/atspi-common/src/state.rs @@ -407,6 +407,36 @@ impl StateSet { } } +impl IntoIterator for StateSet { + type IntoIter = enumflags2::Iter; + type Item = State; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for &StateSet { + type IntoIter = enumflags2::Iter; + type Item = State; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl FromIterator for StateSet { + fn from_iter>(iter: I) -> Self { + StateSet(iter.into_iter().collect()) + } +} + +impl<'a> FromIterator<&'a State> for StateSet { + fn from_iter>(iter: I) -> Self { + StateSet(iter.into_iter().copied().collect()) + } +} + impl<'de> Deserialize<'de> for StateSet { fn deserialize(deserializer: D) -> Result where From d5f1bc058f20ff028aa2a799493c0ef625ffa878 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Tue, 25 Jun 2024 13:33:16 +0200 Subject: [PATCH 26/30] Tests for `FromIterator` and `IntoIterator` for StateSet --- atspi-common/src/state.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/atspi-common/src/state.rs b/atspi-common/src/state.rs index 9031b783..1ee7a3db 100644 --- a/atspi-common/src/state.rs +++ b/atspi-common/src/state.rs @@ -660,4 +660,43 @@ mod tests { assert_eq!(state, state_two, "The {state:?} was serialized as {state_str}, which deserializes to {state_two:?} (serde)"); } } + + #[test] + fn collect_stateset_from_owned_states() { + let states = vec![State::Active, State::Focused, State::Focusable]; + let set = StateSet::from_iter(states); + assert!(set.contains(State::Active)); + assert!(set.contains(State::Focused)); + assert!(set.contains(State::Focusable)); + } + + #[test] + fn collect_stateset_from_borrowed_states() { + // &[T].iter() yields &T + let states = &[State::Active, State::Focused, State::Focusable]; + let set = states.iter().collect::(); + assert!(set.contains(State::Active)); + assert!(set.contains(State::Focused)); + assert!(set.contains(State::Focusable)); + } + + #[test] + fn into_iterator_owned_stateset() { + let set = StateSet::new(State::Active | State::Focused | State::Focusable); + let states: Vec = set.into_iter().collect(); + assert_eq!(states.len(), 3); + assert!(states.contains(&State::Active)); + assert!(states.contains(&State::Focused)); + assert!(states.contains(&State::Focusable)); + } + + #[test] + fn into_iterator_borrowed_stateset() { + let set = StateSet::new(State::Active | State::Focused | State::Focusable); + let states: Vec = (&set).into_iter().collect(); + assert_eq!(states.len(), 3); + assert!(states.contains(&State::Active)); + assert!(states.contains(&State::Focused)); + assert!(states.contains(&State::Focusable)); + } } From 3d2739d11894296edcb33b79336efd2d80809b00 Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Tue, 25 Jun 2024 14:05:14 +0200 Subject: [PATCH 27/30] Add `State` to imports --- atspi-common/src/object_match.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/atspi-common/src/object_match.rs b/atspi-common/src/object_match.rs index 5b939bab..e7b29fe6 100644 --- a/atspi-common/src/object_match.rs +++ b/atspi-common/src/object_match.rs @@ -3,7 +3,7 @@ use std::{borrow::Borrow, collections::HashMap, marker::PhantomData}; use serde::{Deserialize, Serialize}; use zvariant::{Signature, Type}; -use crate::{Interface, InterfaceSet, Role, StateSet}; +use crate::{Interface, InterfaceSet, Role, State, StateSet}; /// Defines how an object-tree is to be traversed. /// Used in `CollectionProxy`. @@ -88,8 +88,12 @@ pub struct ObjectMatchRuleBuilder { impl ObjectMatchRuleBuilder { /// Insert a `StateSet` to the builder #[must_use] - pub fn states(mut self, state_set: StateSet, mt: MatchType) -> Self { - self.states = state_set; + pub fn states(mut self, states: I, mt: MatchType) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + self.states = states.into_iter().map(|state| *state.borrow()).collect(); self.states_mt = mt; self } From 94192a623ea1dc068407a692515cd77a1bca018f Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Tue, 25 Jun 2024 14:24:20 +0200 Subject: [PATCH 28/30] Fixup docs on `Collection::{get_matches_to, get_matches_from}` Accidentally wapped some around, good catch @tait --- atspi-proxies/src/collection.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/atspi-proxies/src/collection.rs b/atspi-proxies/src/collection.rs index c68fd7d6..bd0f5126 100644 --- a/atspi-proxies/src/collection.rs +++ b/atspi-proxies/src/collection.rs @@ -53,9 +53,8 @@ trait Collection { /// * `rule` - An [`ObjectMatchRule`] describing the match criteria. /// * `sortby` - A [`SortOrder`] specifying the way the results are to be sorted. /// * `tree` - A [`TreeTraversalType`] specifying restrictions on the objects to be traversed. - /// * `limit_scope` - If `true`, only descendants of `current_object`'s parent will be returned. Otherwise (if `false`), any accessible may be returned if it would preceed `current_object` in a flattened hierarchy. /// * `count` - The maximum number of results to return, or 0 for no limit. - /// * `traverse` - Not supported. + /// * `traverse` - Not supported by the known implementation (atk-collection). /// /// [`ObjectMatchRule`]: atspi_common::object_match::ObjectMatchRule /// [`SortOrder`]: atspi_common::SortOrder @@ -78,9 +77,10 @@ trait Collection { /// * `rule` - An [`ObjectMatchRule`] describing the match criteria. /// * `sortby` - A [`SortOrder`] specifying the way the results are to be sorted. /// * `tree` - A [`TreeTraversalType`] specifying restrictions on the objects to be traversed. - /// # Maximum number of objects - /// - /// This method will never return more than 65536 objects. + /// * `limit_scope` - If `true`, only descendants of `current_object`'s parent will be returned. + /// Otherwise (if `false`), any accessible may be returned if it would preceed `current_object` in a flattened hierarchy. + /// * `count` - The maximum number of results to return, or 0 for no limit. + /// * `traverse` - Not supported by the known implementation (atk-collection). /// /// [`ObjectMatchRule`]: atspi_common::object_match::ObjectMatchRule /// [`SortOrder`]: atspi_common::SortOrder From d478e27f1ceaf3dd4b5afd4a43db81c99a54408c Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Tue, 25 Jun 2024 15:17:43 +0200 Subject: [PATCH 29/30] Comment on magic numbers while slicing into the signature --- atspi-common/src/object_match.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/atspi-common/src/object_match.rs b/atspi-common/src/object_match.rs index e7b29fe6..555bc28e 100644 --- a/atspi-common/src/object_match.rs +++ b/atspi-common/src/object_match.rs @@ -237,6 +237,7 @@ mod tests { #[test] fn validate_match_type_signature() { let rule_signature = method_args_signature!(member: "GetMatchesTo", interface: "org.a11y.atspi.Collection", argument: "rule"); + // The match type signature is the fourth element in the signature let match_type_signature = rule_signature.slice(3..4); assert_eq!(MatchType::signature(), match_type_signature); } From 1eee24587a446db0e42f128f4a4d07e83be42c7a Mon Sep 17 00:00:00 2001 From: Luuk van der Duim Date: Tue, 25 Jun 2024 21:08:57 +0200 Subject: [PATCH 30/30] Reinstate ` get_active_descendant` atk-adaptor does not offer this method, but another maybe might. Added information in docs. --- atspi-proxies/src/collection.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/atspi-proxies/src/collection.rs b/atspi-proxies/src/collection.rs index bd0f5126..61738442 100644 --- a/atspi-proxies/src/collection.rs +++ b/atspi-proxies/src/collection.rs @@ -18,13 +18,13 @@ use crate::common::{ObjectMatchRule, ObjectRef, SortOrder, TreeTraversalType}; #[zbus::proxy(interface = "org.a11y.atspi.Collection", assume_defaults = true)] trait Collection { - // The active descendant of the given object. - // - // Looks like this is unimplemented. - // - // See [atspi/collection.c](https://gitlab.gnome.org/GNOME/at-spi2-core/-/blob/main/atspi/atspi-collection.c?ref_type=heads#L272) - // - // fn get_active_descendant(&self) -> zbus::Result; + /// The active descendant of the given object. + /// + /// May not be implemented by any known toolkit or private implementation. + /// + /// See [atspi/collection.c](https://gitlab.gnome.org/GNOME/at-spi2-core/-/blob/main/atspi/atspi-collection.c?ref_type=heads#L272) + /// + fn get_active_descendant(&self) -> zbus::Result; /// Retrieves a list of objects that match the specified ObjectMatchRule, ordered according to SortOrder and limited by the count parameter. ///