2023-08-13 23:20:09 +04:00
|
|
|
use std::marker::PhantomData;
|
2023-09-03 02:26:53 +02:00
|
|
|
use std::sync::mpsc::{self, Receiver, Sender};
|
2023-08-13 23:20:09 +04:00
|
|
|
|
2024-05-20 20:27:36 +04:00
|
|
|
use crate::application::ApplicationHandler;
|
2023-08-13 23:20:09 +04:00
|
|
|
use crate::error::EventLoopError;
|
|
|
|
|
use crate::event::Event;
|
2024-01-31 17:29:59 +04:00
|
|
|
use crate::event_loop::ActiveEventLoop as RootActiveEventLoop;
|
2024-06-20 23:07:42 +02:00
|
|
|
use crate::platform::web::{ActiveEventLoopExtWebSys, PollStrategy, WaitUntilStrategy};
|
2023-08-13 23:20:09 +04:00
|
|
|
|
|
|
|
|
use super::{backend, device, window};
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
mod proxy;
|
2023-06-14 09:43:53 +02:00
|
|
|
pub(crate) mod runner;
|
2019-06-25 03:15:34 +02:00
|
|
|
mod state;
|
|
|
|
|
mod window_target;
|
|
|
|
|
|
2024-01-15 11:58:11 -08:00
|
|
|
pub(crate) use proxy::EventLoopProxy;
|
2024-01-31 17:29:59 +04:00
|
|
|
pub(crate) use window_target::{ActiveEventLoop, OwnedDisplayHandle};
|
2019-06-25 03:15:34 +02:00
|
|
|
|
|
|
|
|
pub struct EventLoop<T: 'static> {
|
2024-01-31 17:29:59 +04:00
|
|
|
elw: RootActiveEventLoop,
|
2023-09-03 02:26:53 +02:00
|
|
|
user_event_sender: Sender<T>,
|
|
|
|
|
user_event_receiver: Receiver<T>,
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2022-06-10 13:43:33 +03:00
|
|
|
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
2022-02-16 22:09:03 +01:00
|
|
|
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
impl<T> EventLoop<T> {
|
2023-08-13 23:20:09 +04:00
|
|
|
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
2023-09-03 02:26:53 +02:00
|
|
|
let (user_event_sender, user_event_receiver) = mpsc::channel();
|
2024-01-31 17:29:59 +04:00
|
|
|
let elw = RootActiveEventLoop { p: ActiveEventLoop::new(), _marker: PhantomData };
|
2023-09-03 02:26:53 +02:00
|
|
|
Ok(EventLoop { elw, user_event_sender, user_event_receiver })
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2024-05-20 20:27:36 +04:00
|
|
|
pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> ! {
|
2024-01-31 17:29:59 +04:00
|
|
|
let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData };
|
2023-08-06 01:56:56 +04:00
|
|
|
|
|
|
|
|
// SAFETY: Don't use `move` to make sure we leak the `event_handler` and `target`.
|
2024-05-20 20:27:36 +04:00
|
|
|
let handler: Box<dyn FnMut(Event<()>)> =
|
|
|
|
|
Box::new(|event| handle_event(app, &target, &self.user_event_receiver, event));
|
|
|
|
|
|
2023-08-06 01:56:56 +04:00
|
|
|
// SAFETY: The `transmute` is necessary because `run()` requires `'static`. This is safe
|
|
|
|
|
// because this function will never return and all resources not cleaned up by the point we
|
|
|
|
|
// `throw` will leak, making this actually `'static`.
|
2024-06-15 15:26:26 +03:00
|
|
|
let handler = unsafe {
|
|
|
|
|
std::mem::transmute::<Box<dyn FnMut(Event<()>)>, Box<dyn FnMut(Event<()>) + 'static>>(
|
|
|
|
|
handler,
|
|
|
|
|
)
|
|
|
|
|
};
|
2023-08-06 01:56:56 +04:00
|
|
|
self.elw.p.run(handler, false);
|
2022-07-14 01:17:18 +10:00
|
|
|
|
|
|
|
|
// Throw an exception to break out of Rust execution and use unreachable to tell the
|
|
|
|
|
// compiler this function won't return, giving it a return type of '!'
|
|
|
|
|
backend::throw(
|
|
|
|
|
"Using exceptions for control flow, don't mind me. This isn't actually an error!",
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
unreachable!();
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-20 20:27:36 +04:00
|
|
|
pub fn spawn_app<A: ApplicationHandler<T> + 'static>(self, mut app: A) {
|
2024-01-31 17:29:59 +04:00
|
|
|
let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData };
|
2019-06-25 03:15:34 +02:00
|
|
|
|
2023-06-25 12:03:22 +02:00
|
|
|
self.elw.p.run(
|
2023-09-07 08:25:04 +02:00
|
|
|
Box::new(move |event| {
|
2024-05-20 20:27:36 +04:00
|
|
|
handle_event(&mut app, &target, &self.user_event_receiver, event)
|
2023-09-03 02:26:53 +02:00
|
|
|
}),
|
2023-08-06 01:56:56 +04:00
|
|
|
true,
|
2023-06-25 12:03:22 +02:00
|
|
|
);
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2022-03-18 14:09:39 +01:00
|
|
|
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
2023-10-16 15:50:22 +02:00
|
|
|
EventLoopProxy::new(self.elw.p.waker(), self.user_event_sender.clone())
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2024-01-31 17:29:59 +04:00
|
|
|
pub fn window_target(&self) -> &RootActiveEventLoop {
|
2019-06-25 03:15:34 +02:00
|
|
|
&self.elw
|
|
|
|
|
}
|
2024-06-20 22:56:08 +02:00
|
|
|
|
|
|
|
|
pub fn set_poll_strategy(&self, strategy: PollStrategy) {
|
|
|
|
|
self.elw.set_poll_strategy(strategy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn poll_strategy(&self) -> PollStrategy {
|
|
|
|
|
self.elw.poll_strategy()
|
|
|
|
|
}
|
2024-06-20 23:07:42 +02:00
|
|
|
|
|
|
|
|
pub fn set_wait_until_strategy(&self, strategy: WaitUntilStrategy) {
|
|
|
|
|
self.elw.set_wait_until_strategy(strategy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn wait_until_strategy(&self) -> WaitUntilStrategy {
|
|
|
|
|
self.elw.wait_until_strategy()
|
|
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
2024-05-20 20:27:36 +04:00
|
|
|
|
|
|
|
|
fn handle_event<T: 'static, A: ApplicationHandler<T>>(
|
|
|
|
|
app: &mut A,
|
|
|
|
|
target: &RootActiveEventLoop,
|
|
|
|
|
user_event_receiver: &Receiver<T>,
|
|
|
|
|
event: Event<()>,
|
|
|
|
|
) {
|
|
|
|
|
match event {
|
|
|
|
|
Event::NewEvents(cause) => app.new_events(target, cause),
|
|
|
|
|
Event::WindowEvent { window_id, event } => app.window_event(target, window_id, event),
|
|
|
|
|
Event::DeviceEvent { device_id, event } => app.device_event(target, device_id, event),
|
|
|
|
|
Event::UserEvent(_) => {
|
|
|
|
|
let event =
|
|
|
|
|
user_event_receiver.try_recv().expect("user event signaled but not received");
|
|
|
|
|
app.user_event(target, event);
|
|
|
|
|
},
|
|
|
|
|
Event::Suspended => app.suspended(target),
|
|
|
|
|
Event::Resumed => app.resumed(target),
|
|
|
|
|
Event::AboutToWait => app.about_to_wait(target),
|
|
|
|
|
Event::LoopExiting => app.exiting(target),
|
|
|
|
|
Event::MemoryWarning => app.memory_warning(target),
|
|
|
|
|
}
|
|
|
|
|
}
|