Web: Implement MonitorHandle (#3801)
Requires getting permission from the user to get "detailed" support. Also enables users to go fullscreen on specific monitors. Exposes platform-specific orientation API. Most functionality depends on browser support, currently only Chromium.
This commit is contained in:
parent
2e97ab3d4f
commit
a0bc3e5dc8
21 changed files with 1493 additions and 120 deletions
|
|
@ -7,7 +7,7 @@ use smol_str::SmolStr;
|
|||
use wasm_bindgen::closure::Closure;
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::{
|
||||
CssStyleDeclaration, Document, Event, FocusEvent, HtmlCanvasElement, KeyboardEvent,
|
||||
CssStyleDeclaration, Document, Event, FocusEvent, HtmlCanvasElement, KeyboardEvent, Navigator,
|
||||
PointerEvent, WheelEvent,
|
||||
};
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
|
|||
use crate::error::OsError as RootOE;
|
||||
use crate::event::{Force, InnerSizeWriter, MouseButton, MouseScrollDelta};
|
||||
use crate::keyboard::{Key, KeyLocation, ModifiersState, PhysicalKey};
|
||||
use crate::platform_impl::OsError;
|
||||
use crate::platform_impl::{Fullscreen, OsError};
|
||||
use crate::window::{WindowAttributes, WindowId as RootWindowId};
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
|
@ -57,6 +57,7 @@ struct Handlers {
|
|||
|
||||
pub struct Common {
|
||||
pub window: web_sys::Window,
|
||||
navigator: Navigator,
|
||||
pub document: Document,
|
||||
/// Note: resizing the HTMLCanvasElement should go through `backend::set_canvas_size` to ensure
|
||||
/// the DPI factor is maintained. Note: this is read-only because we use a pointer to this
|
||||
|
|
@ -78,6 +79,7 @@ impl Canvas {
|
|||
main_thread: MainThreadMarker,
|
||||
id: WindowId,
|
||||
window: web_sys::Window,
|
||||
navigator: Navigator,
|
||||
document: Document,
|
||||
attr: WindowAttributes,
|
||||
) -> Result<Self, RootOE> {
|
||||
|
|
@ -116,6 +118,7 @@ impl Canvas {
|
|||
let common = Common {
|
||||
window: window.clone(),
|
||||
document: document.clone(),
|
||||
navigator,
|
||||
raw: Rc::new(canvas.clone()),
|
||||
style,
|
||||
old_size: Rc::default(),
|
||||
|
|
@ -142,8 +145,14 @@ impl Canvas {
|
|||
super::set_canvas_position(&common.document, &common.raw, &common.style, position);
|
||||
}
|
||||
|
||||
if attr.fullscreen.is_some() {
|
||||
fullscreen::request_fullscreen(&document, &canvas);
|
||||
if let Some(fullscreen) = attr.fullscreen {
|
||||
fullscreen::request_fullscreen(
|
||||
main_thread,
|
||||
&window,
|
||||
&document,
|
||||
&canvas,
|
||||
fullscreen.into(),
|
||||
);
|
||||
}
|
||||
|
||||
if attr.active {
|
||||
|
|
@ -222,6 +231,11 @@ impl Canvas {
|
|||
&self.common.window
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn navigator(&self) -> &Navigator {
|
||||
&self.common.navigator
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn document(&self) -> &Document {
|
||||
&self.common.document
|
||||
|
|
@ -445,8 +459,14 @@ impl Canvas {
|
|||
}));
|
||||
}
|
||||
|
||||
pub fn request_fullscreen(&self) {
|
||||
fullscreen::request_fullscreen(self.document(), self.raw());
|
||||
pub(crate) fn request_fullscreen(&self, fullscreen: Fullscreen) {
|
||||
fullscreen::request_fullscreen(
|
||||
self.main_thread,
|
||||
self.window(),
|
||||
self.document(),
|
||||
self.raw(),
|
||||
fullscreen,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn exit_fullscreen(&self) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use dpi::{LogicalPosition, PhysicalPosition, Position};
|
|||
use smol_str::SmolStr;
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::{KeyboardEvent, MouseEvent, PointerEvent, WheelEvent};
|
||||
use web_sys::{KeyboardEvent, MouseEvent, Navigator, PointerEvent, WheelEvent};
|
||||
|
||||
use super::Engine;
|
||||
use crate::event::{MouseButton, MouseScrollDelta};
|
||||
|
|
@ -108,8 +108,8 @@ pub enum MouseDelta {
|
|||
}
|
||||
|
||||
impl MouseDelta {
|
||||
pub fn init(window: &web_sys::Window, event: &PointerEvent) -> Self {
|
||||
match super::engine(window) {
|
||||
pub fn init(navigator: &Navigator, event: &PointerEvent) -> Self {
|
||||
match super::engine(navigator) {
|
||||
Some(Engine::Chromium) => Self::Chromium,
|
||||
// Firefox has wrong movement values in coalesced events.
|
||||
Some(Engine::Gecko) if has_coalesced_events_support(event) => Self::Gecko {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,23 @@
|
|||
use std::cell::OnceCell;
|
||||
|
||||
use js_sys::Promise;
|
||||
use js_sys::{Object, Promise};
|
||||
use tracing::error;
|
||||
use wasm_bindgen::closure::Closure;
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::{Document, Element, HtmlCanvasElement};
|
||||
use web_sys::{console, Document, Element, HtmlCanvasElement, Window};
|
||||
|
||||
pub fn request_fullscreen(document: &Document, canvas: &HtmlCanvasElement) {
|
||||
if is_fullscreen(document, canvas) {
|
||||
return;
|
||||
}
|
||||
use super::super::main_thread::MainThreadMarker;
|
||||
use super::super::monitor::{self, ScreenDetailed};
|
||||
use crate::platform_impl::Fullscreen;
|
||||
|
||||
pub(crate) fn request_fullscreen(
|
||||
main_thread: MainThreadMarker,
|
||||
window: &Window,
|
||||
document: &Document,
|
||||
canvas: &HtmlCanvasElement,
|
||||
fullscreen: Fullscreen,
|
||||
) {
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(extends = HtmlCanvasElement)]
|
||||
|
|
@ -19,21 +26,66 @@ pub fn request_fullscreen(document: &Document, canvas: &HtmlCanvasElement) {
|
|||
#[wasm_bindgen(method, js_name = requestFullscreen)]
|
||||
fn request_fullscreen(this: &RequestFullscreen) -> Promise;
|
||||
|
||||
#[wasm_bindgen(method, js_name = requestFullscreen)]
|
||||
fn request_fullscreen_with_options(
|
||||
this: &RequestFullscreen,
|
||||
options: &FullscreenOptions,
|
||||
) -> Promise;
|
||||
|
||||
#[wasm_bindgen(method, js_name = webkitRequestFullscreen)]
|
||||
fn webkit_request_fullscreen(this: &RequestFullscreen);
|
||||
|
||||
type FullscreenOptions;
|
||||
|
||||
#[wasm_bindgen(method, setter, js_name = screen)]
|
||||
fn set_screen(this: &FullscreenOptions, screen: &ScreenDetailed);
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static REJECT_HANDLER: Closure<dyn FnMut(JsValue)> = Closure::new(|error| {
|
||||
console::error_1(&error);
|
||||
error!("Failed to transition to full screen mode")
|
||||
});
|
||||
}
|
||||
|
||||
if is_fullscreen(document, canvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
let canvas: &RequestFullscreen = canvas.unchecked_ref();
|
||||
|
||||
if has_fullscreen_api_support(canvas) {
|
||||
thread_local! {
|
||||
static REJECT_HANDLER: Closure<dyn FnMut(JsValue)> = Closure::new(|_| ());
|
||||
}
|
||||
REJECT_HANDLER.with(|handler| {
|
||||
let _ = canvas.request_fullscreen().catch(handler);
|
||||
});
|
||||
} else {
|
||||
canvas.webkit_request_fullscreen();
|
||||
match fullscreen {
|
||||
Fullscreen::Exclusive(_) => error!("Exclusive full screen mode is not supported"),
|
||||
Fullscreen::Borderless(Some(monitor)) => {
|
||||
if !monitor::has_screen_details_support(window) {
|
||||
error!(
|
||||
"Fullscreen mode selecting a specific screen is not supported by this browser"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(monitor) = monitor.detailed(main_thread) {
|
||||
let options: FullscreenOptions = Object::new().unchecked_into();
|
||||
options.set_screen(&monitor);
|
||||
REJECT_HANDLER.with(|handler| {
|
||||
let _ = canvas.request_fullscreen_with_options(&options).catch(handler);
|
||||
});
|
||||
} else {
|
||||
error!(
|
||||
"Selecting a specific screen for fullscreen mode requires a detailed screen. \
|
||||
See `MonitorHandleExtWeb::is_detailed()`."
|
||||
)
|
||||
}
|
||||
},
|
||||
Fullscreen::Borderless(None) => {
|
||||
if has_fullscreen_api_support(canvas) {
|
||||
REJECT_HANDLER.with(|handler| {
|
||||
let _ = canvas.request_fullscreen().catch(handler);
|
||||
});
|
||||
} else {
|
||||
canvas.webkit_request_fullscreen();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,7 @@ use js_sys::Array;
|
|||
use wasm_bindgen::closure::Closure;
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::{
|
||||
Document, HtmlCanvasElement, Navigator, PageTransitionEvent, VisibilityState, Window,
|
||||
};
|
||||
use web_sys::{Document, HtmlCanvasElement, Navigator, PageTransitionEvent, VisibilityState};
|
||||
|
||||
pub use self::canvas::{Canvas, Style};
|
||||
pub use self::event::ButtonsState;
|
||||
|
|
@ -182,15 +180,15 @@ thread_local! {
|
|||
static USER_AGENT_DATA: OnceCell<UserAgentData> = const { OnceCell::new() };
|
||||
}
|
||||
|
||||
pub fn chrome_linux(window: &Window) -> bool {
|
||||
USER_AGENT_DATA.with(|data| data.get_or_init(|| user_agent(window)).chrome_linux)
|
||||
pub fn chrome_linux(navigator: &Navigator) -> bool {
|
||||
USER_AGENT_DATA.with(|data| data.get_or_init(|| user_agent(navigator)).chrome_linux)
|
||||
}
|
||||
|
||||
pub fn engine(window: &Window) -> Option<Engine> {
|
||||
USER_AGENT_DATA.with(|data| data.get_or_init(|| user_agent(window)).engine)
|
||||
pub fn engine(navigator: &Navigator) -> Option<Engine> {
|
||||
USER_AGENT_DATA.with(|data| data.get_or_init(|| user_agent(navigator)).engine)
|
||||
}
|
||||
|
||||
fn user_agent(window: &Window) -> UserAgentData {
|
||||
fn user_agent(navigator: &Navigator) -> UserAgentData {
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(extends = Navigator)]
|
||||
|
|
@ -213,7 +211,7 @@ fn user_agent(window: &Window) -> UserAgentData {
|
|||
fn brand(this: &NavigatorUaBrandVersion) -> String;
|
||||
}
|
||||
|
||||
let navigator: NavigatorExt = window.navigator().unchecked_into();
|
||||
let navigator: &NavigatorExt = navigator.unchecked_ref();
|
||||
|
||||
if let Some(data) = navigator.user_agent_data() {
|
||||
let engine = 'engine: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue