diff --git a/Cargo.lock b/Cargo.lock index bec8b4402..19056faa7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,9 +63,11 @@ dependencies = [ "accesskit", "accesskit_consumer", "async-channel 2.1.1", + "async-lock", "async-once-cell", "atspi", "futures-lite", + "futures-util", "once_cell", "serde", "tokio", @@ -858,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" @@ -878,6 +891,7 @@ checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" dependencies = [ "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", 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/Cargo.toml b/platforms/unix/Cargo.toml index 96a789bed..7f53044ec 100644 --- a/platforms/unix/Cargo.toml +++ b/platforms/unix/Cargo.toml @@ -19,11 +19,12 @@ 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" +futures-util = "0.3.27" 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 dc0ce85af..0102eac7f 100644 --- a/platforms/unix/src/adapter.rs +++ b/platforms/unix/src/adapter.rs @@ -5,97 +5,91 @@ use crate::{ atspi::{ - interfaces::{ - AccessibleInterface, ActionInterface, ComponentInterface, Event, ObjectEvent, - ValueInterface, WindowEvent, - }, - Bus, ObjectId, + interfaces::{Event, ObjectEvent, WindowEvent}, + ObjectId, }, - context::{AppContext, Context}, + context::{ActivationContext, AppContext, Context}, filters::{filter, filter_detached}, - node::{NodeWrapper, PlatformNode}, - util::block_on, + 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 atspi::{Interface, InterfaceSet, Live, State}; -use futures_lite::StreamExt; +use async_channel::Sender; +use async_once_cell::Lazy; +use atspi::{InterfaceSet, Live, State}; +use futures_lite::{future::Boxed, FutureExt}; use std::{ - pin::pin, + pin::Pin, sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, Mutex, Weak, }, }; -use zbus::Task; struct AdapterChangeHandler<'a> { - adapter: &'a Adapter, + adapter: &'a AdapterImpl, } 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 = self - .adapter - .context - .read_app_context() - .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; + }); } } @@ -127,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; + }); } } @@ -147,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,292 +198,204 @@ 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, + messages: Sender, context: Arc, } -impl Adapter { - /// Create a new Unix adapter. - pub fn new( - initial_state: impl 'static + FnOnce() -> TreeUpdate, +impl AdapterImpl { + fn new( + id: usize, + 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 })?; - 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, &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()? { - atspi_bus - .emit_object_event( - ObjectId::Root, - ObjectEvent::ChildAdded( - adapter_index, - ObjectId::Node { - adapter: id, - node: root_id, - }, - ), - ) - .await - .ok() - } else { - Some(()) - } - })?; - let adapter = Adapter { + ) -> Self { + let tree = Tree::new(initial_state, is_window_focused); + let (messages, context) = { + let mut app_context = AppContext::write(); + let messages = app_context.messages.clone().unwrap(); + let context = Context::new(tree, action_handler, root_window_bounds); + app_context.push_adapter(id, &context); + (messages, context) + }; + AdapterImpl { id, - atspi_bus, - _event_task: event_task, - events: event_sender, + messages, context, - }; - adapter.register_tree(); - Some(adapter) + } } - 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 = self - .context - .read_app_context() - .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 fn set_root_window_bounds(&self, outer: Rect, inner: Rect) { - let mut bounds = self.context.root_window_bounds.write().unwrap(); - bounds.outer = outer; - bounds.inner = inner; + 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) { + let mut old_bounds = self.context.root_window_bounds.write().unwrap(); + *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) { + 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); } - 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; } } @@ -498,39 +409,116 @@ fn root_window(current_state: &TreeState) -> Option { } } -impl Drop for Adapter { +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 { - self.context - .app_context - .write() - .unwrap() - .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>>>; + +static NEXT_ADAPTER_ID: AtomicUsize = AtomicUsize::new(0); + +pub struct Adapter { + id: usize, + 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 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())); + 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( + id, + source(), + is_window_focused, + root_window_bounds, + action_handler, + ) + } + .boxed(), + )); + let adapter = Self { + id, + r#impl: r#impl.clone(), + is_window_focused, + root_window_bounds, }; + block_on(async move { ActivationContext::activate_eventually(id, r#impl).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(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(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(r#impl) = Lazy::try_get(&self.r#impl) { + r#impl.update_window_focus_state(is_focused); + } } } + +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, + 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 15af7d61e..2565c4762 100644 --- a/platforms/unix/src/atspi/bus.rs +++ b/platforms/unix/src/atspi/bus.rs @@ -5,20 +5,17 @@ use crate::{ atspi::{interfaces::*, ObjectId}, - context::AppContext, - PlatformRootNode, + context::{AppContext, Context}, + PlatformNode, PlatformRootNode, }; -use async_once_cell::OnceCell; +use accesskit::NodeId; use atspi::{ events::EventBody, proxy::{bus::BusProxy, socket::SocketProxy}, + Interface, InterfaceSet, }; use serde::Serialize; -use std::{ - collections::HashMap, - env::var, - sync::{Arc, RwLock}, -}; +use std::{collections::HashMap, env::var, io, sync::Weak}; use zbus::{ names::{BusName, InterfaceName, MemberName, OwnedUniqueName}, zvariant::{Str, Value}, @@ -32,39 +29,25 @@ 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 async fn register_root_node( - &mut self, - app_context: &Arc>, - ) -> Result { - let node = PlatformRootNode::new(app_context); + async fn register_root_node(&mut self) -> Result<()> { + let node = PlatformRootNode::new(); let path = ObjectId::Root.path(); let app_node_added = self @@ -86,11 +69,109 @@ impl Bus { .socket_proxy .embed(&(self.unique_name().as_str(), ObjectId::Root.path().into())) .await?; - app_context.write().unwrap().desktop_address = Some(desktop.into()); - Ok(true) - } else { - Ok(false) + let mut app_context = AppContext::write(); + app_context.desktop_address = Some(desktop.into()); + } + + 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, + { + map_or_ignoring_broken_pipe( + self.conn.object_server().at(path, interface).await, + false, + |result| result, + ) + } + + 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, + { + map_or_ignoring_broken_pipe( + self.conn.object_server().remove::(path).await, + false, + |result| result, + ) } pub(crate) async fn emit_object_event( @@ -263,38 +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, + (), + |_| (), + ) } } -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() +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 8ee883d0e..6f048b58e 100644 --- a/platforms/unix/src/context.rs +++ b/platforms/unix/src/context.rs @@ -5,15 +5,24 @@ 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_util::{pin_mut, select, StreamExt}; use once_cell::sync::OnceCell; -use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, Weak}; +use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak}; +use zbus::{Connection, Task}; -use crate::{atspi::OwnedObjectAddress, util::WindowBounds}; +use crate::{ + adapter::{LazyAdapter, Message}, + atspi::{interfaces::Event, map_or_ignoring_broken_pipe, Bus, 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, } @@ -21,13 +30,12 @@ impl Context { pub(crate) fn new( tree: Tree, action_handler: Box, - app_context: &Arc>, + root_window_bounds: WindowBounds, ) -> 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), }) } @@ -35,10 +43,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() } @@ -59,43 +63,48 @@ 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) messages: 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, + messages: 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> { + 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)) } - 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) { @@ -104,3 +113,132 @@ impl AppContext { } } } + +pub(crate) struct ActivationContext { + _task: Option>, + adapters: Vec<(usize, LazyAdapter)>, +} + +static ACTIVATION_CONTEXT: AsyncOnceCell>> = AsyncOnceCell::new(); + +impl ActivationContext { + async fn get_or_init<'a>() -> AsyncMutexGuard<'a, ActivationContext> { + ACTIVATION_CONTEXT + .get_or_init(async { + 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(), + })) + }) + .await + .lock() + .await + } + + pub(crate) async fn activate_eventually(id: usize, adapter: LazyAdapter) { + let mut activation_context = ActivationContext::get_or_init().await; + 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().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<()> { + let status = StatusProxy::new(&session_bus).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 { + if change.get().await? { + map_or_ignoring_broken_pipe(Bus::new(&session_bus).await, None, Some)? + } else { + 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 { + adapter.as_ref().await.register_tree().await; + } + } + } + } + message = messages.next() => { + if let Some((message, atspi_bus)) = message.zip(atspi_bus.as_ref()) { + 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 fc9789792..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,14 +23,13 @@ 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, }; use std::{ iter::FusedIterator, - sync::{Arc, RwLock, RwLockReadGuard, Weak}, + sync::{Arc, RwLockReadGuard, Weak}, }; use zbus::fdo; @@ -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, } @@ -999,31 +1000,23 @@ 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 { - 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> { @@ -1071,11 +1064,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 { @@ -1083,12 +1076,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(()) } } diff --git a/platforms/unix/src/util.rs b/platforms/unix/src/util.rs index 21b75abf1..38b71a94d 100644 --- a/platforms/unix/src/util.rs +++ b/platforms/unix/src/util.rs @@ -39,13 +39,17 @@ 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, } 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) {