2019-12-31 14:39:33 -08:00
|
|
|
use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size};
|
2019-06-25 03:15:34 +02:00
|
|
|
use crate::error::{ExternalError, NotSupportedError, OsError as RootOE};
|
2020-09-22 06:19:00 +08:00
|
|
|
use crate::event;
|
2019-06-25 03:15:34 +02:00
|
|
|
use crate::icon::Icon;
|
|
|
|
|
use crate::monitor::MonitorHandle as RootMH;
|
2020-11-27 03:03:08 +01:00
|
|
|
use crate::window::{
|
|
|
|
|
CursorIcon, Fullscreen, UserAttentionType, WindowAttributes, WindowId as RootWI,
|
|
|
|
|
};
|
2019-09-24 19:39:13 -04:00
|
|
|
|
2021-11-30 17:50:23 +01:00
|
|
|
use raw_window_handle::{RawWindowHandle, WebHandle};
|
2019-06-25 03:15:34 +02:00
|
|
|
|
|
|
|
|
use super::{backend, monitor, EventLoopWindowTarget};
|
|
|
|
|
|
2020-09-21 06:42:07 +08:00
|
|
|
use std::cell::{Ref, RefCell};
|
2019-06-25 03:15:34 +02:00
|
|
|
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
|
|
|
|
use std::collections::VecDeque;
|
2020-09-21 06:42:07 +08:00
|
|
|
use std::rc::Rc;
|
2019-06-25 03:15:34 +02:00
|
|
|
|
|
|
|
|
pub struct Window {
|
2020-09-21 06:42:07 +08:00
|
|
|
canvas: Rc<RefCell<backend::Canvas>>,
|
2019-06-25 03:15:34 +02:00
|
|
|
previous_pointer: RefCell<&'static str>,
|
2019-09-19 18:40:18 -04:00
|
|
|
id: Id,
|
2019-09-23 09:14:26 -04:00
|
|
|
register_redraw_request: Box<dyn Fn()>,
|
2020-09-22 06:19:00 +08:00
|
|
|
resize_notify_fn: Box<dyn Fn(PhysicalSize<u32>)>,
|
2020-09-21 06:42:07 +08:00
|
|
|
destroy_fn: Option<Box<dyn FnOnce()>>,
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Window {
|
|
|
|
|
pub fn new<T>(
|
|
|
|
|
target: &EventLoopWindowTarget<T>,
|
|
|
|
|
attr: WindowAttributes,
|
2020-01-15 21:20:14 -05:00
|
|
|
platform_attr: PlatformSpecificBuilderAttributes,
|
2019-06-25 03:15:34 +02:00
|
|
|
) -> Result<Self, RootOE> {
|
2019-06-25 18:39:41 +02:00
|
|
|
let runner = target.runner.clone();
|
2019-06-25 03:15:34 +02:00
|
|
|
|
2019-09-19 18:40:18 -04:00
|
|
|
let id = target.generate_id();
|
|
|
|
|
|
2020-09-21 06:42:07 +08:00
|
|
|
let canvas = backend::Canvas::create(platform_attr)?;
|
|
|
|
|
let mut canvas = Rc::new(RefCell::new(canvas));
|
2019-09-23 09:14:26 -04:00
|
|
|
|
|
|
|
|
let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id)));
|
2019-06-25 03:15:34 +02:00
|
|
|
|
2019-09-19 18:40:18 -04:00
|
|
|
target.register(&mut canvas, id);
|
2019-06-25 03:15:34 +02:00
|
|
|
|
2020-09-22 06:19:00 +08:00
|
|
|
let runner = target.runner.clone();
|
|
|
|
|
let resize_notify_fn = Box::new(move |new_size| {
|
|
|
|
|
runner.send_event(event::Event::WindowEvent {
|
|
|
|
|
window_id: RootWI(id),
|
|
|
|
|
event: event::WindowEvent::Resized(new_size),
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2020-09-21 06:42:07 +08:00
|
|
|
let runner = target.runner.clone();
|
|
|
|
|
let destroy_fn = Box::new(move || runner.notify_destroy_window(RootWI(id)));
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
let window = Window {
|
|
|
|
|
canvas,
|
|
|
|
|
previous_pointer: RefCell::new("auto"),
|
2019-09-19 18:40:18 -04:00
|
|
|
id,
|
2019-09-23 09:14:26 -04:00
|
|
|
register_redraw_request,
|
2020-09-22 06:19:00 +08:00
|
|
|
resize_notify_fn,
|
2020-09-21 06:42:07 +08:00
|
|
|
destroy_fn: Some(destroy_fn),
|
2019-06-25 03:15:34 +02:00
|
|
|
};
|
|
|
|
|
|
2020-09-22 06:19:00 +08:00
|
|
|
backend::set_canvas_size(
|
|
|
|
|
window.canvas.borrow().raw(),
|
|
|
|
|
attr.inner_size.unwrap_or(Size::Logical(LogicalSize {
|
|
|
|
|
width: 1024.0,
|
|
|
|
|
height: 768.0,
|
|
|
|
|
})),
|
|
|
|
|
);
|
2019-06-25 03:15:34 +02:00
|
|
|
window.set_title(&attr.title);
|
|
|
|
|
window.set_maximized(attr.maximized);
|
|
|
|
|
window.set_visible(attr.visible);
|
|
|
|
|
window.set_window_icon(attr.window_icon);
|
|
|
|
|
|
|
|
|
|
Ok(window)
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-21 06:42:07 +08:00
|
|
|
pub fn canvas<'a>(&'a self) -> Ref<'a, backend::Canvas> {
|
|
|
|
|
self.canvas.borrow()
|
2019-06-25 18:07:47 +02:00
|
|
|
}
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
pub fn set_title(&self, title: &str) {
|
2020-09-21 06:42:07 +08:00
|
|
|
self.canvas.borrow().set_attribute("alt", title);
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_visible(&self, _visible: bool) {
|
|
|
|
|
// Intentionally a no-op
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn request_redraw(&self) {
|
2019-09-23 09:14:26 -04:00
|
|
|
(self.register_redraw_request)();
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:39:33 -08:00
|
|
|
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
|
2020-09-21 06:42:07 +08:00
|
|
|
Ok(self
|
|
|
|
|
.canvas
|
|
|
|
|
.borrow()
|
|
|
|
|
.position()
|
|
|
|
|
.to_physical(self.scale_factor()))
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:39:33 -08:00
|
|
|
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
|
|
|
|
|
// Note: the canvas element has no window decorations, so this is equal to `outer_position`.
|
|
|
|
|
self.outer_position()
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:39:33 -08:00
|
|
|
pub fn set_outer_position(&self, position: Position) {
|
2020-01-03 14:52:27 -05:00
|
|
|
let position = position.to_logical::<f64>(self.scale_factor());
|
2019-06-25 03:15:34 +02:00
|
|
|
|
2020-09-21 06:42:07 +08:00
|
|
|
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());
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-12-31 14:39:33 -08:00
|
|
|
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
2020-09-21 06:42:07 +08:00
|
|
|
self.canvas.borrow().size()
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-12-31 14:39:33 -08:00
|
|
|
pub fn outer_size(&self) -> PhysicalSize<u32> {
|
|
|
|
|
// Note: the canvas element has no window decorations, so this is equal to `inner_size`.
|
|
|
|
|
self.inner_size()
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-12-31 14:39:33 -08:00
|
|
|
pub fn set_inner_size(&self, size: Size) {
|
2020-09-22 06:19:00 +08:00
|
|
|
let old_size = self.inner_size();
|
2020-09-21 06:42:07 +08:00
|
|
|
backend::set_canvas_size(self.canvas.borrow().raw(), size);
|
2020-09-22 06:19:00 +08:00
|
|
|
let new_size = self.inner_size();
|
|
|
|
|
if old_size != new_size {
|
|
|
|
|
(self.resize_notify_fn)(new_size);
|
|
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-12-31 14:39:33 -08:00
|
|
|
pub fn set_min_inner_size(&self, _dimensions: Option<Size>) {
|
2019-06-25 03:15:34 +02:00
|
|
|
// Intentionally a no-op: users can't resize canvas elements
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-12-31 14:39:33 -08:00
|
|
|
pub fn set_max_inner_size(&self, _dimensions: Option<Size>) {
|
2019-06-25 03:15:34 +02:00
|
|
|
// Intentionally a no-op: users can't resize canvas elements
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_resizable(&self, _resizable: bool) {
|
|
|
|
|
// Intentionally a no-op: users can't resize canvas elements
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-03 14:52:27 -05:00
|
|
|
pub fn scale_factor(&self) -> f64 {
|
|
|
|
|
super::backend::scale_factor()
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
|
|
|
|
|
let text = match cursor {
|
|
|
|
|
CursorIcon::Default => "auto",
|
|
|
|
|
CursorIcon::Crosshair => "crosshair",
|
|
|
|
|
CursorIcon::Hand => "pointer",
|
|
|
|
|
CursorIcon::Arrow => "default",
|
|
|
|
|
CursorIcon::Move => "move",
|
|
|
|
|
CursorIcon::Text => "text",
|
|
|
|
|
CursorIcon::Wait => "wait",
|
|
|
|
|
CursorIcon::Help => "help",
|
|
|
|
|
CursorIcon::Progress => "progress",
|
|
|
|
|
|
|
|
|
|
CursorIcon::NotAllowed => "not-allowed",
|
|
|
|
|
CursorIcon::ContextMenu => "context-menu",
|
|
|
|
|
CursorIcon::Cell => "cell",
|
|
|
|
|
CursorIcon::VerticalText => "vertical-text",
|
|
|
|
|
CursorIcon::Alias => "alias",
|
|
|
|
|
CursorIcon::Copy => "copy",
|
|
|
|
|
CursorIcon::NoDrop => "no-drop",
|
|
|
|
|
CursorIcon::Grab => "grab",
|
|
|
|
|
CursorIcon::Grabbing => "grabbing",
|
|
|
|
|
CursorIcon::AllScroll => "all-scroll",
|
|
|
|
|
CursorIcon::ZoomIn => "zoom-in",
|
|
|
|
|
CursorIcon::ZoomOut => "zoom-out",
|
|
|
|
|
|
|
|
|
|
CursorIcon::EResize => "e-resize",
|
|
|
|
|
CursorIcon::NResize => "n-resize",
|
|
|
|
|
CursorIcon::NeResize => "ne-resize",
|
|
|
|
|
CursorIcon::NwResize => "nw-resize",
|
|
|
|
|
CursorIcon::SResize => "s-resize",
|
|
|
|
|
CursorIcon::SeResize => "se-resize",
|
|
|
|
|
CursorIcon::SwResize => "sw-resize",
|
|
|
|
|
CursorIcon::WResize => "w-resize",
|
|
|
|
|
CursorIcon::EwResize => "ew-resize",
|
|
|
|
|
CursorIcon::NsResize => "ns-resize",
|
|
|
|
|
CursorIcon::NeswResize => "nesw-resize",
|
|
|
|
|
CursorIcon::NwseResize => "nwse-resize",
|
|
|
|
|
CursorIcon::ColResize => "col-resize",
|
|
|
|
|
CursorIcon::RowResize => "row-resize",
|
|
|
|
|
};
|
|
|
|
|
*self.previous_pointer.borrow_mut() = text;
|
2020-09-21 06:42:07 +08:00
|
|
|
backend::set_canvas_style_property(self.canvas.borrow().raw(), "cursor", text);
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-12-31 14:39:33 -08:00
|
|
|
pub fn set_cursor_position(&self, _position: Position) -> Result<(), ExternalError> {
|
2020-07-26 21:13:17 +00:00
|
|
|
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_cursor_grab(&self, _grab: bool) -> Result<(), ExternalError> {
|
2020-07-26 21:13:17 +00:00
|
|
|
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_cursor_visible(&self, visible: bool) {
|
|
|
|
|
if !visible {
|
2020-09-21 06:42:07 +08:00
|
|
|
self.canvas.borrow().set_attribute("cursor", "none");
|
2019-06-25 03:15:34 +02:00
|
|
|
} else {
|
|
|
|
|
self.canvas
|
2020-09-21 06:42:07 +08:00
|
|
|
.borrow()
|
2019-06-25 03:15:34 +02:00
|
|
|
.set_attribute("cursor", *self.previous_pointer.borrow());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-07 10:43:23 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub fn drag_window(&self) -> Result<(), ExternalError> {
|
|
|
|
|
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-22 01:04:11 -05:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_minimized(&self, _minimized: bool) {
|
|
|
|
|
// Intentionally a no-op, as canvases cannot be 'minimized'
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_maximized(&self, _maximized: bool) {
|
2019-09-24 19:33:32 -04:00
|
|
|
// Intentionally a no-op, as canvases cannot be 'maximized'
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2021-01-27 20:01:17 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn is_maximized(&self) -> bool {
|
|
|
|
|
// Canvas cannot be 'maximized'
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
#[inline]
|
2019-09-24 19:39:13 -04:00
|
|
|
pub fn fullscreen(&self) -> Option<Fullscreen> {
|
2020-09-21 06:42:07 +08:00
|
|
|
if self.canvas.borrow().is_fullscreen() {
|
2020-09-22 04:54:47 +03:00
|
|
|
Some(Fullscreen::Borderless(Some(self.current_monitor_inner())))
|
2019-10-11 11:45:07 -04:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-10-11 11:45:07 -04:00
|
|
|
pub fn set_fullscreen(&self, monitor: Option<Fullscreen>) {
|
|
|
|
|
if monitor.is_some() {
|
2020-09-21 06:42:07 +08:00
|
|
|
self.canvas.borrow().request_fullscreen();
|
|
|
|
|
} else if self.canvas.borrow().is_fullscreen() {
|
2019-10-11 11:45:07 -04:00
|
|
|
backend::exit_fullscreen();
|
|
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_decorations(&self, _decorations: bool) {
|
|
|
|
|
// Intentionally a no-op, no canvas decorations
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_always_on_top(&self, _always_on_top: bool) {
|
|
|
|
|
// Intentionally a no-op, no window ordering
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_window_icon(&self, _window_icon: Option<Icon>) {
|
|
|
|
|
// Currently an intentional no-op
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-12-31 14:39:33 -08:00
|
|
|
pub fn set_ime_position(&self, _position: Position) {
|
2019-09-24 19:33:32 -04:00
|
|
|
// Currently a no-op as it does not seem there is good support for this on web
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-19 18:39:53 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn focus_window(&self) {
|
|
|
|
|
// Currently a no-op as it does not seem there is good support for this on web
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-27 03:03:08 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub fn request_user_attention(&self, _request_type: Option<UserAttentionType>) {
|
|
|
|
|
// Currently an intentional no-op
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
#[inline]
|
2020-09-07 20:09:24 +03:00
|
|
|
// Allow directly accessing the current monitor internally without unwrapping.
|
|
|
|
|
fn current_monitor_inner(&self) -> RootMH {
|
2019-06-25 03:15:34 +02:00
|
|
|
RootMH {
|
|
|
|
|
inner: monitor::Handle,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-07 20:09:24 +03:00
|
|
|
#[inline]
|
|
|
|
|
pub fn current_monitor(&self) -> Option<RootMH> {
|
|
|
|
|
Some(self.current_monitor_inner())
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn available_monitors(&self) -> VecDequeIter<monitor::Handle> {
|
|
|
|
|
VecDeque::new().into_iter()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-09-07 20:20:47 +03:00
|
|
|
pub fn primary_monitor(&self) -> Option<RootMH> {
|
|
|
|
|
Some(RootMH {
|
|
|
|
|
inner: monitor::Handle,
|
|
|
|
|
})
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn id(&self) -> Id {
|
2019-09-19 18:40:18 -04:00
|
|
|
return self.id;
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
2019-09-24 19:39:13 -04:00
|
|
|
|
|
|
|
|
#[inline]
|
2021-11-30 17:50:23 +01:00
|
|
|
pub fn raw_window_handle(&self) -> RawWindowHandle {
|
|
|
|
|
let mut handle = WebHandle::empty();
|
|
|
|
|
handle.id = self.id.0;
|
|
|
|
|
RawWindowHandle::Web(handle)
|
2019-09-24 19:39:13 -04:00
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-21 06:42:07 +08:00
|
|
|
impl Drop for Window {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
if let Some(destroy_fn) = self.destroy_fn.take() {
|
|
|
|
|
destroy_fn();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
2019-09-19 18:40:18 -04:00
|
|
|
pub struct Id(pub(crate) u32);
|
2019-06-25 03:15:34 +02:00
|
|
|
|
|
|
|
|
impl Id {
|
2021-08-30 19:40:02 +02:00
|
|
|
pub const unsafe fn dummy() -> Id {
|
2019-09-19 18:40:18 -04:00
|
|
|
Id(0)
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-15 21:20:14 -05:00
|
|
|
#[derive(Default, Clone)]
|
|
|
|
|
pub struct PlatformSpecificBuilderAttributes {
|
|
|
|
|
pub(crate) canvas: Option<backend::RawCanvasType>,
|
|
|
|
|
}
|