use std::sync::{Arc, Mutex, PoisonError};
use accesskit::{ActionHandler, ActionRequest, ActivationHandler, DeactivationHandler, TreeUpdate};
use accesskit_unix::Adapter;
use crate::{ShellEvent, ShellWaker, WindowId};
#[derive(Debug)]
enum Raised {
Activated,
Action(ActionRequest),
Deactivated,
}
#[derive(Clone, Debug, Default)]
struct Queue(Arc<Mutex<Vec<(WindowId, Raised)>>>);
impl Queue {
fn push(&self, window: WindowId, raised: Raised) {
self.0
.lock()
.unwrap_or_else(PoisonError::into_inner)
.push((window, raised));
}
fn take(&self) -> Vec<(WindowId, Raised)> {
core::mem::take(&mut *self.0.lock().unwrap_or_else(PoisonError::into_inner))
}
fn forget(&self, window: WindowId) {
self.0
.lock()
.unwrap_or_else(PoisonError::into_inner)
.retain(|&(known, _)| known != window);
}
}
#[derive(Clone)]
struct Handler {
window: WindowId,
queue: Queue,
waker: Option<ShellWaker>,
}
impl Handler {
fn raise(&self, raised: Raised) {
self.queue.push(self.window, raised);
if let Some(waker) = &self.waker {
waker.wake();
}
}
}
impl ActivationHandler for Handler {
fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
self.raise(Raised::Activated);
None
}
}
impl ActionHandler for Handler {
fn do_action(&mut self, request: ActionRequest) {
self.raise(Raised::Action(request));
}
}
impl DeactivationHandler for Handler {
fn deactivate_accessibility(&mut self) {
self.raise(Raised::Deactivated);
}
}
#[derive(Debug, Default)]
pub(crate) struct Adapters {
adapters: Vec<(WindowId, Adapter)>,
queue: Queue,
}
impl Adapters {
pub(crate) fn open(&mut self, window: WindowId, waker: Option<ShellWaker>) {
let handler = Handler {
window,
queue: self.queue.clone(),
waker,
};
let adapter = Adapter::new(handler.clone(), handler.clone(), handler);
self.adapters.push((window, adapter));
}
pub(crate) fn close(&mut self, window: WindowId) {
self.adapters.retain(|(known, _)| *known != window);
self.queue.forget(window);
}
fn adapter(&mut self, window: WindowId) -> Option<&mut Adapter> {
self.adapters
.iter_mut()
.find(|(known, _)| *known == window)
.map(|(_, adapter)| adapter)
}
pub(crate) fn focus(&mut self, window: WindowId, focused: bool) {
if let Some(adapter) = self.adapter(window) {
adapter.update_window_focus_state(focused);
}
}
pub(crate) fn update(&mut self, window: WindowId, update: TreeUpdate) {
if let Some(adapter) = self.adapter(window) {
adapter.update_if_active(|| update);
}
}
pub(crate) fn take_events(&self) -> impl Iterator<Item = ShellEvent> {
self.queue
.take()
.into_iter()
.map(|(window, raised)| match raised {
Raised::Activated => ShellEvent::AccessibilityActivated { window },
Raised::Action(request) => ShellEvent::AccessibilityAction { window, request },
Raised::Deactivated => ShellEvent::AccessibilityDeactivated { window },
})
}
}