Allow recreating wasm event loop with spawn (#2897)

This commit is contained in:
Josh Groves 2023-06-23 15:01:42 -02:30 committed by GitHub
parent 864a1d5924
commit bc216b8f67
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 6 deletions

View file

@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre
# Unreleased
- On Web, allow event loops to be recreated with `spawn`.
- **Breaking:** Rename `Window::set_ime_position` to `Window::set_ime_cursor_area` adding a way to set exclusive zone.
- On Android, changed default behavior of Android to ignore volume keys letting the operating system handle them.
- On Android, added `EventLoopBuilderExtAndroid::handle_volume_keys` to indicate that the application will handle the volume keys manually.

View file

@ -9,9 +9,9 @@
//! handle events.
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::atomic::{AtomicBool, Ordering};
use std::{error, fmt};
use once_cell::sync::OnceCell;
use raw_window_handle::{HasRawDisplayHandle, RawDisplayHandle};
#[cfg(not(wasm_platform))]
use std::time::{Duration, Instant};
@ -69,6 +69,8 @@ impl EventLoopBuilder<()> {
}
}
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
impl<T> EventLoopBuilder<T> {
/// Start building a new event loop, with the given type as the user event
/// type.
@ -114,10 +116,10 @@ impl<T> EventLoopBuilder<T> {
)]
#[inline]
pub fn build(&mut self) -> EventLoop<T> {
static EVENT_LOOP_CREATED: OnceCell<()> = OnceCell::new();
if EVENT_LOOP_CREATED.set(()).is_err() {
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
panic!("Creating EventLoop multiple times is not supported.");
}
// Certain platforms accept a mutable reference in their API.
#[allow(clippy::unnecessary_mut_passed)]
EventLoop {
@ -125,6 +127,11 @@ impl<T> EventLoopBuilder<T> {
_marker: PhantomData,
}
}
#[cfg(wasm_platform)]
pub(crate) fn allow_event_loop_recreation() {
EVENT_LOOP_CREATED.store(false, Ordering::Relaxed);
}
}
impl<T> fmt::Debug for EventLoop<T> {

View file

@ -66,6 +66,11 @@ pub trait EventLoopExtWebSys {
///
/// Unlike `run`, this returns immediately, and doesn't throw an exception in order to
/// satisfy its `!` return type.
///
/// Once the event loop has been destroyed, it's possible to reinitialize another event loop
/// by calling this function again. This can be useful if you want to recreate the event loop
/// while the WebAssembly module is still loaded. For example, this can be used to recreate the
/// event loop when switching between tabs on a single page application.
fn spawn<F>(self, event_handler: F)
where
F: 'static

View file

@ -8,7 +8,9 @@ pub use self::window_target::EventLoopWindowTarget;
use super::{backend, device, window};
use crate::event::Event;
use crate::event_loop::{ControlFlow, EventLoopWindowTarget as RootEventLoopWindowTarget};
use crate::event_loop::{
ControlFlow, EventLoopBuilder, EventLoopWindowTarget as RootEventLoopWindowTarget,
};
use std::marker::PhantomData;
@ -33,7 +35,7 @@ impl<T> EventLoop<T> {
where
F: 'static + FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
{
self.spawn(event_handler);
self.spawn_inner(event_handler);
// 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 '!'
@ -44,7 +46,15 @@ impl<T> EventLoop<T> {
unreachable!();
}
pub fn spawn<F>(self, mut event_handler: F)
pub fn spawn<F>(self, event_handler: F)
where
F: 'static + FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
{
EventLoopBuilder::<T>::allow_event_loop_recreation();
self.spawn_inner(event_handler);
}
fn spawn_inner<F>(self, mut event_handler: F)
where
F: 'static + FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
{