event_loop: remove generic user event
Let the users wake up the event loop and then they could poll their user sources. Co-authored-by: Mads Marquart <mads@marquart.dk> Co-authored-by: daxpedda <daxpedda@gmail.com>
This commit is contained in:
parent
7d1287958f
commit
ecb887e5c3
44 changed files with 675 additions and 966 deletions
|
|
@ -1,5 +1,4 @@
|
|||
use std::marker::PhantomData;
|
||||
use std::sync::mpsc::{self, Receiver, Sender};
|
||||
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::error::EventLoopError;
|
||||
|
|
@ -17,36 +16,30 @@ mod window_target;
|
|||
pub(crate) use proxy::EventLoopProxy;
|
||||
pub(crate) use window_target::{ActiveEventLoop, OwnedDisplayHandle};
|
||||
|
||||
pub struct EventLoop<T: 'static> {
|
||||
pub struct EventLoop {
|
||||
elw: RootActiveEventLoop,
|
||||
user_event_sender: Sender<T>,
|
||||
user_event_receiver: Receiver<T>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
||||
|
||||
impl<T> EventLoop<T> {
|
||||
impl EventLoop {
|
||||
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
||||
let (user_event_sender, user_event_receiver) = mpsc::channel();
|
||||
let elw = RootActiveEventLoop { p: ActiveEventLoop::new(), _marker: PhantomData };
|
||||
Ok(EventLoop { elw, user_event_sender, user_event_receiver })
|
||||
Ok(EventLoop { elw })
|
||||
}
|
||||
|
||||
pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> ! {
|
||||
pub fn run_app<A: ApplicationHandler>(self, app: &mut A) -> ! {
|
||||
let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData };
|
||||
|
||||
// SAFETY: Don't use `move` to make sure we leak the `event_handler` and `target`.
|
||||
let handler: Box<dyn FnMut(Event<()>)> =
|
||||
Box::new(|event| handle_event(app, &target, &self.user_event_receiver, event));
|
||||
let handler: Box<dyn FnMut(Event)> = Box::new(|event| handle_event(app, &target, event));
|
||||
|
||||
// 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`.
|
||||
let handler = unsafe {
|
||||
std::mem::transmute::<Box<dyn FnMut(Event<()>)>, Box<dyn FnMut(Event<()>) + 'static>>(
|
||||
handler,
|
||||
)
|
||||
std::mem::transmute::<Box<dyn FnMut(Event)>, Box<dyn FnMut(Event) + 'static>>(handler)
|
||||
};
|
||||
self.elw.p.run(handler, false);
|
||||
|
||||
|
|
@ -59,19 +52,14 @@ impl<T> EventLoop<T> {
|
|||
unreachable!();
|
||||
}
|
||||
|
||||
pub fn spawn_app<A: ApplicationHandler<T> + 'static>(self, mut app: A) {
|
||||
pub fn spawn_app<A: ApplicationHandler + 'static>(self, mut app: A) {
|
||||
let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData };
|
||||
|
||||
self.elw.p.run(
|
||||
Box::new(move |event| {
|
||||
handle_event(&mut app, &target, &self.user_event_receiver, event)
|
||||
}),
|
||||
true,
|
||||
);
|
||||
self.elw.p.run(Box::new(move |event| handle_event(&mut app, &target, event)), true);
|
||||
}
|
||||
|
||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
||||
EventLoopProxy::new(self.elw.p.waker(), self.user_event_sender.clone())
|
||||
pub fn create_proxy(&self) -> EventLoopProxy {
|
||||
EventLoopProxy::new(self.elw.p.waker())
|
||||
}
|
||||
|
||||
pub fn window_target(&self) -> &RootActiveEventLoop {
|
||||
|
|
@ -95,21 +83,12 @@ impl<T> EventLoop<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_event<T: 'static, A: ApplicationHandler<T>>(
|
||||
app: &mut A,
|
||||
target: &RootActiveEventLoop,
|
||||
user_event_receiver: &Receiver<T>,
|
||||
event: Event<()>,
|
||||
) {
|
||||
fn handle_event<A: ApplicationHandler>(app: &mut A, target: &RootActiveEventLoop, 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::UserWakeUp => app.proxy_wake_up(target),
|
||||
Event::Suspended => app.suspended(target),
|
||||
Event::Resumed => app.resumed(target),
|
||||
Event::AboutToWait => app.about_to_wait(target),
|
||||
|
|
|
|||
|
|
@ -1,29 +1,19 @@
|
|||
use std::rc::Weak;
|
||||
use std::sync::mpsc::{SendError, Sender};
|
||||
|
||||
use super::runner::Execution;
|
||||
use crate::event_loop::EventLoopClosed;
|
||||
use crate::platform_impl::platform::r#async::Waker;
|
||||
|
||||
pub struct EventLoopProxy<T: 'static> {
|
||||
#[derive(Clone)]
|
||||
pub struct EventLoopProxy {
|
||||
runner: Waker<Weak<Execution>>,
|
||||
sender: Sender<T>,
|
||||
}
|
||||
|
||||
impl<T: 'static> EventLoopProxy<T> {
|
||||
pub fn new(runner: Waker<Weak<Execution>>, sender: Sender<T>) -> Self {
|
||||
Self { runner, sender }
|
||||
impl EventLoopProxy {
|
||||
pub fn new(runner: Waker<Weak<Execution>>) -> Self {
|
||||
Self { runner }
|
||||
}
|
||||
|
||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
||||
self.sender.send(event).map_err(|SendError(event)| EventLoopClosed(event))?;
|
||||
pub fn wake_up(&self) {
|
||||
self.runner.wake();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Clone for EventLoopProxy<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { runner: self.runner.clone(), sender: self.sender.clone() }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ use js_sys::Function;
|
|||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::{HashSet, VecDeque};
|
||||
use std::iter;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::ops::Deref;
|
||||
use std::rc::{Rc, Weak};
|
||||
use wasm_bindgen::prelude::{wasm_bindgen, Closure};
|
||||
|
|
@ -28,7 +27,7 @@ use web_time::{Duration, Instant};
|
|||
|
||||
pub struct Shared(Rc<Execution>);
|
||||
|
||||
pub(super) type EventHandler = dyn FnMut(Event<()>);
|
||||
pub(super) type EventHandler = dyn FnMut(Event);
|
||||
|
||||
impl Clone for Shared {
|
||||
fn clone(&self) -> Self {
|
||||
|
|
@ -137,13 +136,12 @@ impl Shared {
|
|||
let document = window.document().expect("Failed to obtain document");
|
||||
|
||||
Shared(Rc::<Execution>::new_cyclic(|weak| {
|
||||
let proxy_spawner =
|
||||
WakerSpawner::new(main_thread, weak.clone(), |runner, count, local| {
|
||||
if let Some(runner) = runner.upgrade() {
|
||||
Shared(runner).send_user_events(count, local)
|
||||
}
|
||||
})
|
||||
.expect("`EventLoop` has to be created in the main thread");
|
||||
let proxy_spawner = WakerSpawner::new(main_thread, weak.clone(), |runner, local| {
|
||||
if let Some(runner) = runner.upgrade() {
|
||||
Shared(runner).send_proxy_wake_up(local);
|
||||
}
|
||||
})
|
||||
.expect("`EventLoop` has to be created in the main thread");
|
||||
|
||||
Execution {
|
||||
main_thread,
|
||||
|
|
@ -203,7 +201,7 @@ impl Shared {
|
|||
// Set the event callback to use for the event loop runner
|
||||
// This the event callback is a fairly thin layer over the user-provided callback that closes
|
||||
// over a RootActiveEventLoop reference
|
||||
pub fn set_listener(&self, event_handler: Box<EventHandler>) {
|
||||
pub(crate) fn set_listener(&self, event_handler: Box<EventHandler>) {
|
||||
{
|
||||
let mut runner = self.0.runner.borrow_mut();
|
||||
assert!(matches!(*runner, RunnerEnum::Pending));
|
||||
|
|
@ -466,11 +464,11 @@ impl Shared {
|
|||
self.send_events(iter::once(event));
|
||||
}
|
||||
|
||||
// Add a series of user events to the event loop runner
|
||||
// Add a user event to the event loop runner.
|
||||
//
|
||||
// This will schedule the event loop to wake up instead of waking it up immediately if its not
|
||||
// running.
|
||||
pub(crate) fn send_user_events(&self, count: NonZeroUsize, local: bool) {
|
||||
pub(crate) fn send_proxy_wake_up(&self, local: bool) {
|
||||
// If the event loop is closed, it should discard any new events
|
||||
if self.is_closed() {
|
||||
return;
|
||||
|
|
@ -492,9 +490,7 @@ impl Shared {
|
|||
let this = Rc::downgrade(&self.0);
|
||||
move || {
|
||||
if let Some(shared) = this.upgrade() {
|
||||
Shared(shared).send_events(
|
||||
iter::repeat(Event::UserEvent(())).take(count.get()),
|
||||
)
|
||||
Shared(shared).send_event(Event::UserWakeUp)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -505,7 +501,7 @@ impl Shared {
|
|||
}
|
||||
}
|
||||
|
||||
self.send_events(iter::repeat(Event::UserEvent(())).take(count.get()))
|
||||
self.send_event(Event::UserWakeUp);
|
||||
}
|
||||
|
||||
// Add a series of events to the event loop runner
|
||||
|
|
@ -648,8 +644,10 @@ impl Shared {
|
|||
|
||||
// Pre-fetch `UserEvent`s to avoid having to wait until the next event loop cycle.
|
||||
events.extend(
|
||||
iter::repeat(Event::UserEvent(()))
|
||||
.take(self.0.proxy_spawner.fetch())
|
||||
self.0
|
||||
.proxy_spawner
|
||||
.take()
|
||||
.then_some(Event::UserWakeUp)
|
||||
.map(EventWrapper::from),
|
||||
);
|
||||
|
||||
|
|
@ -737,7 +735,7 @@ impl Shared {
|
|||
// * The `register_redraw_request` closure.
|
||||
// * The `destroy_fn` closure.
|
||||
if self.0.event_loop_recreation.get() {
|
||||
crate::event_loop::EventLoopBuilder::<()>::allow_event_loop_recreation();
|
||||
crate::event_loop::EventLoopBuilder::allow_event_loop_recreation();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -817,12 +815,12 @@ impl Shared {
|
|||
}
|
||||
|
||||
pub(crate) enum EventWrapper {
|
||||
Event(Event<()>),
|
||||
Event(Event),
|
||||
ScaleChange { canvas: Weak<RefCell<backend::Canvas>>, size: PhysicalSize<u32>, scale: f64 },
|
||||
}
|
||||
|
||||
impl From<Event<()>> for EventWrapper {
|
||||
fn from(value: Event<()>) -> Self {
|
||||
impl From<Event> for EventWrapper {
|
||||
fn from(value: Event) -> Self {
|
||||
Self::Event(value)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,11 @@ impl ActiveEventLoop {
|
|||
Self { runner: runner::Shared::new(), modifiers: ModifiersShared::default() }
|
||||
}
|
||||
|
||||
pub fn run(&self, event_handler: Box<runner::EventHandler>, event_loop_recreation: bool) {
|
||||
pub(crate) fn run(
|
||||
&self,
|
||||
event_handler: Box<runner::EventHandler>,
|
||||
event_loop_recreation: bool,
|
||||
) {
|
||||
self.runner.event_loop_recreation(event_loop_recreation);
|
||||
self.runner.set_listener(event_handler);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue