mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 22:31:14 +00:00

In previous version, we were setting the constraint with wasm after the window was shown, but this is no longer the case because we delay the window creation by an iteration of the event loop. Now should apply the constraint before showing the window. But on wasm, we also must manually enforce these constraint because the size given to the WindowBuilder is not applied
555 lines
22 KiB
Rust
555 lines
22 KiB
Rust
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
|
|
|
//! This module contains the GraphicsWindow that used to be within corelib.
|
|
|
|
// cspell:ignore borderless corelib nesw webgl winit winsys xlib
|
|
|
|
use core::cell::{Cell, RefCell};
|
|
use core::pin::Pin;
|
|
use std::rc::{Rc, Weak};
|
|
|
|
use crate::event_loop::WinitWindow;
|
|
use crate::renderer::{WinitCompatibleCanvas, WinitCompatibleRenderer};
|
|
use const_field_offset::FieldOffsets;
|
|
use corelib::component::ComponentRc;
|
|
use corelib::input::KeyboardModifiers;
|
|
use corelib::items::{ItemRef, MouseCursor};
|
|
use corelib::layout::Orientation;
|
|
use corelib::window::{WindowAdapter, WindowAdapterSealed, WindowHandleAccess};
|
|
use corelib::Property;
|
|
use corelib::{graphics::*, Coord};
|
|
use i_slint_core as corelib;
|
|
use winit::dpi::LogicalSize;
|
|
|
|
/// GraphicsWindow is an implementation of the [WindowAdapter][`crate::eventloop::WindowAdapter`] trait. This is
|
|
/// typically instantiated by entry factory functions of the different graphics back ends.
|
|
pub(crate) struct GLWindow<Renderer: WinitCompatibleRenderer + 'static> {
|
|
window: corelib::api::Window,
|
|
self_weak: Weak<Self>,
|
|
map_state: RefCell<GraphicsWindowBackendState<Renderer>>,
|
|
keyboard_modifiers: std::cell::Cell<KeyboardModifiers>,
|
|
currently_pressed_key_code: std::cell::Cell<Option<winit::event::VirtualKeyCode>>,
|
|
|
|
renderer: Renderer,
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
virtual_keyboard_helper: RefCell<Option<super::wasm_input_helper::WasmInputHelper>>,
|
|
}
|
|
|
|
impl<Renderer: WinitCompatibleRenderer + 'static> GLWindow<Renderer> {
|
|
/// Creates a new reference-counted instance.
|
|
///
|
|
/// Arguments:
|
|
/// * `graphics_backend_factory`: The factor function stored in the GraphicsWindow that's called when the state
|
|
/// of the window changes to mapped. The event loop and window builder parameters can be used to create a
|
|
/// backing window.
|
|
pub(crate) fn new(#[cfg(target_arch = "wasm32")] canvas_id: String) -> Rc<dyn WindowAdapter> {
|
|
let self_rc = Rc::new_cyclic(|self_weak| Self {
|
|
window: corelib::api::Window::new(self_weak.clone() as _),
|
|
self_weak: self_weak.clone(),
|
|
map_state: RefCell::new(GraphicsWindowBackendState::Unmapped {
|
|
requested_position: None,
|
|
requested_size: None,
|
|
}),
|
|
keyboard_modifiers: Default::default(),
|
|
currently_pressed_key_code: Default::default(),
|
|
renderer: Renderer::new(
|
|
&(self_weak.clone() as _),
|
|
#[cfg(target_arch = "wasm32")]
|
|
canvas_id,
|
|
),
|
|
#[cfg(target_arch = "wasm32")]
|
|
virtual_keyboard_helper: Default::default(),
|
|
});
|
|
self_rc as _
|
|
}
|
|
|
|
fn is_mapped(&self) -> bool {
|
|
matches!(&*self.map_state.borrow(), GraphicsWindowBackendState::Mapped { .. })
|
|
}
|
|
|
|
fn borrow_mapped_window(&self) -> Option<std::cell::Ref<MappedWindow<Renderer>>> {
|
|
if self.is_mapped() {
|
|
std::cell::Ref::map(self.map_state.borrow(), |state| match state {
|
|
GraphicsWindowBackendState::Unmapped{..} => {
|
|
panic!("borrow_mapped_window must be called after checking if the window is mapped")
|
|
}
|
|
GraphicsWindowBackendState::Mapped(window) => window,
|
|
}).into()
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
fn unmap(&self) {
|
|
let old_mapped = match self.map_state.replace(GraphicsWindowBackendState::Unmapped {
|
|
requested_position: None,
|
|
requested_size: None,
|
|
}) {
|
|
GraphicsWindowBackendState::Unmapped { .. } => return,
|
|
GraphicsWindowBackendState::Mapped(old_mapped) => old_mapped,
|
|
};
|
|
|
|
old_mapped.canvas.with_window_handle(|winit_window| {
|
|
crate::event_loop::unregister_window(winit_window.id());
|
|
});
|
|
|
|
self.renderer.release_canvas(old_mapped.canvas);
|
|
}
|
|
|
|
fn show_impl(&self) {
|
|
let (requested_position, requested_size) = match &*self.map_state.borrow() {
|
|
GraphicsWindowBackendState::Unmapped { requested_position, requested_size } => {
|
|
(requested_position.clone(), requested_size.clone())
|
|
}
|
|
GraphicsWindowBackendState::Mapped(_) => return,
|
|
};
|
|
|
|
let runtime_window = self.window().window_handle();
|
|
let component_rc = runtime_window.component();
|
|
let component = ComponentRc::borrow_pin(&component_rc);
|
|
|
|
let (window_title, no_frame, is_resizable) = if let Some(window_item) =
|
|
runtime_window.window_item().as_ref().map(|i| i.as_pin_ref())
|
|
{
|
|
(
|
|
window_item.title().to_string(),
|
|
window_item.no_frame(),
|
|
window_item.height() <= 0 as _ && window_item.width() <= 0 as _,
|
|
)
|
|
} else {
|
|
("Slint Window".to_string(), false, true)
|
|
};
|
|
|
|
let mut window_builder = winit::window::WindowBuilder::new()
|
|
.with_title(window_title)
|
|
.with_resizable(is_resizable);
|
|
|
|
let scale_factor_override = runtime_window.scale_factor();
|
|
// If the scale factor was already set programmatically, use that
|
|
// else, use the SLINT_SCALE_FACTOR if set, otherwise use the one from winit
|
|
let scale_factor_override = if scale_factor_override > 1. {
|
|
Some(scale_factor_override as f64)
|
|
} else {
|
|
std::env::var("SLINT_SCALE_FACTOR")
|
|
.ok()
|
|
.and_then(|x| x.parse::<f64>().ok())
|
|
.filter(|f| *f > 0.)
|
|
};
|
|
|
|
let into_size = |s: winit::dpi::LogicalSize<f32>| -> winit::dpi::Size {
|
|
if let Some(f) = scale_factor_override {
|
|
s.to_physical::<f32>(f).into()
|
|
} else {
|
|
s.into()
|
|
}
|
|
};
|
|
|
|
let layout_info_h = component.as_ref().layout_info(Orientation::Horizontal);
|
|
let layout_info_v = component.as_ref().layout_info(Orientation::Vertical);
|
|
let s =
|
|
LogicalSize::new(layout_info_h.preferred_bounded(), layout_info_v.preferred_bounded());
|
|
|
|
let window_builder =
|
|
if std::env::var("SLINT_FULLSCREEN").is_ok() {
|
|
window_builder.with_fullscreen(Some(winit::window::Fullscreen::Borderless(None)))
|
|
} else {
|
|
if layout_info_h.min >= 1. || layout_info_v.min >= 1. {
|
|
window_builder = window_builder.with_min_inner_size(into_size(
|
|
LogicalSize::new(layout_info_h.min, layout_info_v.min),
|
|
))
|
|
}
|
|
if layout_info_h.max < f32::MAX || layout_info_v.max < f32::MAX {
|
|
window_builder = window_builder.with_max_inner_size(into_size(
|
|
LogicalSize::new(layout_info_h.max, layout_info_v.max),
|
|
))
|
|
}
|
|
|
|
if let Some(requested_size) = requested_size {
|
|
// It would be nice to bound this with our constraints, but those are in logical coordinates
|
|
// and we don't know the scale factor yet...
|
|
window_builder.with_inner_size(winit::dpi::Size::new(
|
|
winit::dpi::PhysicalSize::new(requested_size.width, requested_size.height),
|
|
))
|
|
} else if s.width > 0 as Coord && s.height > 0 as Coord {
|
|
// Make sure that the window's inner size is in sync with the root window item's
|
|
// width/height.
|
|
runtime_window.set_window_item_geometry(s.width, s.height);
|
|
window_builder.with_inner_size(into_size(s))
|
|
} else {
|
|
window_builder
|
|
}
|
|
};
|
|
|
|
let window_builder =
|
|
if no_frame { window_builder.with_decorations(false) } else { window_builder };
|
|
|
|
let window_builder = if let Some(requested_position) = requested_position {
|
|
window_builder.with_position(winit::dpi::Position::new(
|
|
winit::dpi::PhysicalPosition::new(requested_position.x, requested_position.y),
|
|
))
|
|
} else {
|
|
window_builder
|
|
};
|
|
|
|
let canvas = self.renderer.create_canvas(window_builder);
|
|
|
|
let id = canvas.with_window_handle(|winit_window| {
|
|
self.window.window_handle().set_scale_factor(
|
|
scale_factor_override.unwrap_or_else(|| winit_window.scale_factor()) as _,
|
|
);
|
|
// On wasm, with_inner_size on the WindowBuilder don't have effect, so apply manually
|
|
#[cfg(target_arch = "wasm32")]
|
|
if (s.width > 0 as Coord && s.height > 0 as Coord) {
|
|
winit_window.set_inner_size(s);
|
|
}
|
|
winit_window.id()
|
|
});
|
|
|
|
self.map_state.replace(GraphicsWindowBackendState::Mapped(MappedWindow {
|
|
canvas,
|
|
constraints: Default::default(),
|
|
}));
|
|
|
|
crate::event_loop::register_window(id, self.self_weak.upgrade().unwrap());
|
|
}
|
|
}
|
|
|
|
impl<Renderer: WinitCompatibleRenderer + 'static> WinitWindow for GLWindow<Renderer> {
|
|
fn currently_pressed_key_code(&self) -> &Cell<Option<winit::event::VirtualKeyCode>> {
|
|
&self.currently_pressed_key_code
|
|
}
|
|
|
|
fn current_keyboard_modifiers(&self) -> &Cell<KeyboardModifiers> {
|
|
&self.keyboard_modifiers
|
|
}
|
|
|
|
/// Draw the items of the specified `component` in the given window.
|
|
fn draw(&self) {
|
|
let window = match self.borrow_mapped_window() {
|
|
Some(window) => window,
|
|
None => return, // caller bug, doesn't make sense to call draw() when not mapped
|
|
};
|
|
|
|
self.renderer.render(&window.canvas, self);
|
|
}
|
|
|
|
fn with_window_handle(&self, callback: &mut dyn FnMut(&winit::window::Window)) {
|
|
if let Some(mapped_window) = self.borrow_mapped_window() {
|
|
mapped_window.canvas.with_window_handle(callback);
|
|
}
|
|
}
|
|
|
|
fn constraints(&self) -> (corelib::layout::LayoutInfo, corelib::layout::LayoutInfo) {
|
|
self.borrow_mapped_window().map(|window| window.constraints.get()).unwrap_or_default()
|
|
}
|
|
|
|
fn set_constraints(
|
|
&self,
|
|
constraints: (corelib::layout::LayoutInfo, corelib::layout::LayoutInfo),
|
|
) {
|
|
if let Some(window) = self.borrow_mapped_window() {
|
|
window.constraints.set(constraints);
|
|
}
|
|
}
|
|
|
|
fn set_icon(&self, icon: corelib::graphics::Image) {
|
|
let image_inner: &ImageInner = (&icon).into();
|
|
let pixel_buffer = match image_inner {
|
|
ImageInner::EmbeddedImage { buffer, .. } => buffer.clone(),
|
|
_ => return,
|
|
};
|
|
|
|
// This could become a method in SharedPixelBuffer...
|
|
let rgba_pixels: Vec<u8> = match &pixel_buffer {
|
|
SharedImageBuffer::RGB8(pixels) => pixels
|
|
.as_bytes()
|
|
.chunks(3)
|
|
.flat_map(|rgb| IntoIterator::into_iter([rgb[0], rgb[1], rgb[2], 255]))
|
|
.collect(),
|
|
SharedImageBuffer::RGBA8(pixels) => pixels.as_bytes().to_vec(),
|
|
SharedImageBuffer::RGBA8Premultiplied(pixels) => pixels
|
|
.as_bytes()
|
|
.chunks(4)
|
|
.flat_map(|rgba| {
|
|
let alpha = rgba[3] as u32;
|
|
IntoIterator::into_iter(rgba)
|
|
.take(3)
|
|
.map(move |component| (*component as u32 * alpha / 255) as u8)
|
|
.chain(std::iter::once(alpha as u8))
|
|
})
|
|
.collect(),
|
|
};
|
|
|
|
self.with_window_handle(&mut |window| {
|
|
window.set_window_icon(
|
|
winit::window::Icon::from_rgba(
|
|
rgba_pixels.clone(), // FIXME: if the closure were FnOnce we could move rgba_pixels
|
|
pixel_buffer.width(),
|
|
pixel_buffer.height(),
|
|
)
|
|
.ok(),
|
|
);
|
|
})
|
|
}
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
fn input_method_focused(&self) -> bool {
|
|
match self.virtual_keyboard_helper.try_borrow() {
|
|
Ok(vkh) => vkh.as_ref().map_or(false, |h| h.has_focus()),
|
|
// the only location in which the virtual_keyboard_helper is mutably borrowed is from
|
|
// show_virtual_keyboard, which means we have the focus
|
|
Err(_) => true,
|
|
}
|
|
}
|
|
|
|
fn resize_event(&self, size: winit::dpi::PhysicalSize<u32>) {
|
|
if let Some(mapped_window) = self.borrow_mapped_window() {
|
|
self.window().set_size(corelib::api::PhysicalSize::new(size.width, size.height));
|
|
mapped_window.canvas.resize_event()
|
|
}
|
|
}
|
|
|
|
fn inner_size(&self) -> corelib::api::PhysicalSize {
|
|
match &*self.map_state.borrow() {
|
|
GraphicsWindowBackendState::Unmapped { requested_size, .. } => {
|
|
requested_size.unwrap_or_default()
|
|
}
|
|
GraphicsWindowBackendState::Mapped(mapped_window) => {
|
|
mapped_window.canvas.with_window_handle(|winit_window| {
|
|
let size = winit_window.inner_size();
|
|
corelib::api::PhysicalSize::new(size.width, size.height)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<Renderer: WinitCompatibleRenderer + 'static> WindowAdapter for GLWindow<Renderer> {
|
|
fn window(&self) -> &corelib::api::Window {
|
|
&self.window
|
|
}
|
|
}
|
|
|
|
impl<Renderer: WinitCompatibleRenderer + 'static> WindowAdapterSealed for GLWindow<Renderer> {
|
|
fn request_redraw(&self) {
|
|
self.with_window_handle(&mut |window| window.request_redraw())
|
|
}
|
|
|
|
fn unregister_component<'a>(
|
|
&self,
|
|
component: corelib::component::ComponentRef,
|
|
_items: &mut dyn Iterator<Item = Pin<ItemRef<'a>>>,
|
|
) {
|
|
match &*self.map_state.borrow() {
|
|
GraphicsWindowBackendState::Unmapped { .. } => {}
|
|
GraphicsWindowBackendState::Mapped(mapped_window) => {
|
|
mapped_window.canvas.component_destroyed(component)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn request_window_properties_update(&self) {
|
|
self.with_window_handle(&mut |window| {
|
|
let window_id = window.id();
|
|
crate::event_loop::with_window_target(|event_loop| {
|
|
event_loop
|
|
.event_loop_proxy()
|
|
.send_event(crate::event_loop::CustomEvent::UpdateWindowProperties(window_id))
|
|
})
|
|
.ok();
|
|
})
|
|
}
|
|
|
|
fn apply_window_properties(&self, window_item: Pin<&i_slint_core::items::WindowItem>) {
|
|
// Make the unwrap() calls on self.borrow_mapped_window*() safe
|
|
if !self.is_mapped() {
|
|
return;
|
|
}
|
|
|
|
WinitWindow::apply_window_properties(self as &dyn WinitWindow, window_item);
|
|
}
|
|
|
|
fn apply_geometry_constraint(
|
|
&self,
|
|
constraints_horizontal: corelib::layout::LayoutInfo,
|
|
constraints_vertical: corelib::layout::LayoutInfo,
|
|
) {
|
|
self.apply_constraints(constraints_horizontal, constraints_vertical)
|
|
}
|
|
|
|
fn show(&self) {
|
|
// Creating a new winit::Window requires access to the running event loop (`&EventLoopWindowTarget`), which
|
|
// is only possible from within the event loop handler with wasm, as `run()` consumes the event loop. Work
|
|
// around by invoking `show()` from within the event loop handler.
|
|
#[cfg(target_arch = "wasm32")]
|
|
corelib::api::invoke_from_event_loop({
|
|
let self_weak = send_wrapper::SendWrapper::new(self.self_weak.clone());
|
|
|
|
move || {
|
|
if let Some(this) = self_weak.take().upgrade() {
|
|
this.show_impl();
|
|
}
|
|
}
|
|
});
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
self.show_impl();
|
|
}
|
|
|
|
fn hide(&self) {
|
|
self.unmap();
|
|
|
|
/* FIXME:
|
|
if let Some(existing_blinker) = self.cursor_blinker.borrow().upgrade() {
|
|
existing_blinker.stop();
|
|
}*/
|
|
crate::event_loop::with_window_target(|event_loop| {
|
|
event_loop.event_loop_proxy().send_event(crate::event_loop::CustomEvent::WindowHidden)
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
fn set_mouse_cursor(&self, cursor: MouseCursor) {
|
|
let winit_cursor = match cursor {
|
|
MouseCursor::Default => winit::window::CursorIcon::Default,
|
|
MouseCursor::None => winit::window::CursorIcon::Default,
|
|
MouseCursor::Help => winit::window::CursorIcon::Help,
|
|
MouseCursor::Pointer => winit::window::CursorIcon::Hand,
|
|
MouseCursor::Progress => winit::window::CursorIcon::Progress,
|
|
MouseCursor::Wait => winit::window::CursorIcon::Wait,
|
|
MouseCursor::Crosshair => winit::window::CursorIcon::Crosshair,
|
|
MouseCursor::Text => winit::window::CursorIcon::Text,
|
|
MouseCursor::Alias => winit::window::CursorIcon::Alias,
|
|
MouseCursor::Copy => winit::window::CursorIcon::Copy,
|
|
MouseCursor::Move => winit::window::CursorIcon::Move,
|
|
MouseCursor::NoDrop => winit::window::CursorIcon::NoDrop,
|
|
MouseCursor::NotAllowed => winit::window::CursorIcon::NotAllowed,
|
|
MouseCursor::Grab => winit::window::CursorIcon::Grab,
|
|
MouseCursor::Grabbing => winit::window::CursorIcon::Grabbing,
|
|
MouseCursor::ColResize => winit::window::CursorIcon::ColResize,
|
|
MouseCursor::RowResize => winit::window::CursorIcon::RowResize,
|
|
MouseCursor::NResize => winit::window::CursorIcon::NResize,
|
|
MouseCursor::EResize => winit::window::CursorIcon::EResize,
|
|
MouseCursor::SResize => winit::window::CursorIcon::SResize,
|
|
MouseCursor::WResize => winit::window::CursorIcon::WResize,
|
|
MouseCursor::NeResize => winit::window::CursorIcon::NeResize,
|
|
MouseCursor::NwResize => winit::window::CursorIcon::NwResize,
|
|
MouseCursor::SeResize => winit::window::CursorIcon::SeResize,
|
|
MouseCursor::SwResize => winit::window::CursorIcon::SwResize,
|
|
MouseCursor::EwResize => winit::window::CursorIcon::EwResize,
|
|
MouseCursor::NsResize => winit::window::CursorIcon::NsResize,
|
|
MouseCursor::NeswResize => winit::window::CursorIcon::NeswResize,
|
|
MouseCursor::NwseResize => winit::window::CursorIcon::NwseResize,
|
|
};
|
|
self.with_window_handle(&mut |winit_window| {
|
|
winit_window.set_cursor_visible(cursor != MouseCursor::None);
|
|
winit_window.set_cursor_icon(winit_cursor);
|
|
});
|
|
}
|
|
|
|
fn renderer(&self) -> &dyn i_slint_core::renderer::Renderer {
|
|
&self.renderer
|
|
}
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
fn show_virtual_keyboard(&self, _it: corelib::items::InputType) {
|
|
let mut vkh = self.virtual_keyboard_helper.borrow_mut();
|
|
let h = vkh.get_or_insert_with(|| {
|
|
let canvas = self.borrow_mapped_window().unwrap().canvas.html_canvas_element().clone();
|
|
super::wasm_input_helper::WasmInputHelper::new(self.self_weak.clone(), canvas)
|
|
});
|
|
h.show();
|
|
}
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
fn hide_virtual_keyboard(&self) {
|
|
if let Some(h) = &*self.virtual_keyboard_helper.borrow() {
|
|
h.hide()
|
|
}
|
|
}
|
|
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
self
|
|
}
|
|
|
|
fn position(&self) -> corelib::api::PhysicalPosition {
|
|
match &*self.map_state.borrow() {
|
|
GraphicsWindowBackendState::Unmapped { requested_position, .. } => {
|
|
requested_position.unwrap_or_default()
|
|
}
|
|
GraphicsWindowBackendState::Mapped(mapped_window) => mapped_window
|
|
.canvas
|
|
.with_window_handle(|winit_window| match winit_window.outer_position() {
|
|
Ok(outer_position) => {
|
|
corelib::api::PhysicalPosition::new(outer_position.x, outer_position.y)
|
|
}
|
|
Err(_) => Default::default(),
|
|
}),
|
|
}
|
|
}
|
|
|
|
fn set_position(&self, position: corelib::api::PhysicalPosition) {
|
|
match &mut *self.map_state.borrow_mut() {
|
|
GraphicsWindowBackendState::Unmapped { requested_position, .. } => {
|
|
*requested_position = Some(position)
|
|
}
|
|
GraphicsWindowBackendState::Mapped(mapped_window) => {
|
|
mapped_window.canvas.with_window_handle(|winit_window| {
|
|
winit_window.set_outer_position(winit::dpi::Position::new(
|
|
winit::dpi::PhysicalPosition::new(position.x, position.y),
|
|
))
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
fn set_inner_size(&self, size: corelib::api::PhysicalSize) {
|
|
if let Ok(mut map_state) = self.map_state.try_borrow_mut() {
|
|
// otherwise we are called from the resize event
|
|
match &mut *map_state {
|
|
GraphicsWindowBackendState::Unmapped { requested_size, .. } => {
|
|
*requested_size = Some(size)
|
|
}
|
|
GraphicsWindowBackendState::Mapped(mapped_window) => {
|
|
mapped_window.canvas.with_window_handle(|winit_window| {
|
|
winit_window
|
|
.set_inner_size(winit::dpi::PhysicalSize::new(size.width, size.height));
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<Renderer: WinitCompatibleRenderer + 'static> Drop for GLWindow<Renderer> {
|
|
fn drop(&mut self) {
|
|
self.unmap();
|
|
}
|
|
}
|
|
|
|
struct MappedWindow<Renderer: WinitCompatibleRenderer> {
|
|
canvas: Renderer::Canvas,
|
|
constraints: Cell<(corelib::layout::LayoutInfo, corelib::layout::LayoutInfo)>,
|
|
}
|
|
|
|
enum GraphicsWindowBackendState<Renderer: WinitCompatibleRenderer> {
|
|
Unmapped {
|
|
requested_position: Option<corelib::api::PhysicalPosition>,
|
|
requested_size: Option<corelib::api::PhysicalSize>,
|
|
},
|
|
Mapped(MappedWindow<Renderer>),
|
|
}
|
|
|
|
#[derive(FieldOffsets)]
|
|
#[repr(C)]
|
|
#[pin]
|
|
struct WindowProperties {
|
|
scale_factor: Property<f32>,
|
|
}
|
|
|
|
impl Default for WindowProperties {
|
|
fn default() -> Self {
|
|
Self { scale_factor: Property::new(1.0) }
|
|
}
|
|
}
|