web: Avoid top-level Event
This commit is contained in:
parent
f9912baf09
commit
4d6fe7e35c
4 changed files with 75 additions and 87 deletions
|
|
@ -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<A: ApplicationHandler>(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<dyn FnMut(Event)> =
|
||||
Box::new(|event| handle_event(&mut app, &event_loop, event));
|
||||
pub fn run_app<A: ApplicationHandler>(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<dyn FnMut(Event)>, Box<dyn FnMut(Event) + 'static>>(handler)
|
||||
let app = unsafe {
|
||||
std::mem::transmute::<
|
||||
Box<dyn ApplicationHandler + '_>,
|
||||
Box<dyn ApplicationHandler + 'static>,
|
||||
>(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<A: ApplicationHandler + 'static>(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<A: ApplicationHandler + 'static>(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<A: ApplicationHandler>(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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Execution>);
|
||||
|
||||
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<RunnerEnum>,
|
||||
suspended: Cell<bool>,
|
||||
event_loop_recreation: Cell<bool>,
|
||||
events: RefCell<VecDeque<EventWrapper>>,
|
||||
events: RefCell<VecDeque<Event>>,
|
||||
id: Cell<usize>,
|
||||
window: web_sys::Window,
|
||||
navigator: Navigator,
|
||||
|
|
@ -93,12 +92,13 @@ impl RunnerEnum {
|
|||
|
||||
struct Runner {
|
||||
state: State,
|
||||
event_handler: Box<EventHandler>,
|
||||
app: Box<dyn ApplicationHandler>,
|
||||
event_loop: ActiveEventLoop,
|
||||
}
|
||||
|
||||
impl Runner {
|
||||
pub fn new(event_handler: Box<EventHandler>) -> Self {
|
||||
Runner { state: State::Init, event_handler }
|
||||
pub fn new(app: Box<dyn ApplicationHandler>, 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<EventWrapper>) {
|
||||
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<EventHandler>) {
|
||||
pub(crate) fn start(&self, app: Box<dyn ApplicationHandler>, 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::<EventWrapper>(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<E: Into<EventWrapper>>(&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<E: Into<EventWrapper>>(&self, events: impl IntoIterator<Item = E>) {
|
||||
pub(crate) fn send_events(&self, events: impl IntoIterator<Item = Event>) {
|
||||
// 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<E: Into<EventWrapper>>(&self, events: impl Iterator<Item = E>) {
|
||||
fn run_until_cleared(&self, events: impl Iterator<Item = Event>) {
|
||||
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<EventWrapper>) {
|
||||
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<backend::Canvas>, size: PhysicalSize<u32>, scale: f64 },
|
||||
}
|
||||
|
||||
impl From<Event> for EventWrapper {
|
||||
fn from(value: Event) -> Self {
|
||||
Self::Event(value)
|
||||
}
|
||||
DeviceEvent { device_id: Option<DeviceId>, event: DeviceEvent },
|
||||
Suspended,
|
||||
CreateSurfaces,
|
||||
Resumed,
|
||||
AboutToWait,
|
||||
LoopExiting,
|
||||
UserWakeUp,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<runner::EventHandler>,
|
||||
event_loop_recreation: bool,
|
||||
) {
|
||||
pub(crate) fn run(&self, app: Box<dyn ApplicationHandler>, 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,
|
||||
|
|
|
|||
|
|
@ -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<u32>,
|
||||
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),
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue