use crate::handler::Handler;
use crate::reactor::{EventLoopOp, Reactor};
use crate::sync::ThreadSafety;
use crate::DefaultThreadSafety;
use std::convert::Infallible;
use std::fmt;
use std::future::Future;
use std::ops;
use raw_window_handle::{HasRawDisplayHandle, RawDisplayHandle};
use winit::event_loop::EventLoopProxy;
#[doc(inline)]
pub use winit::event_loop::{ControlFlow, DeviceEventFilter, EventLoopClosed};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Wakeup {
pub(crate) _private: (),
}
pub struct EventLoop<TS: ThreadSafety = DefaultThreadSafety> {
pub(crate) inner: winit::event_loop::EventLoop<Wakeup>,
window_target: EventLoopWindowTarget<TS>,
}
impl<TS: ThreadSafety> fmt::Debug for EventLoop<TS> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("EventLoop { .. }")
}
}
pub struct EventLoopWindowTarget<TS: ThreadSafety = DefaultThreadSafety> {
reactor: TS::Rc<Reactor<TS>>,
proxy: EventLoopProxy<Wakeup>,
raw_display_handle: RawDisplayHandle,
#[cfg(any(x11_platform, wayland_platform))]
pub(crate) is_wayland: bool,
}
impl<TS: ThreadSafety> fmt::Debug for EventLoopWindowTarget<TS> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("EventLoopWindowTarget { .. }")
}
}
impl<TS: ThreadSafety> Clone for EventLoopWindowTarget<TS> {
fn clone(&self) -> Self {
Self {
reactor: self.reactor.clone(),
proxy: self.proxy.clone(),
raw_display_handle: self.raw_display_handle,
#[cfg(any(x11_platform, wayland_platform))]
is_wayland: self.is_wayland,
}
}
}
pub struct EventLoopBuilder {
pub(crate) inner: winit::event_loop::EventLoopBuilder<Wakeup>,
}
impl fmt::Debug for EventLoopBuilder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("EventLoopBuilder { .. }")
}
}
impl EventLoopBuilder {
pub fn new() -> Self {
Self {
inner: winit::event_loop::EventLoopBuilder::with_user_event(),
}
}
pub fn build<TS: ThreadSafety>(&mut self) -> EventLoop<TS> {
let inner = self.inner.build();
EventLoop {
window_target: EventLoopWindowTarget {
reactor: Reactor::<TS>::get(),
proxy: inner.create_proxy(),
raw_display_handle: inner.raw_display_handle(),
#[cfg(any(x11_platform, wayland_platform))]
is_wayland: {
cfg_if::cfg_if! {
if #[cfg(feature = "x11")] {
use winit::platform::x11::EventLoopWindowTargetExtX11;
!inner.is_x11()
} else if #[cfg(feature = "wayland")] {
use winit::platform::wayland::EventLoopWindowTargetExtWayland;
inner.is_wayland()
} else {
false
}
}
},
},
inner,
}
}
}
impl Default for EventLoopBuilder {
fn default() -> Self {
Self::new()
}
}
unsafe impl<TS: ThreadSafety> HasRawDisplayHandle for EventLoop<TS> {
fn raw_display_handle(&self) -> RawDisplayHandle {
self.window_target.raw_display_handle
}
}
impl<TS: ThreadSafety> EventLoop<TS> {
#[inline]
pub fn new() -> EventLoop<TS> {
EventLoopBuilder::new().build()
}
}
impl<TS: ThreadSafety> Default for EventLoop<TS> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<TS: ThreadSafety> EventLoopWindowTarget<TS> {
#[inline]
pub fn set_exit(&self) {
self.reactor.request_exit(0);
}
#[inline]
pub fn set_exit_with_code(&self, code: i32) {
self.reactor.request_exit(code);
}
#[inline]
pub async fn exit(&self) -> ! {
self.set_exit();
futures_lite::future::pending().await
}
#[inline]
pub async fn exit_with_code(&self, code: i32) -> ! {
self.set_exit_with_code(code);
futures_lite::future::pending().await
}
#[inline]
pub fn resumed(&self) -> &Handler<(), TS> {
&self.reactor.evl_registration.resumed
}
#[inline]
pub fn suspended(&self) -> &Handler<(), TS> {
&self.reactor.evl_registration.suspended
}
#[inline]
pub async fn primary_monitor(&self) -> Option<winit::monitor::MonitorHandle> {
let (tx, rx) = crate::oneoff::oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::PrimaryMonitor(tx))
.await;
rx.recv().await
}
#[inline]
pub async fn available_monitors(&self) -> impl Iterator<Item = winit::monitor::MonitorHandle> {
let (tx, rx) = crate::oneoff::oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::AvailableMonitors(tx))
.await;
rx.recv().await.into_iter()
}
#[inline]
pub async fn set_device_event_filter(&self, filter: DeviceEventFilter) {
let (tx, rx) = crate::oneoff::oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetDeviceFilter { filter, waker: tx })
.await;
rx.recv().await;
}
}
unsafe impl<TS: ThreadSafety> HasRawDisplayHandle for EventLoopWindowTarget<TS> {
fn raw_display_handle(&self) -> RawDisplayHandle {
self.raw_display_handle
}
}
impl<TS: ThreadSafety + 'static> EventLoop<TS> {
#[inline]
pub fn window_target(&self) -> &EventLoopWindowTarget<TS> {
&self.window_target
}
#[inline]
pub fn block_on(self, future: impl Future<Output = Infallible> + 'static) -> ! {
let inner = self.inner;
let mut future = Box::pin(future);
let mut filter = crate::filter::Filter::<TS>::new(&inner);
inner.run(move |event, elwt, flow| {
filter.handle_event(future.as_mut(), event, elwt, flow);
})
}
}
impl<TS: ThreadSafety> ops::Deref for EventLoop<TS> {
type Target = EventLoopWindowTarget<TS>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.window_target
}
}
impl<TS: ThreadSafety> ops::DerefMut for EventLoop<TS> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.window_target
}
}