diff --git a/src/platform_impl/web/event_loop/mod.rs b/src/platform_impl/web/event_loop/mod.rs index f42baf5728..112dd7d237 100644 --- a/src/platform_impl/web/event_loop/mod.rs +++ b/src/platform_impl/web/event_loop/mod.rs @@ -1,7 +1,6 @@ use super::{backend, HasMonitorPermissionFuture, MonitorPermissionFuture}; use crate::application::ApplicationHandler; use crate::error::{EventLoopError, NotSupportedError}; -use crate::event::Event; use crate::event_loop::ActiveEventLoop as RootActiveEventLoop; use crate::platform::web::{PollStrategy, WaitUntilStrategy}; @@ -24,20 +23,20 @@ impl EventLoop { Ok(EventLoop { elw: ActiveEventLoop::new() }) } - pub fn run_app(self, mut app: A) -> ! { - let event_loop = self.elw.clone(); - - // SAFETY: Don't use `move` to make sure we leak the `event_handler` and `target`. - let handler: Box = - Box::new(|event| handle_event(&mut app, &event_loop, event)); + pub fn run_app(self, app: A) -> ! { + let app = Box::new(app); // 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>(handler) + let app = unsafe { + std::mem::transmute::< + Box, + Box, + >(app) }; - self.elw.run(handler, false); + + self.elw.run(app, false); // 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 '!' @@ -48,9 +47,8 @@ impl EventLoop { unreachable!(); } - pub fn spawn_app(self, mut app: A) { - let event_loop = self.elw.clone(); - self.elw.run(Box::new(move |event| handle_event(&mut app, &event_loop, event)), true); + pub fn spawn_app(self, app: A) { + self.elw.run(Box::new(app), true); } pub fn window_target(&self) -> &dyn RootActiveEventLoop { @@ -85,18 +83,3 @@ impl EventLoop { self.elw.runner.monitor().has_detailed_monitor_permission_async() } } - -fn handle_event(app: &mut A, target: &ActiveEventLoop, 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::UserWakeUp => app.proxy_wake_up(target), - Event::Suspended => app.suspended(target), - Event::Resumed => app.resumed(target), - Event::CreateSurfaces => app.can_create_surfaces(target), - Event::AboutToWait => app.about_to_wait(target), - Event::LoopExiting => app.exiting(target), - Event::MemoryWarning => app.memory_warning(target), - } -} diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index a7a8e920de..b5022c9253 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -13,11 +13,12 @@ use web_time::{Duration, Instant}; use super::super::event; use super::super::main_thread::MainThreadMarker; use super::super::monitor::MonitorHandler; -use super::backend; use super::proxy::EventLoopProxy; use super::state::State; +use super::{backend, ActiveEventLoop}; +use crate::application::ApplicationHandler; use crate::dpi::PhysicalSize; -use crate::event::{DeviceEvent, ElementState, Event, RawKeyEvent, StartCause, WindowEvent}; +use crate::event::{DeviceEvent, DeviceId, ElementState, RawKeyEvent, StartCause, WindowEvent}; use crate::event_loop::{ControlFlow, DeviceEvents}; use crate::platform::web::{PollStrategy, WaitUntilStrategy}; use crate::platform_impl::platform::backend::{EventListenerHandle, SafeAreaHandle}; @@ -27,8 +28,6 @@ use crate::window::WindowId; pub struct Shared(Rc); -pub(super) type EventHandler = dyn FnMut(Event); - impl Clone for Shared { fn clone(&self) -> Self { Shared(self.0.clone()) @@ -47,7 +46,7 @@ struct Execution { runner: RefCell, suspended: Cell, event_loop_recreation: Cell, - events: RefCell>, + events: RefCell>, id: Cell, window: web_sys::Window, navigator: Navigator, @@ -93,12 +92,13 @@ impl RunnerEnum { struct Runner { state: State, - event_handler: Box, + app: Box, + event_loop: ActiveEventLoop, } impl Runner { - pub fn new(event_handler: Box) -> Self { - Runner { state: State::Init, event_handler } + pub fn new(app: Box, event_loop: ActiveEventLoop) -> Self { + Runner { state: State::Init, app, event_loop } } /// Returns the corresponding `StartCause` for the current `state`, or `None` @@ -115,19 +115,33 @@ impl Runner { }) } - fn handle_single_event(&mut self, runner: &Shared, event: impl Into) { - match event.into() { - EventWrapper::Event(event) => (self.event_handler)(event), - EventWrapper::ScaleChange { canvas, size, scale } => { + fn handle_single_event(&mut self, runner: &Shared, event: Event) { + match event { + Event::NewEvents(cause) => self.app.new_events(&self.event_loop, cause), + Event::WindowEvent { window_id, event } => { + self.app.window_event(&self.event_loop, window_id, event) + }, + Event::ScaleChange { canvas, size, scale } => { if let Some(canvas) = canvas.upgrade() { canvas.handle_scale_change( runner, - |event| (self.event_handler)(event), + |window_id, event| { + self.app.window_event(&self.event_loop, window_id, event); + }, size, scale, ) } }, + Event::DeviceEvent { device_id, event } => { + self.app.device_event(&self.event_loop, device_id, event) + }, + Event::UserWakeUp => self.app.proxy_wake_up(&self.event_loop), + Event::Suspended => self.app.suspended(&self.event_loop), + Event::Resumed => self.app.resumed(&self.event_loop), + Event::CreateSurfaces => self.app.can_create_surfaces(&self.event_loop), + Event::AboutToWait => self.app.about_to_wait(&self.event_loop), + Event::LoopExiting => self.app.exiting(&self.event_loop), } } } @@ -216,13 +230,13 @@ impl Shared { self.0.destroy_pending.borrow_mut().push_back(id); } - pub(crate) fn start(&self, event_handler: Box) { + pub(crate) fn start(&self, app: Box, event_loop: ActiveEventLoop) { let mut runner = self.0.runner.borrow_mut(); assert!(matches!(*runner, RunnerEnum::Pending)); if self.0.monitor.is_initializing() { - *runner = RunnerEnum::Initializing(Runner::new(event_handler)); + *runner = RunnerEnum::Initializing(Runner::new(app, event_loop)); } else { - *runner = RunnerEnum::Running(Runner::new(event_handler)); + *runner = RunnerEnum::Running(Runner::new(app, event_loop)); drop(runner); @@ -445,7 +459,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([]); } fn init(&self) { @@ -473,7 +487,7 @@ 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: Event) { self.send_events(iter::once(event)); } @@ -514,7 +528,7 @@ impl Shared { // 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; @@ -539,7 +553,7 @@ impl Shared { } if !process_immediately { // Queue these events to look at later - self.0.events.borrow_mut().extend(events.into_iter().map(Into::into)); + self.0.events.borrow_mut().extend(events); return; } // At this point, we know this is a fresh set of events @@ -557,8 +571,7 @@ impl Shared { // Take the start event, then the events provided to this function, and run an iteration of // the event loop let start_event = Event::NewEvents(start_cause); - let events = - iter::once(EventWrapper::from(start_event)).chain(events.into_iter().map(Into::into)); + let events = iter::once(start_event).chain(events); self.run_until_cleared(events); } @@ -579,9 +592,9 @@ 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) { for event in events { - self.handle_event(event.into()); + self.handle_event(event); } self.process_destroy_pending_windows(); @@ -615,7 +628,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) { + fn handle_event(&self, event: Event) { if self.is_closed() { self.exit(); } @@ -625,7 +638,7 @@ impl Shared { }, // If an event is being handled without a runner somehow, add it to the event queue so // it will eventually be processed - RunnerEnum::Pending => self.0.events.borrow_mut().push_back(event.into()), + RunnerEnum::Pending => self.0.events.borrow_mut().push_back(event), // If the Runner has been destroyed, there is nothing to do. RunnerEnum::Destroyed => return, // This function should never be called if we are still waiting for something. @@ -652,13 +665,7 @@ impl Shared { let mut events = self.0.events.borrow_mut(); // Pre-fetch `UserEvent`s to avoid having to wait until the next event loop cycle. - events.extend( - self.0 - .event_loop_proxy - .take() - .then_some(Event::UserWakeUp) - .map(EventWrapper::from), - ); + events.extend(self.0.event_loop_proxy.take().then_some(Event::UserWakeUp)); events.pop_front() }; @@ -845,13 +852,16 @@ impl WeakShared { } } -pub(crate) enum EventWrapper { - Event(Event), +#[allow(clippy::enum_variant_names)] +pub(crate) enum Event { + NewEvents(StartCause), + WindowEvent { window_id: WindowId, event: WindowEvent }, ScaleChange { canvas: Weak, size: PhysicalSize, scale: f64 }, -} - -impl From for EventWrapper { - fn from(value: Event) -> Self { - Self::Event(value) - } + DeviceEvent { device_id: Option, event: DeviceEvent }, + Suspended, + CreateSurfaces, + Resumed, + AboutToWait, + LoopExiting, + UserWakeUp, } diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 2ab0e78f8c..39984e9a5a 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -8,10 +8,11 @@ use web_sys::Element; use super::super::monitor::MonitorPermissionFuture; use super::super::{lock, KeyEventExtra}; -use super::runner::EventWrapper; +use super::runner::Event; use super::{backend, runner}; +use crate::application::ApplicationHandler; use crate::error::{NotSupportedError, RequestError}; -use crate::event::{ElementState, Event, KeyEvent, TouchPhase, WindowEvent}; +use crate::event::{ElementState, KeyEvent, TouchPhase, WindowEvent}; use crate::event_loop::{ ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, EventLoopProxy as RootEventLoopProxy, OwnedDisplayHandle as CoreOwnedDisplayHandle, @@ -54,13 +55,9 @@ impl ActiveEventLoop { Self { runner: runner::Shared::new(), modifiers: ModifiersShared::default() } } - pub(crate) fn run( - &self, - event_handler: Box, - event_loop_recreation: bool, - ) { + pub(crate) fn run(&self, app: Box, event_loop_recreation: bool) { self.runner.event_loop_recreation(event_loop_recreation); - self.runner.start(event_handler); + self.runner.start(app, self.clone()); } pub fn generate_id(&self) -> WindowId { @@ -396,7 +393,7 @@ impl ActiveEventLoop { let canvas = canvas_clone.clone(); move |size, scale| { - runner.send_event(EventWrapper::ScaleChange { + runner.send_event(Event::ScaleChange { canvas: Rc::downgrade(&canvas), size, scale, diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index c39d6ed4fd..8de5411206 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -12,6 +12,7 @@ use web_sys::{ }; use super::super::cursor::CursorHandler; +use super::super::event_loop::runner; use super::super::main_thread::MainThreadMarker; use super::animation_frame::AnimationFrameHandler; use super::event_handle::EventListenerHandle; @@ -23,7 +24,7 @@ use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; use crate::error::RequestError; use crate::event::{ ButtonSource, DeviceId, ElementState, MouseScrollDelta, PointerKind, PointerSource, - SurfaceSizeWriter, + SurfaceSizeWriter, WindowEvent, }; use crate::keyboard::{Key, KeyLocation, ModifiersState, PhysicalKey}; use crate::platform_impl::Fullscreen; @@ -487,7 +488,7 @@ impl Canvas { pub(crate) fn handle_scale_change( &self, runner: &super::super::event_loop::runner::Shared, - event_handler: impl FnOnce(crate::event::Event), + event_handler: impl FnOnce(WindowId, WindowEvent), current_size: PhysicalSize, scale: f64, ) { @@ -495,12 +496,9 @@ impl Canvas { self.set_current_size(current_size); let new_size = { let new_size = Arc::new(Mutex::new(current_size)); - event_handler(crate::event::Event::WindowEvent { - window_id: self.id, - event: crate::event::WindowEvent::ScaleFactorChanged { - scale_factor: scale, - surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(&new_size)), - }, + event_handler(self.id, WindowEvent::ScaleFactorChanged { + scale_factor: scale, + surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(&new_size)), }); let new_size = *new_size.lock().unwrap(); @@ -523,7 +521,7 @@ impl Canvas { } else if self.old_size() != new_size { // Then we at least send a resized event. self.set_old_size(new_size); - runner.send_event(crate::event::Event::WindowEvent { + runner.send_event(runner::Event::WindowEvent { window_id: self.id, event: crate::event::WindowEvent::SurfaceResized(new_size), })