diff --git a/api/wasm-interpreter/src/lib.rs b/api/wasm-interpreter/src/lib.rs index 913c2f592..6a0785993 100644 --- a/api/wasm-interpreter/src/lib.rs +++ b/api/wasm-interpreter/src/lib.rs @@ -193,8 +193,26 @@ impl WrappedCompiledComp { pub fn create_with_existing_window( &self, instance: WrappedInstance, - ) -> Result { - Ok(WrappedInstance(self.0.create_with_existing_window(instance.0.window()).unwrap())) + ) -> Result { + Ok(JsValue::from(js_sys::Promise::new(&mut |resolve, reject| { + let comp = send_wrapper::SendWrapper::new(self.0.clone()); + let instance = send_wrapper::SendWrapper::new(instance.0.clone_strong()); + let resolve = send_wrapper::SendWrapper::new(resolve); + if let Err(e) = slint_interpreter::invoke_from_event_loop(move || { + let instance = + WrappedInstance(comp.take().create_with_existing_window(instance.take().window()).unwrap()); + resolve.take().call1(&JsValue::UNDEFINED, &JsValue::from(instance)).unwrap_throw(); + }) { + reject + .call1( + &JsValue::UNDEFINED, + &JsValue::from( + format!("internal error: Failed to queue closure for event loop invocation: {e}"), + ), + ) + .unwrap_throw(); + } + })).unchecked_into::()) } } @@ -212,17 +230,35 @@ impl WrappedInstance { /// Marks this instance for rendering and input handling. #[wasm_bindgen] pub fn show(&self) -> Result { + self.invoke_from_event_loop_wrapped_in_promise(|instance| instance.show()) + } + /// Hides this instance and prevents further updates of the canvas element. + #[wasm_bindgen] + pub fn hide(&self) -> Result { + self.invoke_from_event_loop_wrapped_in_promise(|instance| instance.hide()) + } + + fn invoke_from_event_loop_wrapped_in_promise( + &self, + callback: impl FnOnce( + &slint_interpreter::ComponentInstance, + ) -> Result<(), slint_interpreter::PlatformError> + + 'static, + ) -> Result { + let callback = std::cell::RefCell::new(Some(callback)); Ok(js_sys::Promise::new(&mut |resolve, reject| { let inst_weak = self.0.as_weak(); if let Err(e) = slint_interpreter::invoke_from_event_loop({ let resolve = send_wrapper::SendWrapper::new(resolve); let reject = send_wrapper::SendWrapper::new(reject.clone()); + let callback = send_wrapper::SendWrapper::new(callback.take().unwrap()); move || { let resolve = resolve.take(); let reject = reject.take(); + let callback = callback.take(); match inst_weak.upgrade() { - Some(instance) => match instance.show() { + Some(instance) => match callback(&instance) { Ok(()) => { resolve.call0(&JsValue::UNDEFINED).unwrap_throw(); } @@ -231,7 +267,7 @@ impl WrappedInstance { .call1( &JsValue::UNDEFINED, &JsValue::from(format!( - "Calling show() on ComponentInstance failed: {e}" + "Invocation on ComponentInstance from within event loop failed: {e}" )), ) .unwrap_throw(); @@ -242,7 +278,7 @@ impl WrappedInstance { .call1( &JsValue::UNDEFINED, &JsValue::from(format!( - "Calling show() on ComponentInstance failed because instance was deleted too soon" + "Invocation on ComponentInstance failed because instance was deleted too soon" )), ) .unwrap_throw(); @@ -261,11 +297,6 @@ impl WrappedInstance { } })) } - /// Hides this instance and prevents further updates of the canvas element. - #[wasm_bindgen] - pub fn hide(&self) -> Result<(), JsValue> { - self.0.hide().map_err(|e| -> JsValue { format!("{e}").into() }) - } /// THIS FUNCTION IS NOT PART THE PUBLIC API! /// Highlights instances of the requested component diff --git a/editors/vscode/src/wasm_preview.ts b/editors/vscode/src/wasm_preview.ts index 251bc887a..0c5bbd466 100644 --- a/editors/vscode/src/wasm_preview.ts +++ b/editors/vscode/src/wasm_preview.ts @@ -237,7 +237,7 @@ function getPreviewHtml(slint_wasm_interpreter_url: Uri): string { if (component !== undefined) { document.getElementById("slint_error_div").innerHTML = ""; if (current_instance !== null) { - current_instance = component.create_with_existing_window(current_instance); + current_instance = await component.create_with_existing_window(current_instance); } else { try { slint.run_event_loop(); diff --git a/tools/slintpad/src/lsp.ts b/tools/slintpad/src/lsp.ts index feec0440b..8d49c13dc 100644 --- a/tools/slintpad/src/lsp.ts +++ b/tools/slintpad/src/lsp.ts @@ -120,7 +120,6 @@ class PreviewerBackend { #canvas_id: string | null = null; #instance: slint_preview.WrappedInstance | null = null; #to_highlight: HighlightInfo = { file: "", offset: 0 }; - #is_rendering = false; #picker_mode = false; constructor(client_port: MessagePort, lsp_port: MessagePort) { @@ -142,15 +141,6 @@ class PreviewerBackend { } if (m.data.command === "render") { const port = m.ports[0]; - if (this.#is_rendering) { - port.postMessage({ - type: "Error", - data: "Already rendering", - }); - port.close(); - return; - } - this.#is_rendering = true; this.render( m.data.style, @@ -192,8 +182,7 @@ class PreviewerBackend { .catch((e) => { port.postMessage({ type: "Error", data: e }); port.close(); - }); - this.#is_rendering = false; + }) } } catch (e) { client_port.postMessage({ type: "Error", data: e }); @@ -290,7 +279,7 @@ class PreviewerBackend { this.#instance = await component.create(this.canvas_id!); // eslint-disable-line await this.#instance.show(); } else { - this.#instance = component.create_with_existing_window( + this.#instance = await component.create_with_existing_window( this.#instance, ); this.configure_picker_mode();