winit: replace special private function to spawn event loop with public API in the winit backend builder

This means the event loop spawning goes through the backend, which will permit for state from the Backend struct to be available when spinning the event loop even when spawning it merely.
This commit is contained in:
Simon Hausmann 2025-04-08 10:19:40 +02:00 committed by Simon Hausmann
parent 33561b0457
commit ac256d61d8
5 changed files with 48 additions and 23 deletions

View file

@ -72,9 +72,6 @@ pub async fn compile_from_string_with_style(
style: String,
optional_import_callback: Option<ImportCallbackFunction>,
) -> Result<CompilationResult, JsValue> {
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
#[allow(deprecated)]
let mut compiler = slint_interpreter::ComponentCompiler::default();
if !style.is_empty() {
@ -162,7 +159,8 @@ impl WrappedCompiledComp {
});
let component = self.0.create().unwrap();
component.show().unwrap();
slint_interpreter::spawn_event_loop().unwrap();
// Merely spawns the event loop, but does not block.
slint_interpreter::run_event_loop().unwrap();
}
/// Creates this compiled component in a canvas, wrapped in a promise.
/// The HTML must contains a <canvas> element with the given `canvas_id`
@ -319,7 +317,8 @@ impl WrappedInstance {
/// to ignore.
#[wasm_bindgen]
pub fn run_event_loop() -> Result<(), JsValue> {
slint_interpreter::spawn_event_loop().map_err(|e| -> JsValue { format!("{e}").into() })?;
// Merely spawns the event loop, but does not block.
slint_interpreter::run_event_loop().map_err(|e| -> JsValue { format!("{e}").into() })?;
Ok(())
}
@ -329,7 +328,10 @@ thread_local!(
#[wasm_bindgen(start)]
pub fn init() -> Result<(), JsValue> {
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
let backend = i_slint_backend_winit::Backend::builder()
.with_spawn_event_loop(true)
.with_window_attributes_hook(|mut attrs| {
NEXT_CANVAS_ID.with(|next_id| {
if let Some(canvas_id) = next_id.borrow_mut().take() {

View file

@ -164,6 +164,8 @@ pub struct BackendBuilder {
event_loop_builder: Option<winit::event_loop::EventLoopBuilder<SlintUserEvent>>,
#[cfg(all(muda, target_os = "macos"))]
muda_enable_default_menu_bar_bar: bool,
#[cfg(target_family = "wasm")]
spawn_event_loop: bool,
}
impl BackendBuilder {
@ -227,6 +229,14 @@ impl BackendBuilder {
self
}
#[cfg(target_family = "wasm")]
/// Configures this builder to spawn the event loop using [`winit::platform::web::EventLoopExtWebSys::spawn()`]
/// run `run_event_loop()` is called.
pub fn with_spawn_event_loop(mut self, enable: bool) -> Self {
self.spawn_event_loop = enable;
self
}
/// Builds the backend with the parameters configured previously. Set the resulting backend
/// with `slint::platform::set_platform()`:
///
@ -333,6 +343,8 @@ impl BackendBuilder {
proxy,
#[cfg(all(muda, target_os = "macos"))]
muda_enable_default_menu_bar_bar: self.muda_enable_default_menu_bar_bar,
#[cfg(target_family = "wasm")]
spawn_event_loop: self.spawn_event_loop,
})
}
}
@ -373,6 +385,9 @@ pub struct Backend {
#[cfg(all(muda, target_os = "macos"))]
muda_enable_default_menu_bar_bar: bool,
#[cfg(target_family = "wasm")]
spawn_event_loop: bool,
}
impl Backend {
@ -409,6 +424,8 @@ impl Backend {
event_loop_builder: None,
#[cfg(all(muda, target_os = "macos"))]
muda_enable_default_menu_bar_bar: true,
#[cfg(target_family = "wasm")]
spawn_event_loop: false,
}
}
}
@ -474,6 +491,12 @@ impl i_slint_core::platform::Platform for Backend {
}
fn run_event_loop(&self) -> Result<(), PlatformError> {
#[cfg(target_family = "wasm")]
{
if self.spawn_event_loop {
return crate::event_loop::spawn();
}
}
let loop_state = self.event_loop_state.borrow_mut().take().unwrap_or_default();
let new_state = loop_state.run()?;
*self.event_loop_state.borrow_mut() = Some(new_state);
@ -548,12 +571,6 @@ impl i_slint_core::platform::Platform for Backend {
}
}
/// Spawn the event loop, using [`winit::platform::web::EventLoopExtWebSys::spawn()`]
#[cfg(target_arch = "wasm32")]
pub fn spawn_event_loop() -> Result<(), PlatformError> {
crate::event_loop::spawn()
}
mod private {
pub trait WinitWindowAccessorSealed {}
}

View file

@ -1644,15 +1644,6 @@ pub fn spawn_local<F: Future + 'static>(fut: F) -> Result<JoinHandle<F::Output>,
.map_err(|_| EventLoopError::NoEventLoopProvider)?
}
#[cfg(all(feature = "internal", target_arch = "wasm32"))]
/// Spawn the event loop.
///
/// Like [`run_event_loop()`], but returns immediately as the loop is running within
/// the browser's runtime
pub fn spawn_event_loop() -> Result<(), PlatformError> {
i_slint_backend_selector::with_platform(|_| i_slint_backend_winit::spawn_event_loop())
}
/// This module contains a few functions used by the tests
#[doc(hidden)]
pub mod testing {

View file

@ -131,6 +131,7 @@ send_wrapper = { workspace = true }
serde-wasm-bindgen = "0.6.0"
wasm-bindgen = "0.2.80"
wasm-bindgen-futures = "0.4.30"
i-slint-backend-winit = { workspace = true }
[target.'cfg(target_vendor = "apple")'.dependencies]
i-slint-backend-winit = { workspace = true, optional = true }

View file

@ -39,12 +39,26 @@ struct WasmCallbacks {
thread_local! {static WASM_CALLBACKS: RefCell<Option<WasmCallbacks>> = Default::default();}
#[wasm_bindgen(start)]
pub fn init_backend() -> Result<(), JsValue> {
console_error_panic_hook::set_once();
// Initialize the winit backend when we're used in the browser's main thread.
if web_sys::window().is_some() {
let backend =
i_slint_backend_winit::Backend::builder().with_spawn_event_loop(true).build().unwrap();
i_slint_core::platform::set_platform(Box::new(backend))
.map_err(|e| -> JsValue { format!("{e}").into() })?;
}
Ok(())
}
/// Register DOM event handlers on all instance and set up the event loop for that.
/// You can call this function only once. It will throw an exception but that is safe
/// to ignore.
/// You can call this function only once.
#[wasm_bindgen]
pub fn run_event_loop() -> Result<(), JsValue> {
slint_interpreter::spawn_event_loop().map_err(|e| -> JsValue { format!("{e}").into() })
slint_interpreter::run_event_loop().map_err(|e| -> JsValue { format!("{e}").into() })
}
#[wasm_bindgen]