diff --git a/platforms/unix/src/atspi/bus.rs b/platforms/unix/src/atspi/bus.rs index e793af5e..23095a62 100644 --- a/platforms/unix/src/atspi/bus.rs +++ b/platforms/unix/src/atspi/bus.rs @@ -12,11 +12,15 @@ use accesskit_atspi_common::{ NodeId, NodeIdOrRoot, ObjectEvent, PlatformNode, PlatformRoot, Property, WindowEvent, }; use atspi::{ - Interface, InterfaceSet, + Interface, InterfaceSet, ObjectRefOwned, events::EventBodyBorrowed, proxy::{bus::BusProxy, socket::SocketProxy}, }; -use std::{env::var, io}; +use std::{ + env::var, + io, + sync::{Arc, OnceLock}, +}; use zbus::{ Address, Connection, Result, connection::Builder, @@ -28,6 +32,7 @@ pub(crate) struct Bus { conn: Connection, _task: Task<()>, socket_proxy: SocketProxy<'static>, + desktop: Arc>, } impl Bus { @@ -58,6 +63,7 @@ impl Bus { conn, _task, socket_proxy, + desktop: Arc::new(OnceLock::new()), }; bus.register_root_node().await?; Ok(bus) @@ -77,15 +83,21 @@ impl Bus { .at(path.clone(), ApplicationInterface(node.clone())) .await? { - self.socket_proxy + let desktop = self + .socket_proxy .embed(&(self.unique_name().as_str(), ObjectId::Root.path().into())) .await?; + let _ = self.desktop.set(desktop); self.conn .object_server() .at( path, - RootAccessibleInterface::new(self.unique_name().to_owned(), node.clone()), + RootAccessibleInterface::new( + self.unique_name().to_owned(), + node.clone(), + Arc::clone(&self.desktop), + ), ) .await?; @@ -93,7 +105,11 @@ impl Bus { .object_server() .at( cache_path(), - CacheInterface::new(self.unique_name().to_owned(), node), + CacheInterface::new( + self.unique_name().to_owned(), + node, + Arc::clone(&self.desktop), + ), ) .await?; } diff --git a/platforms/unix/src/atspi/interfaces/accessible.rs b/platforms/unix/src/atspi/interfaces/accessible.rs index 797b2371..ad61060c 100644 --- a/platforms/unix/src/atspi/interfaces/accessible.rs +++ b/platforms/unix/src/atspi/interfaces/accessible.rs @@ -3,10 +3,13 @@ // the LICENSE-APACHE file) or the MIT license (found in // the LICENSE-MIT file), at your option. -use std::collections::HashMap; +use std::{ + collections::HashMap, + sync::{Arc, OnceLock}, +}; use accesskit_atspi_common::{NodeIdOrRoot, PlatformNode, PlatformRoot}; -use atspi::{InterfaceSet, RelationType, Role, StateSet}; +use atspi::{InterfaceSet, ObjectRefOwned, RelationType, Role, StateSet}; use zbus::{fdo, interface, names::OwnedUniqueName}; use super::map_root_error; @@ -143,11 +146,20 @@ impl NodeAccessibleInterface { pub(crate) struct RootAccessibleInterface { bus_name: OwnedUniqueName, root: PlatformRoot, + desktop: Arc>, } impl RootAccessibleInterface { - pub fn new(bus_name: OwnedUniqueName, root: PlatformRoot) -> Self { - Self { bus_name, root } + pub fn new( + bus_name: OwnedUniqueName, + root: PlatformRoot, + desktop: Arc>, + ) -> Self { + Self { + bus_name, + root, + desktop, + } } } @@ -165,7 +177,12 @@ impl RootAccessibleInterface { #[zbus(property)] fn parent(&self) -> OwnedObjectAddress { - OwnedObjectAddress::null() + self.desktop + .get() + .cloned() + .unwrap_or_default() + .into_inner() + .into() } #[zbus(property)] diff --git a/platforms/unix/src/atspi/interfaces/cache.rs b/platforms/unix/src/atspi/interfaces/cache.rs index ad2a219e..349eb501 100644 --- a/platforms/unix/src/atspi/interfaces/cache.rs +++ b/platforms/unix/src/atspi/interfaces/cache.rs @@ -5,6 +5,7 @@ use accesskit_atspi_common::{CacheNode, Error, NodeIdOrRoot, PlatformNode, PlatformRoot}; use atspi::{CacheItem, ObjectRef, ObjectRefOwned}; +use std::sync::{Arc, OnceLock}; use zbus::{ fdo, interface, names::{OwnedUniqueName, UniqueName}, @@ -52,11 +53,15 @@ fn cache_item(bus_name: &UniqueName, node: CacheNode) -> CacheItem { } } -fn application_cache_item(bus_name: &UniqueName, root: &PlatformRoot) -> Result { +fn application_cache_item( + bus_name: &UniqueName, + root: &PlatformRoot, + desktop: ObjectRefOwned, +) -> Result { Ok(CacheItem { object: object_ref(bus_name, ObjectId::Root), app: object_ref(bus_name, ObjectId::Root), - parent: ObjectRefOwned::new(ObjectRef::Null), + parent: desktop, index: root.index_in_parent(), children: root.child_count()?, ifaces: root.interfaces(), @@ -70,11 +75,20 @@ fn application_cache_item(bus_name: &UniqueName, root: &PlatformRoot) -> Result< pub(crate) struct CacheInterface { bus_name: OwnedUniqueName, root: PlatformRoot, + desktop: Arc>, } impl CacheInterface { - pub fn new(bus_name: OwnedUniqueName, root: PlatformRoot) -> Self { - Self { bus_name, root } + pub fn new( + bus_name: OwnedUniqueName, + root: PlatformRoot, + desktop: Arc>, + ) -> Self { + Self { + bus_name, + root, + desktop, + } } fn items(&self) -> Result, Error> { @@ -83,8 +97,9 @@ impl CacheInterface { .root .map_descendant_cache_nodes(|node| cache_item(bus_name, node))?; + let desktop = self.desktop.get().cloned().unwrap_or_default(); let mut items = Vec::with_capacity(descendants.len() + 1); - items.push(application_cache_item(bus_name, &self.root)?); + items.push(application_cache_item(bus_name, &self.root, desktop)?); items.extend(descendants); Ok(items) } @@ -107,7 +122,8 @@ mod tests { use accesskit_atspi_common::{ Adapter, AdapterCallback, AppContext, Event, NodeId, PlatformRoot, WindowBounds, }; - use atspi::{Interface, ObjectRef, ObjectRefOwned, Role as AtspiRole}; + use atspi::{Interface, ObjectRefOwned, Role as AtspiRole}; + use std::sync::{Arc, OnceLock}; use zbus::names::{OwnedUniqueName, UniqueName}; struct NoOpActionHandler; @@ -150,7 +166,9 @@ mod tests { fn cache(update: TreeUpdate) -> (Adapter, CacheInterface) { let (adapter, root) = root_for(update); - (adapter, CacheInterface::new(bus_name(), root)) + let desktop = Arc::new(OnceLock::new()); + desktop.set(desktop_ref()).unwrap(); + (adapter, CacheInterface::new(bus_name(), root, desktop)) } fn window_with_button() -> TreeUpdate { @@ -175,6 +193,10 @@ mod tests { ) } + fn desktop_ref() -> ObjectRefOwned { + ObjectRefOwned::from_static_str_unchecked(":1.1", "/org/a11y/atspi/accessible/root") + } + #[test] fn get_items_prepends_application_root() { let (_adapter, iface) = cache(window_with_button()); @@ -184,7 +206,7 @@ mod tests { }; assert_eq!(app.object, root_ref()); assert_eq!(app.app, root_ref()); - assert_eq!(app.parent, ObjectRefOwned::new(ObjectRef::Null)); + assert_eq!(app.parent, desktop_ref()); assert_eq!(app.index, -1); assert_eq!(app.children, 1); assert_eq!(app.role, AtspiRole::Application); @@ -274,7 +296,11 @@ mod tests { WindowBounds::default(), NoOpActionHandler, ); - let iface = CacheInterface::new(bus_name(), PlatformRoot::new(&app_context)); + let iface = CacheInterface::new( + bus_name(), + PlatformRoot::new(&app_context), + Arc::new(OnceLock::new()), + ); let items = iface.items().unwrap(); let app_root = &items[0];