On Web, implement Send and Sync where appropriate (#2834)

This commit is contained in:
daxpedda 2023-06-05 02:44:54 +02:00 committed by GitHub
parent eb2d3894ef
commit 8f7f3efc0d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 609 additions and 196 deletions

View file

@ -8,22 +8,31 @@ use crate::window::{
};
use raw_window_handle::{RawDisplayHandle, RawWindowHandle, WebDisplayHandle, WebWindowHandle};
use web_sys::HtmlCanvasElement;
use super::r#async::Dispatcher;
use super::{backend, monitor::MonitorHandle, EventLoopWindowTarget, Fullscreen};
use std::cell::{Cell, Ref, RefCell};
use std::cell::RefCell;
use std::collections::vec_deque::IntoIter as VecDequeIter;
use std::collections::VecDeque;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
pub struct Window {
id: WindowId,
has_focus: Arc<AtomicBool>,
pub inner: Dispatcher<Inner>,
}
pub struct Inner {
pub window: web_sys::Window,
canvas: Rc<RefCell<backend::Canvas>>,
previous_pointer: RefCell<&'static str>,
id: WindowId,
register_redraw_request: Box<dyn Fn()>,
resize_notify_fn: Box<dyn Fn(PhysicalSize<u32>)>,
destroy_fn: Option<Box<dyn FnOnce()>>,
has_focus: Rc<Cell<bool>>,
}
impl Window {
@ -38,12 +47,13 @@ impl Window {
let prevent_default = platform_attr.prevent_default;
let canvas = backend::Canvas::create(platform_attr)?;
let window = target.runner.window();
let canvas = backend::Canvas::create(window.clone(), platform_attr)?;
let canvas = Rc::new(RefCell::new(canvas));
let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id)));
let has_focus = Rc::new(Cell::new(false));
let has_focus = Arc::new(AtomicBool::new(false));
target.register(&canvas, id, prevent_default, has_focus.clone());
let runner = target.runner.clone();
@ -57,23 +67,29 @@ impl Window {
let runner = target.runner.clone();
let destroy_fn = Box::new(move || runner.notify_destroy_window(RootWI(id)));
let window = Window {
canvas,
previous_pointer: RefCell::new("auto"),
id,
register_redraw_request,
resize_notify_fn,
destroy_fn: Some(destroy_fn),
has_focus,
};
backend::set_canvas_size(
window.canvas.borrow().raw(),
window,
canvas.borrow().raw(),
attr.inner_size.unwrap_or(Size::Logical(LogicalSize {
width: 1024.0,
height: 768.0,
})),
);
let window = Window {
id,
has_focus,
inner: Dispatcher::new(Inner {
window: window.clone(),
canvas,
previous_pointer: RefCell::new("auto"),
register_redraw_request,
resize_notify_fn,
destroy_fn: Some(destroy_fn),
})
.unwrap(),
};
window.set_title(&attr.title);
window.set_maximized(attr.maximized);
window.set_visible(attr.visible);
@ -82,12 +98,20 @@ impl Window {
Ok(window)
}
pub fn canvas(&self) -> Ref<'_, backend::Canvas> {
self.canvas.borrow()
pub fn canvas(&self) -> Option<HtmlCanvasElement> {
self.inner.with(|inner| inner.canvas.borrow().raw().clone())
}
pub fn set_title(&self, title: &str) {
self.canvas.borrow().set_attribute("alt", title);
if self
.inner
.with(|inner| inner.canvas.borrow().set_attribute("alt", title))
.is_none()
{
let title = title.to_owned();
self.inner
.dispatch(move |inner| inner.canvas.borrow().set_attribute("alt", &title));
}
}
pub fn set_transparent(&self, _transparent: bool) {}
@ -102,15 +126,18 @@ impl Window {
}
pub fn request_redraw(&self) {
(self.register_redraw_request)();
self.inner
.dispatch(|inner| (inner.register_redraw_request)());
}
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
Ok(self
.canvas
.borrow()
.position()
.to_physical(self.scale_factor()))
self.inner.queue(|inner| {
Ok(inner
.canvas
.borrow()
.position()
.to_physical(inner.scale_factor()))
})
}
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
@ -119,17 +146,19 @@ impl Window {
}
pub fn set_outer_position(&self, position: Position) {
let position = position.to_logical::<f64>(self.scale_factor());
self.inner.dispatch(move |inner| {
let position = position.to_logical::<f64>(inner.scale_factor());
let canvas = self.canvas.borrow();
canvas.set_attribute("position", "fixed");
canvas.set_attribute("left", &position.x.to_string());
canvas.set_attribute("top", &position.y.to_string());
let canvas = inner.canvas.borrow();
canvas.set_attribute("position", "fixed");
canvas.set_attribute("left", &position.x.to_string());
canvas.set_attribute("top", &position.y.to_string());
});
}
#[inline]
pub fn inner_size(&self) -> PhysicalSize<u32> {
self.canvas.borrow().size()
self.inner.queue(|inner| inner.inner_size())
}
#[inline]
@ -140,12 +169,14 @@ impl Window {
#[inline]
pub fn set_inner_size(&self, size: Size) {
let old_size = self.inner_size();
backend::set_canvas_size(self.canvas.borrow().raw(), size);
let new_size = self.inner_size();
if old_size != new_size {
(self.resize_notify_fn)(new_size);
}
self.inner.dispatch(move |inner| {
let old_size = inner.inner_size();
backend::set_canvas_size(&inner.window, inner.canvas.borrow().raw(), size);
let new_size = inner.inner_size();
if old_size != new_size {
(inner.resize_notify_fn)(new_size);
}
});
}
#[inline]
@ -187,13 +218,19 @@ impl Window {
#[inline]
pub fn scale_factor(&self) -> f64 {
super::backend::scale_factor()
self.inner.queue(|inner| inner.scale_factor())
}
#[inline]
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
*self.previous_pointer.borrow_mut() = cursor.name();
backend::set_canvas_style_property(self.canvas.borrow().raw(), "cursor", cursor.name());
self.inner.dispatch(move |inner| {
*inner.previous_pointer.borrow_mut() = cursor.name();
backend::set_canvas_style_property(
inner.canvas.borrow().raw(),
"cursor",
cursor.name(),
);
});
}
#[inline]
@ -203,29 +240,35 @@ impl Window {
#[inline]
pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
let lock = match mode {
CursorGrabMode::None => false,
CursorGrabMode::Locked => true,
CursorGrabMode::Confined => {
return Err(ExternalError::NotSupported(NotSupportedError::new()))
}
};
self.inner.queue(move |inner| {
let lock = match mode {
CursorGrabMode::None => false,
CursorGrabMode::Locked => true,
CursorGrabMode::Confined => {
return Err(ExternalError::NotSupported(NotSupportedError::new()))
}
};
self.canvas
.borrow()
.set_cursor_lock(lock)
.map_err(ExternalError::Os)
inner
.canvas
.borrow()
.set_cursor_lock(lock)
.map_err(ExternalError::Os)
})
}
#[inline]
pub fn set_cursor_visible(&self, visible: bool) {
if !visible {
self.canvas.borrow().set_attribute("cursor", "none");
} else {
self.canvas
.borrow()
.set_attribute("cursor", &self.previous_pointer.borrow());
}
self.inner.dispatch(move |inner| {
if !visible {
inner.canvas.borrow().set_attribute("cursor", "none");
} else {
inner
.canvas
.borrow()
.set_attribute("cursor", &inner.previous_pointer.borrow());
}
});
}
#[inline]
@ -267,20 +310,24 @@ impl Window {
#[inline]
pub(crate) fn fullscreen(&self) -> Option<Fullscreen> {
if self.canvas.borrow().is_fullscreen() {
Some(Fullscreen::Borderless(Some(self.current_monitor_inner())))
} else {
None
}
self.inner.queue(|inner| {
if inner.canvas.borrow().is_fullscreen() {
Some(Fullscreen::Borderless(Some(MonitorHandle)))
} else {
None
}
})
}
#[inline]
pub(crate) fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
if fullscreen.is_some() {
self.canvas.borrow().request_fullscreen();
} else if self.canvas.borrow().is_fullscreen() {
backend::exit_fullscreen();
}
self.inner.dispatch(move |inner| {
if fullscreen.is_some() {
inner.canvas.borrow().request_fullscreen();
} else if inner.canvas.borrow().is_fullscreen() {
backend::exit_fullscreen(&inner.window);
}
});
}
#[inline]
@ -327,15 +374,9 @@ impl Window {
// Currently an intentional no-op
}
#[inline]
// Allow directly accessing the current monitor internally without unwrapping.
fn current_monitor_inner(&self) -> MonitorHandle {
MonitorHandle
}
#[inline]
pub fn current_monitor(&self) -> Option<MonitorHandle> {
Some(self.current_monitor_inner())
Some(MonitorHandle)
}
#[inline]
@ -370,25 +411,20 @@ impl Window {
#[inline]
pub fn theme(&self) -> Option<Theme> {
web_sys::window()
.and_then(|window| {
window
.match_media("(prefers-color-scheme: dark)")
.ok()
.flatten()
})
.map(|media_query_list| {
if media_query_list.matches() {
self.inner.queue(|inner| {
backend::is_dark_mode(&inner.window).map(|is_dark_mode| {
if is_dark_mode {
Theme::Dark
} else {
Theme::Light
}
})
})
}
#[inline]
pub fn has_focus(&self) -> bool {
self.has_focus.get()
self.has_focus.load(Ordering::Relaxed)
}
pub fn title(&self) -> String {
@ -402,9 +438,23 @@ impl Window {
impl Drop for Window {
fn drop(&mut self) {
if let Some(destroy_fn) = self.destroy_fn.take() {
destroy_fn();
}
self.inner.dispatch_mut(|inner| {
if let Some(destroy_fn) = inner.destroy_fn.take() {
destroy_fn();
}
});
}
}
impl Inner {
#[inline]
pub fn scale_factor(&self) -> f64 {
super::backend::scale_factor(&self.window)
}
#[inline]
pub fn inner_size(&self) -> PhysicalSize<u32> {
self.canvas.borrow().size()
}
}