Draft web platform structure

This commit is contained in:
Héctor Ramón Jiménez 2019-06-25 03:15:34 +02:00
parent eea9530f38
commit c5703eb00a
26 changed files with 1171 additions and 153 deletions

View file

@ -0,0 +1,8 @@
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Id(pub i32);
impl Id {
pub unsafe fn dummy() -> Self {
Id(0)
}
}

View file

@ -0,0 +1,10 @@
use std::fmt;
#[derive(Debug)]
pub struct OsError(pub String);
impl fmt::Display for OsError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}

View file

@ -0,0 +1,112 @@
mod proxy;
mod runner;
mod state;
mod window_target;
pub use self::proxy::Proxy;
pub use self::window_target::WindowTarget;
use super::{backend, device, monitor, window};
use crate::event::{DeviceId, ElementState, Event, KeyboardInput, WindowEvent};
use crate::event_loop as root;
use crate::window::WindowId;
use std::collections::{vec_deque::IntoIter as VecDequeIter, VecDeque};
use std::marker::PhantomData;
pub struct EventLoop<T: 'static> {
elw: root::EventLoopWindowTarget<T>,
}
impl<T> EventLoop<T> {
pub fn new() -> Self {
EventLoop {
elw: root::EventLoopWindowTarget {
p: WindowTarget::new(),
_marker: PhantomData,
},
}
}
pub fn available_monitors(&self) -> VecDequeIter<monitor::Handle> {
VecDeque::new().into_iter()
}
pub fn primary_monitor(&self) -> monitor::Handle {
monitor::Handle
}
pub fn run<F>(self, mut event_handler: F) -> !
where
F: 'static + FnMut(Event<T>, &root::EventLoopWindowTarget<T>, &mut root::ControlFlow),
{
let target = root::EventLoopWindowTarget {
p: self.elw.p.clone(),
_marker: PhantomData,
};
let runner = self.elw.p.run(Box::new(move |event, flow| {
event_handler(event, &target, flow)
}));
backend::Document::on_blur(|| {
runner.send_event(Event::WindowEvent {
window_id: WindowId(window::Id),
event: WindowEvent::Focused(false),
});
});
backend::Document::on_focus(|| {
runner.send_event(Event::WindowEvent {
window_id: WindowId(window::Id),
event: WindowEvent::Focused(true),
});
});
backend::Document::on_key_down(|scancode, virtual_keycode, modifiers| {
runner.send_event(Event::WindowEvent {
window_id: WindowId(window::Id),
event: WindowEvent::KeyboardInput {
device_id: DeviceId(unsafe { device::Id::dummy() }),
input: KeyboardInput {
scancode,
state: ElementState::Pressed,
virtual_keycode,
modifiers,
},
},
});
});
backend::Document::on_key_up(|scancode, virtual_keycode, modifiers| {
runner.send_event(Event::WindowEvent {
window_id: WindowId(window::Id),
event: WindowEvent::KeyboardInput {
device_id: DeviceId(unsafe { device::Id::dummy() }),
input: KeyboardInput {
scancode,
state: ElementState::Released,
virtual_keycode,
modifiers,
},
},
});
});
// Throw an exception to break out of Rust exceution and use unreachable to tell the
// compiler this function won't return, giving it a return type of '!'
backend::throw(
"Using exceptions for control flow, don't mind me. This isn't actually an error!",
);
unreachable!();
}
pub fn create_proxy(&self) -> Proxy<T> {
self.elw.p.proxy()
}
pub fn window_target(&self) -> &root::EventLoopWindowTarget<T> {
&self.elw
}
}

View file

@ -0,0 +1,19 @@
use super::runner;
use crate::event::Event;
use crate::event_loop::EventLoopClosed;
#[derive(Clone)]
pub struct Proxy<T: 'static> {
runner: runner::Shared<T>,
}
impl<T: 'static> Proxy<T> {
pub fn new(runner: runner::Shared<T>) -> Self {
Proxy { runner }
}
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
self.runner.send_event(Event::UserEvent(event));
Ok(())
}
}

View file

@ -0,0 +1,216 @@
use super::{backend, state::State};
use crate::event::{Event, StartCause};
use crate::event_loop as root;
use instant::{Duration, Instant};
use std::{cell::RefCell, clone::Clone, collections::VecDeque, rc::Rc};
pub struct Shared<T>(Rc<Execution<T>>);
impl<T> Clone for Shared<T> {
fn clone(&self) -> Self {
Shared(self.0.clone())
}
}
pub struct Execution<T> {
runner: RefCell<Option<Runner<T>>>,
events: RefCell<VecDeque<Event<T>>>,
}
struct Runner<T> {
state: State,
is_busy: bool,
event_handler: Box<dyn FnMut(Event<T>, &mut root::ControlFlow)>,
}
impl<T: 'static> Runner<T> {
pub fn new(event_handler: Box<dyn FnMut(Event<T>, &mut root::ControlFlow)>) -> Self {
Runner {
state: State::Init,
is_busy: false,
event_handler,
}
}
}
impl<T: 'static> Shared<T> {
pub fn new() -> Self {
Shared(Rc::new(Execution {
runner: RefCell::new(None),
events: RefCell::new(VecDeque::new()),
}))
}
// Set the event callback to use for the event loop runner
// This the event callback is a fairly thin layer over the user-provided callback that closes
// over a RootEventLoopWindowTarget reference
pub fn set_listener(&self, event_handler: Box<dyn FnMut(Event<T>, &mut root::ControlFlow)>) {
self.0.runner.replace(Some(Runner::new(event_handler)));
self.send_event(Event::NewEvents(StartCause::Init));
}
// Add an event to the event loop runner
//
// It will determine if the event should be immediately sent to the user or buffered for later
pub fn send_event(&self, event: Event<T>) {
// If the event loop is closed, it should discard any new events
if self.closed() {
return;
}
// Determine if event handling is in process, and then release the borrow on the runner
let (start_cause, event_is_start) = match *self.0.runner.borrow() {
Some(ref runner) if !runner.is_busy => {
if let Event::NewEvents(cause) = event {
(cause, true)
} else {
(
match runner.state {
State::Init => StartCause::Init,
State::Poll { .. } => StartCause::Poll,
State::Wait { start } => StartCause::WaitCancelled {
start,
requested_resume: None,
},
State::WaitUntil { start, end, .. } => StartCause::WaitCancelled {
start,
requested_resume: Some(end),
},
State::Exit => {
return;
}
},
false,
)
}
}
_ => {
// Events are currently being handled, so queue this one and don't try to
// double-process the event queue
self.0.events.borrow_mut().push_back(event);
return;
}
};
let mut control = self.current_control_flow();
// Handle starting a new batch of events
//
// The user is informed via Event::NewEvents that there is a batch of events to process
// However, there is only one of these per batch of events
self.handle_event(Event::NewEvents(start_cause), &mut control);
if !event_is_start {
self.handle_event(event, &mut control);
}
self.handle_event(Event::EventsCleared, &mut control);
self.apply_control_flow(control);
// If the event loop is closed, it has been closed this iteration and now the closing
// event should be emitted
if self.closed() {
self.handle_event(Event::LoopDestroyed, &mut control);
}
}
// handle_event takes in events and either queues them or applies a callback
//
// It should only ever be called from send_event
fn handle_event(&self, event: Event<T>, control: &mut root::ControlFlow) {
let closed = self.closed();
match *self.0.runner.borrow_mut() {
Some(ref mut runner) => {
// An event is being processed, so the runner should be marked busy
runner.is_busy = true;
(runner.event_handler)(event, control);
// Maintain closed state, even if the callback changes it
if closed {
*control = root::ControlFlow::Exit;
}
// An event is no longer being processed
runner.is_busy = false;
}
// If an event is being handled without a runner somehow, add it to the event queue so
// it will eventually be processed
_ => self.0.events.borrow_mut().push_back(event),
}
// Don't take events out of the queue if the loop is closed or the runner doesn't exist
// If the runner doesn't exist and this method recurses, it will recurse infinitely
if !closed && self.0.runner.borrow().is_some() {
// Take an event out of the queue and handle it
if let Some(event) = self.0.events.borrow_mut().pop_front() {
self.handle_event(event, control);
}
}
}
// Apply the new ControlFlow that has been selected by the user
// Start any necessary timeouts etc
fn apply_control_flow(&self, control_flow: root::ControlFlow) {
let mut control_flow_status = match control_flow {
root::ControlFlow::Poll => {
let cloned = self.clone();
State::Poll {
timeout: backend::Timeout::new(
move || cloned.send_event(Event::NewEvents(StartCause::Poll)),
Duration::from_millis(1),
),
}
}
root::ControlFlow::Wait => State::Wait {
start: Instant::now(),
},
root::ControlFlow::WaitUntil(end) => {
let cloned = self.clone();
let start = Instant::now();
let delay = if end <= start {
Duration::from_millis(0)
} else {
end - start
};
State::WaitUntil {
start,
end,
timeout: backend::Timeout::new(
move || cloned.send_event(Event::NewEvents(StartCause::Poll)),
delay,
),
}
}
root::ControlFlow::Exit => State::Exit,
};
match *self.0.runner.borrow_mut() {
Some(ref mut runner) => {
// Put the new control flow status in the runner, and take out the old one
// This way we can safely take ownership of the TimeoutHandle and clear it,
// so that we don't get 'ghost' invocations of Poll or WaitUntil from earlier
// set_timeout invocations
std::mem::swap(&mut runner.state, &mut control_flow_status);
match control_flow_status {
State::Poll { timeout } | State::WaitUntil { timeout, .. } => timeout.clear(),
_ => (),
}
}
None => (),
}
}
// Check if the event loop is currntly closed
fn closed(&self) -> bool {
match *self.0.runner.borrow() {
Some(ref runner) => runner.state.is_exit(),
None => false, // If the event loop is None, it has not been intialised yet, so it cannot be closed
}
}
// Get the current control flow state
fn current_control_flow(&self) -> root::ControlFlow {
match *self.0.runner.borrow() {
Some(ref runner) => runner.state.into(),
None => root::ControlFlow::Poll,
}
}
}

View file

@ -0,0 +1,42 @@
use super::backend;
use crate::event_loop::ControlFlow;
use instant::Instant;
#[derive(Debug, Clone, Copy)]
pub enum State {
Init,
WaitUntil {
timeout: backend::Timeout,
start: Instant,
end: Instant,
},
Wait {
start: Instant,
},
Poll {
timeout: backend::Timeout,
},
Exit,
}
impl State {
pub fn is_exit(&self) -> bool {
match self {
State::Exit => true,
_ => false,
}
}
}
impl From<State> for ControlFlow {
fn from(state: State) -> ControlFlow {
match state {
State::Init => ControlFlow::Poll,
State::WaitUntil { end, .. } => ControlFlow::WaitUntil(end),
State::Wait { .. } => ControlFlow::Wait,
State::Poll { .. } => ControlFlow::Poll,
State::Exit => ControlFlow::Exit,
}
}
}

View file

@ -0,0 +1,106 @@
use super::{backend, device, proxy::Proxy, runner, window};
use crate::event::{DeviceId, ElementState, Event, TouchPhase, WindowEvent};
use crate::event_loop::ControlFlow;
use crate::window::WindowId;
use std::clone::Clone;
pub struct WindowTarget<T: 'static> {
pub(crate) runner: runner::Shared<T>,
}
impl<T> Clone for WindowTarget<T> {
fn clone(&self) -> Self {
WindowTarget {
runner: self.runner.clone(),
}
}
}
impl<T> WindowTarget<T> {
pub fn new() -> Self {
WindowTarget {
runner: runner::Shared::new(),
}
}
pub fn proxy(&self) -> Proxy<T> {
Proxy::new(self.runner.clone())
}
pub fn run(
&self,
event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
) -> &runner::Shared<T> {
self.runner.set_listener(event_handler);
&self.runner
}
pub fn register(&self, canvas: &backend::Canvas) {
let runner = &self.runner;
canvas.on_mouse_out(|pointer_id| {
runner.send_event(Event::WindowEvent {
window_id: WindowId(window::Id),
event: WindowEvent::CursorLeft {
device_id: DeviceId(device::Id(pointer_id)),
},
});
});
canvas.on_mouse_over(|pointer_id| {
runner.send_event(Event::WindowEvent {
window_id: WindowId(window::Id),
event: WindowEvent::CursorEntered {
device_id: DeviceId(device::Id(pointer_id)),
},
});
});
canvas.on_mouse_move(|pointer_id, position, modifiers| {
runner.send_event(Event::WindowEvent {
window_id: WindowId(window::Id),
event: WindowEvent::CursorMoved {
device_id: DeviceId(device::Id(pointer_id)),
position,
modifiers,
},
});
});
canvas.on_mouse_up(|pointer_id, button, modifiers| {
runner.send_event(Event::WindowEvent {
window_id: WindowId(window::Id),
event: WindowEvent::MouseInput {
device_id: DeviceId(device::Id(pointer_id)),
state: ElementState::Released,
button,
modifiers,
},
});
});
canvas.on_mouse_down(|pointer_id, button, modifiers| {
runner.send_event(Event::WindowEvent {
window_id: WindowId(window::Id),
event: WindowEvent::MouseInput {
device_id: DeviceId(device::Id(pointer_id)),
state: ElementState::Pressed,
button,
modifiers,
},
});
});
canvas.on_mouse_scroll(|pointer_id, delta, modifiers| {
runner.send_event(Event::WindowEvent {
window_id: WindowId(window::Id),
event: WindowEvent::MouseWheel {
device_id: DeviceId(device::Id(pointer_id)),
delta,
phase: TouchPhase::Moved,
modifiers,
},
});
});
}
}

View file

@ -0,0 +1,27 @@
// TODO: dpi
// TODO: close events (stdweb PR required)
// TODO: pointer locking (stdweb PR required)
// TODO: mouse wheel events (stdweb PR required)
// TODO: key event: .which() (stdweb PR)
// TODO: should there be a maximization / fullscreen API?
mod device;
mod error;
mod event_loop;
mod monitor;
mod window;
#[cfg(feature = "web_sys")]
#[path = "web_sys/mod.rs"]
mod backend;
pub use self::device::Id as DeviceId;
pub use self::error::OsError;
pub use self::event_loop::{
EventLoop, Proxy as EventLoopProxy, WindowTarget as EventLoopWindowTarget,
};
pub use self::monitor::Handle as MonitorHandle;
pub use self::window::{
Id as WindowId, PlatformSpecificBuilderAttributes as PlatformSpecificWindowBuilderAttributes,
Window,
};

View file

@ -0,0 +1,22 @@
use crate::dpi::{PhysicalPosition, PhysicalSize};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Handle;
impl Handle {
pub fn hidpi_factor(&self) -> f64 {
1.0
}
pub fn position(&self) -> PhysicalPosition {
unimplemented!();
}
pub fn dimensions(&self) -> PhysicalSize {
unimplemented!();
}
pub fn name(&self) -> Option<String> {
unimplemented!();
}
}

View file

@ -0,0 +1,20 @@
pub struct Canvas;
impl Canvas {
pub fn new() -> Self {
let element = document()
.create_element("canvas")
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?;
let canvas: CanvasElement = element
.try_into()
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?;
document()
.body()
.ok_or_else(|| os_error!(OsError("Failed to find body node".to_owned())))?
.append_child(&canvas);
Canvas(canvas)
}
}

View file

View file

@ -0,0 +1,66 @@
use crate::dpi::LogicalSize;
use crate::error::OsError as RootOE;
use crate::platform_impl::OsError;
use wasm_bindgen::JsCast;
use web_sys::HtmlCanvasElement;
pub struct Canvas {
raw: HtmlCanvasElement,
}
impl Canvas {
pub fn create() -> Result<Self, RootOE> {
let window = web_sys::window().expect("Failed to obtain window");
let document = window.document().expect("Failed to obtain document");
let canvas: HtmlCanvasElement = document
.create_element("canvas")
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?
.unchecked_into();
document
.body()
.ok_or_else(|| os_error!(OsError("Failed to find body node".to_owned())))?
.append_child(&canvas)
.map_err(|_| os_error!(OsError("Failed to append canvas".to_owned())))?;
Ok(Canvas { raw: canvas })
}
pub fn set_attribute(&self, attribute: &str, value: &str) {
self.raw
.set_attribute(attribute, value)
.expect(&format!("Set attribute: {}", attribute));
}
pub fn position(&self) -> (f64, f64) {
let bounds = self.raw.get_bounding_client_rect();
(bounds.x(), bounds.y())
}
pub fn width(&self) -> f64 {
self.raw.width() as f64
}
pub fn height(&self) -> f64 {
self.raw.height() as f64
}
pub fn set_size(&self, size: LogicalSize) {
self.raw.set_width(size.width as u32);
self.raw.set_height(size.height as u32);
}
pub fn raw(&self) -> HtmlCanvasElement {
self.raw.clone()
}
pub fn on_mouse_out<F>(&self, f: F) {}
pub fn on_mouse_over<F>(&self, f: F) {}
pub fn on_mouse_up<F>(&self, f: F) {}
pub fn on_mouse_down<F>(&self, f: F) {}
pub fn on_mouse_move<F>(&self, f: F) {}
pub fn on_mouse_scroll<F>(&self, f: F) {}
}

View file

@ -0,0 +1,13 @@
pub struct Document;
impl Document {
pub fn set_title(title: &str) {}
pub fn on_blur<F>(f: F) {}
pub fn on_focus<F>(f: F) {}
pub fn on_key_up<F>(f: F) {}
pub fn on_key_down<F>(f: F) {}
}

View file

@ -0,0 +1,17 @@
mod canvas;
mod document;
mod timeout;
pub use self::canvas::Canvas;
pub use self::document::Document;
pub use self::timeout::Timeout;
pub fn request_animation_frame<F>(f: F)
where
F: Fn(),
{
}
pub fn throw(msg: &str) {
wasm_bindgen::throw_str(msg);
}

View file

@ -0,0 +1,12 @@
use std::time::Duration;
#[derive(Debug, Clone, Copy)]
pub struct Timeout {}
impl Timeout {
pub fn new<F>(f: F, duration: Duration) -> Timeout {
Timeout {}
}
pub fn clear(self) {}
}

View file

@ -0,0 +1,276 @@
use crate::dpi::{LogicalPosition, LogicalSize};
use crate::error::{ExternalError, NotSupportedError, OsError as RootOE};
use crate::event::{Event, WindowEvent};
use crate::icon::Icon;
use crate::monitor::MonitorHandle as RootMH;
use crate::window::{CursorIcon, WindowAttributes, WindowId as RootWI};
use super::{backend, monitor, EventLoopWindowTarget};
use std::cell::RefCell;
use std::collections::vec_deque::IntoIter as VecDequeIter;
use std::collections::VecDeque;
pub struct Window {
canvas: backend::Canvas,
redraw: Box<dyn Fn()>,
previous_pointer: RefCell<&'static str>,
position: RefCell<LogicalPosition>,
}
impl Window {
pub fn new<T>(
target: &EventLoopWindowTarget<T>,
attr: WindowAttributes,
_: PlatformSpecificBuilderAttributes,
) -> Result<Self, RootOE> {
let canvas = backend::Canvas::create()?;
target.register(&canvas);
let runner = target.runner.clone();
let redraw = Box::new(move || {
let runner = runner.clone();
backend::request_animation_frame(move || {
runner.send_event(Event::WindowEvent {
window_id: RootWI(Id),
event: WindowEvent::RedrawRequested,
})
});
});
let window = Window {
canvas,
redraw,
previous_pointer: RefCell::new("auto"),
position: RefCell::new(LogicalPosition { x: 0.0, y: 0.0 }),
};
window.set_inner_size(attr.inner_size.unwrap_or(LogicalSize {
width: 1024.0,
height: 768.0,
}));
window.set_title(&attr.title);
window.set_maximized(attr.maximized);
window.set_visible(attr.visible);
window.set_window_icon(attr.window_icon);
Ok(window)
}
pub fn set_title(&self, title: &str) {
backend::Document::set_title(title);
}
pub fn set_visible(&self, _visible: bool) {
// Intentionally a no-op
}
pub fn request_redraw(&self) {
(self.redraw)();
}
pub fn outer_position(&self) -> Result<LogicalPosition, NotSupportedError> {
let (x, y) = self.canvas.position();
Ok(LogicalPosition { x, y })
}
pub fn inner_position(&self) -> Result<LogicalPosition, NotSupportedError> {
Ok(*self.position.borrow())
}
pub fn set_outer_position(&self, position: LogicalPosition) {
*self.position.borrow_mut() = position;
self.canvas.set_attribute("position", "fixed");
self.canvas.set_attribute("left", &position.x.to_string());
self.canvas.set_attribute("top", &position.y.to_string());
}
#[inline]
pub fn inner_size(&self) -> LogicalSize {
LogicalSize {
width: self.canvas.width() as f64,
height: self.canvas.height() as f64,
}
}
#[inline]
pub fn outer_size(&self) -> LogicalSize {
LogicalSize {
width: self.canvas.width() as f64,
height: self.canvas.height() as f64,
}
}
#[inline]
pub fn set_inner_size(&self, size: LogicalSize) {
self.canvas.set_size(size);
}
#[inline]
pub fn set_min_inner_size(&self, _dimensions: Option<LogicalSize>) {
// Intentionally a no-op: users can't resize canvas elements
}
#[inline]
pub fn set_max_inner_size(&self, _dimensions: Option<LogicalSize>) {
// 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]
pub fn hidpi_factor(&self) -> f64 {
1.0
}
#[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;
self.canvas.set_attribute("cursor", text);
}
#[inline]
pub fn set_cursor_position(&self, _position: LogicalPosition) -> Result<(), ExternalError> {
// TODO: pointer capture
Ok(())
}
#[inline]
pub fn set_cursor_grab(&self, _grab: bool) -> Result<(), ExternalError> {
// TODO: pointer capture
Ok(())
}
#[inline]
pub fn set_cursor_visible(&self, visible: bool) {
if !visible {
self.canvas.set_attribute("cursor", "none");
} else {
self.canvas
.set_attribute("cursor", *self.previous_pointer.borrow());
}
}
#[inline]
pub fn set_maximized(&self, _maximized: bool) {
// TODO: should there be a maximization / fullscreen API?
}
#[inline]
pub fn fullscreen(&self) -> Option<RootMH> {
// TODO: should there be a maximization / fullscreen API?
None
}
#[inline]
pub fn set_fullscreen(&self, _monitor: Option<RootMH>) {
// TODO: should there be a maximization / fullscreen API?
}
#[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]
pub fn set_ime_position(&self, _position: LogicalPosition) {
// TODO: what is this?
}
#[inline]
pub fn current_monitor(&self) -> RootMH {
RootMH {
inner: monitor::Handle,
}
}
#[inline]
pub fn available_monitors(&self) -> VecDequeIter<monitor::Handle> {
VecDeque::new().into_iter()
}
#[inline]
pub fn primary_monitor(&self) -> monitor::Handle {
monitor::Handle
}
#[inline]
pub fn id(&self) -> Id {
// TODO ?
unsafe { Id::dummy() }
}
}
#[cfg(feature = "stdweb")]
impl WindowExtStdweb for RootWindow {
fn canvas(&self) -> CanvasElement {
self.window.canvas.clone()
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Id;
impl Id {
pub unsafe fn dummy() -> Id {
Id
}
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlatformSpecificBuilderAttributes;