Skip to content

Commit

Permalink
Fix the slide_puzzle canvas size on wasm
Browse files Browse the repository at this point in the history
Since winit can't handle resize from the CSS or JS, work it around in
the demo by calling set_size on the slint window.

Also fix slint_size panicking not working on wasm as the map_state was
mutably borrowed by the set_size, and this may recurse into other
functions (eg, draw) causing a panic. So don't keep the state borrowed
when calling winit.

Another fix is fixing the initialization size of the window item when
the initial size is set with set_size

Fixes slint-ui#547
  • Loading branch information
ogoffart committed Mar 29, 2023
1 parent c00afe5 commit e8f2103
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 27 deletions.
2 changes: 1 addition & 1 deletion examples/slide_puzzle/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ slint-build = { path = "../../api/rs/build" }

#wasm# [target.'cfg(target_arch = "wasm32")'.dependencies]
#wasm# wasm-bindgen = { version = "0.2" }
#wasm# web-sys = { version = "0.3", features=["console"] }
#wasm# web-sys = { version = "0.3", features=["console", "Element", "HtmlCollection"] }
#wasm# console_error_panic_hook = "0.1.5"
#wasm# getrandom = { version = "0.2.2", features = ["js"] }
44 changes: 44 additions & 0 deletions examples/slide_puzzle/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ pub fn main() {
console_error_panic_hook::set_once();

let main_window = MainWindow::new().unwrap();

#[cfg(target_arch = "wasm32")]
handle_resize(main_window.as_weak());

let state = Rc::new(RefCell::new(AppState {
pieces: Rc::new(slint::VecModel::<Piece>::from(vec![Piece::default(); 15])),
main_window: main_window.as_weak(),
Expand Down Expand Up @@ -231,3 +235,43 @@ pub fn main() {
});
main_window.run().unwrap();
}

#[cfg(target_arch = "wasm32")]
/// winit doesn't handle the resizing of the canvas from CSS well
/// https://github.com/rust-windowing/winit/issues/1661
/// in the mean time, adjust the size manually
fn handle_resize(slint_window: slint::Weak<MainWindow>) -> Option<()> {
let window = web_sys::window()?;
let resize_handler = move || {
let window = web_sys::window()?;
let doc = window.document()?;

let container = doc.get_element_by_id("container")?;
let children = container.children();
let mut height_sum = 0.;
for i in 0..children.length() {
let child = children.item(i).unwrap();
if child.tag_name().to_lowercase() == "canvas" {
continue;
}
let style = window.get_computed_style(&child).ok()?;
let get_margin = |m| {
style.as_ref()?.get_property_value(m).ok()?.strip_suffix("px")?.parse::<f32>().ok()
};
height_sum += child.scroll_height() as f32
+ get_margin("margin-top").unwrap_or(0.)
+ get_margin("margin-bottom").unwrap_or(0.)
+ 1.;
}

let width = doc.body()?.client_width() as f32;
let height = doc.body()?.client_height() as f32 - height_sum;
slint_window.upgrade()?.window().set_size(slint::LogicalSize { width, height });
Some(())
};
resize_handler();
let closure = Closure::wrap(Box::new(move || drop(resize_handler())) as Box<dyn FnMut()>);
window.set_onresize(Some(closure.as_ref().unchecked_ref()));
closure.forget();
Some(())
}
47 changes: 21 additions & 26 deletions internal/backends/winit/glwindow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,9 +539,6 @@ impl<Renderer: WinitCompatibleRenderer + 'static> WindowAdapterSealed for GLWind
window_builder.with_inner_size(window_size_to_slint(requested_size))
}
} else if s.width > 0 as Coord && s.height > 0 as Coord {
// Make sure that the window's inner size is in sync with the root window item's
// width/height.
runtime_window.set_window_item_geometry(LogicalSize::new(s.width, s.height));
window_builder.with_inner_size(into_size(s))
} else {
window_builder
Expand All @@ -566,14 +563,12 @@ impl<Renderer: WinitCompatibleRenderer + 'static> WindowAdapterSealed for GLWind
&self_.canvas_id,
)?;

WindowInner::from_pub(&self_.window).set_scale_factor(
scale_factor_override.unwrap_or_else(|| winit_window.scale_factor()) as _,
);
// On wasm, with_inner_size on the WindowBuilder don't have effect, so apply manually
#[cfg(target_arch = "wasm32")]
if s.width > 0 as Coord && s.height > 0 as Coord {
winit_window.set_inner_size(s);
}
let scale_factor = scale_factor_override.unwrap_or_else(|| winit_window.scale_factor());
WindowInner::from_pub(&self_.window).set_scale_factor(scale_factor as _);
let s = winit_window.inner_size().to_logical(scale_factor);
// Make sure that the window's inner size is in sync with the root window item's
// width/height.
runtime_window.set_window_item_geometry(LogicalSize::new(s.width, s.height));
let id = winit_window.id();

self_.map_state.replace(GraphicsWindowBackendState::Mapped(MappedWindow {
Expand Down Expand Up @@ -699,30 +694,30 @@ impl<Renderer: WinitCompatibleRenderer + 'static> WindowAdapterSealed for GLWind
}

fn set_position(&self, position: corelib::api::WindowPosition) {
match &mut *self.map_state.borrow_mut() {
let w = match &mut *self.map_state.borrow_mut() {
GraphicsWindowBackendState::Unmapped { requested_position, .. } => {
*requested_position = Some(position)
}
GraphicsWindowBackendState::Mapped(mapped_window) => {
mapped_window.winit_window.set_outer_position(position_to_winit(&position))
*requested_position = Some(position);
return;
}
}
GraphicsWindowBackendState::Mapped(mapped_window) => mapped_window.winit_window.clone(),
};
w.set_outer_position(position_to_winit(&position))
}

fn set_size(&self, size: corelib::api::WindowSize) {
if self.in_resize_event.get() {
return;
}
if let Ok(mut map_state) = self.map_state.try_borrow_mut() {
match &mut *map_state {
GraphicsWindowBackendState::Unmapped { requested_size, .. } => {
*requested_size = Some(size)
}
GraphicsWindowBackendState::Mapped(mapped_window) => {
mapped_window.winit_window.set_inner_size(window_size_to_slint(&size));
}
let Ok(mut map_state) = self.map_state.try_borrow_mut() else { return };
let w = match &mut *map_state {
GraphicsWindowBackendState::Unmapped { requested_size, .. } => {
*requested_size = Some(size);
return;
}
}
GraphicsWindowBackendState::Mapped(mapped_window) => mapped_window.winit_window.clone(),
};
drop(map_state);
w.set_inner_size(window_size_to_slint(&size))
}

fn dark_color_scheme(&self) -> bool {
Expand Down

0 comments on commit e8f2103

Please sign in to comment.