Prospective fix for making invoke_from_event_loop work better in WASM

When called from inside some winit event handler, we'd go straight to
`with_window_target` to get hold of the event proxy and send it. However
when called through some external event handler (DOM), the scoped
CURRENT_WINDOW_TARGET would not be set and MAYBE_LOOP_INSTANCE would
also be empty because `run` takes it. So instead we'd end up creating an
new event loop instance and the event would sit in there forever.

Instead, this change brings WASM in line with the other platforms by
using the dedicated event loop proxy (global_proxy). Because of the lack
of threading the dance of storage for that is a little different though.
This commit is contained in:
Simon Hausmann 2021-11-12 14:37:41 +01:00 committed by Simon Hausmann
parent e0a942dc1c
commit d8988cae6c
2 changed files with 16 additions and 13 deletions

View file

@ -226,13 +226,11 @@ thread_local! {
scoped_tls_hkt::scoped_thread_local!(static CURRENT_WINDOW_TARGET : for<'a> &'a RunningEventLoop<'a>); scoped_tls_hkt::scoped_thread_local!(static CURRENT_WINDOW_TARGET : for<'a> &'a RunningEventLoop<'a>);
#[cfg(not(target_arch = "wasm32"))]
pub(crate) enum GlobalEventLoopProxyOrEventQueue { pub(crate) enum GlobalEventLoopProxyOrEventQueue {
Proxy(winit::event_loop::EventLoopProxy<CustomEvent>), Proxy(winit::event_loop::EventLoopProxy<CustomEvent>),
Queue(Vec<CustomEvent>), Queue(Vec<CustomEvent>),
} }
#[cfg(not(target_arch = "wasm32"))]
impl GlobalEventLoopProxyOrEventQueue { impl GlobalEventLoopProxyOrEventQueue {
pub(crate) fn send_event(&mut self, event: CustomEvent) { pub(crate) fn send_event(&mut self, event: CustomEvent) {
match self { match self {
@ -256,7 +254,6 @@ impl GlobalEventLoopProxyOrEventQueue {
} }
} }
#[cfg(not(target_arch = "wasm32"))]
impl Default for GlobalEventLoopProxyOrEventQueue { impl Default for GlobalEventLoopProxyOrEventQueue {
fn default() -> Self { fn default() -> Self {
Self::Queue(Vec::new()) Self::Queue(Vec::new())
@ -268,6 +265,11 @@ pub(crate) static GLOBAL_PROXY: once_cell::sync::OnceCell<
std::sync::Mutex<GlobalEventLoopProxyOrEventQueue>, std::sync::Mutex<GlobalEventLoopProxyOrEventQueue>,
> = once_cell::sync::OnceCell::new(); > = once_cell::sync::OnceCell::new();
#[cfg(target_arch = "wasm32")]
thread_local! {
pub(crate) static GLOBAL_PROXY: RefCell<Option<GlobalEventLoopProxyOrEventQueue>> = RefCell::new(None)
}
pub(crate) fn with_window_target<T>(callback: impl FnOnce(&dyn EventLoopInterface) -> T) -> T { pub(crate) fn with_window_target<T>(callback: impl FnOnce(&dyn EventLoopInterface) -> T) -> T {
if CURRENT_WINDOW_TARGET.is_set() { if CURRENT_WINDOW_TARGET.is_set() {
CURRENT_WINDOW_TARGET.with(|current_target| callback(current_target)) CURRENT_WINDOW_TARGET.with(|current_target| callback(current_target))
@ -519,13 +521,14 @@ pub fn run(quit_behavior: sixtyfps_corelib::backend::EventLoopQuitBehavior) {
let event_loop_proxy = not_running_loop_instance.event_loop_proxy; let event_loop_proxy = not_running_loop_instance.event_loop_proxy;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
{ GLOBAL_PROXY.get_or_init(Default::default).lock().unwrap().set_proxy(event_loop_proxy.clone());
GLOBAL_PROXY #[cfg(target_arch = "wasm32")]
.get_or_init(Default::default) GLOBAL_PROXY.with(|global_proxy| {
.lock() global_proxy
.unwrap() .borrow_mut()
.set_proxy(event_loop_proxy.clone()); .get_or_insert_with(Default::default)
} .set_proxy(event_loop_proxy.clone())
});
let mut winit_loop = not_running_loop_instance.instance; let mut winit_loop = not_running_loop_instance.instance;

View file

@ -1228,9 +1228,9 @@ impl sixtyfps_corelib::backend::Backend for Backend {
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
crate::event_loop::GLOBAL_PROXY.get_or_init(Default::default).lock().unwrap().send_event(e); crate::event_loop::GLOBAL_PROXY.get_or_init(Default::default).lock().unwrap().send_event(e);
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
crate::event_loop::with_window_target(|event_loop| { crate::event_loop::GLOBAL_PROXY.with(|global_proxy| {
event_loop.event_loop_proxy().send_event(e).ok(); global_proxy.borrow_mut().get_or_insert_with(Default::default).send_event(e)
}) });
} }
fn image_size(&'static self, image: &Image) -> Size { fn image_size(&'static self, image: &Image) -> Size {