From 7c8d1ff251f66034a40d24b80071d73518bac79e Mon Sep 17 00:00:00 2001 From: DataTriny Date: Sun, 19 Nov 2023 20:14:13 +0100 Subject: [PATCH 1/9] Store window focused state and root window bounds in the adapter --- platforms/unix/src/adapter.rs | 26 ++++++++++++++++++++------ platforms/unix/src/context.rs | 3 ++- platforms/unix/src/util.rs | 2 +- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/platforms/unix/src/adapter.rs b/platforms/unix/src/adapter.rs index dc0ce85af..f25ad0e84 100644 --- a/platforms/unix/src/adapter.rs +++ b/platforms/unix/src/adapter.rs @@ -14,7 +14,7 @@ use crate::{ context::{AppContext, Context}, filters::{filter, filter_detached}, node::{NodeWrapper, PlatformNode}, - util::block_on, + util::{block_on, WindowBounds}, }; use accesskit::{ActionHandler, NodeId, Rect, Role, TreeUpdate}; use accesskit_consumer::{DetachedNode, FilterResult, Node, Tree, TreeChangeHandler, TreeState}; @@ -24,8 +24,8 @@ use futures_lite::StreamExt; use std::{ pin::pin, sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, Mutex, }, }; use zbus::Task; @@ -207,6 +207,8 @@ pub struct Adapter { _event_task: Task<()>, events: Sender, context: Arc, + is_window_focused: Arc, + root_window_bounds: Arc>, } impl Adapter { @@ -227,7 +229,9 @@ impl Adapter { }, "accesskit_event_task", ); - let tree = Tree::new(initial_state(), is_window_focused); + let is_window_focused = Arc::new(AtomicBool::new(is_window_focused)); + let root_window_bounds = Arc::new(Mutex::new(Default::default())); + let tree = Tree::new(initial_state(), is_window_focused.load(Ordering::Relaxed)); let id = NEXT_ADAPTER_ID.fetch_add(1, Ordering::SeqCst); let root_id = tree.state().root_id(); let app_context = AppContext::get_or_init( @@ -235,7 +239,12 @@ impl Adapter { tree.state().toolkit_name().unwrap_or_default(), tree.state().toolkit_version().unwrap_or_default(), ); - let context = Context::new(tree, action_handler, &app_context); + let context = Context::new( + tree, + action_handler, + *root_window_bounds.lock().unwrap(), + &app_context, + ); let adapter_index = app_context.write().unwrap().push_adapter(id, &context); block_on(async { if !atspi_bus.register_root_node(&app_context).await.ok()? { @@ -262,6 +271,8 @@ impl Adapter { _event_task: event_task, events: event_sender, context, + is_window_focused, + root_window_bounds, }; adapter.register_tree(); Some(adapter) @@ -388,9 +399,11 @@ impl Adapter { } pub fn set_root_window_bounds(&self, outer: Rect, inner: Rect) { - let mut bounds = self.context.root_window_bounds.write().unwrap(); + let mut bounds = self.root_window_bounds.lock().unwrap(); bounds.outer = outer; bounds.inner = inner; + let mut old_bounds = self.context.root_window_bounds.write().unwrap(); + *old_bounds = *bounds; } /// Apply the provided update to the tree. @@ -402,6 +415,7 @@ impl Adapter { /// Update the tree state based on whether the window is focused. pub fn update_window_focus_state(&self, is_focused: bool) { + self.is_window_focused.store(is_focused, Ordering::SeqCst); let mut handler = AdapterChangeHandler { adapter: self }; let mut tree = self.context.tree.write().unwrap(); tree.update_host_focus_state_and_process_changes(is_focused, &mut handler); diff --git a/platforms/unix/src/context.rs b/platforms/unix/src/context.rs index 8ee883d0e..44e37151f 100644 --- a/platforms/unix/src/context.rs +++ b/platforms/unix/src/context.rs @@ -21,13 +21,14 @@ impl Context { pub(crate) fn new( tree: Tree, action_handler: Box, + root_window_bounds: WindowBounds, app_context: &Arc>, ) -> Arc { Arc::new(Self { tree: RwLock::new(tree), action_handler: Mutex::new(action_handler), app_context: app_context.clone(), - root_window_bounds: RwLock::new(Default::default()), + root_window_bounds: RwLock::new(root_window_bounds), }) } diff --git a/platforms/unix/src/util.rs b/platforms/unix/src/util.rs index 21b75abf1..2f827c45d 100644 --- a/platforms/unix/src/util.rs +++ b/platforms/unix/src/util.rs @@ -39,7 +39,7 @@ pub(crate) fn block_on(future: F) -> F::Output { TOKIO_RT.block_on(future) } -#[derive(Default)] +#[derive(Clone, Copy, Default)] pub(crate) struct WindowBounds { pub(crate) outer: Rect, pub(crate) inner: Rect, From 8da66c2e765a3803f51dbc300ecc2e7d1adb64df Mon Sep 17 00:00:00 2001 From: DataTriny Date: Sun, 19 Nov 2023 22:26:19 +0100 Subject: [PATCH 2/9] Store adapter state into a Lazy cell --- bindings/c/examples/sdl/hello_world.c | 36 +++---- bindings/c/src/common.rs | 8 +- bindings/c/src/macos.rs | 7 +- bindings/c/src/unix.rs | 36 +++---- bindings/c/src/windows.rs | 4 +- platforms/unix/src/adapter.rs | 122 +++++++++++++++------- platforms/unix/src/util.rs | 4 + platforms/winit/src/platform_impl/unix.rs | 18 ++-- 8 files changed, 145 insertions(+), 90 deletions(-) diff --git a/bindings/c/examples/sdl/hello_world.c b/bindings/c/examples/sdl/hello_world.c index 1199cbbbc..94863ccef 100644 --- a/bindings/c/examples/sdl/hello_world.c +++ b/bindings/c/examples/sdl/hello_world.c @@ -77,7 +77,7 @@ void accesskit_sdl_adapter_init(struct accesskit_sdl_adapter *adapter, (void *)wmInfo.info.cocoa.window, source, source_userdata, handler); #elif defined(UNIX) adapter->adapter = - accesskit_unix_adapter_new(source, source_userdata, false, handler); + accesskit_unix_adapter_new(source, source_userdata, handler); #elif defined(_WIN32) SDL_SysWMinfo wmInfo; SDL_VERSION(&wmInfo.version); @@ -111,10 +111,8 @@ void accesskit_sdl_adapter_update_if_active( accesskit_macos_queued_events_raise(events); } #elif defined(UNIX) - if (adapter->adapter != NULL) { - accesskit_unix_adapter_update(adapter->adapter, - update_factory(update_factory_userdata)); - } + accesskit_unix_adapter_update_if_active(adapter->adapter, update_factory, + update_factory_userdata); #elif defined(_WIN32) accesskit_windows_queued_events *events = accesskit_windows_subclassing_adapter_update_if_active( @@ -135,10 +133,8 @@ void accesskit_sdl_adapter_update_window_focus_state( accesskit_macos_queued_events_raise(events); } #elif defined(UNIX) - if (adapter->adapter != NULL) { - accesskit_unix_adapter_update_window_focus_state(adapter->adapter, - is_focused); - } + accesskit_unix_adapter_update_window_focus_state(adapter->adapter, + is_focused); #endif /* On Windows, the subclassing adapter takes care of this. */ } @@ -146,18 +142,16 @@ void accesskit_sdl_adapter_update_window_focus_state( void accesskit_sdl_adapter_update_root_window_bounds( const struct accesskit_sdl_adapter *adapter, SDL_Window *window) { #if defined(UNIX) - if (adapter->adapter != NULL) { - int x, y, width, height; - SDL_GetWindowPosition(window, &x, &y); - SDL_GetWindowSize(window, &width, &height); - int top, left, bottom, right; - SDL_GetWindowBordersSize(window, &top, &left, &bottom, &right); - accesskit_rect outer_bounds = {x - left, y - top, x + width + right, - y + height + bottom}; - accesskit_rect inner_bounds = {x, y, x + width, y + height}; - accesskit_unix_adapter_set_root_window_bounds(adapter->adapter, - outer_bounds, inner_bounds); - } + int x, y, width, height; + SDL_GetWindowPosition(window, &x, &y); + SDL_GetWindowSize(window, &width, &height); + int top, left, bottom, right; + SDL_GetWindowBordersSize(window, &top, &left, &bottom, &right); + accesskit_rect outer_bounds = {x - left, y - top, x + width + right, + y + height + bottom}; + accesskit_rect inner_bounds = {x, y, x + width, y + height}; + accesskit_unix_adapter_set_root_window_bounds(adapter->adapter, outer_bounds, + inner_bounds); #endif } diff --git a/bindings/c/src/common.rs b/bindings/c/src/common.rs index 32a6a4364..a62100022 100644 --- a/bindings/c/src/common.rs +++ b/bindings/c/src/common.rs @@ -1123,5 +1123,11 @@ impl ActionHandler for FfiActionHandler { } } +#[repr(transparent)] +pub struct tree_update_factory_userdata(pub *mut c_void); + +unsafe impl Send for tree_update_factory_userdata {} + /// This function can't return a null pointer. Ownership of the returned value will be transfered to the caller. -pub type tree_update_factory = Option *mut tree_update>; +pub type tree_update_factory = + Option *mut tree_update>; diff --git a/bindings/c/src/macos.rs b/bindings/c/src/macos.rs index d54d53eae..e8debfb16 100644 --- a/bindings/c/src/macos.rs +++ b/bindings/c/src/macos.rs @@ -4,8 +4,8 @@ // the LICENSE-MIT file), at your option. use crate::{ - action_handler, box_from_ptr, ref_from_ptr, tree_update, tree_update_factory, BoxCastPtr, - CastPtr, + action_handler, box_from_ptr, ref_from_ptr, tree_update, tree_update_factory, + tree_update_factory_userdata, BoxCastPtr, CastPtr, }; use accesskit_macos::{ add_focus_forwarder_to_window_class, Adapter, NSPoint, QueuedEvents, SubclassingAdapter, @@ -147,6 +147,7 @@ impl macos_subclassing_adapter { handler: *mut action_handler, ) -> *mut macos_subclassing_adapter { let source = source.unwrap(); + let source_userdata = tree_update_factory_userdata(source_userdata); let handler = box_from_ptr(handler); let adapter = SubclassingAdapter::new( view, @@ -174,6 +175,7 @@ impl macos_subclassing_adapter { handler: *mut action_handler, ) -> *mut macos_subclassing_adapter { let source = source.unwrap(); + let source_userdata = tree_update_factory_userdata(source_userdata); let handler = box_from_ptr(handler); let adapter = SubclassingAdapter::for_window( window, @@ -211,6 +213,7 @@ impl macos_subclassing_adapter { update_factory_userdata: *mut c_void, ) -> *mut macos_queued_events { let update_factory = update_factory.unwrap(); + let update_factory_userdata = tree_update_factory_userdata(update_factory_userdata); let adapter = ref_from_ptr(adapter); let events = adapter.update_if_active(|| *box_from_ptr(update_factory(update_factory_userdata))); diff --git a/bindings/c/src/unix.rs b/bindings/c/src/unix.rs index 63b676d8d..60cb0485e 100644 --- a/bindings/c/src/unix.rs +++ b/bindings/c/src/unix.rs @@ -4,12 +4,12 @@ // the LICENSE-MIT file), at your option. use crate::{ - action_handler, box_from_ptr, ref_from_ptr, tree_update, tree_update_factory, BoxCastPtr, - CastPtr, + action_handler, box_from_ptr, ref_from_ptr, tree_update_factory, tree_update_factory_userdata, + BoxCastPtr, CastPtr, }; use accesskit::Rect; use accesskit_unix::Adapter; -use std::{os::raw::c_void, ptr}; +use std::os::raw::c_void; pub struct unix_adapter { _private: [u8; 0], @@ -22,22 +22,20 @@ impl CastPtr for unix_adapter { impl BoxCastPtr for unix_adapter {} impl unix_adapter { - /// This function will take ownership of the pointer returned by `initial_state`, which can't be null. + /// This function will take ownership of the pointer returned by `source`, which can't be null. + /// + /// `source` can be called from any thread. #[no_mangle] pub extern "C" fn accesskit_unix_adapter_new( - initial_state: tree_update_factory, - initial_state_userdata: *mut c_void, - is_window_focused: bool, + source: tree_update_factory, + source_userdata: *mut c_void, handler: *mut action_handler, ) -> *mut unix_adapter { - let initial_state = initial_state.unwrap(); + let source = source.unwrap(); + let source_userdata = tree_update_factory_userdata(source_userdata); let handler = box_from_ptr(handler); - let adapter = Adapter::new( - move || *box_from_ptr(initial_state(initial_state_userdata)), - is_window_focused, - handler, - ); - adapter.map_or_else(ptr::null_mut, BoxCastPtr::to_mut_ptr) + let adapter = Adapter::new(move || *box_from_ptr(source(source_userdata)), handler); + BoxCastPtr::to_mut_ptr(adapter) } #[no_mangle] @@ -57,13 +55,15 @@ impl unix_adapter { /// This function takes ownership of `update`. #[no_mangle] - pub extern "C" fn accesskit_unix_adapter_update( + pub extern "C" fn accesskit_unix_adapter_update_if_active( adapter: *const unix_adapter, - update: *mut tree_update, + update_factory: tree_update_factory, + update_factory_userdata: *mut c_void, ) { + let update_factory = update_factory.unwrap(); + let update_factory_userdata = tree_update_factory_userdata(update_factory_userdata); let adapter = ref_from_ptr(adapter); - let update = box_from_ptr(update); - adapter.update(*update); + adapter.update_if_active(|| *box_from_ptr(update_factory(update_factory_userdata))); } /// Update the tree state based on whether the window is focused. diff --git a/bindings/c/src/windows.rs b/bindings/c/src/windows.rs index 60a270ffa..a810d5477 100644 --- a/bindings/c/src/windows.rs +++ b/bindings/c/src/windows.rs @@ -5,7 +5,7 @@ use crate::{ action_handler, box_from_ptr, opt_struct, ref_from_ptr, tree_update, tree_update_factory, - BoxCastPtr, CastPtr, + tree_update_factory_userdata, BoxCastPtr, CastPtr, }; use accesskit_windows::*; use std::{os::raw::c_void, ptr}; @@ -151,6 +151,7 @@ impl windows_subclassing_adapter { handler: *mut action_handler, ) -> *mut windows_subclassing_adapter { let source = source.unwrap(); + let source_userdata = tree_update_factory_userdata(source_userdata); let handler = box_from_ptr(handler); let adapter = SubclassingAdapter::new( hwnd, @@ -188,6 +189,7 @@ impl windows_subclassing_adapter { update_factory_userdata: *mut c_void, ) -> *mut windows_queued_events { let update_factory = update_factory.unwrap(); + let update_factory_userdata = tree_update_factory_userdata(update_factory_userdata); let adapter = ref_from_ptr(adapter); let events = adapter.update_if_active(|| *box_from_ptr(update_factory(update_factory_userdata))); diff --git a/platforms/unix/src/adapter.rs b/platforms/unix/src/adapter.rs index f25ad0e84..81620f62f 100644 --- a/platforms/unix/src/adapter.rs +++ b/platforms/unix/src/adapter.rs @@ -19,10 +19,11 @@ use crate::{ use accesskit::{ActionHandler, NodeId, Rect, Role, TreeUpdate}; use accesskit_consumer::{DetachedNode, FilterResult, Node, Tree, TreeChangeHandler, TreeState}; use async_channel::{Receiver, Sender}; +use async_once_cell::Lazy; use atspi::{Interface, InterfaceSet, Live, State}; -use futures_lite::StreamExt; +use futures_lite::{future::Boxed, FutureExt, StreamExt}; use std::{ - pin::pin, + pin::{pin, Pin}, sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, Arc, Mutex, @@ -31,7 +32,7 @@ use std::{ use zbus::Task; struct AdapterChangeHandler<'a> { - adapter: &'a Adapter, + adapter: &'a AdapterImpl, } impl AdapterChangeHandler<'_> { @@ -201,21 +202,19 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> { static NEXT_ADAPTER_ID: AtomicUsize = AtomicUsize::new(0); -pub struct Adapter { +pub(crate) struct AdapterImpl { id: usize, atspi_bus: Bus, _event_task: Task<()>, events: Sender, context: Arc, - is_window_focused: Arc, - root_window_bounds: Arc>, } -impl Adapter { - /// Create a new Unix adapter. - pub fn new( - initial_state: impl 'static + FnOnce() -> TreeUpdate, +impl AdapterImpl { + fn new( + initial_state: TreeUpdate, is_window_focused: bool, + root_window_bounds: WindowBounds, action_handler: Box, ) -> Option { let mut atspi_bus = block_on(async { Bus::a11y_bus().await })?; @@ -229,9 +228,7 @@ impl Adapter { }, "accesskit_event_task", ); - let is_window_focused = Arc::new(AtomicBool::new(is_window_focused)); - let root_window_bounds = Arc::new(Mutex::new(Default::default())); - let tree = Tree::new(initial_state(), is_window_focused.load(Ordering::Relaxed)); + let tree = Tree::new(initial_state, is_window_focused); let id = NEXT_ADAPTER_ID.fetch_add(1, Ordering::SeqCst); let root_id = tree.state().root_id(); let app_context = AppContext::get_or_init( @@ -239,12 +236,7 @@ impl Adapter { tree.state().toolkit_name().unwrap_or_default(), tree.state().toolkit_version().unwrap_or_default(), ); - let context = Context::new( - tree, - action_handler, - *root_window_bounds.lock().unwrap(), - &app_context, - ); + let context = Context::new(tree, action_handler, root_window_bounds, &app_context); let adapter_index = app_context.write().unwrap().push_adapter(id, &context); block_on(async { if !atspi_bus.register_root_node(&app_context).await.ok()? { @@ -265,17 +257,15 @@ impl Adapter { Some(()) } })?; - let adapter = Adapter { + let r#impl = AdapterImpl { id, atspi_bus, _event_task: event_task, events: event_sender, context, - is_window_focused, - root_window_bounds, }; - adapter.register_tree(); - Some(adapter) + r#impl.register_tree(); + Some(r#impl) } fn register_tree(&self) { @@ -398,24 +388,18 @@ impl Adapter { }) } - pub fn set_root_window_bounds(&self, outer: Rect, inner: Rect) { - let mut bounds = self.root_window_bounds.lock().unwrap(); - bounds.outer = outer; - bounds.inner = inner; + fn set_root_window_bounds(&self, bounds: WindowBounds) { let mut old_bounds = self.context.root_window_bounds.write().unwrap(); - *old_bounds = *bounds; + *old_bounds = bounds; } - /// Apply the provided update to the tree. - pub fn update(&self, update: TreeUpdate) { + fn update(&self, update: TreeUpdate) { let mut handler = AdapterChangeHandler { adapter: self }; let mut tree = self.context.tree.write().unwrap(); tree.update_and_process_changes(update, &mut handler); } - /// Update the tree state based on whether the window is focused. - pub fn update_window_focus_state(&self, is_focused: bool) { - self.is_window_focused.store(is_focused, Ordering::SeqCst); + fn update_window_focus_state(&self, is_focused: bool) { let mut handler = AdapterChangeHandler { adapter: self }; let mut tree = self.context.tree.write().unwrap(); tree.update_host_focus_state_and_process_changes(is_focused, &mut handler); @@ -512,7 +496,7 @@ fn root_window(current_state: &TreeState) -> Option { } } -impl Drop for Adapter { +impl Drop for AdapterImpl { fn drop(&mut self) { block_on(async { self.context @@ -548,3 +532,71 @@ async fn handle_events(bus: Bus, mut events: Receiver) { }; } } + +pub(crate) type LazyAdapter = Pin, Boxed>>>>; + +pub struct Adapter { + r#impl: LazyAdapter, + is_window_focused: Arc, + root_window_bounds: Arc>, +} + +impl Adapter { + /// Create a new Unix adapter. + pub fn new( + source: impl 'static + FnOnce() -> TreeUpdate + Send, + action_handler: Box, + ) -> Self { + let is_window_focused = Arc::new(AtomicBool::new(false)); + let is_window_focused_copy = is_window_focused.clone(); + let root_window_bounds = Arc::new(Mutex::new(Default::default())); + let root_window_bounds_copy = root_window_bounds.clone(); + let r#impl = Arc::pin(Lazy::new( + async move { + let is_window_focused = is_window_focused_copy.load(Ordering::Relaxed); + let root_window_bounds = *root_window_bounds_copy.lock().unwrap(); + AdapterImpl::new( + source(), + is_window_focused, + root_window_bounds, + action_handler, + ) + } + .boxed(), + )); + let adapter = Self { + r#impl: r#impl.clone(), + is_window_focused, + root_window_bounds, + }; + block_on(async { r#impl.as_ref().await }); + adapter + } + + pub fn set_root_window_bounds(&self, outer: Rect, inner: Rect) { + let new_bounds = WindowBounds::new(outer, inner); + { + let mut bounds = self.root_window_bounds.lock().unwrap(); + *bounds = new_bounds; + } + if let Some(Some(r#impl)) = Lazy::try_get(&self.r#impl) { + r#impl.set_root_window_bounds(new_bounds); + } + } + + /// If and only if the tree has been initialized, call the provided function + /// and apply the resulting update. + pub fn update_if_active(&self, update_factory: impl FnOnce() -> TreeUpdate) { + if let Some(Some(r#impl)) = Lazy::try_get(&self.r#impl) { + r#impl.update(update_factory()); + } + } + + /// Update the tree state based on whether the window is focused. + pub fn update_window_focus_state(&self, is_focused: bool) { + self.is_window_focused.store(is_focused, Ordering::SeqCst); + if let Some(Some(r#impl)) = Lazy::try_get(&self.r#impl) { + r#impl.update_window_focus_state(is_focused); + } + } +} diff --git a/platforms/unix/src/util.rs b/platforms/unix/src/util.rs index 2f827c45d..38b71a94d 100644 --- a/platforms/unix/src/util.rs +++ b/platforms/unix/src/util.rs @@ -46,6 +46,10 @@ pub(crate) struct WindowBounds { } impl WindowBounds { + pub(crate) fn new(outer: Rect, inner: Rect) -> Self { + Self { outer, inner } + } + pub(crate) fn top_left(&self, coord_type: CoordType, is_root: bool) -> Point { match coord_type { CoordType::Screen if is_root => self.outer.origin(), diff --git a/platforms/winit/src/platform_impl/unix.rs b/platforms/winit/src/platform_impl/unix.rs index 3fd9886aa..5a1b0dceb 100644 --- a/platforms/winit/src/platform_impl/unix.rs +++ b/platforms/winit/src/platform_impl/unix.rs @@ -9,35 +9,29 @@ use winit::{event::WindowEvent, window::Window}; pub type ActionHandlerBox = Box; pub struct Adapter { - adapter: Option, + adapter: UnixAdapter, } impl Adapter { pub fn new( _: &Window, - source: impl 'static + FnOnce() -> TreeUpdate, + source: impl 'static + FnOnce() -> TreeUpdate + Send, action_handler: ActionHandlerBox, ) -> Self { - let adapter = UnixAdapter::new(source, false, action_handler); + let adapter = UnixAdapter::new(source, action_handler); Self { adapter } } fn set_root_window_bounds(&self, outer: Rect, inner: Rect) { - if let Some(adapter) = &self.adapter { - adapter.set_root_window_bounds(outer, inner); - } + self.adapter.set_root_window_bounds(outer, inner); } pub fn update_if_active(&self, updater: impl FnOnce() -> TreeUpdate) { - if let Some(adapter) = &self.adapter { - adapter.update(updater()); - } + self.adapter.update_if_active(updater); } fn update_window_focus_state(&self, is_focused: bool) { - if let Some(adapter) = &self.adapter { - adapter.update_window_focus_state(is_focused); - } + self.adapter.update_window_focus_state(is_focused); } pub fn process_event(&self, window: &Window, event: &WindowEvent) { From 8fecaf4757180fa8ce36d12ad23e7bf70f0c5c9c Mon Sep 17 00:00:00 2001 From: DataTriny Date: Fri, 8 Dec 2023 20:15:27 +0100 Subject: [PATCH 3/9] Remove useless pointer to AppContext inside Context --- platforms/unix/src/adapter.rs | 23 +++++------------------ platforms/unix/src/atspi/bus.rs | 16 +++++----------- platforms/unix/src/context.rs | 17 +++++++++-------- platforms/unix/src/node.rs | 30 +++++++++--------------------- 4 files changed, 28 insertions(+), 58 deletions(-) diff --git a/platforms/unix/src/adapter.rs b/platforms/unix/src/adapter.rs index 81620f62f..52af11068 100644 --- a/platforms/unix/src/adapter.rs +++ b/platforms/unix/src/adapter.rs @@ -48,12 +48,7 @@ impl AdapterChangeHandler<'_> { .register_interfaces(node.id(), interfaces) .unwrap(); if is_root && role == Role::Window { - let adapter_index = self - .adapter - .context - .read_app_context() - .adapter_index(self.adapter.id) - .unwrap(); + let adapter_index = AppContext::read().adapter_index(self.adapter.id).unwrap(); self.adapter.window_created(adapter_index, node.id()); } @@ -236,10 +231,10 @@ impl AdapterImpl { tree.state().toolkit_name().unwrap_or_default(), tree.state().toolkit_version().unwrap_or_default(), ); - let context = Context::new(tree, action_handler, root_window_bounds, &app_context); + let context = Context::new(tree, action_handler, root_window_bounds); let adapter_index = app_context.write().unwrap().push_adapter(id, &context); block_on(async { - if !atspi_bus.register_root_node(&app_context).await.ok()? { + if !atspi_bus.register_root_node().await.ok()? { atspi_bus .emit_object_event( ObjectId::Root, @@ -291,11 +286,7 @@ impl AdapterImpl { let interfaces = wrapper.interfaces(); self.register_interfaces(id, interfaces).unwrap(); if node.is_root() && node.role() == Role::Window { - let adapter_index = self - .context - .read_app_context() - .adapter_index(self.id) - .unwrap(); + let adapter_index = AppContext::read().adapter_index(self.id).unwrap(); self.window_created(adapter_index, node.id()); } } @@ -499,11 +490,7 @@ fn root_window(current_state: &TreeState) -> Option { impl Drop for AdapterImpl { fn drop(&mut self) { block_on(async { - self.context - .app_context - .write() - .unwrap() - .remove_adapter(self.id); + AppContext::write().remove_adapter(self.id); let root_id = self.context.read_tree().state().root_id(); self.atspi_bus .emit_object_event( diff --git a/platforms/unix/src/atspi/bus.rs b/platforms/unix/src/atspi/bus.rs index 15af7d61e..a1ab97aff 100644 --- a/platforms/unix/src/atspi/bus.rs +++ b/platforms/unix/src/atspi/bus.rs @@ -14,11 +14,7 @@ use atspi::{ proxy::{bus::BusProxy, socket::SocketProxy}, }; use serde::Serialize; -use std::{ - collections::HashMap, - env::var, - sync::{Arc, RwLock}, -}; +use std::{collections::HashMap, env::var}; use zbus::{ names::{BusName, InterfaceName, MemberName, OwnedUniqueName}, zvariant::{Str, Value}, @@ -60,11 +56,8 @@ impl Bus { self.conn.object_server().remove::(path).await } - pub async fn register_root_node( - &mut self, - app_context: &Arc>, - ) -> Result { - let node = PlatformRootNode::new(app_context); + pub(crate) async fn register_root_node(&mut self) -> Result { + let node = PlatformRootNode::new(); let path = ObjectId::Root.path(); let app_node_added = self @@ -86,7 +79,8 @@ impl Bus { .socket_proxy .embed(&(self.unique_name().as_str(), ObjectId::Root.path().into())) .await?; - app_context.write().unwrap().desktop_address = Some(desktop.into()); + let mut app_context = AppContext::write(); + app_context.desktop_address = Some(desktop.into()); Ok(true) } else { Ok(false) diff --git a/platforms/unix/src/context.rs b/platforms/unix/src/context.rs index 44e37151f..b20a4ee2e 100644 --- a/platforms/unix/src/context.rs +++ b/platforms/unix/src/context.rs @@ -6,14 +6,13 @@ use accesskit::{ActionHandler, ActionRequest}; use accesskit_consumer::Tree; use once_cell::sync::OnceCell; -use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, Weak}; +use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak}; use crate::{atspi::OwnedObjectAddress, util::WindowBounds}; pub(crate) struct Context { pub(crate) tree: RwLock, pub(crate) action_handler: Mutex>, - pub(crate) app_context: Arc>, pub(crate) root_window_bounds: RwLock, } @@ -22,12 +21,10 @@ impl Context { tree: Tree, action_handler: Box, root_window_bounds: WindowBounds, - app_context: &Arc>, ) -> Arc { Arc::new(Self { tree: RwLock::new(tree), action_handler: Mutex::new(action_handler), - app_context: app_context.clone(), root_window_bounds: RwLock::new(root_window_bounds), }) } @@ -36,10 +33,6 @@ impl Context { self.tree.read().unwrap() } - pub(crate) fn read_app_context(&self) -> RwLockReadGuard<'_, AppContext> { - self.app_context.read().unwrap() - } - pub(crate) fn read_root_window_bounds(&self) -> RwLockReadGuard<'_, WindowBounds> { self.root_window_bounds.read().unwrap() } @@ -88,6 +81,14 @@ impl AppContext { .clone() } + pub(crate) fn read<'a>() -> RwLockReadGuard<'a, AppContext> { + APP_CONTEXT.get().unwrap().read().unwrap() + } + + pub(crate) fn write<'a>() -> RwLockWriteGuard<'a, AppContext> { + APP_CONTEXT.get().unwrap().write().unwrap() + } + pub(crate) fn adapter_index(&self, id: usize) -> Result { self.adapters.binary_search_by(|adapter| adapter.0.cmp(&id)) } diff --git a/platforms/unix/src/node.rs b/platforms/unix/src/node.rs index fc9789792..8ed5ac413 100644 --- a/platforms/unix/src/node.rs +++ b/platforms/unix/src/node.rs @@ -29,7 +29,7 @@ use atspi::{ }; use std::{ iter::FusedIterator, - sync::{Arc, RwLock, RwLockReadGuard, Weak}, + sync::{Arc, RwLockReadGuard, Weak}, }; use zbus::fdo; @@ -999,27 +999,19 @@ impl PlatformNode { } #[derive(Clone)] -pub(crate) struct PlatformRootNode { - pub(crate) app_context: Weak>, -} +pub(crate) struct PlatformRootNode; impl PlatformRootNode { - pub(crate) fn new(app_context: &Arc>) -> Self { - Self { - app_context: Arc::downgrade(app_context), - } + pub(crate) fn new() -> Self { + Self {} } fn resolve_app_context(&self, f: F) -> fdo::Result where for<'a> F: FnOnce(RwLockReadGuard<'a, AppContext>) -> fdo::Result, { - if let Some(context) = self.app_context.upgrade() { - if let Ok(context) = context.read() { - return f(context); - } - } - Err(unknown_object(&self.accessible_id())) + let app_context = AppContext::read(); + f(app_context) } pub(crate) fn name(&self) -> fdo::Result { @@ -1083,12 +1075,8 @@ impl PlatformRootNode { } pub(crate) fn set_id(&mut self, id: i32) -> fdo::Result<()> { - if let Some(context) = self.app_context.upgrade() { - if let Ok(mut context) = context.write() { - context.id = Some(id); - return Ok(()); - } - } - Err(unknown_object(&self.accessible_id())) + let mut app_context = AppContext::write(); + app_context.id = Some(id); + Ok(()) } } From f6595efa1abf2a591109e438d5206e58fc8fbea6 Mon Sep 17 00:00:00 2001 From: DataTriny Date: Sun, 10 Dec 2023 20:16:54 +0100 Subject: [PATCH 4/9] Initialize the adapter if AT-SPI is currently enabled --- Cargo.lock | 1 + platforms/unix/Cargo.toml | 2 +- platforms/unix/src/adapter.rs | 42 ++++++++-------- platforms/unix/src/atspi/bus.rs | 36 ++++++------- platforms/unix/src/context.rs | 89 ++++++++++++++++++++++++++++----- platforms/unix/src/node.rs | 6 +-- 6 files changed, 117 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bec8b4402..7225fc605 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,6 +63,7 @@ dependencies = [ "accesskit", "accesskit_consumer", "async-channel 2.1.1", + "async-lock", "async-once-cell", "atspi", "futures-lite", diff --git a/platforms/unix/Cargo.toml b/platforms/unix/Cargo.toml index 96a789bed..0e0eebcac 100644 --- a/platforms/unix/Cargo.toml +++ b/platforms/unix/Cargo.toml @@ -19,6 +19,7 @@ tokio = ["dep:tokio", "atspi/tokio", "zbus/tokio"] accesskit = { version = "0.12.1", path = "../../common" } accesskit_consumer = { version = "0.16.1", path = "../../consumer" } async-channel = "2.1.1" +async-lock = "2.7.0" async-once-cell = "0.5.3" atspi = { version = "0.19", default-features = false } futures-lite = "1.13" @@ -26,4 +27,3 @@ once_cell = "1.17.1" serde = "1.0" tokio = { version = "1.32.0", optional = true, features = ["rt", "net", "time"] } zbus = { version = "3.14", default-features = false } - diff --git a/platforms/unix/src/adapter.rs b/platforms/unix/src/adapter.rs index 52af11068..c3ff0faf9 100644 --- a/platforms/unix/src/adapter.rs +++ b/platforms/unix/src/adapter.rs @@ -11,7 +11,7 @@ use crate::{ }, Bus, ObjectId, }, - context::{AppContext, Context}, + context::{ActivationContext, AppContext, Context}, filters::{filter, filter_detached}, node::{NodeWrapper, PlatformNode}, util::{block_on, WindowBounds}, @@ -212,27 +212,29 @@ impl AdapterImpl { root_window_bounds: WindowBounds, action_handler: Box, ) -> Option { - let mut atspi_bus = block_on(async { Bus::a11y_bus().await })?; - let (event_sender, event_receiver) = async_channel::unbounded(); - let atspi_bus_copy = atspi_bus.clone(); - #[cfg(feature = "tokio")] - let _guard = crate::util::TOKIO_RT.enter(); - let event_task = atspi_bus.connection().executor().spawn( - async move { - handle_events(atspi_bus_copy, event_receiver).await; - }, - "accesskit_event_task", - ); let tree = Tree::new(initial_state, is_window_focused); let id = NEXT_ADAPTER_ID.fetch_add(1, Ordering::SeqCst); let root_id = tree.state().root_id(); - let app_context = AppContext::get_or_init( - tree.state().app_name().unwrap_or_default(), - tree.state().toolkit_name().unwrap_or_default(), - tree.state().toolkit_version().unwrap_or_default(), - ); - let context = Context::new(tree, action_handler, root_window_bounds); - let adapter_index = app_context.write().unwrap().push_adapter(id, &context); + let (event_sender, event_receiver) = async_channel::unbounded(); + let (mut atspi_bus, event_task, context, adapter_index) = { + let mut app_context = AppContext::write(); + app_context.name = tree.state().app_name(); + app_context.toolkit_name = tree.state().toolkit_name(); + app_context.toolkit_version = tree.state().toolkit_version(); + let atspi_bus = app_context.atspi_bus.clone().unwrap(); + let atspi_bus_copy = atspi_bus.clone(); + #[cfg(feature = "tokio")] + let _guard = crate::util::TOKIO_RT.enter(); + let event_task = atspi_bus.connection().executor().spawn( + async move { + handle_events(atspi_bus_copy, event_receiver).await; + }, + "accesskit_event_task", + ); + let context = Context::new(tree, action_handler, root_window_bounds); + let adapter_index = app_context.push_adapter(id, &context); + (atspi_bus, event_task, context, adapter_index) + }; block_on(async { if !atspi_bus.register_root_node().await.ok()? { atspi_bus @@ -556,7 +558,7 @@ impl Adapter { is_window_focused, root_window_bounds, }; - block_on(async { r#impl.as_ref().await }); + block_on(async move { ActivationContext::activate_eventually(r#impl).await }); adapter } diff --git a/platforms/unix/src/atspi/bus.rs b/platforms/unix/src/atspi/bus.rs index a1ab97aff..1ed25fd4a 100644 --- a/platforms/unix/src/atspi/bus.rs +++ b/platforms/unix/src/atspi/bus.rs @@ -8,7 +8,6 @@ use crate::{ context::AppContext, PlatformRootNode, }; -use async_once_cell::OnceCell; use atspi::{ events::EventBody, proxy::{bus::BusProxy, socket::SocketProxy}, @@ -269,26 +268,19 @@ impl Bus { } } -static A11Y_BUS: OnceCell> = OnceCell::new(); - async fn a11y_bus() -> Option { - A11Y_BUS - .get_or_init(async { - let address = match var("AT_SPI_BUS_ADDRESS") { - Ok(address) if !address.is_empty() => address, - _ => { - let session_bus = Connection::session().await.ok()?; - BusProxy::new(&session_bus) - .await - .ok()? - .get_address() - .await - .ok()? - } - }; - let address: Address = address.as_str().try_into().ok()?; - ConnectionBuilder::address(address).ok()?.build().await.ok() - }) - .await - .clone() + let address = match var("AT_SPI_BUS_ADDRESS") { + Ok(address) if !address.is_empty() => address, + _ => { + let session_bus = Connection::session().await.ok()?; + BusProxy::new(&session_bus) + .await + .ok()? + .get_address() + .await + .ok()? + } + }; + let address: Address = address.as_str().try_into().ok()?; + ConnectionBuilder::address(address).ok()?.build().await.ok() } diff --git a/platforms/unix/src/context.rs b/platforms/unix/src/context.rs index b20a4ee2e..6f652e533 100644 --- a/platforms/unix/src/context.rs +++ b/platforms/unix/src/context.rs @@ -5,10 +5,19 @@ use accesskit::{ActionHandler, ActionRequest}; use accesskit_consumer::Tree; +use async_lock::{Mutex as AsyncMutex, MutexGuard as AsyncMutexGuard}; +use async_once_cell::OnceCell as AsyncOnceCell; +use atspi::proxy::bus::StatusProxy; +use futures_lite::StreamExt; use once_cell::sync::OnceCell; use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak}; +use zbus::{Connection, Task}; -use crate::{atspi::OwnedObjectAddress, util::WindowBounds}; +use crate::{ + adapter::LazyAdapter, + atspi::{Bus, OwnedObjectAddress}, + util::WindowBounds, +}; pub(crate) struct Context { pub(crate) tree: RwLock, @@ -53,32 +62,31 @@ impl AdapterAndContext { static APP_CONTEXT: OnceCell>> = OnceCell::new(); pub(crate) struct AppContext { - pub(crate) name: String, - pub(crate) toolkit_name: String, - pub(crate) toolkit_version: String, + pub(crate) atspi_bus: Option, + pub(crate) name: Option, + pub(crate) toolkit_name: Option, + pub(crate) toolkit_version: Option, pub(crate) id: Option, pub(crate) desktop_address: Option, pub(crate) adapters: Vec, } impl AppContext { - pub(crate) fn get_or_init( - name: String, - toolkit_name: String, - toolkit_version: String, - ) -> Arc> { + fn get_or_init<'a>() -> RwLockWriteGuard<'a, Self> { APP_CONTEXT .get_or_init(|| { Arc::new(RwLock::new(Self { - name, - toolkit_name, - toolkit_version, + atspi_bus: None, + name: None, + toolkit_name: None, + toolkit_version: None, id: None, desktop_address: None, adapters: Vec::new(), })) }) - .clone() + .write() + .unwrap() } pub(crate) fn read<'a>() -> RwLockReadGuard<'a, AppContext> { @@ -106,3 +114,58 @@ impl AppContext { } } } + +pub(crate) struct ActivationContext { + _monitoring_task: Task<()>, + adapters: Vec, +} + +static ACTIVATION_CONTEXT: AsyncOnceCell>> = AsyncOnceCell::new(); + +impl ActivationContext { + async fn get_or_init<'a>() -> AsyncMutexGuard<'a, ActivationContext> { + ACTIVATION_CONTEXT + .get_or_init(async { + let session_bus = Connection::session().await.unwrap(); + let session_bus_copy = session_bus.clone(); + let monitoring_task = session_bus.executor().spawn( + async move { + let _ = monitor_a11y_status(session_bus_copy).await; + }, + "accesskit_a11y_monitoring_task", + ); + Arc::new(AsyncMutex::new(ActivationContext { + _monitoring_task: monitoring_task, + adapters: Vec::new(), + })) + }) + .await + .lock() + .await + } + + pub(crate) async fn activate_eventually(adapter: LazyAdapter) { + let mut activation_context = ActivationContext::get_or_init().await; + activation_context.adapters.push(adapter); + let adapter = activation_context.adapters.last().unwrap(); + let is_a11y_enabled = AppContext::get_or_init().atspi_bus.is_some(); + if is_a11y_enabled { + adapter.as_ref().await; + } + } +} + +async fn monitor_a11y_status(session_bus: Connection) -> zbus::Result<()> { + let status = StatusProxy::new(&session_bus).await?; + let mut changes = status.receive_is_enabled_changed().await; + + while let Some(change) = changes.next().await { + if let Ok(true) = change.get().await { + let atspi_bus = Bus::a11y_bus().await; + let mut app_context = AppContext::get_or_init(); + app_context.atspi_bus = atspi_bus; + } + } + + Ok(()) +} diff --git a/platforms/unix/src/node.rs b/platforms/unix/src/node.rs index 8ed5ac413..f344d4e22 100644 --- a/platforms/unix/src/node.rs +++ b/platforms/unix/src/node.rs @@ -1015,7 +1015,7 @@ impl PlatformRootNode { } pub(crate) fn name(&self) -> fdo::Result { - self.resolve_app_context(|context| Ok(context.name.clone())) + self.resolve_app_context(|context| Ok(context.name.clone().unwrap_or_default())) } pub(crate) fn parent(&self) -> fdo::Result> { @@ -1063,11 +1063,11 @@ impl PlatformRootNode { } pub(crate) fn toolkit_name(&self) -> fdo::Result { - self.resolve_app_context(|context| Ok(context.toolkit_name.clone())) + self.resolve_app_context(|context| Ok(context.toolkit_name.clone().unwrap_or_default())) } pub(crate) fn toolkit_version(&self) -> fdo::Result { - self.resolve_app_context(|context| Ok(context.toolkit_version.clone())) + self.resolve_app_context(|context| Ok(context.toolkit_version.clone().unwrap_or_default())) } pub(crate) fn id(&self) -> fdo::Result { From abfade2d7a268e5d547ffc8eeed46aab5f5c3cd8 Mon Sep 17 00:00:00 2001 From: DataTriny Date: Sun, 10 Dec 2023 21:41:30 +0100 Subject: [PATCH 5/9] Also initialize adapters if AT-SPI is enabled later --- platforms/unix/src/context.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/platforms/unix/src/context.rs b/platforms/unix/src/context.rs index 6f652e533..a44e12365 100644 --- a/platforms/unix/src/context.rs +++ b/platforms/unix/src/context.rs @@ -160,11 +160,23 @@ async fn monitor_a11y_status(session_bus: Connection) -> zbus::Result<()> { let mut changes = status.receive_is_enabled_changed().await; while let Some(change) = changes.next().await { - if let Ok(true) = change.get().await { - let atspi_bus = Bus::a11y_bus().await; + let atspi_bus = match change.get().await { + Ok(true) => Bus::a11y_bus().await, + _ => None, + }; + let activate = atspi_bus.is_some(); + { let mut app_context = AppContext::get_or_init(); app_context.atspi_bus = atspi_bus; } + if activate { + if let Some(activation_context) = ACTIVATION_CONTEXT.get() { + let activation_context = activation_context.lock().await; + for adapter in &activation_context.adapters { + adapter.as_ref().await; + } + } + } } Ok(()) From d6394ba544f0a08bc23cdfdf219959fa89b03d2b Mon Sep 17 00:00:00 2001 From: DataTriny Date: Tue, 26 Dec 2023 12:10:01 +0100 Subject: [PATCH 6/9] Centralize D-Bus tree manipulation and signal emitting to allow re-activating adapters --- Cargo.lock | 13 + platforms/unix/Cargo.toml | 1 + platforms/unix/src/adapter.rs | 615 ++++++++++++++------------------ platforms/unix/src/atspi/bus.rs | 159 ++++++--- platforms/unix/src/context.rs | 115 ++++-- platforms/unix/src/node.rs | 183 +++++----- 6 files changed, 568 insertions(+), 518 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7225fc605..19056faa7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,6 +67,7 @@ dependencies = [ "async-once-cell", "atspi", "futures-lite", + "futures-util", "once_cell", "serde", "tokio", @@ -859,6 +860,17 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-macro" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "futures-sink" version = "0.3.27" @@ -879,6 +891,7 @@ checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" dependencies = [ "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", diff --git a/platforms/unix/Cargo.toml b/platforms/unix/Cargo.toml index 0e0eebcac..7f53044ec 100644 --- a/platforms/unix/Cargo.toml +++ b/platforms/unix/Cargo.toml @@ -23,6 +23,7 @@ async-lock = "2.7.0" async-once-cell = "0.5.3" atspi = { version = "0.19", default-features = false } futures-lite = "1.13" +futures-util = "0.3.27" once_cell = "1.17.1" serde = "1.0" tokio = { version = "1.32.0", optional = true, features = ["rt", "net", "time"] } diff --git a/platforms/unix/src/adapter.rs b/platforms/unix/src/adapter.rs index c3ff0faf9..de0439435 100644 --- a/platforms/unix/src/adapter.rs +++ b/platforms/unix/src/adapter.rs @@ -5,31 +5,27 @@ use crate::{ atspi::{ - interfaces::{ - AccessibleInterface, ActionInterface, ComponentInterface, Event, ObjectEvent, - ValueInterface, WindowEvent, - }, - Bus, ObjectId, + interfaces::{Event, ObjectEvent, WindowEvent}, + ObjectId, }, context::{ActivationContext, AppContext, Context}, filters::{filter, filter_detached}, - node::{NodeWrapper, PlatformNode}, + node::NodeWrapper, util::{block_on, WindowBounds}, }; use accesskit::{ActionHandler, NodeId, Rect, Role, TreeUpdate}; use accesskit_consumer::{DetachedNode, FilterResult, Node, Tree, TreeChangeHandler, TreeState}; -use async_channel::{Receiver, Sender}; +use async_channel::Sender; use async_once_cell::Lazy; -use atspi::{Interface, InterfaceSet, Live, State}; -use futures_lite::{future::Boxed, FutureExt, StreamExt}; +use atspi::{InterfaceSet, Live, State}; +use futures_lite::{future::Boxed, FutureExt}; use std::{ - pin::{pin, Pin}, + pin::Pin, sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, - Arc, Mutex, + Arc, Mutex, Weak, }, }; -use zbus::Task; struct AdapterChangeHandler<'a> { adapter: &'a AdapterImpl, @@ -37,61 +33,63 @@ struct AdapterChangeHandler<'a> { impl AdapterChangeHandler<'_> { fn add_node(&mut self, node: &Node) { - let role = node.role(); - let is_root = node.is_root(); - let node = NodeWrapper::Node { - adapter: self.adapter.id, - node, - }; - let interfaces = node.interfaces(); - self.adapter - .register_interfaces(node.id(), interfaces) - .unwrap(); - if is_root && role == Role::Window { - let adapter_index = AppContext::read().adapter_index(self.adapter.id).unwrap(); - self.adapter.window_created(adapter_index, node.id()); - } + block_on(async { + let role = node.role(); + let is_root = node.is_root(); + let node = NodeWrapper::Node { + adapter: self.adapter.id, + node, + }; + let interfaces = node.interfaces(); + self.adapter + .register_interfaces(node.id(), interfaces) + .await; + if is_root && role == Role::Window { + let adapter_index = AppContext::read().adapter_index(self.adapter.id).unwrap(); + self.adapter.window_created(adapter_index, node.id()).await; + } - let live = node.live(); - if live != Live::None { - if let Some(name) = node.name() { - self.adapter - .events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter: self.adapter.id, - node: node.id(), - }, - event: ObjectEvent::Announcement(name, live), - }) - .unwrap(); + let live = node.live(); + if live != Live::None { + if let Some(name) = node.name() { + self.adapter + .emit_object_event( + ObjectId::Node { + adapter: self.adapter.id, + node: node.id(), + }, + ObjectEvent::Announcement(name, live), + ) + .await; + } } - } + }) } fn remove_node(&mut self, node: &DetachedNode) { - let role = node.role(); - let is_root = node.is_root(); - let node = NodeWrapper::DetachedNode { - adapter: self.adapter.id, - node, - }; - if is_root && role == Role::Window { - self.adapter.window_destroyed(node.id()); - } - self.adapter - .events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter: self.adapter.id, - node: node.id(), - }, - event: ObjectEvent::StateChanged(State::Defunct, true), - }) - .unwrap(); - self.adapter - .unregister_interfaces(node.id(), node.interfaces()) - .unwrap(); + block_on(async { + let role = node.role(); + let is_root = node.is_root(); + let node = NodeWrapper::DetachedNode { + adapter: self.adapter.id, + node, + }; + if is_root && role == Role::Window { + self.adapter.window_destroyed(node.id()).await; + } + self.adapter + .emit_object_event( + ObjectId::Node { + adapter: self.adapter.id, + node: node.id(), + }, + ObjectEvent::StateChanged(State::Defunct, true), + ) + .await; + self.adapter + .unregister_interfaces(node.id(), node.interfaces()) + .await; + }); } } @@ -123,17 +121,18 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> { let old_interfaces = old_wrapper.interfaces(); let new_interfaces = new_wrapper.interfaces(); let kept_interfaces = old_interfaces & new_interfaces; - self.adapter - .unregister_interfaces(new_wrapper.id(), old_interfaces ^ kept_interfaces) - .unwrap(); - self.adapter - .register_interfaces(new_node.id(), new_interfaces ^ kept_interfaces) - .unwrap(); - new_wrapper.notify_changes( - &self.adapter.context.read_root_window_bounds(), - &self.adapter.events, - &old_wrapper, - ); + block_on(async { + self.adapter + .unregister_interfaces(new_wrapper.id(), old_interfaces ^ kept_interfaces) + .await; + self.adapter + .register_interfaces(new_node.id(), new_interfaces ^ kept_interfaces) + .await; + let bounds = *self.adapter.context.read_root_window_bounds(); + new_wrapper + .notify_changes(&bounds, self.adapter, &old_wrapper) + .await; + }); } } @@ -143,49 +142,53 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> { new_node: Option<&Node>, current_state: &TreeState, ) { - if let Some(root_window) = root_window(current_state) { - if old_node.is_none() && new_node.is_some() { - self.adapter.window_activated(&NodeWrapper::Node { - adapter: self.adapter.id, - node: &root_window, - }); - } else if old_node.is_some() && new_node.is_none() { - self.adapter.window_deactivated(&NodeWrapper::Node { - adapter: self.adapter.id, - node: &root_window, - }); + block_on(async { + if let Some(root_window) = root_window(current_state) { + if old_node.is_none() && new_node.is_some() { + self.adapter + .window_activated(&NodeWrapper::Node { + adapter: self.adapter.id, + node: &root_window, + }) + .await; + } else if old_node.is_some() && new_node.is_none() { + self.adapter + .window_deactivated(&NodeWrapper::Node { + adapter: self.adapter.id, + node: &root_window, + }) + .await; + } } - } - if let Some(node) = new_node.map(|node| NodeWrapper::Node { - adapter: self.adapter.id, - node, - }) { - self.adapter - .events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter: self.adapter.id, - node: node.id(), - }, - event: ObjectEvent::StateChanged(State::Focused, true), - }) - .unwrap(); - } - if let Some(node) = old_node.map(|node| NodeWrapper::DetachedNode { - adapter: self.adapter.id, - node, - }) { - self.adapter - .events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter: self.adapter.id, - node: node.id(), - }, - event: ObjectEvent::StateChanged(State::Focused, false), - }) - .unwrap(); - } + if let Some(node) = new_node.map(|node| NodeWrapper::Node { + adapter: self.adapter.id, + node, + }) { + self.adapter + .emit_object_event( + ObjectId::Node { + adapter: self.adapter.id, + node: node.id(), + }, + ObjectEvent::StateChanged(State::Focused, true), + ) + .await; + } + if let Some(node) = old_node.map(|node| NodeWrapper::DetachedNode { + adapter: self.adapter.id, + node, + }) { + self.adapter + .emit_object_event( + ObjectId::Node { + adapter: self.adapter.id, + node: node.id(), + }, + ObjectEvent::StateChanged(State::Focused, false), + ) + .await; + } + }); } fn node_removed(&mut self, node: &DetachedNode, _: &TreeState) { @@ -199,9 +202,7 @@ static NEXT_ADAPTER_ID: AtomicUsize = AtomicUsize::new(0); pub(crate) struct AdapterImpl { id: usize, - atspi_bus: Bus, - _event_task: Task<()>, - events: Sender, + messages: Sender, context: Arc, } @@ -214,171 +215,95 @@ impl AdapterImpl { ) -> Option { let tree = Tree::new(initial_state, is_window_focused); let id = NEXT_ADAPTER_ID.fetch_add(1, Ordering::SeqCst); - let root_id = tree.state().root_id(); - let (event_sender, event_receiver) = async_channel::unbounded(); - let (mut atspi_bus, event_task, context, adapter_index) = { + let (messages, context) = { let mut app_context = AppContext::write(); - app_context.name = tree.state().app_name(); - app_context.toolkit_name = tree.state().toolkit_name(); - app_context.toolkit_version = tree.state().toolkit_version(); - let atspi_bus = app_context.atspi_bus.clone().unwrap(); - let atspi_bus_copy = atspi_bus.clone(); - #[cfg(feature = "tokio")] - let _guard = crate::util::TOKIO_RT.enter(); - let event_task = atspi_bus.connection().executor().spawn( - async move { - handle_events(atspi_bus_copy, event_receiver).await; - }, - "accesskit_event_task", - ); + let messages = app_context.messages.clone().unwrap(); let context = Context::new(tree, action_handler, root_window_bounds); - let adapter_index = app_context.push_adapter(id, &context); - (atspi_bus, event_task, context, adapter_index) + app_context.push_adapter(id, &context); + (messages, context) }; - block_on(async { - if !atspi_bus.register_root_node().await.ok()? { - atspi_bus - .emit_object_event( - ObjectId::Root, - ObjectEvent::ChildAdded( - adapter_index, - ObjectId::Node { - adapter: id, - node: root_id, - }, - ), - ) - .await - .ok() - } else { - Some(()) - } - })?; - let r#impl = AdapterImpl { + Some(AdapterImpl { id, - atspi_bus, - _event_task: event_task, - events: event_sender, + messages, context, - }; - r#impl.register_tree(); - Some(r#impl) + }) } - fn register_tree(&self) { - let tree = self.context.read_tree(); - let tree_state = tree.state(); - let mut objects_to_add = Vec::new(); - - fn add_children(node: Node<'_>, to_add: &mut Vec) { + pub(crate) async fn register_tree(&self) { + fn add_children( + node: Node<'_>, + to_add: &mut Vec<(NodeId, InterfaceSet)>, + adapter_id: usize, + ) { for child in node.filtered_children(&filter) { - to_add.push(child.id()); - add_children(child, to_add); + let child_id = child.id(); + let wrapper = NodeWrapper::Node { + adapter: adapter_id, + node: &child, + }; + let interfaces = wrapper.interfaces(); + to_add.push((child_id, interfaces)); + add_children(child, to_add, adapter_id); } } - objects_to_add.push(tree_state.root().id()); - add_children(tree_state.root(), &mut objects_to_add); - for id in objects_to_add { - let node = tree_state.node_by_id(id).unwrap(); + let mut objects_to_add = Vec::new(); + + let (adapter_index, root_id) = { + let tree = self.context.read_tree(); + let tree_state = tree.state(); + let mut app_context = AppContext::write(); + app_context.name = tree_state.app_name(); + app_context.toolkit_name = tree_state.toolkit_name(); + app_context.toolkit_version = tree_state.toolkit_version(); + let adapter_index = app_context.adapter_index(self.id).unwrap(); + let root = tree_state.root(); + let root_id = root.id(); let wrapper = NodeWrapper::Node { adapter: self.id, - node: &node, + node: &root, }; - let interfaces = wrapper.interfaces(); - self.register_interfaces(id, interfaces).unwrap(); - if node.is_root() && node.role() == Role::Window { - let adapter_index = AppContext::read().adapter_index(self.id).unwrap(); - self.window_created(adapter_index, node.id()); + objects_to_add.push((root_id, wrapper.interfaces())); + add_children(root, &mut objects_to_add, self.id); + (adapter_index, root_id) + }; + + for (id, interfaces) in objects_to_add { + self.register_interfaces(id, interfaces).await; + if id == root_id { + self.window_created(adapter_index, id).await; } } } - fn register_interfaces(&self, id: NodeId, new_interfaces: InterfaceSet) -> zbus::Result { - let path = ObjectId::Node { - adapter: self.id, - node: id, - } - .path(); - if new_interfaces.contains(Interface::Accessible) { - block_on(async { - self.atspi_bus - .register_interface( - &path, - AccessibleInterface::new( - self.atspi_bus.unique_name().to_owned(), - PlatformNode::new(&self.context, self.id, id), - ), - ) - .await - })?; - } - if new_interfaces.contains(Interface::Action) { - block_on(async { - self.atspi_bus - .register_interface( - &path, - ActionInterface::new(PlatformNode::new(&self.context, self.id, id)), - ) - .await - })?; - } - if new_interfaces.contains(Interface::Component) { - block_on(async { - self.atspi_bus - .register_interface( - &path, - ComponentInterface::new(PlatformNode::new(&self.context, self.id, id)), - ) - .await - })?; - } - if new_interfaces.contains(Interface::Value) { - block_on(async { - self.atspi_bus - .register_interface( - &path, - ValueInterface::new(PlatformNode::new(&self.context, self.id, id)), - ) - .await - })?; - } - Ok(true) + async fn register_interfaces(&self, id: NodeId, new_interfaces: InterfaceSet) { + self.messages + .send(Message::RegisterInterfaces { + adapter_id: self.id, + context: Arc::downgrade(&self.context), + node_id: id, + interfaces: new_interfaces, + }) + .await + .unwrap(); } - fn unregister_interfaces( - &self, - id: NodeId, - old_interfaces: InterfaceSet, - ) -> zbus::Result { - block_on(async { - let path = ObjectId::Node { - adapter: self.id, - node: id, - } - .path(); - if old_interfaces.contains(Interface::Accessible) { - self.atspi_bus - .unregister_interface::>(&path) - .await?; - } - if old_interfaces.contains(Interface::Action) { - self.atspi_bus - .unregister_interface::(&path) - .await?; - } - if old_interfaces.contains(Interface::Component) { - self.atspi_bus - .unregister_interface::(&path) - .await?; - } - if old_interfaces.contains(Interface::Value) { - self.atspi_bus - .unregister_interface::(&path) - .await?; - } - Ok(true) - }) + async fn unregister_interfaces(&self, id: NodeId, old_interfaces: InterfaceSet) { + self.messages + .send(Message::UnregisterInterfaces { + adapter_id: self.id, + node_id: id, + interfaces: old_interfaces, + }) + .await + .unwrap(); + } + + pub(crate) async fn emit_object_event(&self, target: ObjectId, event: ObjectEvent) { + self.messages + .send(Message::EmitEvent(Event::Object { target, event })) + .await + .unwrap(); } fn set_root_window_bounds(&self, bounds: WindowBounds) { @@ -398,84 +323,81 @@ impl AdapterImpl { tree.update_host_focus_state_and_process_changes(is_focused, &mut handler); } - fn window_created(&self, adapter_index: usize, window: NodeId) { - self.events - .send_blocking(Event::Object { - target: ObjectId::Root, - event: ObjectEvent::ChildAdded( - adapter_index, - ObjectId::Node { - adapter: self.id, - node: window, - }, - ), - }) - .unwrap(); + async fn window_created(&self, adapter_index: usize, window: NodeId) { + self.emit_object_event( + ObjectId::Root, + ObjectEvent::ChildAdded( + adapter_index, + ObjectId::Node { + adapter: self.id, + node: window, + }, + ), + ) + .await; } - fn window_activated(&self, window: &NodeWrapper) { - self.events - .send_blocking(Event::Window { + async fn window_activated(&self, window: &NodeWrapper<'_>) { + self.messages + .send(Message::EmitEvent(Event::Window { target: ObjectId::Node { adapter: self.id, node: window.id(), }, name: window.name().unwrap_or_default(), event: WindowEvent::Activated, - }) - .unwrap(); - self.events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter: self.id, - node: window.id(), - }, - event: ObjectEvent::StateChanged(State::Active, true), - }) - .unwrap(); - self.events - .send_blocking(Event::Object { - target: ObjectId::Root, - event: ObjectEvent::ActiveDescendantChanged(ObjectId::Node { - adapter: self.id, - node: window.id(), - }), - }) + })) + .await .unwrap(); + self.emit_object_event( + ObjectId::Node { + adapter: self.id, + node: window.id(), + }, + ObjectEvent::StateChanged(State::Active, true), + ) + .await; + self.emit_object_event( + ObjectId::Root, + ObjectEvent::ActiveDescendantChanged(ObjectId::Node { + adapter: self.id, + node: window.id(), + }), + ) + .await; } - fn window_deactivated(&self, window: &NodeWrapper) { - self.events - .send_blocking(Event::Window { + async fn window_deactivated(&self, window: &NodeWrapper<'_>) { + self.messages + .send(Message::EmitEvent(Event::Window { target: ObjectId::Node { adapter: self.id, node: window.id(), }, name: window.name().unwrap_or_default(), event: WindowEvent::Deactivated, - }) - .unwrap(); - self.events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter: self.id, - node: window.id(), - }, - event: ObjectEvent::StateChanged(State::Active, false), - }) + })) + .await .unwrap(); + self.emit_object_event( + ObjectId::Node { + adapter: self.id, + node: window.id(), + }, + ObjectEvent::StateChanged(State::Active, false), + ) + .await; } - fn window_destroyed(&self, window: NodeId) { - self.events - .send_blocking(Event::Object { - target: ObjectId::Root, - event: ObjectEvent::ChildRemoved(ObjectId::Node { - adapter: self.id, - node: window, - }), - }) - .unwrap(); + async fn window_destroyed(&self, window: NodeId) { + self.emit_object_event( + ObjectId::Root, + ObjectEvent::ChildRemoved(ObjectId::Node { + adapter: self.id, + node: window, + }), + ) + .await; } } @@ -491,37 +413,21 @@ fn root_window(current_state: &TreeState) -> Option { impl Drop for AdapterImpl { fn drop(&mut self) { + AppContext::write().remove_adapter(self.id); + let root_id = self.context.read_tree().state().root_id(); block_on(async { - AppContext::write().remove_adapter(self.id); - let root_id = self.context.read_tree().state().root_id(); - self.atspi_bus - .emit_object_event( - ObjectId::Root, - ObjectEvent::ChildRemoved(ObjectId::Node { - adapter: self.id, - node: root_id, - }), - ) - .await - .unwrap(); + self.emit_object_event( + ObjectId::Root, + ObjectEvent::ChildRemoved(ObjectId::Node { + adapter: self.id, + node: root_id, + }), + ) + .await; }); } } -async fn handle_events(bus: Bus, mut events: Receiver) { - let mut events = pin!(events); - while let Some(event) = events.next().await { - let _ = match event { - Event::Object { target, event } => bus.emit_object_event(target, event).await, - Event::Window { - target, - name, - event, - } => bus.emit_window_event(target, name, event).await, - }; - } -} - pub(crate) type LazyAdapter = Pin, Boxed>>>>; pub struct Adapter { @@ -589,3 +495,18 @@ impl Adapter { } } } + +pub(crate) enum Message { + RegisterInterfaces { + adapter_id: usize, + context: Weak, + node_id: NodeId, + interfaces: InterfaceSet, + }, + UnregisterInterfaces { + adapter_id: usize, + node_id: NodeId, + interfaces: InterfaceSet, + }, + EmitEvent(Event), +} diff --git a/platforms/unix/src/atspi/bus.rs b/platforms/unix/src/atspi/bus.rs index 1ed25fd4a..8aeb33608 100644 --- a/platforms/unix/src/atspi/bus.rs +++ b/platforms/unix/src/atspi/bus.rs @@ -5,15 +5,17 @@ use crate::{ atspi::{interfaces::*, ObjectId}, - context::AppContext, - PlatformRootNode, + context::{AppContext, Context}, + PlatformNode, PlatformRootNode, }; +use accesskit::NodeId; use atspi::{ events::EventBody, proxy::{bus::BusProxy, socket::SocketProxy}, + Interface, InterfaceSet, }; use serde::Serialize; -use std::{collections::HashMap, env::var}; +use std::{collections::HashMap, env::var, sync::Weak}; use zbus::{ names::{BusName, InterfaceName, MemberName, OwnedUniqueName}, zvariant::{Str, Value}, @@ -27,35 +29,24 @@ pub(crate) struct Bus { } impl Bus { - pub async fn a11y_bus() -> Option { - let conn = a11y_bus().await?; - let socket_proxy = SocketProxy::new(&conn).await.ok()?; - Some(Bus { conn, socket_proxy }) - } - - pub(crate) fn connection(&self) -> &Connection { - &self.conn + pub(crate) async fn new(session_bus: &Connection) -> zbus::Result { + let address = match var("AT_SPI_BUS_ADDRESS") { + Ok(address) if !address.is_empty() => address, + _ => BusProxy::new(session_bus).await?.get_address().await?, + }; + let address: Address = address.as_str().try_into()?; + let conn = ConnectionBuilder::address(address)?.build().await?; + let socket_proxy = SocketProxy::new(&conn).await?; + let mut bus = Bus { conn, socket_proxy }; + bus.register_root_node().await?; + Ok(bus) } - pub fn unique_name(&self) -> &OwnedUniqueName { + fn unique_name(&self) -> &OwnedUniqueName { self.conn.unique_name().unwrap() } - pub async fn register_interface(&self, path: &str, interface: T) -> Result - where - T: zbus::Interface, - { - self.conn.object_server().at(path, interface).await - } - - pub async fn unregister_interface(&self, path: &str) -> Result - where - T: zbus::Interface, - { - self.conn.object_server().remove::(path).await - } - - pub(crate) async fn register_root_node(&mut self) -> Result { + async fn register_root_node(&mut self) -> Result<()> { let node = PlatformRootNode::new(); let path = ObjectId::Root.path(); @@ -80,10 +71,101 @@ impl Bus { .await?; let mut app_context = AppContext::write(); app_context.desktop_address = Some(desktop.into()); - Ok(true) - } else { - Ok(false) } + + Ok(()) + } + + pub(crate) async fn register_interfaces( + &self, + adapter_id: usize, + context: Weak, + node_id: NodeId, + new_interfaces: InterfaceSet, + ) -> zbus::Result<()> { + let path = ObjectId::Node { + adapter: adapter_id, + node: node_id, + } + .path(); + if new_interfaces.contains(Interface::Accessible) { + self.register_interface( + &path, + AccessibleInterface::new( + self.unique_name().to_owned(), + PlatformNode::new(context.clone(), adapter_id, node_id), + ), + ) + .await?; + } + if new_interfaces.contains(Interface::Action) { + self.register_interface( + &path, + ActionInterface::new(PlatformNode::new(context.clone(), adapter_id, node_id)), + ) + .await?; + } + if new_interfaces.contains(Interface::Component) { + self.register_interface( + &path, + ComponentInterface::new(PlatformNode::new(context.clone(), adapter_id, node_id)), + ) + .await?; + } + if new_interfaces.contains(Interface::Value) { + self.register_interface( + &path, + ValueInterface::new(PlatformNode::new(context, adapter_id, node_id)), + ) + .await?; + } + + Ok(()) + } + + async fn register_interface(&self, path: &str, interface: T) -> Result<()> + where + T: zbus::Interface, + { + self.conn.object_server().at(path, interface).await?; + Ok(()) + } + + pub(crate) async fn unregister_interfaces( + &self, + adapter_id: usize, + node_id: NodeId, + old_interfaces: InterfaceSet, + ) -> zbus::Result<()> { + let path = ObjectId::Node { + adapter: adapter_id, + node: node_id, + } + .path(); + if old_interfaces.contains(Interface::Accessible) { + self.unregister_interface::>(&path) + .await?; + } + if old_interfaces.contains(Interface::Action) { + self.unregister_interface::(&path).await?; + } + if old_interfaces.contains(Interface::Component) { + self.unregister_interface::(&path) + .await?; + } + if old_interfaces.contains(Interface::Value) { + self.unregister_interface::(&path).await?; + } + + Ok(()) + } + + async fn unregister_interface(&self, path: &str) -> Result<()> + where + T: zbus::Interface, + { + self.conn.object_server().remove::(path).await?; + Ok(()) } pub(crate) async fn emit_object_event( @@ -267,20 +349,3 @@ impl Bus { .await } } - -async fn a11y_bus() -> Option { - let address = match var("AT_SPI_BUS_ADDRESS") { - Ok(address) if !address.is_empty() => address, - _ => { - let session_bus = Connection::session().await.ok()?; - BusProxy::new(&session_bus) - .await - .ok()? - .get_address() - .await - .ok()? - } - }; - let address: Address = address.as_str().try_into().ok()?; - ConnectionBuilder::address(address).ok()?.build().await.ok() -} diff --git a/platforms/unix/src/context.rs b/platforms/unix/src/context.rs index a44e12365..d86167759 100644 --- a/platforms/unix/src/context.rs +++ b/platforms/unix/src/context.rs @@ -5,17 +5,18 @@ use accesskit::{ActionHandler, ActionRequest}; use accesskit_consumer::Tree; +use async_channel::Sender; use async_lock::{Mutex as AsyncMutex, MutexGuard as AsyncMutexGuard}; use async_once_cell::OnceCell as AsyncOnceCell; use atspi::proxy::bus::StatusProxy; -use futures_lite::StreamExt; +use futures_util::{pin_mut, select, StreamExt}; use once_cell::sync::OnceCell; use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak}; use zbus::{Connection, Task}; use crate::{ - adapter::LazyAdapter, - atspi::{Bus, OwnedObjectAddress}, + adapter::{LazyAdapter, Message}, + atspi::{interfaces::Event, Bus, OwnedObjectAddress}, util::WindowBounds, }; @@ -62,7 +63,7 @@ impl AdapterAndContext { static APP_CONTEXT: OnceCell>> = OnceCell::new(); pub(crate) struct AppContext { - pub(crate) atspi_bus: Option, + pub(crate) messages: Option>, pub(crate) name: Option, pub(crate) toolkit_name: Option, pub(crate) toolkit_version: Option, @@ -76,7 +77,7 @@ impl AppContext { APP_CONTEXT .get_or_init(|| { Arc::new(RwLock::new(Self { - atspi_bus: None, + messages: None, name: None, toolkit_name: None, toolkit_version: None, @@ -101,11 +102,9 @@ impl AppContext { self.adapters.binary_search_by(|adapter| adapter.0.cmp(&id)) } - pub(crate) fn push_adapter(&mut self, id: usize, context: &Arc) -> usize { - let index = self.adapters.len(); + pub(crate) fn push_adapter(&mut self, id: usize, context: &Arc) { self.adapters .push(AdapterAndContext(id, Arc::downgrade(context))); - index } pub(crate) fn remove_adapter(&mut self, id: usize) { @@ -116,7 +115,7 @@ impl AppContext { } pub(crate) struct ActivationContext { - _monitoring_task: Task<()>, + _task: Task<()>, adapters: Vec, } @@ -128,14 +127,14 @@ impl ActivationContext { .get_or_init(async { let session_bus = Connection::session().await.unwrap(); let session_bus_copy = session_bus.clone(); - let monitoring_task = session_bus.executor().spawn( + let task = session_bus.executor().spawn( async move { - let _ = monitor_a11y_status(session_bus_copy).await; + listen(session_bus_copy).await.unwrap(); }, - "accesskit_a11y_monitoring_task", + "accesskit_task", ); Arc::new(AsyncMutex::new(ActivationContext { - _monitoring_task: monitoring_task, + _task: task, adapters: Vec::new(), })) }) @@ -147,36 +146,86 @@ impl ActivationContext { pub(crate) async fn activate_eventually(adapter: LazyAdapter) { let mut activation_context = ActivationContext::get_or_init().await; activation_context.adapters.push(adapter); - let adapter = activation_context.adapters.last().unwrap(); - let is_a11y_enabled = AppContext::get_or_init().atspi_bus.is_some(); + let is_a11y_enabled = AppContext::get_or_init().messages.is_some(); if is_a11y_enabled { + let adapter = activation_context.adapters.last().unwrap(); adapter.as_ref().await; } } } -async fn monitor_a11y_status(session_bus: Connection) -> zbus::Result<()> { +async fn listen(session_bus: Connection) -> zbus::Result<()> { let status = StatusProxy::new(&session_bus).await?; - let mut changes = status.receive_is_enabled_changed().await; - - while let Some(change) = changes.next().await { - let atspi_bus = match change.get().await { - Ok(true) => Bus::a11y_bus().await, - _ => None, - }; - let activate = atspi_bus.is_some(); - { - let mut app_context = AppContext::get_or_init(); - app_context.atspi_bus = atspi_bus; - } - if activate { - if let Some(activation_context) = ACTIVATION_CONTEXT.get() { - let activation_context = activation_context.lock().await; - for adapter in &activation_context.adapters { - adapter.as_ref().await; + let changes = status.receive_is_enabled_changed().await.fuse(); + pin_mut!(changes); + let (tx, rx) = async_channel::unbounded(); + let messages = rx.fuse(); + pin_mut!(messages); + let mut atspi_bus = None; + + loop { + select! { + change = changes.next() => { + atspi_bus = if let Some(change) = change { + match change.get().await { + Ok(true) => Bus::new(&session_bus).await.ok(), + _ => None, + } + } else { + None + }; + { + let mut app_context = AppContext::get_or_init(); + app_context.messages = Some(tx.clone()); + } + if atspi_bus.is_some() { + if let Some(activation_context) = ACTIVATION_CONTEXT.get() { + let activation_context = activation_context.lock().await; + for adapter in &activation_context.adapters { + if let Some(adapter) = &*adapter.as_ref().await { + adapter.register_tree().await; + } + } + } } } + message = messages.next() => { + if let Some((message, atspi_bus)) = message.zip(atspi_bus.as_ref()) { + let _ = process_adapter_message(atspi_bus, message).await; + } + } + complete => return Ok(()), + } + } +} + +async fn process_adapter_message(bus: &Bus, message: Message) -> zbus::Result<()> { + match message { + Message::RegisterInterfaces { + adapter_id, + context, + node_id, + interfaces, + } => { + bus.register_interfaces(adapter_id, context, node_id, interfaces) + .await? + } + Message::UnregisterInterfaces { + adapter_id, + node_id, + interfaces, + } => { + bus.unregister_interfaces(adapter_id, node_id, interfaces) + .await? + } + Message::EmitEvent(Event::Object { target, event }) => { + bus.emit_object_event(target, event).await? } + Message::EmitEvent(Event::Window { + target, + name, + event, + }) => bus.emit_window_event(target, name, event).await?, } Ok(()) diff --git a/platforms/unix/src/node.rs b/platforms/unix/src/node.rs index f344d4e22..94567fc3c 100644 --- a/platforms/unix/src/node.rs +++ b/platforms/unix/src/node.rs @@ -9,8 +9,9 @@ // found in the LICENSE.chromium file. use crate::{ + adapter::AdapterImpl, atspi::{ - interfaces::{Action as AtspiAction, Event, ObjectEvent, Property}, + interfaces::{Action as AtspiAction, ObjectEvent, Property}, ObjectId, OwnedObjectAddress, Rect as AtspiRect, }, context::{AdapterAndContext, AppContext, Context}, @@ -22,7 +23,6 @@ use accesskit::{ Rect, Role, }; use accesskit_consumer::{DetachedNode, FilterResult, Node, NodeState, TreeState}; -use async_channel::Sender; use atspi::{ CoordType, Interface, InterfaceSet, Layer, Live as AtspiLive, Role as AtspiRole, State, StateSet, @@ -482,171 +482,172 @@ impl<'a> NodeWrapper<'a> { self.node_state().numeric_value() } - pub fn notify_changes( + pub(crate) async fn notify_changes( &self, window_bounds: &WindowBounds, - events: &Sender, - old: &NodeWrapper, + adapter: &AdapterImpl, + old: &NodeWrapper<'_>, ) { - self.notify_state_changes(events, old); - self.notify_property_changes(events, old); - self.notify_bounds_changes(window_bounds, events, old); - self.notify_children_changes(events, old); + self.notify_state_changes(adapter, old).await; + self.notify_property_changes(adapter, old).await; + self.notify_bounds_changes(window_bounds, adapter, old) + .await; + self.notify_children_changes(adapter, old).await; } - fn notify_state_changes(&self, events: &Sender, old: &NodeWrapper) { - let adapter = self.adapter(); + async fn notify_state_changes(&self, adapter: &AdapterImpl, old: &NodeWrapper<'_>) { + let adapter_id = self.adapter(); let old_state = old.state(true); let new_state = self.state(true); let changed_states = old_state ^ new_state; for state in changed_states.iter() { - events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter, + adapter + .emit_object_event( + ObjectId::Node { + adapter: adapter_id, node: self.id(), }, - event: ObjectEvent::StateChanged(state, new_state.contains(state)), - }) - .unwrap(); + ObjectEvent::StateChanged(state, new_state.contains(state)), + ) + .await; } } - fn notify_property_changes(&self, events: &Sender, old: &NodeWrapper) { - let adapter = self.adapter(); + async fn notify_property_changes(&self, adapter: &AdapterImpl, old: &NodeWrapper<'_>) { + let adapter_id = self.adapter(); let name = self.name(); if name != old.name() { let name = name.unwrap_or_default(); - events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter, + adapter + .emit_object_event( + ObjectId::Node { + adapter: adapter_id, node: self.id(), }, - event: ObjectEvent::PropertyChanged(Property::Name(name.clone())), - }) - .unwrap(); + ObjectEvent::PropertyChanged(Property::Name(name.clone())), + ) + .await; let live = self.live(); if live != AtspiLive::None { - events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter, + adapter + .emit_object_event( + ObjectId::Node { + adapter: adapter_id, node: self.id(), }, - event: ObjectEvent::Announcement(name, live), - }) - .unwrap(); + ObjectEvent::Announcement(name, live), + ) + .await; } } let description = self.description(); if description != old.description() { - events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter, + adapter + .emit_object_event( + ObjectId::Node { + adapter: adapter_id, node: self.id(), }, - event: ObjectEvent::PropertyChanged(Property::Description(description)), - }) - .unwrap(); + ObjectEvent::PropertyChanged(Property::Description(description)), + ) + .await; } let parent_id = self.parent_id(); if parent_id != old.parent_id() { - events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter, + adapter + .emit_object_event( + ObjectId::Node { + adapter: adapter_id, node: self.id(), }, - event: ObjectEvent::PropertyChanged(Property::Parent(self.filtered_parent())), - }) - .unwrap(); + ObjectEvent::PropertyChanged(Property::Parent(self.filtered_parent())), + ) + .await; } let role = self.role(); if role != old.role() { - events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter, + adapter + .emit_object_event( + ObjectId::Node { + adapter: adapter_id, node: self.id(), }, - event: ObjectEvent::PropertyChanged(Property::Role(role)), - }) - .unwrap(); + ObjectEvent::PropertyChanged(Property::Role(role)), + ) + .await; } if let Some(value) = self.current_value() { if Some(value) != old.current_value() { - events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter, + adapter + .emit_object_event( + ObjectId::Node { + adapter: adapter_id, node: self.id(), }, - event: ObjectEvent::PropertyChanged(Property::Value(value)), - }) - .unwrap(); + ObjectEvent::PropertyChanged(Property::Value(value)), + ) + .await; } } } - fn notify_bounds_changes( + async fn notify_bounds_changes( &self, window_bounds: &WindowBounds, - events: &Sender, - old: &NodeWrapper, + adapter: &AdapterImpl, + old: &NodeWrapper<'_>, ) { if self.raw_bounds_and_transform() != old.raw_bounds_and_transform() { - events - .send_blocking(Event::Object { - target: ObjectId::Node { + adapter + .emit_object_event( + ObjectId::Node { adapter: self.adapter(), node: self.id(), }, - event: ObjectEvent::BoundsChanged(self.extents(window_bounds)), - }) - .unwrap(); + ObjectEvent::BoundsChanged(self.extents(window_bounds)), + ) + .await; } } - fn notify_children_changes(&self, events: &Sender, old: &NodeWrapper) { - let adapter = self.adapter(); + async fn notify_children_changes(&self, adapter: &AdapterImpl, old: &NodeWrapper<'_>) { + let adapter_id = self.adapter(); let old_children = old.child_ids().collect::>(); let filtered_children = self.filtered_child_ids().collect::>(); for (index, child) in filtered_children.iter().enumerate() { if !old_children.contains(child) { - events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter, + adapter + .emit_object_event( + ObjectId::Node { + adapter: adapter_id, node: self.id(), }, - event: ObjectEvent::ChildAdded( + ObjectEvent::ChildAdded( index, ObjectId::Node { - adapter, + adapter: adapter_id, node: *child, }, ), - }) - .unwrap(); + ) + .await; } } for child in old_children.into_iter() { if !filtered_children.contains(&child) { - events - .send_blocking(Event::Object { - target: ObjectId::Node { - adapter, + adapter + .emit_object_event( + ObjectId::Node { + adapter: adapter_id, node: self.id(), }, - event: ObjectEvent::ChildRemoved(ObjectId::Node { - adapter, + ObjectEvent::ChildRemoved(ObjectId::Node { + adapter: adapter_id, node: child, }), - }) - .unwrap(); + ) + .await; } } } @@ -664,9 +665,9 @@ pub(crate) struct PlatformNode { } impl PlatformNode { - pub(crate) fn new(context: &Arc, adapter_id: usize, node_id: NodeId) -> Self { + pub(crate) fn new(context: Weak, adapter_id: usize, node_id: NodeId) -> Self { Self { - context: Arc::downgrade(context), + context, adapter_id, node_id, } From e38a55ea370a9f6c1e156ddb3700c3b252df9fb7 Mon Sep 17 00:00:00 2001 From: DataTriny Date: Tue, 26 Dec 2023 15:35:06 +0100 Subject: [PATCH 7/9] Ignore broken pipe error from zbus --- platforms/unix/src/adapter.rs | 14 ++++---- platforms/unix/src/atspi/bus.rs | 59 ++++++++++++++++++++++++--------- platforms/unix/src/atspi/mod.rs | 2 +- platforms/unix/src/context.rs | 15 ++++----- 4 files changed, 58 insertions(+), 32 deletions(-) diff --git a/platforms/unix/src/adapter.rs b/platforms/unix/src/adapter.rs index de0439435..e8c37e53b 100644 --- a/platforms/unix/src/adapter.rs +++ b/platforms/unix/src/adapter.rs @@ -212,7 +212,7 @@ impl AdapterImpl { is_window_focused: bool, root_window_bounds: WindowBounds, action_handler: Box, - ) -> Option { + ) -> Self { let tree = Tree::new(initial_state, is_window_focused); let id = NEXT_ADAPTER_ID.fetch_add(1, Ordering::SeqCst); let (messages, context) = { @@ -222,11 +222,11 @@ impl AdapterImpl { app_context.push_adapter(id, &context); (messages, context) }; - Some(AdapterImpl { + AdapterImpl { id, messages, context, - }) + } } pub(crate) async fn register_tree(&self) { @@ -428,7 +428,7 @@ impl Drop for AdapterImpl { } } -pub(crate) type LazyAdapter = Pin, Boxed>>>>; +pub(crate) type LazyAdapter = Pin>>>; pub struct Adapter { r#impl: LazyAdapter, @@ -474,7 +474,7 @@ impl Adapter { let mut bounds = self.root_window_bounds.lock().unwrap(); *bounds = new_bounds; } - if let Some(Some(r#impl)) = Lazy::try_get(&self.r#impl) { + if let Some(r#impl) = Lazy::try_get(&self.r#impl) { r#impl.set_root_window_bounds(new_bounds); } } @@ -482,7 +482,7 @@ impl Adapter { /// If and only if the tree has been initialized, call the provided function /// and apply the resulting update. pub fn update_if_active(&self, update_factory: impl FnOnce() -> TreeUpdate) { - if let Some(Some(r#impl)) = Lazy::try_get(&self.r#impl) { + if let Some(r#impl) = Lazy::try_get(&self.r#impl) { r#impl.update(update_factory()); } } @@ -490,7 +490,7 @@ impl Adapter { /// Update the tree state based on whether the window is focused. pub fn update_window_focus_state(&self, is_focused: bool) { self.is_window_focused.store(is_focused, Ordering::SeqCst); - if let Some(Some(r#impl)) = Lazy::try_get(&self.r#impl) { + if let Some(r#impl) = Lazy::try_get(&self.r#impl) { r#impl.update_window_focus_state(is_focused); } } diff --git a/platforms/unix/src/atspi/bus.rs b/platforms/unix/src/atspi/bus.rs index 8aeb33608..2565c4762 100644 --- a/platforms/unix/src/atspi/bus.rs +++ b/platforms/unix/src/atspi/bus.rs @@ -15,7 +15,7 @@ use atspi::{ Interface, InterfaceSet, }; use serde::Serialize; -use std::{collections::HashMap, env::var, sync::Weak}; +use std::{collections::HashMap, env::var, io, sync::Weak}; use zbus::{ names::{BusName, InterfaceName, MemberName, OwnedUniqueName}, zvariant::{Str, Value}, @@ -123,12 +123,15 @@ impl Bus { Ok(()) } - async fn register_interface(&self, path: &str, interface: T) -> Result<()> + async fn register_interface(&self, path: &str, interface: T) -> Result where T: zbus::Interface, { - self.conn.object_server().at(path, interface).await?; - Ok(()) + map_or_ignoring_broken_pipe( + self.conn.object_server().at(path, interface).await, + false, + |result| result, + ) } pub(crate) async fn unregister_interfaces( @@ -160,12 +163,15 @@ impl Bus { Ok(()) } - async fn unregister_interface(&self, path: &str) -> Result<()> + async fn unregister_interface(&self, path: &str) -> Result where T: zbus::Interface, { - self.conn.object_server().remove::(path).await?; - Ok(()) + map_or_ignoring_broken_pipe( + self.conn.object_server().remove::(path).await, + false, + |result| result, + ) } pub(crate) async fn emit_object_event( @@ -338,14 +344,35 @@ impl Bus { signal_name: &str, body: EventBody<'_, T>, ) -> Result<()> { - self.conn - .emit_signal( - Option::::None, - target.path(), - InterfaceName::from_str_unchecked(interface), - MemberName::from_str_unchecked(signal_name), - &body, - ) - .await + map_or_ignoring_broken_pipe( + self.conn + .emit_signal( + Option::::None, + target.path(), + InterfaceName::from_str_unchecked(interface), + MemberName::from_str_unchecked(signal_name), + &body, + ) + .await, + (), + |_| (), + ) + } +} + +pub(crate) fn map_or_ignoring_broken_pipe( + result: zbus::Result, + default: U, + f: F, +) -> zbus::Result +where + F: FnOnce(T) -> U, +{ + match result { + Ok(result) => Ok(f(result)), + Err(zbus::Error::InputOutput(error)) if error.kind() == io::ErrorKind::BrokenPipe => { + Ok(default) + } + Err(error) => Err(error), } } diff --git a/platforms/unix/src/atspi/mod.rs b/platforms/unix/src/atspi/mod.rs index fc3c1c061..510557bc4 100644 --- a/platforms/unix/src/atspi/mod.rs +++ b/platforms/unix/src/atspi/mod.rs @@ -39,6 +39,6 @@ impl From for Rect { } } -pub(crate) use bus::Bus; +pub(crate) use bus::*; pub(crate) use object_address::OwnedObjectAddress; pub(crate) use object_id::ObjectId; diff --git a/platforms/unix/src/context.rs b/platforms/unix/src/context.rs index d86167759..cde8c7215 100644 --- a/platforms/unix/src/context.rs +++ b/platforms/unix/src/context.rs @@ -16,7 +16,7 @@ use zbus::{Connection, Task}; use crate::{ adapter::{LazyAdapter, Message}, - atspi::{interfaces::Event, Bus, OwnedObjectAddress}, + atspi::{interfaces::Event, map_or_ignoring_broken_pipe, Bus, OwnedObjectAddress}, util::WindowBounds, }; @@ -167,9 +167,10 @@ async fn listen(session_bus: Connection) -> zbus::Result<()> { select! { change = changes.next() => { atspi_bus = if let Some(change) = change { - match change.get().await { - Ok(true) => Bus::new(&session_bus).await.ok(), - _ => None, + if change.get().await? { + map_or_ignoring_broken_pipe(Bus::new(&session_bus).await, None, Some)? + } else { + None } } else { None @@ -182,16 +183,14 @@ async fn listen(session_bus: Connection) -> zbus::Result<()> { if let Some(activation_context) = ACTIVATION_CONTEXT.get() { let activation_context = activation_context.lock().await; for adapter in &activation_context.adapters { - if let Some(adapter) = &*adapter.as_ref().await { - adapter.register_tree().await; - } + adapter.as_ref().await.register_tree().await; } } } } message = messages.next() => { if let Some((message, atspi_bus)) = message.zip(atspi_bus.as_ref()) { - let _ = process_adapter_message(atspi_bus, message).await; + process_adapter_message(atspi_bus, message).await?; } } complete => return Ok(()), From bac1e56842a67fca28fbba720408d8e6309a75f1 Mon Sep 17 00:00:00 2001 From: DataTriny Date: Tue, 26 Dec 2023 19:01:01 +0100 Subject: [PATCH 8/9] Properly drop the top-level adapter struct --- platforms/unix/src/adapter.rs | 20 ++++++++++++++++---- platforms/unix/src/context.rs | 22 +++++++++++++++++----- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/platforms/unix/src/adapter.rs b/platforms/unix/src/adapter.rs index e8c37e53b..0102eac7f 100644 --- a/platforms/unix/src/adapter.rs +++ b/platforms/unix/src/adapter.rs @@ -198,8 +198,6 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> { } } -static NEXT_ADAPTER_ID: AtomicUsize = AtomicUsize::new(0); - pub(crate) struct AdapterImpl { id: usize, messages: Sender, @@ -208,13 +206,13 @@ pub(crate) struct AdapterImpl { impl AdapterImpl { fn new( + id: usize, initial_state: TreeUpdate, is_window_focused: bool, root_window_bounds: WindowBounds, action_handler: Box, ) -> Self { let tree = Tree::new(initial_state, is_window_focused); - let id = NEXT_ADAPTER_ID.fetch_add(1, Ordering::SeqCst); let (messages, context) = { let mut app_context = AppContext::write(); let messages = app_context.messages.clone().unwrap(); @@ -430,7 +428,10 @@ impl Drop for AdapterImpl { pub(crate) type LazyAdapter = Pin>>>; +static NEXT_ADAPTER_ID: AtomicUsize = AtomicUsize::new(0); + pub struct Adapter { + id: usize, r#impl: LazyAdapter, is_window_focused: Arc, root_window_bounds: Arc>, @@ -442,6 +443,7 @@ impl Adapter { source: impl 'static + FnOnce() -> TreeUpdate + Send, action_handler: Box, ) -> Self { + let id = NEXT_ADAPTER_ID.fetch_add(1, Ordering::SeqCst); let is_window_focused = Arc::new(AtomicBool::new(false)); let is_window_focused_copy = is_window_focused.clone(); let root_window_bounds = Arc::new(Mutex::new(Default::default())); @@ -451,6 +453,7 @@ impl Adapter { let is_window_focused = is_window_focused_copy.load(Ordering::Relaxed); let root_window_bounds = *root_window_bounds_copy.lock().unwrap(); AdapterImpl::new( + id, source(), is_window_focused, root_window_bounds, @@ -460,11 +463,12 @@ impl Adapter { .boxed(), )); let adapter = Self { + id, r#impl: r#impl.clone(), is_window_focused, root_window_bounds, }; - block_on(async move { ActivationContext::activate_eventually(r#impl).await }); + block_on(async move { ActivationContext::activate_eventually(id, r#impl).await }); adapter } @@ -496,6 +500,14 @@ impl Adapter { } } +impl Drop for Adapter { + fn drop(&mut self) { + block_on(async { + ActivationContext::remove_adapter(self.id).await; + }) + } +} + pub(crate) enum Message { RegisterInterfaces { adapter_id: usize, diff --git a/platforms/unix/src/context.rs b/platforms/unix/src/context.rs index cde8c7215..794181d79 100644 --- a/platforms/unix/src/context.rs +++ b/platforms/unix/src/context.rs @@ -116,7 +116,7 @@ impl AppContext { pub(crate) struct ActivationContext { _task: Task<()>, - adapters: Vec, + adapters: Vec<(usize, LazyAdapter)>, } static ACTIVATION_CONTEXT: AsyncOnceCell>> = AsyncOnceCell::new(); @@ -143,15 +143,27 @@ impl ActivationContext { .await } - pub(crate) async fn activate_eventually(adapter: LazyAdapter) { + pub(crate) async fn activate_eventually(id: usize, adapter: LazyAdapter) { let mut activation_context = ActivationContext::get_or_init().await; - activation_context.adapters.push(adapter); + activation_context.adapters.push((id, adapter)); let is_a11y_enabled = AppContext::get_or_init().messages.is_some(); if is_a11y_enabled { - let adapter = activation_context.adapters.last().unwrap(); + let adapter = &activation_context.adapters.last().unwrap().1; adapter.as_ref().await; } } + + pub(crate) async fn remove_adapter(id: usize) { + if let Some(activation_context) = ACTIVATION_CONTEXT.get() { + let mut context = activation_context.lock().await; + if let Ok(index) = context + .adapters + .binary_search_by(|adapter| adapter.0.cmp(&id)) + { + context.adapters.remove(index); + } + } + } } async fn listen(session_bus: Connection) -> zbus::Result<()> { @@ -182,7 +194,7 @@ async fn listen(session_bus: Connection) -> zbus::Result<()> { if atspi_bus.is_some() { if let Some(activation_context) = ACTIVATION_CONTEXT.get() { let activation_context = activation_context.lock().await; - for adapter in &activation_context.adapters { + for (_, adapter) in &activation_context.adapters { adapter.as_ref().await.register_tree().await; } } From c8bf388247ef38b62f8387483c20ec47eef389c7 Mon Sep 17 00:00:00 2001 From: DataTriny Date: Wed, 27 Dec 2023 18:29:07 +0100 Subject: [PATCH 9/9] Gracefully handle the lack of a session bus --- platforms/unix/src/context.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/platforms/unix/src/context.rs b/platforms/unix/src/context.rs index 794181d79..6f048b58e 100644 --- a/platforms/unix/src/context.rs +++ b/platforms/unix/src/context.rs @@ -115,7 +115,7 @@ impl AppContext { } pub(crate) struct ActivationContext { - _task: Task<()>, + _task: Option>, adapters: Vec<(usize, LazyAdapter)>, } @@ -125,14 +125,15 @@ impl ActivationContext { async fn get_or_init<'a>() -> AsyncMutexGuard<'a, ActivationContext> { ACTIVATION_CONTEXT .get_or_init(async { - let session_bus = Connection::session().await.unwrap(); - let session_bus_copy = session_bus.clone(); - let task = session_bus.executor().spawn( - async move { - listen(session_bus_copy).await.unwrap(); - }, - "accesskit_task", - ); + let task = Connection::session().await.ok().map(|session_bus| { + let session_bus_copy = session_bus.clone(); + session_bus.executor().spawn( + async move { + listen(session_bus_copy).await.unwrap(); + }, + "accesskit_task", + ) + }); Arc::new(AsyncMutex::new(ActivationContext { _task: task, adapters: Vec::new(),