use crate::access_winit_active_event_loop::AccessWinitActiveEventLoop;
use crate::window::{Window, Windows};
use aeth_event::{Pub, Sub, new_pubsub};
use aeth_task::foreground;
use futures::channel::oneshot;
use std::cell::RefCell;
use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
use std::rc::{Rc, Weak};
use winit::error::RequestError;
use winit::event::{DeviceEvent as WinitDeviceEvent, DeviceId};
use winit::event_loop::ActiveEventLoop;
use winit::window::WindowAttributes;
type ActiveEventLoopJob = Box<dyn FnOnce(&dyn ActiveEventLoop)>;
#[derive(Clone)]
pub struct WakeUpEvent;
#[derive(Clone)]
pub struct DeviceEvent {
pub event: WinitDeviceEvent,
pub device_id: Option<DeviceId>,
}
pub(crate) struct ManagerInner {
active_event_loop_jobs: RefCell<Vec<ActiveEventLoopJob>>,
windows: Rc<RefCell<Windows>>,
draining_foreground_loopback: RefCell<bool>,
wakeup_event_pub: Pub<WakeUpEvent>,
wakeup_event_sub: Sub<WakeUpEvent>,
device_event_pub: Pub<DeviceEvent>,
device_event_sub: Sub<DeviceEvent>,
}
impl ManagerInner {
pub(crate) fn new(windows: Rc<RefCell<Windows>>) -> Self {
let (wakeup_event_pub, wakeup_event_sub) = new_pubsub();
let (device_event_pub, device_event_sub) = new_pubsub();
Self {
active_event_loop_jobs: RefCell::new(Vec::new()),
windows,
draining_foreground_loopback: RefCell::new(false),
wakeup_event_pub,
wakeup_event_sub,
device_event_pub,
device_event_sub,
}
}
pub(crate) fn is_draining_foreground_loopback(&self) -> bool {
*self.draining_foreground_loopback.borrow()
}
pub(crate) fn wakeup_event_pub(&self) -> Pub<WakeUpEvent> {
self.wakeup_event_pub.clone()
}
pub(crate) fn device_event_pub(&self) -> Pub<DeviceEvent> {
self.device_event_pub.clone()
}
pub(crate) fn drain_active_event_loop_jobs(&self, event_loop: &dyn ActiveEventLoop) -> bool {
let mut target = Vec::new();
std::mem::swap(&mut target, &mut self.active_event_loop_jobs.borrow_mut());
let processed = target.len() > 0;
for job in target.drain(..) {
job(event_loop)
}
processed
}
async fn run_with_active_event_loop<F, T>(&self, f: F) -> T
where
F: FnOnce(&dyn ActiveEventLoop) -> T + 'static,
T: 'static,
{
let (sender, receiver) = oneshot::channel();
self.active_event_loop_jobs
.borrow_mut()
.push(Box::new(move |v| {
let _ = sender.send(catch_unwind(AssertUnwindSafe(move || f(v))));
}));
match receiver.await.expect("Execution cancelled.") {
Ok(value) => value,
Err(payload) => resume_unwind(payload),
}
}
}
pub struct Manager {
inner: Weak<ManagerInner>,
}
impl Manager {
fn must_upgrade_manager(&self) -> Rc<ManagerInner> {
self.inner
.upgrade()
.expect("Window manager has been destroyed")
}
pub fn set_draining_foreground_loopback(&self, value: bool) {
let inner = self.must_upgrade_manager();
*inner.draining_foreground_loopback.borrow_mut() = value;
}
pub async fn create_window(&self, attrs: WindowAttributes) -> Result<Window, RequestError> {
let inner = self.must_upgrade_manager();
let window = inner
.run_with_active_event_loop(|v| v.create_window(attrs))
.await?;
Ok(Windows::allocate(&inner.windows, window))
}
pub fn wakeup_event_sub(&self) -> Sub<WakeUpEvent> {
self.must_upgrade_manager().wakeup_event_sub.clone()
}
pub fn device_event_sub(&self) -> Sub<DeviceEvent> {
self.must_upgrade_manager().device_event_sub.clone()
}
}
impl AccessWinitActiveEventLoop for Manager {
async fn run_with_active_event_loop<F, T>(&self, f: F) -> T
where
F: FnOnce(&dyn ActiveEventLoop) -> T + 'static,
T: 'static,
{
let inner = self.must_upgrade_manager();
inner.run_with_active_event_loop(f).await
}
}
thread_local! {
pub(crate) static MANAGER: RefCell<Option<Weak<ManagerInner>>> = RefCell::new(None);
}
pub async fn manager() -> Manager {
foreground::assert();
MANAGER.with_borrow(|v| {
let manager = v.as_ref().expect("Window manager is not initialized");
Manager {
inner: manager.clone(),
}
})
}