From 7a2a2341c2f22c52caaf896bdb4572d9b45f3f10 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sun, 3 Sep 2023 02:26:53 +0200 Subject: [PATCH] Remove `T` from `EventLoopTargetWindow` (#3081) Co-authored-by: nerditation <12248559+nerditation@users.noreply.github.com> --- src/platform_impl/web/event_loop/mod.rs | 35 +++++++++-- src/platform_impl/web/event_loop/proxy.rs | 13 +++- src/platform_impl/web/event_loop/runner.rs | 59 +++++++++---------- .../web/event_loop/window_target.rs | 13 ++-- src/platform_impl/web/web_sys/canvas.rs | 6 +- 5 files changed, 78 insertions(+), 48 deletions(-) diff --git a/src/platform_impl/web/event_loop/mod.rs b/src/platform_impl/web/event_loop/mod.rs index 48c95fc2..a5a2886d 100644 --- a/src/platform_impl/web/event_loop/mod.rs +++ b/src/platform_impl/web/event_loop/mod.rs @@ -1,4 +1,5 @@ use std::marker::PhantomData; +use std::sync::mpsc::{self, Receiver, Sender}; use crate::error::EventLoopError; use crate::event::Event; @@ -16,6 +17,8 @@ pub use window_target::EventLoopWindowTarget; pub struct EventLoop { elw: RootEventLoopWindowTarget, + user_event_sender: Sender, + user_event_receiver: Receiver, } #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -23,11 +26,14 @@ pub(crate) struct PlatformSpecificEventLoopAttributes {} impl EventLoop { pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result { + let (user_event_sender, user_event_receiver) = mpsc::channel(); Ok(EventLoop { elw: RootEventLoopWindowTarget { p: EventLoopWindowTarget::new(), _marker: PhantomData, }, + user_event_sender, + user_event_receiver, }) } @@ -41,8 +47,18 @@ impl EventLoop { }; // SAFETY: Don't use `move` to make sure we leak the `event_handler` and `target`. - let handler: Box = - Box::new(|event, flow| event_handler(event, &target, flow)); + let handler: Box, _)> = Box::new(|event, flow| { + let event = match event.map_nonuser_event() { + Ok(event) => event, + Err(Event::UserEvent(())) => Event::UserEvent( + self.user_event_receiver + .try_recv() + .expect("handler woken up without user event"), + ), + Err(_) => unreachable!(), + }; + event_handler(event, &target, flow) + }); // 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`. @@ -68,13 +84,24 @@ impl EventLoop { }; self.elw.p.run( - Box::new(move |event, flow| event_handler(event, &target, flow)), + Box::new(move |event, flow| { + let event = match event.map_nonuser_event() { + Ok(event) => event, + Err(Event::UserEvent(())) => Event::UserEvent( + self.user_event_receiver + .try_recv() + .expect("handler woken up without user event"), + ), + Err(_) => unreachable!(), + }; + event_handler(event, &target, flow) + }), true, ); } pub fn create_proxy(&self) -> EventLoopProxy { - self.elw.p.proxy() + EventLoopProxy::new(self.elw.p.runner.clone(), self.user_event_sender.clone()) } pub fn window_target(&self) -> &RootEventLoopWindowTarget { diff --git a/src/platform_impl/web/event_loop/proxy.rs b/src/platform_impl/web/event_loop/proxy.rs index 7094daaf..bb1ea207 100644 --- a/src/platform_impl/web/event_loop/proxy.rs +++ b/src/platform_impl/web/event_loop/proxy.rs @@ -1,24 +1,30 @@ +use std::sync::mpsc::Sender; + use super::runner; use crate::event::Event; use crate::event_loop::EventLoopClosed; use crate::platform_impl::platform::r#async::Channel; pub struct EventLoopProxy { - runner: Channel, T>, + // used to wake the event loop handler, not to actually pass data + runner: Channel, + sender: Sender, } impl EventLoopProxy { - pub fn new(runner: runner::Shared) -> Self { + pub fn new(runner: runner::Shared, sender: Sender) -> Self { Self { runner: Channel::new(runner, |runner, event| { runner.send_event(Event::UserEvent(event)) }) .unwrap(), + sender, } } pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { - self.runner.send(event); + self.sender.send(event).unwrap(); + self.runner.send(()); Ok(()) } } @@ -27,6 +33,7 @@ impl Clone for EventLoopProxy { fn clone(&self) -> Self { Self { runner: self.runner.clone(), + sender: self.sender.clone(), } } } diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index a9dd861f..c6dd652c 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -22,11 +22,11 @@ use wasm_bindgen::prelude::Closure; use web_sys::{Document, KeyboardEvent, PageTransitionEvent, PointerEvent, WheelEvent}; use web_time::{Duration, Instant}; -pub struct Shared(Rc>); +pub struct Shared(Rc); -pub(super) type EventHandler = dyn FnMut(Event, &mut ControlFlow); +pub(super) type EventHandler = dyn FnMut(Event<()>, &mut ControlFlow); -impl Clone for Shared { +impl Clone for Shared { fn clone(&self) -> Self { Shared(self.0.clone()) } @@ -34,11 +34,11 @@ impl Clone for Shared { type OnEventHandle = RefCell>>; -pub struct Execution { - runner: RefCell>, +pub struct Execution { + runner: RefCell, suspended: Cell, event_loop_recreation: Cell, - events: RefCell>>, + events: RefCell>, id: RefCell, window: web_sys::Window, document: Document, @@ -57,19 +57,19 @@ pub struct Execution { on_touch_end: OnEventHandle, } -enum RunnerEnum { +enum RunnerEnum { /// The `EventLoop` is created but not being run. Pending, /// The `EventLoop` is being run. - Running(Runner), + Running(Runner), /// The `EventLoop` is exited after being started with `EventLoop::run`. Since /// `EventLoop::run` takes ownership of the `EventLoop`, we can be certain /// that this event loop will never be run again. Destroyed, } -impl RunnerEnum { - fn maybe_runner(&self) -> Option<&Runner> { +impl RunnerEnum { + fn maybe_runner(&self) -> Option<&Runner> { match self { RunnerEnum::Running(runner) => Some(runner), _ => None, @@ -77,13 +77,13 @@ impl RunnerEnum { } } -struct Runner { +struct Runner { state: State, - event_handler: Box>, + event_handler: Box, } -impl Runner { - pub fn new(event_handler: Box>) -> Self { +impl Runner { + pub fn new(event_handler: Box) -> Self { Runner { state: State::Init, event_handler, @@ -110,8 +110,8 @@ impl Runner { fn handle_single_event( &mut self, - runner: &Shared, - event: impl Into>, + runner: &Shared, + event: impl Into, control: &mut ControlFlow, ) { let is_closed = matches!(*control, ControlFlow::ExitWithCode(_)); @@ -141,7 +141,7 @@ impl Runner { } } -impl Shared { +impl Shared { pub fn new() -> Self { #[allow(clippy::disallowed_methods)] let window = web_sys::window().expect("only callable from inside the `Window`"); @@ -194,7 +194,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 RootEventLoopWindowTarget reference - pub fn set_listener(&self, event_handler: Box>) { + pub fn set_listener(&self, event_handler: Box) { { let mut runner = self.0.runner.borrow_mut(); assert!(matches!(*runner, RunnerEnum::Pending)); @@ -457,7 +457,7 @@ impl Shared { pub fn request_redraw(&self, id: WindowId) { self.0.redraw_pending.borrow_mut().insert(id); - self.send_events::>(iter::empty()); + self.send_events::(iter::empty()); } pub fn init(&self) { @@ -485,17 +485,14 @@ impl Shared { // Add an event to the event loop runner, from the user or an event handler // // It will determine if the event should be immediately sent to the user or buffered for later - pub(crate) fn send_event>>(&self, event: E) { + pub(crate) fn send_event>(&self, event: E) { self.send_events(iter::once(event)); } // Add a series of events to the event loop runner // // It will determine if the event should be immediately sent to the user or buffered for later - pub(crate) fn send_events>>( - &self, - events: impl IntoIterator, - ) { + pub(crate) fn send_events>(&self, events: impl IntoIterator) { // If the event loop is closed, it should discard any new events if self.is_closed() { return; @@ -573,7 +570,7 @@ impl Shared { // cleared // // This will also process any events that have been queued or that are queued during processing - fn run_until_cleared>>(&self, events: impl Iterator) { + fn run_until_cleared>(&self, events: impl Iterator) { let mut control = self.current_control_flow(); for event in events { self.handle_event(event.into(), &mut control); @@ -613,7 +610,7 @@ impl Shared { // handle_event takes in events and either queues them or applies a callback // // It should only ever be called from `run_until_cleared`. - fn handle_event(&self, event: impl Into>, control: &mut ControlFlow) { + fn handle_event(&self, event: impl Into, control: &mut ControlFlow) { if self.is_closed() { *control = ControlFlow::Exit; } @@ -721,7 +718,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(); } } @@ -779,8 +776,8 @@ impl Shared { } } -pub(crate) enum EventWrapper { - Event(Event), +pub(crate) enum EventWrapper { + Event(Event<()>), ScaleChange { canvas: Weak>, size: PhysicalSize, @@ -788,8 +785,8 @@ pub(crate) enum EventWrapper { }, } -impl From> for EventWrapper { - fn from(value: Event) -> Self { +impl From> for EventWrapper { + fn from(value: Event<()>) -> Self { Self::Event(value) } } diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 71522a16..d080dabb 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -2,6 +2,7 @@ use std::cell::{Cell, RefCell}; use std::clone::Clone; use std::collections::{vec_deque::IntoIter as VecDequeIter, VecDeque}; use std::iter; +use std::marker::PhantomData; use std::rc::Rc; use std::sync::atomic::Ordering; @@ -12,7 +13,6 @@ use super::{ super::{monitor::MonitorHandle, KeyEventExtra}, backend, device::DeviceId, - proxy::EventLoopProxy, runner, window::WindowId, }; @@ -43,8 +43,9 @@ impl Clone for ModifiersShared { } pub struct EventLoopWindowTarget { - pub(crate) runner: runner::Shared, + pub(crate) runner: runner::Shared, modifiers: ModifiersShared, + _marker: PhantomData, } impl Clone for EventLoopWindowTarget { @@ -52,6 +53,7 @@ impl Clone for EventLoopWindowTarget { Self { runner: self.runner.clone(), modifiers: self.modifiers.clone(), + _marker: PhantomData, } } } @@ -61,14 +63,11 @@ impl EventLoopWindowTarget { Self { runner: runner::Shared::new(), modifiers: ModifiersShared::default(), + _marker: PhantomData, } } - pub fn proxy(&self) -> EventLoopProxy { - EventLoopProxy::new(self.runner.clone()) - } - - pub fn run(&self, event_handler: Box>, event_loop_recreation: bool) { + pub fn run(&self, event_handler: Box, event_loop_recreation: bool) { self.runner.event_loop_recreation(event_loop_recreation); self.runner.set_listener(event_handler); } diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index 3be75dae..049c8916 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -463,10 +463,10 @@ impl Canvas { self.animation_frame_handler.request(); } - pub(crate) fn handle_scale_change( + pub(crate) fn handle_scale_change( &self, - runner: &super::super::event_loop::runner::Shared, - event_handler: impl FnOnce(crate::event::Event), + runner: &super::super::event_loop::runner::Shared, + event_handler: impl FnOnce(crate::event::Event<()>), current_size: PhysicalSize, scale: f64, ) {