Skip to content

Commit

Permalink
fix: Make the test focus event handler thread-safe again (#306)
Browse files Browse the repository at this point in the history
  • Loading branch information
mwcampbell authored Nov 4, 2023
1 parent abbb7d8 commit bb479c6
Showing 1 changed file with 18 additions and 9 deletions.
27 changes: 18 additions & 9 deletions platforms/windows/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use once_cell::{sync::Lazy as SyncLazy, unsync::Lazy};
use std::{
cell::RefCell,
rc::Rc,
sync::{Condvar, Mutex},
sync::{Arc, Condvar, Mutex},
thread,
time::Duration,
};
Expand Down Expand Up @@ -262,14 +262,19 @@ where
})
}

/// This must only be used to wrap UIA elements returned by a UIA client
/// that was created in the MTA. Those are safe to send between threads.
struct SendableUiaElement(IUIAutomationElement);
unsafe impl Send for SendableUiaElement {}

pub(crate) struct ReceivedFocusEvent {
mutex: Mutex<Option<IUIAutomationElement>>,
mutex: Mutex<Option<SendableUiaElement>>,
cv: Condvar,
}

impl ReceivedFocusEvent {
fn new() -> Rc<Self> {
Rc::new(Self {
fn new() -> Arc<Self> {
Arc::new(Self {
mutex: Mutex::new(None),
cv: Condvar::new(),
})
Expand All @@ -281,7 +286,7 @@ impl ReceivedFocusEvent {
{
let mut received = self.mutex.lock().unwrap();
loop {
if let Some(element) = received.take() {
if let Some(SendableUiaElement(element)) = received.take() {
if f(&element) {
return element;
}
Expand All @@ -294,26 +299,30 @@ impl ReceivedFocusEvent {

fn put(&self, element: IUIAutomationElement) {
let mut received = self.mutex.lock().unwrap();
*received = Some(element);
*received = Some(SendableUiaElement(element));
self.cv.notify_one();
}
}

#[implement(Windows::Win32::UI::Accessibility::IUIAutomationFocusChangedEventHandler)]
pub(crate) struct FocusEventHandler {
received: Rc<ReceivedFocusEvent>,
received: Arc<ReceivedFocusEvent>,
}
// Because we create a UIA client in the COM MTA, this event handler
// _will_ be called from a different thread, and possibly multiple threads
// at once.
static_assertions::assert_impl_all!(FocusEventHandler: Send, Sync);

impl FocusEventHandler {
#[allow(clippy::new_ret_no_self)] // it does return self, but wrapped
pub(crate) fn new() -> (
IUIAutomationFocusChangedEventHandler,
Rc<ReceivedFocusEvent>,
Arc<ReceivedFocusEvent>,
) {
let received = ReceivedFocusEvent::new();
(
Self {
received: received.clone(),
received: Arc::clone(&received),
}
.into(),
received,
Expand Down

0 comments on commit bb479c6

Please sign in to comment.