use std::any::Any;
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use crate::shell::IdleHandle;
use crate::win_handler::EXT_EVENT_IDLE_TOKEN;
use crate::{Command, Selector, Target, WindowId};
pub(crate) type ExtCommand = (Selector, Option<Box<dyn Any + Send>>, Option<Target>);
#[derive(Clone)]
pub struct ExtEventSink {
queue: Arc<Mutex<VecDeque<ExtCommand>>>,
handle: Arc<Mutex<Option<IdleHandle>>>,
}
#[derive(Default)]
pub(crate) struct ExtEventHost {
queue: Arc<Mutex<VecDeque<ExtCommand>>>,
handle: Arc<Mutex<Option<IdleHandle>>>,
pub(crate) handle_window_id: Option<WindowId>,
}
#[derive(Debug, Clone)]
pub struct ExtEventError;
impl ExtEventHost {
pub(crate) fn new() -> Self {
Default::default()
}
pub(crate) fn make_sink(&self) -> ExtEventSink {
ExtEventSink {
queue: self.queue.clone(),
handle: self.handle.clone(),
}
}
pub(crate) fn set_idle(&mut self, handle: IdleHandle, window_id: WindowId) {
self.handle.lock().unwrap().replace(handle);
self.handle_window_id = Some(window_id);
}
pub(crate) fn has_pending_items(&self) -> bool {
!self.queue.lock().unwrap().is_empty()
}
pub(crate) fn recv(&mut self) -> Option<(Option<Target>, Command)> {
self.queue
.lock()
.unwrap()
.pop_front()
.map(|(sel, obj, targ)| (targ, Command::from_ext(sel, obj)))
}
}
impl ExtEventSink {
pub fn submit_command<T: Any + Send>(
&self,
sel: Selector,
obj: impl Into<Option<T>>,
target: impl Into<Option<Target>>,
) -> Result<(), ExtEventError> {
let target = target.into();
let obj = obj.into().map(|o| Box::new(o) as Box<dyn Any + Send>);
if let Some(handle) = self.handle.lock().unwrap().as_mut() {
handle.schedule_idle(EXT_EVENT_IDLE_TOKEN);
}
self.queue
.lock()
.map_err(|_| ExtEventError)?
.push_back((sel, obj, target));
Ok(())
}
}
impl std::fmt::Display for ExtEventError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Window missing for external event")
}
}
impl std::error::Error for ExtEventError {}