diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dd8f6dd..91d23a38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,8 @@ And please only add new entries to the top of this list, right below the `# Unre - On Web, the canvas output bitmap size is no longer adjusted. - On Web: fix `Window::request_redraw` not waking the event loop when called from outside the loop. - On Web: fix position of touch events to be relative to the canvas. +- On Web, fix `Window:::set_fullscreen` doing nothing when called outside the event loop but during + a transient activation. # 0.28.6 diff --git a/Cargo.toml b/Cargo.toml index bd36953f..8f66bd06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -156,8 +156,10 @@ features = [ 'WheelEvent' ] -[target.'cfg(target_family = "wasm")'.dependencies.wasm-bindgen] -version = "0.2.45" +[target.'cfg(target_family = "wasm")'.dependencies] +js-sys = "0.3" +wasm-bindgen = "0.2.45" +wasm-bindgen-futures = "0.4" [target.'cfg(target_family = "wasm")'.dev-dependencies] console_log = "0.2" diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index 89a2935a..513561fc 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -10,8 +10,11 @@ use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes}; use std::cell::RefCell; use std::rc::Rc; +use js_sys::Promise; use smol_str::SmolStr; -use wasm_bindgen::{closure::Closure, JsCast}; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::{closure::Closure, JsCast, JsValue}; +use wasm_bindgen_futures::JsFuture; use web_sys::{ AddEventListenerOptions, Event, FocusEvent, HtmlCanvasElement, KeyboardEvent, MediaQueryListEvent, MouseEvent, WheelEvent, @@ -439,7 +442,30 @@ impl Common { } pub fn request_fullscreen(&self) { - *self.wants_fullscreen.borrow_mut() = true; + #[wasm_bindgen] + extern "C" { + type ElementExt; + + #[wasm_bindgen(catch, method, js_name = requestFullscreen)] + fn request_fullscreen(this: &ElementExt) -> Result; + } + + let raw: &ElementExt = self.raw.unchecked_ref(); + + // This should return a `Promise`, but Safari v<16.4 is not up-to-date with the spec. + match raw.request_fullscreen() { + Ok(value) if !value.is_undefined() => { + let promise: Promise = value.unchecked_into(); + let wants_fullscreen = self.wants_fullscreen.clone(); + wasm_bindgen_futures::spawn_local(async move { + if JsFuture::from(promise).await.is_err() { + *wants_fullscreen.borrow_mut() = true + } + }); + } + // We are on Safari v<16.4, let's try again on the next transient activation. + _ => *self.wants_fullscreen.borrow_mut() = true, + } } pub fn is_fullscreen(&self) -> bool { diff --git a/src/window.rs b/src/window.rs index f7694bae..a3e49654 100644 --- a/src/window.rs +++ b/src/window.rs @@ -941,6 +941,10 @@ impl Window { /// - **Wayland:** Does not support exclusive fullscreen mode and will no-op a request. /// - **Windows:** Screen saver is disabled in fullscreen mode. /// - **Android / Orbital:** Unsupported. + /// - **Web:** Does nothing without a [transient activation], but queues the request + /// for the next activation. + /// + /// [transient activation]: https://developer.mozilla.org/en-US/docs/Glossary/Transient_activation #[inline] pub fn set_fullscreen(&self, fullscreen: Option) { self.window.set_fullscreen(fullscreen.map(|f| f.into()))