diff --git a/platforms/atspi-common/src/adapter.rs b/platforms/atspi-common/src/adapter.rs index 80d9a0194..b3114e45e 100644 --- a/platforms/atspi-common/src/adapter.rs +++ b/platforms/atspi-common/src/adapter.rs @@ -4,7 +4,7 @@ // the LICENSE-MIT file), at your option. use accesskit::{ActionHandler, NodeId, Role, TreeUpdate}; -use accesskit_consumer::{DetachedNode, FilterResult, Node, Tree, TreeChangeHandler, TreeState}; +use accesskit_consumer::{FilterResult, Node, Tree, TreeChangeHandler, TreeState}; use atspi_common::{InterfaceSet, Live, State}; use std::sync::{ atomic::{AtomicUsize, Ordering}, @@ -13,7 +13,7 @@ use std::sync::{ use crate::{ context::{ActionHandlerNoMut, ActionHandlerWrapper, AppContext, Context}, - filters::{filter, filter_detached}, + filters::filter, node::{NodeIdOrRoot, NodeWrapper, PlatformNode, PlatformRoot}, util::WindowBounds, AdapterCallback, Event, ObjectEvent, WindowEvent, @@ -27,7 +27,7 @@ impl AdapterChangeHandler<'_> { fn add_node(&mut self, node: &Node) { let role = node.role(); let is_root = node.is_root(); - let node = NodeWrapper::Node(node); + let node = NodeWrapper(node); let interfaces = node.interfaces(); self.adapter.register_interfaces(node.id(), interfaces); if is_root && role == Role::Window { @@ -49,10 +49,10 @@ impl AdapterChangeHandler<'_> { } } - fn remove_node(&mut self, node: &DetachedNode) { + fn remove_node(&mut self, node: &Node) { let role = node.role(); let is_root = node.is_root(); - let node = NodeWrapper::DetachedNode(node); + let node = NodeWrapper(node); if is_root && role == Role::Window { self.adapter.window_destroyed(node.id()); } @@ -70,8 +70,8 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> { } } - fn node_updated(&mut self, old_node: &DetachedNode, new_node: &Node) { - let filter_old = filter_detached(old_node); + fn node_updated(&mut self, old_node: &Node, new_node: &Node) { + let filter_old = filter(old_node); let filter_new = filter(new_node); if filter_new != filter_old { if filter_new == FilterResult::Include { @@ -80,8 +80,8 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> { self.remove_node(old_node); } } else if filter_new == FilterResult::Include { - let old_wrapper = NodeWrapper::DetachedNode(old_node); - let new_wrapper = NodeWrapper::Node(new_node); + let old_wrapper = NodeWrapper(old_node); + let new_wrapper = NodeWrapper(new_node); let old_interfaces = old_wrapper.interfaces(); let new_interfaces = new_wrapper.interfaces(); let kept_interfaces = old_interfaces & new_interfaces; @@ -94,25 +94,20 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> { } } - fn focus_moved( - &mut self, - old_node: Option<&DetachedNode>, - 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(&root_window)); - } else if old_node.is_some() && new_node.is_none() { - self.adapter - .window_deactivated(&NodeWrapper::Node(&root_window)); + fn focus_moved(&mut self, old_node: Option<&Node>, new_node: Option<&Node>) { + if let (None, Some(new_node)) = (old_node, new_node) { + if let Some(root_window) = root_window(new_node.tree_state) { + self.adapter.window_activated(&NodeWrapper(&root_window)); + } + } else if let (Some(old_node), None) = (old_node, new_node) { + if let Some(root_window) = root_window(old_node.tree_state) { + self.adapter.window_deactivated(&NodeWrapper(&root_window)); } } } - fn node_removed(&mut self, node: &DetachedNode, _: &TreeState) { - if filter_detached(node) == FilterResult::Include { + fn node_removed(&mut self, node: &Node) { + if filter(node) == FilterResult::Include { self.remove_node(node); } } @@ -204,7 +199,7 @@ impl Adapter { fn add_children(node: Node<'_>, to_add: &mut Vec<(NodeId, InterfaceSet)>) { for child in node.filtered_children(&filter) { let child_id = child.id(); - let wrapper = NodeWrapper::Node(&child); + let wrapper = NodeWrapper(&child); let interfaces = wrapper.interfaces(); to_add.push((child_id, interfaces)); add_children(child, to_add); @@ -223,7 +218,7 @@ impl Adapter { let adapter_index = app_context.adapter_index(self.id).unwrap(); let root = tree_state.root(); let root_id = root.id(); - let wrapper = NodeWrapper::Node(&root); + let wrapper = NodeWrapper(&root); objects_to_add.push((root_id, wrapper.interfaces())); add_children(root, &mut objects_to_add); (adapter_index, root_id) diff --git a/platforms/atspi-common/src/filters.rs b/platforms/atspi-common/src/filters.rs index f062ee72c..2802d57e6 100644 --- a/platforms/atspi-common/src/filters.rs +++ b/platforms/atspi-common/src/filters.rs @@ -3,6 +3,4 @@ // the LICENSE-APACHE file) or the MIT license (found in // the LICENSE-MIT file), at your option. -pub(crate) use accesskit_consumer::{ - common_filter as filter, common_filter_detached as filter_detached, -}; +pub(crate) use accesskit_consumer::common_filter as filter; diff --git a/platforms/atspi-common/src/node.rs b/platforms/atspi-common/src/node.rs index c825d1520..56978b011 100644 --- a/platforms/atspi-common/src/node.rs +++ b/platforms/atspi-common/src/node.rs @@ -12,7 +12,7 @@ use accesskit::{ Action, ActionData, ActionRequest, Affine, DefaultActionVerb, Live, NodeId, Point, Rect, Role, Toggled, }; -use accesskit_consumer::{DetachedNode, FilterResult, Node, NodeState, TreeState}; +use accesskit_consumer::{FilterResult, Node, TreeState}; use atspi_common::{ CoordType, Interface, InterfaceSet, Layer, Live as AtspiLive, Role as AtspiRole, State, StateSet, @@ -26,44 +26,28 @@ use std::{ use crate::{ adapter::Adapter, context::{AppContext, Context}, - filters::{filter, filter_detached}, + filters::filter, util::WindowBounds, Action as AtspiAction, Error, ObjectEvent, Property, Rect as AtspiRect, Result, }; -pub(crate) enum NodeWrapper<'a> { - Node(&'a Node<'a>), - DetachedNode(&'a DetachedNode), -} +pub(crate) struct NodeWrapper<'a>(pub(crate) &'a Node<'a>); impl<'a> NodeWrapper<'a> { - fn node_state(&self) -> &NodeState { - match self { - Self::Node(node) => node.state(), - Self::DetachedNode(node) => node.state(), - } - } - pub(crate) fn name(&self) -> Option { - match self { - Self::Node(node) => node.name(), - Self::DetachedNode(node) => node.name(), - } + self.0.name() } pub(crate) fn description(&self) -> Option { - match self { - Self::Node(node) => node.description(), - Self::DetachedNode(node) => node.description(), - } + self.0.description() } pub(crate) fn parent_id(&self) -> Option { - self.node_state().parent_id() + self.0.parent_id() } pub(crate) fn id(&self) -> NodeId { - self.node_state().id() + self.0.id() } fn child_ids( @@ -72,24 +56,21 @@ impl<'a> NodeWrapper<'a> { + ExactSizeIterator + FusedIterator + '_ { - self.node_state().child_ids() + self.0.child_ids() } fn filtered_child_ids( &self, ) -> impl DoubleEndedIterator + FusedIterator + '_ { - match self { - Self::Node(node) => node.filtered_children(&filter).map(|child| child.id()), - _ => unreachable!(), - } + self.0.filtered_children(&filter).map(|child| child.id()) } pub(crate) fn role(&self) -> AtspiRole { - if self.node_state().has_role_description() { + if self.0.has_role_description() { return AtspiRole::Extended; } - match self.node_state().role() { + match self.0.role() { Role::Alert => AtspiRole::Notification, Role::AlertDialog => AtspiRole::Alert, Role::Comment | Role::Suggestion => AtspiRole::Section, @@ -101,7 +82,7 @@ impl<'a> NodeWrapper<'a> { Role::Blockquote => AtspiRole::BlockQuote, Role::Caret => AtspiRole::Unknown, Role::Button => { - if self.node_state().toggled().is_some() { + if self.0.toggled().is_some() { AtspiRole::ToggleButton } else { AtspiRole::PushButton @@ -209,7 +190,6 @@ impl<'a> NodeWrapper<'a> { // only if it still has non-ignored descendants, which happens only when => // - The list marker itself is ignored but the descendants are not // - Or the list marker contains images - // TODO: How to check for unignored children when the node is detached? Role::ListMarker => AtspiRole::Static, Role::Log => AtspiRole::Log, Role::Main => AtspiRole::Landmark, @@ -301,14 +281,11 @@ impl<'a> NodeWrapper<'a> { } fn is_focused(&self) -> bool { - match self { - Self::Node(node) => node.is_focused(), - Self::DetachedNode(node) => node.is_focused(), - } + self.0.is_focused() } pub(crate) fn state(&self, is_window_focused: bool) -> StateSet { - let state = self.node_state(); + let state = self.0; let atspi_role = self.role(); let mut atspi_state = StateSet::empty(); if state.parent_id().is_none() && state.role() == Role::Window && is_window_focused { @@ -318,10 +295,7 @@ impl<'a> NodeWrapper<'a> { if state.is_focusable() { atspi_state.insert(State::Focusable); } - let filter_result = match self { - Self::Node(node) => filter(node), - Self::DetachedNode(node) => filter_detached(node), - }; + let filter_result = filter(self.0); if filter_result == FilterResult::Include { atspi_state.insert(State::Visible | State::Showing); } @@ -373,18 +347,15 @@ impl<'a> NodeWrapper<'a> { } fn is_root(&self) -> bool { - match self { - Self::Node(node) => node.is_root(), - Self::DetachedNode(node) => node.is_root(), - } + self.0.is_root() } fn supports_action(&self) -> bool { - self.node_state().default_action_verb().is_some() + self.0.default_action_verb().is_some() } fn supports_component(&self) -> bool { - self.node_state().raw_bounds().is_some() || self.is_root() + self.0.raw_bounds().is_some() || self.is_root() } fn supports_value(&self) -> bool { @@ -406,10 +377,7 @@ impl<'a> NodeWrapper<'a> { } pub(crate) fn live(&self) -> AtspiLive { - let live = match self { - Self::Node(node) => node.live(), - Self::DetachedNode(node) => node.live(), - }; + let live = self.0.live(); match live { Live::Off => AtspiLive::None, Live::Polite => AtspiLive::Polite, @@ -418,7 +386,7 @@ impl<'a> NodeWrapper<'a> { } fn n_actions(&self) -> i32 { - match self.node_state().default_action_verb() { + match self.0.default_action_verb() { Some(_) => 1, None => 0, } @@ -428,7 +396,7 @@ impl<'a> NodeWrapper<'a> { if index != 0 { return String::new(); } - String::from(match self.node_state().default_action_verb() { + String::from(match self.0.default_action_verb() { Some(DefaultActionVerb::Click) => "click", Some(DefaultActionVerb::Focus) => "focus", Some(DefaultActionVerb::Check) => "check", @@ -444,7 +412,7 @@ impl<'a> NodeWrapper<'a> { } fn raw_bounds_and_transform(&self) -> (Option, Affine) { - let state = self.node_state(); + let state = self.0; (state.raw_bounds(), state.direct_transform()) } @@ -452,25 +420,22 @@ impl<'a> NodeWrapper<'a> { if self.is_root() { return window_bounds.outer.into(); } - match self { - Self::Node(node) => node.bounding_box().map_or_else( - || AtspiRect::INVALID, - |bounds| { - let window_top_left = window_bounds.inner.origin(); - let node_origin = bounds.origin(); - let new_origin = Point::new( - window_top_left.x + node_origin.x, - window_top_left.y + node_origin.y, - ); - bounds.with_origin(new_origin).into() - }, - ), - _ => unreachable!(), - } + self.0.bounding_box().map_or_else( + || AtspiRect::INVALID, + |bounds| { + let window_top_left = window_bounds.inner.origin(); + let node_origin = bounds.origin(); + let new_origin = Point::new( + window_top_left.x + node_origin.x, + window_top_left.y + node_origin.y, + ); + bounds.with_origin(new_origin).into() + }, + ) } fn current_value(&self) -> Option { - self.node_state().numeric_value() + self.0.numeric_value() } pub(crate) fn notify_changes( @@ -522,11 +487,8 @@ impl<'a> NodeWrapper<'a> { } let parent_id = self.parent_id(); if parent_id != old.parent_id() { - let node = match self { - NodeWrapper::Node(node) => node, - _ => unreachable!(), - }; - let parent = node + let parent = self + .0 .filtered_parent(&filter) .map_or(NodeIdOrRoot::Root, |node| NodeIdOrRoot::Node(node.id())); adapter.emit_object_event( @@ -666,14 +628,14 @@ impl PlatformNode { pub fn name(&self) -> Result { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); Ok(wrapper.name().unwrap_or_default()) }) } pub fn description(&self) -> Result { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); Ok(wrapper.description().unwrap_or_default()) }) } @@ -756,18 +718,18 @@ impl PlatformNode { pub fn role(&self) -> Result { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); Ok(wrapper.role()) }) } pub fn localized_role_name(&self) -> Result { - self.resolve(|node| Ok(node.state().role_description().unwrap_or_default())) + self.resolve(|node| Ok(node.role_description().unwrap_or_default())) } pub fn state(&self) -> StateSet { self.resolve_with_context(|node, context| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); Ok(wrapper.state(context.read_tree().state().focus_id().is_some())) }) .unwrap_or(State::Defunct.into()) @@ -775,49 +737,49 @@ impl PlatformNode { pub fn supports_action(&self) -> Result { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); Ok(wrapper.supports_action()) }) } pub fn supports_component(&self) -> Result { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); Ok(wrapper.supports_component()) }) } pub fn supports_value(&self) -> Result { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); Ok(wrapper.supports_value()) }) } pub fn interfaces(&self) -> Result { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); Ok(wrapper.interfaces()) }) } pub fn n_actions(&self) -> Result { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); Ok(wrapper.n_actions()) }) } pub fn action_name(&self, index: i32) -> Result { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); Ok(wrapper.get_action_name(index)) }) } pub fn actions(&self) -> Result> { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); let n_actions = wrapper.n_actions() as usize; let mut actions = Vec::with_capacity(n_actions); for i in 0..n_actions { @@ -907,7 +869,7 @@ impl PlatformNode { pub fn layer(&self) -> Result { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); if wrapper.role() == AtspiRole::Window { Ok(Layer::Window) } else { @@ -941,20 +903,20 @@ impl PlatformNode { } pub fn minimum_value(&self) -> Result { - self.resolve(|node| Ok(node.state().min_numeric_value().unwrap_or(f64::MIN))) + self.resolve(|node| Ok(node.min_numeric_value().unwrap_or(f64::MIN))) } pub fn maximum_value(&self) -> Result { - self.resolve(|node| Ok(node.state().max_numeric_value().unwrap_or(f64::MAX))) + self.resolve(|node| Ok(node.max_numeric_value().unwrap_or(f64::MAX))) } pub fn minimum_increment(&self) -> Result { - self.resolve(|node| Ok(node.state().numeric_value_step().unwrap_or(0.0))) + self.resolve(|node| Ok(node.numeric_value_step().unwrap_or(0.0))) } pub fn current_value(&self) -> Result { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); Ok(wrapper.current_value().unwrap_or(0.0)) }) } diff --git a/platforms/macos/src/event.rs b/platforms/macos/src/event.rs index 218ca2661..a3f26df46 100644 --- a/platforms/macos/src/event.rs +++ b/platforms/macos/src/event.rs @@ -4,17 +4,13 @@ // the LICENSE-MIT file), at your option. use accesskit::{Live, NodeId, Role}; -use accesskit_consumer::{DetachedNode, FilterResult, Node, TreeChangeHandler, TreeState}; +use accesskit_consumer::{FilterResult, Node, TreeChangeHandler}; use objc2::runtime::{AnyObject, ProtocolObject}; use objc2_app_kit::*; use objc2_foundation::{NSMutableDictionary, NSNumber, NSString}; use std::{collections::HashSet, rc::Rc}; -use crate::{ - context::Context, - filters::{filter, filter_detached}, - node::NodeWrapper, -}; +use crate::{context::Context, filters::filter, node::NodeWrapper}; // This type is designed to be safe to create on a non-main thread // and send to the main thread. This ability isn't yet used though. @@ -184,21 +180,6 @@ impl EventGenerator { self.insert_text_change_if_needed_parent(node); } } - - fn insert_text_change_if_needed_for_removed_node( - &mut self, - node: &DetachedNode, - current_state: &TreeState, - ) { - if node.role() != Role::InlineTextBox { - return; - } - if let Some(id) = node.parent_id() { - if let Some(node) = current_state.node_by_id(id) { - self.insert_text_change_if_needed_parent(node); - } - } - } } impl TreeChangeHandler for EventGenerator { @@ -213,7 +194,7 @@ impl TreeChangeHandler for EventGenerator { } } - fn node_updated(&mut self, old_node: &DetachedNode, new_node: &Node) { + fn node_updated(&mut self, old_node: &Node, new_node: &Node) { if old_node.raw_value() != new_node.raw_value() { self.insert_text_change_if_needed(new_node); } @@ -221,8 +202,8 @@ impl TreeChangeHandler for EventGenerator { return; } let node_id = new_node.id(); - let old_wrapper = NodeWrapper::DetachedNode(old_node); - let new_wrapper = NodeWrapper::Node(new_node); + let old_wrapper = NodeWrapper(old_node); + let new_wrapper = NodeWrapper(new_node); if old_wrapper.title() != new_wrapper.title() { self.events.push(QueuedEvent::Generic { node_id, @@ -248,19 +229,14 @@ impl TreeChangeHandler for EventGenerator { && new_node.live() != Live::Off && (new_node.name() != old_node.name() || new_node.live() != old_node.live() - || filter_detached(old_node) != FilterResult::Include) + || filter(old_node) != FilterResult::Include) { self.events .push(QueuedEvent::live_region_announcement(new_node)); } } - fn focus_moved( - &mut self, - _old_node: Option<&DetachedNode>, - new_node: Option<&Node>, - _current_state: &TreeState, - ) { + fn focus_moved(&mut self, _old_node: Option<&Node>, new_node: Option<&Node>) { if let Some(new_node) = new_node { if filter(new_node) != FilterResult::Include { return; @@ -269,8 +245,8 @@ impl TreeChangeHandler for EventGenerator { } } - fn node_removed(&mut self, node: &DetachedNode, current_state: &TreeState) { - self.insert_text_change_if_needed_for_removed_node(node, current_state); + fn node_removed(&mut self, node: &Node) { + self.insert_text_change_if_needed(node); self.events.push(QueuedEvent::NodeDestroyed(node.id())); } } diff --git a/platforms/macos/src/filters.rs b/platforms/macos/src/filters.rs index f062ee72c..2802d57e6 100644 --- a/platforms/macos/src/filters.rs +++ b/platforms/macos/src/filters.rs @@ -3,6 +3,4 @@ // the LICENSE-APACHE file) or the MIT license (found in // the LICENSE-MIT file), at your option. -pub(crate) use accesskit_consumer::{ - common_filter as filter, common_filter_detached as filter_detached, -}; +pub(crate) use accesskit_consumer::common_filter as filter; diff --git a/platforms/macos/src/node.rs b/platforms/macos/src/node.rs index 21c35d424..7102d2797 100644 --- a/platforms/macos/src/node.rs +++ b/platforms/macos/src/node.rs @@ -11,7 +11,7 @@ #![allow(non_upper_case_globals)] use accesskit::{Action, ActionData, ActionRequest, NodeId, Role, TextSelection, Toggled}; -use accesskit_consumer::{DetachedNode, FilterResult, Node, NodeState}; +use accesskit_consumer::{FilterResult, Node}; use objc2::{ declare_class, msg_send_id, mutability::InteriorMutable, @@ -28,8 +28,8 @@ use std::rc::{Rc, Weak}; use crate::{context::Context, filters::filter, util::*}; -fn ns_role(node_state: &NodeState) -> &'static NSAccessibilityRole { - let role = node_state.role(); +fn ns_role(node: &Node) -> &'static NSAccessibilityRole { + let role = node.role(); // TODO: Handle special cases. unsafe { match role { @@ -58,7 +58,7 @@ fn ns_role(node_state: &NodeState) -> &'static NSAccessibilityRole { | Role::PhoneNumberInput | Role::UrlInput => NSAccessibilityTextFieldRole, Role::Button => { - if node_state.toggled().is_some() { + if node.toggled().is_some() { NSAccessibilityCheckBoxRole } else { NSAccessibilityButtonRole @@ -241,43 +241,24 @@ pub(crate) enum Value { String(String), } -pub(crate) enum NodeWrapper<'a> { - Node(&'a Node<'a>), - DetachedNode(&'a DetachedNode), -} +pub(crate) struct NodeWrapper<'a>(pub(crate) &'a Node<'a>); impl<'a> NodeWrapper<'a> { - fn node_state(&self) -> &'a NodeState { - match self { - Self::Node(node) => node.state(), - Self::DetachedNode(node) => node.state(), - } - } - fn is_root(&self) -> bool { - match self { - Self::Node(node) => node.is_root(), - Self::DetachedNode(node) => node.is_root(), - } + self.0.is_root() } fn name(&self) -> Option { - if self.is_root() && self.node_state().role() == Role::Window { + if self.is_root() && self.0.role() == Role::Window { // If the group element that we expose for the top-level window // includes a title, VoiceOver behavior is broken. return None; } - match self { - Self::Node(node) => node.name(), - Self::DetachedNode(node) => node.name(), - } + self.0.name() } fn node_value(&self) -> Option { - match self { - Self::Node(node) => node.value(), - Self::DetachedNode(node) => node.value(), - } + self.0.value() } // TODO: implement proper logic for title and value; @@ -285,7 +266,7 @@ impl<'a> NodeWrapper<'a> { // and figure out how this is different in the macOS 10.10+ protocol pub(crate) fn title(&self) -> Option { - let state = self.node_state(); + let state = self.0; if state.role() == Role::StaticText && state.raw_value().is_none() { // In this case, macOS wants the text to be the value, not title. return None; @@ -294,14 +275,11 @@ impl<'a> NodeWrapper<'a> { } pub(crate) fn description(&self) -> Option { - match self { - Self::Node(node) => node.description(), - Self::DetachedNode(node) => node.description(), - } + self.0.description() } pub(crate) fn value(&self) -> Option { - let state = self.node_state(); + let state = self.0; if let Some(toggled) = state.toggled() { return Some(Value::Bool(toggled != Toggled::False)); } @@ -320,14 +298,11 @@ impl<'a> NodeWrapper<'a> { } pub(crate) fn supports_text_ranges(&self) -> bool { - match self { - Self::Node(node) => node.supports_text_ranges(), - Self::DetachedNode(node) => node.supports_text_ranges(), - } + self.0.supports_text_ranges() } pub(crate) fn raw_text_selection(&self) -> Option<&TextSelection> { - self.node_state().raw_text_selection() + self.0.raw_text_selection() } } @@ -403,7 +378,7 @@ declare_class!( #[method_id(accessibilityRole)] fn role(&self) -> Id { - self.resolve(|node| ns_role(node.state())) + self.resolve(ns_role) .unwrap_or(unsafe { NSAccessibilityUnknownRole }) .copy() } @@ -423,7 +398,7 @@ declare_class!( #[method_id(accessibilityTitle)] fn title(&self) -> Option> { self.resolve(|node| { - let wrapper = NodeWrapper::Node(node); + let wrapper = NodeWrapper(node); wrapper.title().map(|title| NSString::from_str(&title)) }) .flatten() @@ -432,7 +407,7 @@ declare_class!( #[method_id(accessibilityHelp)] fn description(&self) -> Option> { self.resolve(|node| { - let wrapper = NodeWrapper::Node(node); + let wrapper = NodeWrapper(node); wrapper.description().map(|description| NSString::from_str(&description)) }) .flatten() @@ -441,7 +416,7 @@ declare_class!( #[method_id(accessibilityValue)] fn value(&self) -> Option> { self.resolve(|node| { - let wrapper = NodeWrapper::Node(node); + let wrapper = NodeWrapper(node); wrapper.value().map(|value| match value { Value::Bool(value) => { Id::into_super(Id::into_super(NSNumber::new_bool(value))) diff --git a/platforms/windows/src/adapter.rs b/platforms/windows/src/adapter.rs index 4e69aac0c..362b4cdfc 100644 --- a/platforms/windows/src/adapter.rs +++ b/platforms/windows/src/adapter.rs @@ -6,7 +6,7 @@ use accesskit::{ ActionHandler, ActivationHandler, Live, NodeBuilder, NodeId, Role, Tree as TreeData, TreeUpdate, }; -use accesskit_consumer::{DetachedNode, FilterResult, Node, Tree, TreeChangeHandler, TreeState}; +use accesskit_consumer::{FilterResult, Node, Tree, TreeChangeHandler}; use std::{ collections::HashSet, sync::{atomic::Ordering, Arc}, @@ -18,7 +18,7 @@ use windows::Win32::{ use crate::{ context::{ActionHandlerNoMut, ActionHandlerWrapper, Context}, - filters::{filter, filter_detached}, + filters::filter, node::{NodeWrapper, PlatformNode}, util::QueuedEvent, }; @@ -80,21 +80,6 @@ impl AdapterChangeHandler<'_> { self.insert_text_change_if_needed_parent(node); } } - - fn insert_text_change_if_needed_for_removed_node( - &mut self, - node: &DetachedNode, - current_state: &TreeState, - ) { - if node.role() != Role::InlineTextBox { - return; - } - if let Some(id) = node.parent_id() { - if let Some(node) = current_state.node_by_id(id) { - self.insert_text_change_if_needed_parent(node); - } - } - } } impl TreeChangeHandler for AdapterChangeHandler<'_> { @@ -113,7 +98,7 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> { } } - fn node_updated(&mut self, old_node: &DetachedNode, new_node: &Node) { + fn node_updated(&mut self, old_node: &Node, new_node: &Node) { if old_node.raw_value() != new_node.raw_value() { self.insert_text_change_if_needed(new_node); } @@ -122,14 +107,14 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> { } let platform_node = PlatformNode::new(self.context, new_node.id()); let element: IRawElementProviderSimple = platform_node.into(); - let old_wrapper = NodeWrapper::DetachedNode(old_node); - let new_wrapper = NodeWrapper::Node(new_node); + let old_wrapper = NodeWrapper(old_node); + let new_wrapper = NodeWrapper(new_node); new_wrapper.enqueue_property_changes(&mut self.queue, &element, &old_wrapper); if new_node.name().is_some() && new_node.live() != Live::Off && (new_node.name() != old_node.name() || new_node.live() != old_node.live() - || filter_detached(old_node) != FilterResult::Include) + || filter(old_node) != FilterResult::Include) { self.queue.push(QueuedEvent::Simple { element, @@ -138,19 +123,14 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> { } } - fn focus_moved( - &mut self, - _old_node: Option<&DetachedNode>, - new_node: Option<&Node>, - _current_state: &TreeState, - ) { + fn focus_moved(&mut self, _old_node: Option<&Node>, new_node: Option<&Node>) { if let Some(new_node) = new_node { self.queue.push(focus_event(self.context, new_node.id())); } } - fn node_removed(&mut self, node: &DetachedNode, current_state: &TreeState) { - self.insert_text_change_if_needed_for_removed_node(node, current_state); + fn node_removed(&mut self, node: &Node) { + self.insert_text_change_if_needed(node); } // TODO: handle other events (#20) diff --git a/platforms/windows/src/filters.rs b/platforms/windows/src/filters.rs index e5d21d7ae..e8614e8d1 100644 --- a/platforms/windows/src/filters.rs +++ b/platforms/windows/src/filters.rs @@ -4,6 +4,5 @@ // the LICENSE-MIT file), at your option. pub(crate) use accesskit_consumer::{ - common_filter as filter, common_filter_detached as filter_detached, - common_filter_with_root_exception as filter_with_root_exception, + common_filter as filter, common_filter_with_root_exception as filter_with_root_exception, }; diff --git a/platforms/windows/src/node.rs b/platforms/windows/src/node.rs index 9ec43371b..d7c4ad942 100644 --- a/platforms/windows/src/node.rs +++ b/platforms/windows/src/node.rs @@ -13,7 +13,7 @@ use accesskit::{ Action, ActionData, ActionRequest, Live, NodeId, NodeIdContent, Point, Role, Toggled, }; -use accesskit_consumer::{DetachedNode, FilterResult, Node, NodeState, TreeState}; +use accesskit_consumer::{FilterResult, Node, TreeState}; use paste::paste; use std::sync::{atomic::Ordering, Arc, Weak}; use windows::{ @@ -23,7 +23,7 @@ use windows::{ use crate::{ context::Context, - filters::{filter, filter_detached, filter_with_root_exception}, + filters::{filter, filter_with_root_exception}, text::PlatformRange as PlatformTextRange, util::*, }; @@ -40,21 +40,11 @@ fn runtime_id_from_node_id(id: NodeId) -> [i32; RUNTIME_ID_SIZE] { ] } -pub(crate) enum NodeWrapper<'a> { - Node(&'a Node<'a>), - DetachedNode(&'a DetachedNode), -} +pub(crate) struct NodeWrapper<'a>(pub(crate) &'a Node<'a>); impl<'a> NodeWrapper<'a> { - fn node_state(&self) -> &'a NodeState { - match self { - Self::Node(node) => node.state(), - Self::DetachedNode(node) => node.state(), - } - } - fn control_type(&self) -> UIA_CONTROLTYPE_ID { - let role = self.node_state().role(); + let role = self.0.role(); // TODO: Handle special cases. (#14) match role { Role::Unknown => UIA_CustomControlTypeId, @@ -264,51 +254,35 @@ impl<'a> NodeWrapper<'a> { } fn localized_control_type(&self) -> Option { - self.node_state().role_description() + self.0.role_description() } fn name(&self) -> Option { - match self { - Self::Node(node) => node.name(), - Self::DetachedNode(node) => node.name(), - } + self.0.name() } fn description(&self) -> Option { - match self { - Self::Node(node) => node.description(), - Self::DetachedNode(node) => node.description(), - } + self.0.description() } fn is_content_element(&self) -> bool { - let result = match self { - Self::Node(node) => filter(node), - Self::DetachedNode(node) => filter_detached(node), - }; - result == FilterResult::Include + filter(self.0) == FilterResult::Include } fn is_enabled(&self) -> bool { - !self.node_state().is_disabled() + !self.0.is_disabled() } fn is_focusable(&self) -> bool { - self.node_state().is_focusable() + self.0.is_focusable() } fn is_focused(&self) -> bool { - match self { - Self::Node(node) => node.is_focused(), - Self::DetachedNode(node) => node.is_focused(), - } + self.0.is_focused() } fn live_setting(&self) -> LiveSetting { - let live = match self { - Self::Node(node) => node.live(), - Self::DetachedNode(node) => node.live(), - }; + let live = self.0.live(); match live { Live::Off => Off, Live::Polite => Polite, @@ -317,15 +291,15 @@ impl<'a> NodeWrapper<'a> { } fn class_name(&self) -> Option<&str> { - self.node_state().class_name() + self.0.class_name() } fn is_toggle_pattern_supported(&self) -> bool { - self.node_state().toggled().is_some() && !self.is_selection_item_pattern_supported() + self.0.toggled().is_some() && !self.is_selection_item_pattern_supported() } fn toggle_state(&self) -> ToggleState { - match self.node_state().toggled().unwrap() { + match self.0.toggled().unwrap() { Toggled::False => ToggleState_Off, Toggled::True => ToggleState_On, Toggled::Mixed => ToggleState_Indeterminate, @@ -333,94 +307,82 @@ impl<'a> NodeWrapper<'a> { } fn is_invoke_pattern_supported(&self) -> bool { - self.node_state().is_invocable() + self.0.is_invocable() } fn is_value_pattern_supported(&self) -> bool { - match self { - Self::Node(node) => node.has_value(), - Self::DetachedNode(node) => node.has_value(), - } + self.0.has_value() } fn is_range_value_pattern_supported(&self) -> bool { - self.node_state().numeric_value().is_some() + self.0.numeric_value().is_some() } fn value(&self) -> String { - match self { - Self::Node(node) => node.value().unwrap(), - Self::DetachedNode(node) => node.value().unwrap(), - } + self.0.value().unwrap() } fn is_read_only(&self) -> bool { - self.node_state().is_read_only() + self.0.is_read_only() } fn numeric_value(&self) -> f64 { - self.node_state().numeric_value().unwrap() + self.0.numeric_value().unwrap() } fn min_numeric_value(&self) -> f64 { - self.node_state().min_numeric_value().unwrap_or(0.0) + self.0.min_numeric_value().unwrap_or(0.0) } fn max_numeric_value(&self) -> f64 { - self.node_state().max_numeric_value().unwrap_or(0.0) + self.0.max_numeric_value().unwrap_or(0.0) } fn numeric_value_step(&self) -> f64 { - self.node_state().numeric_value_step().unwrap_or(0.0) + self.0.numeric_value_step().unwrap_or(0.0) } fn numeric_value_jump(&self) -> f64 { - self.node_state() + self.0 .numeric_value_jump() .unwrap_or_else(|| self.numeric_value_step()) } fn is_selection_item_pattern_supported(&self) -> bool { - match self.node_state().role() { + match self.0.role() { // TODO: tables (#29) // https://www.w3.org/TR/core-aam-1.1/#mapping_state-property_table // SelectionItem.IsSelected is exposed when aria-checked is True or // False, for 'radio' and 'menuitemradio' roles. - Role::RadioButton | Role::MenuItemRadio => matches!( - self.node_state().toggled(), - Some(Toggled::True | Toggled::False) - ), + Role::RadioButton | Role::MenuItemRadio => { + matches!(self.0.toggled(), Some(Toggled::True | Toggled::False)) + } // https://www.w3.org/TR/wai-aria-1.1/#aria-selected // SelectionItem.IsSelected is exposed when aria-select is True or False. Role::ListBoxOption | Role::ListItem | Role::MenuListOption | Role::Tab - | Role::TreeItem => self.node_state().is_selected().is_some(), + | Role::TreeItem => self.0.is_selected().is_some(), _ => false, } } fn is_selected(&self) -> bool { - match self.node_state().role() { + match self.0.role() { // https://www.w3.org/TR/core-aam-1.1/#mapping_state-property_table // SelectionItem.IsSelected is set according to the True or False // value of aria-checked for 'radio' and 'menuitemradio' roles. - Role::RadioButton | Role::MenuItemRadio => { - self.node_state().toggled() == Some(Toggled::True) - } + Role::RadioButton | Role::MenuItemRadio => self.0.toggled() == Some(Toggled::True), // https://www.w3.org/TR/wai-aria-1.1/#aria-selected // SelectionItem.IsSelected is set according to the True or False // value of aria-selected. - _ => self.node_state().is_selected().unwrap_or(false), + _ => self.0.is_selected().unwrap_or(false), } } fn is_text_pattern_supported(&self) -> bool { - match self { - Self::Node(node) => node.supports_text_ranges(), - Self::DetachedNode(node) => node.supports_text_ranges(), - } + self.0.supports_text_ranges() } pub(crate) fn enqueue_property_changes( @@ -451,7 +413,7 @@ impl<'a> NodeWrapper<'a> { } if self.is_text_pattern_supported() && old.is_text_pattern_supported() - && self.node_state().raw_text_selection() != old.node_state().raw_text_selection() + && self.0.raw_text_selection() != old.0.raw_text_selection() { queue.push(QueuedEvent::Simple { element: element.clone(), @@ -646,7 +608,7 @@ impl IRawElementProviderSimple_Impl for PlatformNode { fn GetPropertyValue(&self, property_id: UIA_PROPERTY_ID) -> Result { self.resolve_with_tree_state_and_context(|node, state, context| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); let mut result = wrapper.get_property_value(property_id); if result.is_empty() { if node.is_root() { @@ -830,7 +792,7 @@ macro_rules! patterns { impl PlatformNode { fn pattern_provider(&self, pattern_id: UIA_PATTERN_ID) -> Result { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); match pattern_id { $(paste! { [< UIA_ $base_pattern_id PatternId>] } => { if wrapper.$is_supported() { @@ -875,7 +837,7 @@ macro_rules! patterns { impl [< I $base_pattern_id Provider_Impl>] for PlatformNode { $(fn $base_property_id(&self) -> Result<$com_type> { self.resolve(|node| { - let wrapper = NodeWrapper::Node(&node); + let wrapper = NodeWrapper(&node); Ok(wrapper.$getter().into()) }) })*