Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 49 additions & 35 deletions platforms/windows/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ use crate::{
};

fn focus_event(context: &Arc<Context>, node_id: NodeId) -> QueuedEvent {
let platform_node = PlatformNode::new(context, node_id);
let element: IRawElementProviderSimple = platform_node.into();
let platform_node = context.get_or_create_platform_node(node_id);
let element: IRawElementProviderSimple = platform_node.into_interface();
QueuedEvent::Simple {
element,
event_id: UIA_AutomationFocusChangedEventId,
Expand Down Expand Up @@ -60,8 +60,8 @@ impl AdapterChangeHandler<'_> {
if self.text_changed.contains(&id) {
return;
}
let platform_node = PlatformNode::new(self.context, node.id());
let element: IRawElementProviderSimple = platform_node.into();
let platform_node = self.context.get_or_create_platform_node(node.id());
let element: IRawElementProviderSimple = platform_node.into_interface();
// Text change events must come before selection change
// events. It doesn't matter if text change events come
// before other events.
Expand Down Expand Up @@ -135,19 +135,25 @@ impl AdapterChangeHandler<'_> {

if let Some(only_selected_child) = only_selected_child {
self.queue.push(QueuedEvent::Simple {
element: PlatformNode::new(self.context, only_selected_child.id()).into(),
element: self
.context
.get_or_create_platform_node(only_selected_child.id())
.into_interface(),
event_id: UIA_SelectionItem_ElementSelectedEventId,
});
self.queue.push(QueuedEvent::PropertyChanged {
element: PlatformNode::new(self.context, only_selected_child.id()).into(),
element: self
.context
.get_or_create_platform_node(only_selected_child.id())
.into_interface(),
property_id: UIA_SelectionItemIsSelectedPropertyId,
old_value: false.into(),
new_value: true.into(),
});
for child_id in changes.removed_items.iter() {
let platform_node = PlatformNode::new(self.context, *child_id);
let platform_node = self.context.get_or_create_platform_node(*child_id);
self.queue.push(QueuedEvent::PropertyChanged {
element: platform_node.into(),
element: platform_node.into_interface(),
property_id: UIA_SelectionItemIsSelectedPropertyId,
old_value: true.into(),
new_value: false.into(),
Expand All @@ -161,36 +167,48 @@ impl AdapterChangeHandler<'_> {
if let Some(container) = container.filter(|_| {
changes.added_items.len() + changes.removed_items.len() > INVALIDATE_LIMIT
}) {
let platform_node = PlatformNode::new(self.context, container.id());
let platform_node = self.context.get_or_create_platform_node(container.id());
self.queue.push(QueuedEvent::Simple {
element: platform_node.into(),
element: platform_node.into_interface(),
event_id: UIA_Selection_InvalidatedEventId,
});
} else {
let container_is_multiselectable =
container.is_some_and(|c| c.is_multiselectable());
for added_id in changes.added_items.iter() {
self.queue.push(QueuedEvent::Simple {
element: PlatformNode::new(self.context, *added_id).into(),
element: self
.context
.get_or_create_platform_node(*added_id)
.into_interface(),
event_id: match container_is_multiselectable {
true => UIA_SelectionItem_ElementAddedToSelectionEventId,
false => UIA_SelectionItem_ElementSelectedEventId,
},
});
self.queue.push(QueuedEvent::PropertyChanged {
element: PlatformNode::new(self.context, *added_id).into(),
element: self
.context
.get_or_create_platform_node(*added_id)
.into_interface(),
property_id: UIA_SelectionItemIsSelectedPropertyId,
old_value: false.into(),
new_value: true.into(),
});
}
for removed_id in changes.removed_items.iter() {
self.queue.push(QueuedEvent::Simple {
element: PlatformNode::new(self.context, *removed_id).into(),
element: self
.context
.get_or_create_platform_node(*removed_id)
.into_interface(),
event_id: UIA_SelectionItem_ElementRemovedFromSelectionEventId,
});
self.queue.push(QueuedEvent::PropertyChanged {
element: PlatformNode::new(self.context, *removed_id).into(),
element: self
.context
.get_or_create_platform_node(*removed_id)
.into_interface(),
property_id: UIA_SelectionItemIsSelectedPropertyId,
old_value: true.into(),
new_value: false.into(),
Expand All @@ -215,16 +233,16 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> {
}
let wrapper = NodeWrapper(node);
if node.is_dialog() {
let platform_node = PlatformNode::new(self.context, node.id());
let element: IRawElementProviderSimple = platform_node.into();
let platform_node = self.context.get_or_create_platform_node(node.id());
let element: IRawElementProviderSimple = platform_node.into_interface();
self.queue.push(QueuedEvent::Simple {
element,
event_id: UIA_Window_WindowOpenedEventId,
});
}
if wrapper.name().is_some() && node.live() != Live::Off {
let platform_node = PlatformNode::new(self.context, node.id());
let element: IRawElementProviderSimple = platform_node.into();
let platform_node = self.context.get_or_create_platform_node(node.id());
let element: IRawElementProviderSimple = platform_node.into_interface();
self.queue.push(QueuedEvent::Simple {
element,
event_id: UIA_LiveRegionChangedEventId,
Expand All @@ -243,8 +261,8 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> {
if filter(new_node) != FilterResult::Include {
if !old_node_was_filtered_out {
if old_node.is_dialog() {
let platform_node = PlatformNode::new(self.context, old_node.id());
let element: IRawElementProviderSimple = platform_node.into();
let platform_node = self.context.get_or_create_platform_node(old_node.id());
let element: IRawElementProviderSimple = platform_node.into_interface();
self.queue.push(QueuedEvent::Simple {
element,
event_id: UIA_Window_WindowClosedEventId,
Expand All @@ -257,16 +275,11 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> {
}
return;
}
let platform_node = PlatformNode::new(self.context, new_node.id());
let element: IRawElementProviderSimple = platform_node.into();
let platform_node = self.context.get_or_create_platform_node(new_node.id());
let element: IRawElementProviderSimple = platform_node.into_interface();
let old_wrapper = NodeWrapper(old_node);
let new_wrapper = NodeWrapper(new_node);
new_wrapper.enqueue_property_changes(
&mut self.queue,
&PlatformNode::new(self.context, new_node.id()),
&element,
&old_wrapper,
);
new_wrapper.enqueue_property_changes(&mut self.queue, self.context, &element, &old_wrapper);
let new_name = new_wrapper.name();
if new_name.is_some()
&& new_node.live() != Live::Off
Expand All @@ -280,8 +293,8 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> {
});
}
if old_node_was_filtered_out && new_node.is_dialog() {
let platform_node = PlatformNode::new(self.context, new_node.id());
let element: IRawElementProviderSimple = platform_node.into();
let platform_node = self.context.get_or_create_platform_node(new_node.id());
let element: IRawElementProviderSimple = platform_node.into_interface();
self.queue.push(QueuedEvent::Simple {
element,
event_id: UIA_Window_WindowOpenedEventId,
Expand All @@ -303,12 +316,13 @@ impl TreeChangeHandler for AdapterChangeHandler<'_> {

fn node_removed(&mut self, node: &Node) {
self.insert_text_change_if_needed(node);
self.context.remove_platform_node(node.id());
if filter(node) != FilterResult::Include {
return;
}
if node.is_dialog() {
let platform_node = PlatformNode::new(self.context, node.id());
let element: IRawElementProviderSimple = platform_node.into();
let platform_node = self.context.get_or_create_platform_node(node.id());
let element: IRawElementProviderSimple = platform_node.into_interface();
self.queue.push(QueuedEvent::Simple {
element,
event_id: UIA_Window_WindowClosedEventId,
Expand Down Expand Up @@ -509,7 +523,7 @@ impl Adapter {
let tree = Tree::new(initial_state, *is_window_focused);
let context = Context::new(hwnd, tree, Arc::clone(action_handler), false);
let node_id = context.read_tree().state().root_id();
let platform_node = PlatformNode::new(&context, node_id);
let platform_node = context.get_or_create_platform_node(node_id);
self.state = State::Active(context);
(hwnd, platform_node)
}
Expand All @@ -532,10 +546,10 @@ impl Adapter {
State::Placeholder(context) => (context.hwnd, PlatformNode::unspecified_root(context)),
State::Active(context) => {
let node_id = context.read_tree().state().root_id();
(context.hwnd, PlatformNode::new(context, node_id))
(context.hwnd, context.get_or_create_platform_node(node_id))
}
};
let el: IRawElementProviderSimple = platform_node.into();
let el: IRawElementProviderSimple = platform_node.into_interface();
Some(WmGetObjectResult {
hwnd,
wparam,
Expand Down
27 changes: 25 additions & 2 deletions platforms/windows/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
// the LICENSE-MIT file), at your option.

use accesskit::{ActionHandler, ActionRequest, Point};
use accesskit_consumer::Tree;
use accesskit_consumer::{NodeId, Tree};
use hashbrown::HashMap;
use std::fmt::{Debug, Formatter};
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, atomic::AtomicBool};
use windows::core::ComObject;

use crate::{util::*, window_handle::WindowHandle};
use crate::{node::PlatformNode, util::*, window_handle::WindowHandle};

pub(crate) trait ActionHandlerNoMut {
fn do_action(&self, request: ActionRequest);
Expand All @@ -33,6 +35,7 @@ pub(crate) struct Context {
pub(crate) tree: RwLock<Tree>,
pub(crate) action_handler: Arc<dyn ActionHandlerNoMut + Send + Sync>,
pub(crate) is_placeholder: AtomicBool,
platform_nodes: Mutex<HashMap<NodeId, ComObject<PlatformNode>>>,
}

impl Debug for Context {
Expand All @@ -58,6 +61,7 @@ impl Context {
tree: RwLock::new(tree),
action_handler,
is_placeholder: AtomicBool::new(is_placeholder),
platform_nodes: Mutex::new(HashMap::new()),
})
}

Expand All @@ -72,4 +76,23 @@ impl Context {
pub(crate) fn do_action(&self, request: ActionRequest) {
self.action_handler.do_action(request);
}

pub(crate) fn get_or_create_platform_node(
self: &Arc<Self>,
id: NodeId,
) -> ComObject<PlatformNode> {
let mut platform_nodes = self.platform_nodes.lock().unwrap();
if let Some(result) = platform_nodes.get(&id) {
return result.clone();
}

let result = PlatformNode::new(self, id);
platform_nodes.insert(id, result.clone());
result
}

pub(crate) fn remove_platform_node(&self, id: NodeId) {
let mut platform_nodes = self.platform_nodes.lock().unwrap();
platform_nodes.remove(&id);
}
}
Loading
Loading