use std::any::Any;
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use crate::command::SelectorSymbol;
use crate::shell::IdleHandle;
use crate::win_handler::EXT_EVENT_IDLE_TOKEN;
use crate::{Command, Data, DruidHandler, Selector, Target, WindowId};
pub(crate) type ExtCommand = (SelectorSymbol, Box<dyn Any + Send>, 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<Command> {
self.queue
.lock()
.unwrap()
.pop_front()
.map(|(selector, payload, target)| Command::from_ext(selector, payload, target))
}
}
impl ExtEventSink {
pub fn submit_command<T: Any + Send>(
&self,
selector: Selector<T>,
payload: impl Into<Box<T>>,
target: impl Into<Target>,
) -> Result<(), ExtEventError> {
let target = target.into();
let payload = payload.into();
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((
selector.symbol(),
payload,
target,
));
Ok(())
}
pub fn add_idle_callback<T: 'static + Data>(&self, cb: impl FnOnce(&mut T) + Send + 'static) {
let mut handle = self.handle.lock().unwrap();
if let Some(handle) = handle.as_mut() {
handle.add_idle(|win_handler| {
if let Some(win_handler) = win_handler.as_any().downcast_mut::<DruidHandler<T>>() {
win_handler.app_state.handle_idle_callback(cb);
} else {
debug_panic!(
"{} is not the type of root data",
std::any::type_name::<T>()
);
}
});
}
}
}
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 {}