diff --git a/internal/backends/winit/event_loop.rs b/internal/backends/winit/event_loop.rs index f0365705673..3a0b70b7f5d 100644 --- a/internal/backends/winit/event_loop.rs +++ b/internal/backends/winit/event_loop.rs @@ -10,7 +10,6 @@ use crate::drag_resize_window::{handle_cursor_move_for_resize, handle_resize}; use crate::winitwindowadapter::WinitWindowAdapter; use crate::SlintUserEvent; -use corelib::api::EventLoopError; use corelib::graphics::euclid; use corelib::input::{KeyEvent, KeyEventType, MouseEvent}; use corelib::items::{ColorScheme, PointerEventButton}; @@ -30,7 +29,6 @@ use winit::event_loop::ControlFlow; use winit::window::ResizeDirection; struct NotRunningEventLoop { instance: winit::event_loop::EventLoop, - event_loop_proxy: winit::event_loop::EventLoopProxy, } impl NotRunningEventLoop { @@ -58,8 +56,7 @@ impl NotRunningEventLoop { let instance = builder.build().map_err(|e| format!("Error initializing winit event loop: {e}"))?; - let event_loop_proxy = instance.create_proxy(); - Ok(Self { instance, event_loop_proxy }) + Ok(Self { instance }) } } @@ -130,53 +127,6 @@ thread_local! { scoped_tls_hkt::scoped_thread_local!(static CURRENT_WINDOW_TARGET : for<'a> &'a RunningEventLoop<'a>); -pub(crate) enum GlobalEventLoopProxyOrEventQueue { - Proxy(winit::event_loop::EventLoopProxy), - Queue(Vec), -} - -impl GlobalEventLoopProxyOrEventQueue { - pub(crate) fn send_event(&mut self, event: SlintUserEvent) -> Result<(), EventLoopError> { - match self { - GlobalEventLoopProxyOrEventQueue::Proxy(proxy) => { - proxy.send_event(event).map_err(|_| EventLoopError::EventLoopTerminated) - } - GlobalEventLoopProxyOrEventQueue::Queue(queue) => { - queue.push(event); - Ok(()) - } - } - } - - fn set_proxy(&mut self, proxy: winit::event_loop::EventLoopProxy) { - match self { - GlobalEventLoopProxyOrEventQueue::Proxy(_) => {} - GlobalEventLoopProxyOrEventQueue::Queue(queue) => { - std::mem::take(queue) - .into_iter() - .for_each(|event| proxy.send_event(event).ok().unwrap()); - *self = GlobalEventLoopProxyOrEventQueue::Proxy(proxy); - } - } - } -} - -impl Default for GlobalEventLoopProxyOrEventQueue { - fn default() -> Self { - Self::Queue(Vec::new()) - } -} - -#[cfg(not(target_arch = "wasm32"))] -pub(crate) static GLOBAL_PROXY: once_cell::sync::OnceCell< - std::sync::Mutex, -> = once_cell::sync::OnceCell::new(); - -#[cfg(target_arch = "wasm32")] -thread_local! { - pub(crate) static GLOBAL_PROXY: RefCell> = RefCell::new(None) -} - pub(crate) fn with_window_target( callback: impl FnOnce( &dyn EventLoopInterface, @@ -609,21 +559,6 @@ impl EventLoopState { }) .map_err(|e| format!("Error initializing winit event loop: {e}"))?; - let event_loop_proxy = not_running_loop_instance.event_loop_proxy; - #[cfg(not(target_arch = "wasm32"))] - GLOBAL_PROXY - .get_or_init(Default::default) - .lock() - .unwrap() - .set_proxy(event_loop_proxy.clone()); - #[cfg(target_arch = "wasm32")] - GLOBAL_PROXY.with(|global_proxy| { - global_proxy - .borrow_mut() - .get_or_insert_with(Default::default) - .set_proxy(event_loop_proxy.clone()) - }); - let mut winit_loop = not_running_loop_instance.instance; #[cfg(not(target_arch = "wasm32"))] @@ -633,11 +568,9 @@ impl EventLoopState { .run_app_on_demand(&mut ActiveEventLoopSetterDuringEventProcessing(&mut self)) .map_err(|e| format!("Error running winit event loop: {e}"))?; - *GLOBAL_PROXY.get_or_init(Default::default).lock().unwrap() = Default::default(); - // Keep the EventLoop instance alive and re-use it in future invocations of run_event_loop(). // Winit does not support creating multiple instances of the event loop. - let nre = NotRunningEventLoop { instance: winit_loop, event_loop_proxy }; + let nre = NotRunningEventLoop { instance: winit_loop }; MAYBE_LOOP_INSTANCE.with(|loop_instance| *loop_instance.borrow_mut() = Some(nre)); if let Some(error) = self.loop_error { @@ -673,23 +606,14 @@ impl EventLoopState { }) .map_err(|e| format!("Error initializing winit event loop: {e}"))?; - let event_loop_proxy = not_running_loop_instance.event_loop_proxy; - GLOBAL_PROXY - .get_or_init(Default::default) - .lock() - .unwrap() - .set_proxy(event_loop_proxy.clone()); - let mut winit_loop = not_running_loop_instance.instance; let result = winit_loop .pump_app_events(timeout, &mut ActiveEventLoopSetterDuringEventProcessing(&mut self)); - *GLOBAL_PROXY.get_or_init(Default::default).lock().unwrap() = Default::default(); - // Keep the EventLoop instance alive and re-use it in future invocations of run_event_loop(). // Winit does not support creating multiple instances of the event loop. - let nre = NotRunningEventLoop { instance: winit_loop, event_loop_proxy }; + let nre = NotRunningEventLoop { instance: winit_loop }; MAYBE_LOOP_INSTANCE.with(|loop_instance| *loop_instance.borrow_mut() = Some(nre)); if let Some(error) = self.loop_error { @@ -709,14 +633,6 @@ pub fn spawn() -> Result<(), corelib::platform::PlatformError> { }) .map_err(|e| format!("Error initializing winit event loop: {e}"))?; - let event_loop_proxy = not_running_loop_instance.event_loop_proxy; - GLOBAL_PROXY.with(|global_proxy| { - global_proxy - .borrow_mut() - .get_or_insert_with(Default::default) - .set_proxy(event_loop_proxy.clone()) - }); - let loop_state = EventLoopState::default(); not_running_loop_instance diff --git a/internal/backends/winit/lib.rs b/internal/backends/winit/lib.rs index d3a1c2f1a10..0ae7617a668 100644 --- a/internal/backends/winit/lib.rs +++ b/internal/backends/winit/lib.rs @@ -7,7 +7,8 @@ extern crate alloc; use event_loop::CustomEvent; -use i_slint_core::platform::EventLoopProxy; +use i_slint_core::api::EventLoopError; +use i_slint_core::platform::{EventLoopProxy, PlatformError}; use i_slint_core::window::WindowAdapter; use renderer::WinitCompatibleRenderer; use std::rc::Rc; @@ -16,8 +17,6 @@ use std::rc::Rc; mod clipboard; mod drag_resize_window; mod winitwindowadapter; - -use i_slint_core::platform::PlatformError; use winitwindowadapter::*; pub(crate) mod event_loop; @@ -226,37 +225,6 @@ impl Backend { } } -fn send_event_via_global_event_loop_proxy( - event: SlintUserEvent, -) -> Result<(), i_slint_core::api::EventLoopError> { - #[cfg(not(target_arch = "wasm32"))] - crate::event_loop::GLOBAL_PROXY - .get_or_init(Default::default) - .lock() - .unwrap() - .send_event(event)?; - #[cfg(target_arch = "wasm32")] - { - crate::event_loop::GLOBAL_PROXY.with(|global_proxy| { - let mut maybe_proxy = global_proxy.borrow_mut(); - let proxy = maybe_proxy.get_or_insert_with(Default::default); - // Calling send_event is usually done by winit at the bottom of the stack, - // in event handlers, and thus winit might decide to process the event - // immediately within that stack. - // To prevent re-entrancy issues that might happen by getting the application - // event processed on top of the current stack, set winit in Poll mode so that - // events are queued and process on top of a clean stack during a requested animation - // frame a few moments later. - // This also allows batching multiple post_event calls and redraw their state changes - // all at once. - proxy.send_event(SlintUserEvent(CustomEvent::WakeEventLoopWorkaround))?; - proxy.send_event(event)?; - Ok(()) - })? - } - Ok(()) -} - impl i_slint_core::platform::Platform for Backend { fn create_window_adapter(&self) -> Result, PlatformError> { let mut builder = WinitWindowAdapter::window_attributes( @@ -315,21 +283,38 @@ impl i_slint_core::platform::Platform for Backend { } fn new_event_loop_proxy(&self) -> Option> { - struct Proxy; + struct Proxy(winit::event_loop::EventLoopProxy); impl EventLoopProxy for Proxy { - fn quit_event_loop(&self) -> Result<(), i_slint_core::api::EventLoopError> { - send_event_via_global_event_loop_proxy(SlintUserEvent(CustomEvent::Exit)) + fn quit_event_loop(&self) -> Result<(), EventLoopError> { + self.0 + .send_event(SlintUserEvent(CustomEvent::Exit)) + .map_err(|_| EventLoopError::EventLoopTerminated) } fn invoke_from_event_loop( &self, event: Box, - ) -> Result<(), i_slint_core::api::EventLoopError> { - let e = SlintUserEvent(CustomEvent::UserEvent(event)); - send_event_via_global_event_loop_proxy(e) + ) -> Result<(), EventLoopError> { + // Calling send_event is usually done by winit at the bottom of the stack, + // in event handlers, and thus winit might decide to process the event + // immediately within that stack. + // To prevent re-entrancy issues that might happen by getting the application + // event processed on top of the current stack, set winit in Poll mode so that + // events are queued and process on top of a clean stack during a requested animation + // frame a few moments later. + // This also allows batching multiple post_event calls and redraw their state changes + // all at once. + #[cfg(target_arch = "wasm32")] + self.0 + .send_event(SlintUserEvent(CustomEvent::WakeEventLoopWorkaround)) + .map_err(|_| EventLoopError::EventLoopTerminated)?; + + self.0 + .send_event(SlintUserEvent(CustomEvent::UserEvent(event))) + .map_err(|_| EventLoopError::EventLoopTerminated) } } - Some(Box::new(Proxy)) + Some(Box::new(Proxy(self.proxy.clone()))) } #[cfg(target_arch = "wasm32")]