mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 18:58:36 +00:00
Fix delayed docs preview not working
After commit7df902b53c
, the winit window is not created when calling show() anymore but it's now created at component creation time. That means the event loop workaround removed in459f810bd8
is now needed at construction time. Since this is a winit and wasm specific issue, it's now dealt with in the wasm interpreter implementation, by invoking the creation from the event loop from there and returning a promise in the API. This changes the API therefore: create() can only be called after the event loop is running.
This commit is contained in:
parent
c428601370
commit
a8fcb5acd6
8 changed files with 65 additions and 13 deletions
|
@ -94,6 +94,7 @@ rust-version = "1.66"
|
|||
resvg = { version= "0.32.0", default-features = false, features = ["text"] }
|
||||
fontdb = { version = "0.13.1", default-features = false }
|
||||
yeslogic-fontconfig-sys = { version = "3.2.0", features = ["dlopen"] }
|
||||
send_wrapper = { version = "0.6.0" }
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
|
@ -20,6 +20,7 @@ highlight = ["slint-interpreter/highlight"]
|
|||
|
||||
[dependencies]
|
||||
slint-interpreter = { path = "../../internal/interpreter", default-features = false, features = ["std", "backend-winit", "renderer-winit-femtovg", "compat-1-0"] }
|
||||
send_wrapper = { workspace = true }
|
||||
|
||||
vtable = { version = "0.1.6", path="../../helper_crates/vtable" }
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ extern "C" {
|
|||
|
||||
#[wasm_bindgen(typescript_type = "CurrentElementInformationCallbackFunction")]
|
||||
pub type CurrentElementInformationCallbackFunction;
|
||||
#[wasm_bindgen(typescript_type = "Promise<WrappedInstance>")]
|
||||
pub type InstancePromise;
|
||||
}
|
||||
|
||||
/// Compile the content of a string.
|
||||
|
@ -155,14 +157,35 @@ impl WrappedCompiledComp {
|
|||
let component = self.0.create_with_canvas_id(&canvas_id).unwrap();
|
||||
component.run().unwrap();
|
||||
}
|
||||
/// Creates this compiled component in a canvas.
|
||||
/// Creates this compiled component in a canvas, wrapped in a promise.
|
||||
/// The HTML must contains a <canvas> element with the given `canvas_id`
|
||||
/// where the result is gonna be rendered.
|
||||
/// You need to call `show()` on the returned instance for rendering and
|
||||
/// `slint.run_event_loop()` loop to make it interactive.
|
||||
/// You need to call `show()` on the returned instance for rendering.
|
||||
///
|
||||
/// Note that the promise will only be resolved after calling `slint.run_event_loop()`.
|
||||
#[wasm_bindgen]
|
||||
pub fn create(&self, canvas_id: String) -> Result<WrappedInstance, JsValue> {
|
||||
Ok(WrappedInstance(self.0.create_with_canvas_id(&canvas_id).unwrap()))
|
||||
pub fn create(&self, canvas_id: String) -> Result<InstancePromise, JsValue> {
|
||||
Ok(JsValue::from(js_sys::Promise::new(&mut |resolve, reject| {
|
||||
let comp = send_wrapper::SendWrapper::new(self.0.clone());
|
||||
let canvas_id = canvas_id.clone();
|
||||
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_canvas_id(&canvas_id).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::<InstancePromise>())
|
||||
|
||||
//Ok()
|
||||
}
|
||||
/// Creates this compiled component in the canvas of the provided instance.
|
||||
/// For this to work, the provided instance needs to be visible (show() must've been
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
div.innerHTML = "<pre style='color: red; background-color:#fee; margin:0'>" + p.innerHTML + "</pre>";
|
||||
}
|
||||
if (component !== undefined) {
|
||||
let instance = component.create(canvas_id);
|
||||
let instance = await component.create(canvas_id);
|
||||
instance.show();
|
||||
all_instances.push(instance);
|
||||
}
|
||||
|
@ -81,13 +81,23 @@
|
|||
|
||||
async function run() {
|
||||
await slint.default();
|
||||
|
||||
try {
|
||||
slint.run_event_loop();
|
||||
// this will trigger a JS exception, so this line will never be reached!
|
||||
} catch (e) {
|
||||
// The winit event loop, when targeting wasm, throws a JavaScript exception to break out of
|
||||
// Rust without running any destructors. Don't rethrow the exception but swallow it, as
|
||||
// this is no error and we truly want to resolve the promise of this function by returning
|
||||
// the model markers.
|
||||
}
|
||||
|
||||
let selector = ["code.language-slint", ".rustdoc pre.language-slint", "div.highlight-slint div.highlight", "div.highlight-slint\\,no-auto-preview div.highlight"]
|
||||
.map((sel) => `${sel}:not([class*=slint\\,ignore]):not([class*=slint\\,no-preview])`).join(",");
|
||||
var elements = document.querySelectorAll(selector);
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
await create_click_to_play_and_edit_buttons(elements[i]);
|
||||
}
|
||||
slint.run_event_loop();
|
||||
}
|
||||
run();
|
||||
|
||||
|
|
|
@ -239,9 +239,13 @@ function getPreviewHtml(slint_wasm_interpreter_url: Uri): string {
|
|||
if (current_instance !== null) {
|
||||
current_instance = component.create_with_existing_window(current_instance);
|
||||
} else {
|
||||
current_instance = component.create("slint_canvas");
|
||||
try {
|
||||
slint.run_event_loop();
|
||||
} catch (e) {
|
||||
// ignore winit event loop exception
|
||||
}
|
||||
current_instance = await component.create("slint_canvas");
|
||||
current_instance.show();
|
||||
slint.run_event_loop();
|
||||
}
|
||||
current_instance?.set_design_mode(design_mode);
|
||||
current_instance?.on_element_selected(element_selected);
|
||||
|
@ -354,7 +358,7 @@ function initPreviewPanel(
|
|||
);
|
||||
const outside_uri = Uri.parse(
|
||||
uriMapping.get(d.url) ??
|
||||
Uri.file(inside_uri.fsPath).toString(),
|
||||
Uri.file(inside_uri.fsPath).toString(),
|
||||
);
|
||||
if (outside_uri.scheme !== "invalid") {
|
||||
vscode.window.showTextDocument(outside_uri, {
|
||||
|
|
|
@ -64,7 +64,7 @@ rgb = { version = "0.8.27", optional = true }
|
|||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
web-sys = { version = "0.3", features=["HtmlInputElement", "HtmlCanvasElement", "Window", "Document", "Event", "KeyboardEvent", "InputEvent", "CompositionEvent", "DomStringMap", "ClipboardEvent", "DataTransfer"] }
|
||||
wasm-bindgen = { version = "0.2" }
|
||||
send_wrapper = "0.6.0"
|
||||
send_wrapper = { workspace = true }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
glutin = { version = "0.30", optional = true, default-features = false, features = ["egl", "wgl"] }
|
||||
|
|
|
@ -746,6 +746,19 @@ pub enum EventLoopError {
|
|||
NoEventLoopProvider,
|
||||
}
|
||||
|
||||
impl core::fmt::Display for EventLoopError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
EventLoopError::EventLoopTerminated => {
|
||||
f.write_str("The event loop was already terminated")
|
||||
}
|
||||
EventLoopError::NoEventLoopProvider => {
|
||||
f.write_str("The Slint platform do not provide an event loop")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The platform encountered a fatal error.
|
||||
///
|
||||
/// This error typically indicates an issue with initialization or connecting to the windowing system.
|
||||
|
|
|
@ -275,8 +275,6 @@ class PreviewerBackend {
|
|||
// It's not enough for the canvas element to exist, in order to extract a webgl rendering
|
||||
// context, the element needs to be attached to the window's dom.
|
||||
if (this.#instance == null) {
|
||||
this.#instance = component.create(this.canvas_id!); // eslint-disable-line
|
||||
this.#instance.show();
|
||||
try {
|
||||
if (!is_event_loop_running) {
|
||||
slint_preview.run_event_loop();
|
||||
|
@ -289,6 +287,8 @@ class PreviewerBackend {
|
|||
// the model markers.
|
||||
is_event_loop_running = true; // Assume the winit caused the exception and that the event loop is up now
|
||||
}
|
||||
this.#instance = await component.create(this.canvas_id!); // eslint-disable-line
|
||||
this.#instance.show();
|
||||
} else {
|
||||
this.#instance = component.create_with_existing_window(
|
||||
this.#instance,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue