use crate::{
accessible::{AccessibleProxy, RelationType, Role},
collection::MatchType,
convertable::Convertable,
error::ObjectPathConversionError,
InterfaceSet,
};
use async_recursion::async_recursion;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, error::Error};
use zbus::{
zvariant::{ObjectPath, OwnedObjectPath},
CacheProperties,
};
pub type MatcherArgs =
(Vec<Role>, MatchType, HashMap<String, String>, MatchType, InterfaceSet, MatchType);
#[async_trait]
pub trait AccessibleExt {
fn get_id(&self) -> Option<AccessibleId>;
async fn get_parent_ext<'a>(&self) -> zbus::Result<AccessibleProxy<'a>>;
async fn get_children_ext<'a>(&self) -> zbus::Result<Vec<AccessibleProxy<'a>>>;
async fn get_siblings<'a>(&self) -> Result<Vec<AccessibleProxy<'a>>, Box<dyn Error>>;
async fn get_children_indexes<'a>(&self) -> zbus::Result<Vec<i32>>;
async fn get_siblings_before<'a>(&self) -> Result<Vec<AccessibleProxy<'a>>, Box<dyn Error>>;
async fn get_siblings_after<'a>(&self) -> Result<Vec<AccessibleProxy<'a>>, Box<dyn Error>>;
async fn get_ancestors<'a>(&self) -> zbus::Result<Vec<AccessibleProxy<'a>>>;
async fn get_ancestor_with_role<'a>(&self, role: Role) -> zbus::Result<AccessibleProxy<'a>>;
async fn get_children_caret<'a>(&self, after: bool) -> zbus::Result<Vec<AccessibleProxy<'a>>>;
async fn get_next<'a>(
&self,
matcher_args: &MatcherArgs,
backward: bool,
) -> zbus::Result<Option<AccessibleProxy<'a>>>;
async fn get_relation_set_ext<'a>(
&self,
) -> zbus::Result<HashMap<RelationType, Vec<AccessibleProxy<'a>>>>;
}
async fn match_(
accessible: &AccessibleProxy<'_>,
matcher_args: &MatcherArgs,
) -> zbus::Result<bool> {
let roles = &matcher_args.0;
if roles.len() != 1 {
return Ok(false);
}
Ok(accessible.get_role().await? == *roles.get(0).unwrap())
}
impl AccessibleProxy<'_> {
#[async_recursion]
async fn find_inner<'a>(
&self,
after_or_before: i32,
matcher_args: &MatcherArgs,
backward: bool,
recur: bool,
) -> zbus::Result<Option<AccessibleProxy<'a>>> {
let children = if backward {
let mut vec = self.get_children_ext().await?;
vec.reverse();
vec
} else {
self.get_children_ext().await?
};
for child in children {
let child_index = child.get_index_in_parent().await?;
if !recur
&& ((child_index <= after_or_before && !backward)
|| (child_index >= after_or_before && backward))
{
continue;
}
if match_(&child.clone(), matcher_args).await? {
return Ok(Some(child));
}
if let Some(found_decendant) = child.find_inner(0, matcher_args, backward, true).await?
{
return Ok(Some(found_decendant));
}
}
Ok(None)
}
}
#[derive(Clone, Copy, Hash, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum AccessibleId {
Null,
Root,
Number(i64),
}
impl ToString for AccessibleId {
fn to_string(&self) -> String {
let ending = match self {
Self::Null => "null".to_string(),
Self::Root => "root".to_string(),
Self::Number(int) => int.to_string(),
};
format!("/org/a11y/atspi/accessible/{ending}")
}
}
impl<'a> TryInto<ObjectPath<'a>> for AccessibleId {
type Error = zbus::zvariant::Error;
fn try_into(self) -> Result<ObjectPath<'a>, Self::Error> {
ObjectPath::try_from(self.to_string())
}
}
impl TryFrom<OwnedObjectPath> for AccessibleId {
type Error = ObjectPathConversionError;
fn try_from(path: OwnedObjectPath) -> Result<Self, Self::Error> {
match path.split('/').next_back() {
Some("null") => Ok(AccessibleId::Null),
Some("root") => Ok(AccessibleId::Root),
Some(id) => match id.parse::<i64>() {
Ok(uid) => Ok(AccessibleId::Number(uid)),
Err(e) => Err(Self::Error::ParseError(e)),
},
None => Err(Self::Error::NoIdAvailable),
}
}
}
impl<'a> TryFrom<ObjectPath<'a>> for AccessibleId {
type Error = ObjectPathConversionError;
fn try_from(path: ObjectPath<'a>) -> Result<Self, Self::Error> {
match path.split('/').next_back() {
Some("null") => Ok(AccessibleId::Null),
Some("root") => Ok(AccessibleId::Root),
Some(id) => match id.parse::<i64>() {
Ok(uid) => Ok(AccessibleId::Number(uid)),
Err(e) => Err(Self::Error::ParseError(e)),
},
None => Err(Self::Error::NoIdAvailable),
}
}
}
impl<'a> TryFrom<&ObjectPath<'a>> for AccessibleId {
type Error = ObjectPathConversionError;
fn try_from(path: &ObjectPath<'a>) -> Result<Self, Self::Error> {
match path.split('/').next_back() {
Some("null") => Ok(AccessibleId::Null),
Some("root") => Ok(AccessibleId::Root),
Some(id) => match id.parse::<i64>() {
Ok(uid) => Ok(AccessibleId::Number(uid)),
Err(e) => Err(Self::Error::ParseError(e)),
},
None => Err(Self::Error::NoIdAvailable),
}
}
}
#[async_trait]
impl AccessibleExt for AccessibleProxy<'_> {
fn get_id(&self) -> Option<AccessibleId> {
let path = self.path();
match path.split('/').next_back() {
Some("null") => Some(AccessibleId::Null),
Some("root") => Some(AccessibleId::Root),
Some(id) => match id.parse::<i64>() {
Ok(uid) => Some(AccessibleId::Number(uid)),
_ => None,
},
_ => None,
}
}
async fn get_parent_ext<'a>(&self) -> zbus::Result<AccessibleProxy<'a>> {
let parent_parts = self.parent().await?;
AccessibleProxy::builder(self.connection())
.destination(parent_parts.0)?
.cache_properties(CacheProperties::No)
.path(parent_parts.1)?
.build()
.await
}
async fn get_children_indexes<'a>(&self) -> zbus::Result<Vec<i32>> {
let mut indexes = Vec::new();
for child in self.get_children_ext().await? {
indexes.push(child.get_index_in_parent().await?);
}
Ok(indexes)
}
async fn get_children_ext<'a>(&self) -> zbus::Result<Vec<AccessibleProxy<'a>>> {
let children_parts = self.get_children().await?;
let mut children = Vec::new();
for child_parts in children_parts {
let acc = AccessibleProxy::builder(self.connection())
.destination(child_parts.0)?
.cache_properties(CacheProperties::No)
.path(child_parts.1)?
.build()
.await?;
children.push(acc);
}
Ok(children)
}
async fn get_siblings<'a>(&self) -> Result<Vec<AccessibleProxy<'a>>, Box<dyn Error>> {
let parent = self.get_parent_ext().await?;
let index = self.get_index_in_parent().await?.try_into()?;
#[allow(clippy::if_not_else)]
let children: Vec<AccessibleProxy<'a>> = parent
.get_children_ext()
.await?
.into_iter()
.enumerate()
.filter_map(|(i, a)| if i != index { Some(a) } else { None })
.collect();
Ok(children)
}
async fn get_siblings_before<'a>(&self) -> Result<Vec<AccessibleProxy<'a>>, Box<dyn Error>> {
let parent = self.get_parent_ext().await?;
let index = self.get_index_in_parent().await?.try_into()?;
let children: Vec<AccessibleProxy<'a>> = parent
.get_children_ext()
.await?
.into_iter()
.enumerate()
.filter_map(|(i, a)| if i < index { Some(a) } else { None })
.collect();
Ok(children)
}
async fn get_siblings_after<'a>(&self) -> Result<Vec<AccessibleProxy<'a>>, Box<dyn Error>> {
let parent = self.get_parent_ext().await?;
let index = self.get_index_in_parent().await?.try_into()?;
let children: Vec<AccessibleProxy<'a>> = parent
.get_children_ext()
.await?
.into_iter()
.enumerate()
.filter_map(|(i, a)| if i > index { Some(a) } else { None })
.collect();
Ok(children)
}
async fn get_ancestors<'a>(&self) -> zbus::Result<Vec<AccessibleProxy<'a>>> {
let mut ancestors = Vec::new();
let mut ancestor = self.get_parent_ext().await?;
while ancestor.get_role().await? != Role::Frame {
ancestors.push(ancestor.clone());
ancestor = ancestor.get_parent_ext().await?;
}
Ok(ancestors)
}
async fn get_ancestor_with_role<'a>(&self, role: Role) -> zbus::Result<AccessibleProxy<'a>> {
let mut ancestor = self.get_parent_ext().await?;
while ancestor.get_role().await? != role && ancestor.get_role().await? != Role::Frame {
ancestor = ancestor.get_parent_ext().await?;
}
Ok(ancestor)
}
async fn get_children_caret<'a>(
&self,
backward: bool,
) -> zbus::Result<Vec<AccessibleProxy<'a>>> {
let mut children_after_before = Vec::new();
let caret_pos = self.to_text().await?.caret_offset().await?;
let children_hyperlink = self.to_accessible().await?.get_children_ext().await?;
for child in children_hyperlink {
let hyperlink = child.to_hyperlink().await?;
if let Ok(start_index) = hyperlink.start_index().await {
if (start_index <= caret_pos && backward) || (start_index >= caret_pos && !backward)
{
children_after_before.push(child);
}
} else {
children_after_before.push(child);
}
}
Ok(children_after_before)
}
async fn get_next<'a>(
&self,
matcher_args: &MatcherArgs,
backward: bool,
) -> zbus::Result<Option<AccessibleProxy<'a>>> {
let caret_children = self.get_children_caret(backward).await?;
for child in caret_children {
if match_(&child.clone(), matcher_args).await? {
return Ok(Some(child));
} else if let Some(found_sub) =
child.find_inner(0, matcher_args, backward, true).await?
{
return Ok(Some(found_sub));
}
}
let mut last_parent_index = self.get_index_in_parent().await?;
if let Ok(mut parent) = self.get_parent_ext().await {
while parent.get_role().await? != Role::InternalFrame {
let found_inner_child = parent
.find_inner(last_parent_index, matcher_args, backward, false)
.await?;
if found_inner_child.is_some() {
return Ok(found_inner_child);
}
last_parent_index = parent.get_index_in_parent().await?;
parent = parent.get_parent_ext().await?;
}
}
Ok(None)
}
async fn get_relation_set_ext<'a>(
&self,
) -> zbus::Result<HashMap<RelationType, Vec<AccessibleProxy<'a>>>> {
let raw_relations = self.get_relation_set().await?;
let mut relations = HashMap::new();
for relation in raw_relations {
let mut related_vec = Vec::new();
for related in relation.1 {
let accessible = AccessibleProxy::builder(self.connection())
.destination(related.0)?
.cache_properties(CacheProperties::No)
.path(related.1)?
.build()
.await?;
related_vec.push(accessible);
}
relations.insert(relation.0, related_vec);
}
Ok(relations)
}
}