Invert slint:🪟:WindowInner and PlatformWindow ownership

Previously: Window is an Rc<WindowInner>, which has an Rc<dyn
PLatformWindow> - and weak references the other way around.

Now: Rc<dyn PlatformWindow> is the root of window ownership. The impl
PlatformWindow has a slint::api::Window, which just holds a WindowInner.

This change is incomplete on a few levels, mainly that neither of the
code generators nor the interpreter is ported.
This commit is contained in:
Simon Hausmann 2022-08-18 11:38:30 +02:00 committed by Simon Hausmann
parent f88b688fbf
commit af86f36157
32 changed files with 494 additions and 533 deletions

View file

@ -135,7 +135,7 @@ fn gen_corelib(
config.export.include = [ config.export.include = [
"ComponentVTable", "ComponentVTable",
"Slice", "Slice",
"WindowRcOpaque", "PlatformWindowRcOpaque",
"PropertyAnimation", "PropertyAnimation",
"EasingCurve", "EasingCurve",
"TextHorizontalAlignment", "TextHorizontalAlignment",

View file

@ -86,7 +86,9 @@ inline void assert_main_thread()
class WindowRc class WindowRc
{ {
public: public:
explicit WindowRc(cbindgen_private::WindowRcOpaque adopted_inner) : inner(adopted_inner) { } explicit WindowRc(cbindgen_private::PlatformWindowRcOpaque adopted_inner) : inner(adopted_inner)
{
}
WindowRc() { cbindgen_private::slint_windowrc_init(&inner); } WindowRc() { cbindgen_private::slint_windowrc_init(&inner); }
~WindowRc() { cbindgen_private::slint_windowrc_drop(&inner); } ~WindowRc() { cbindgen_private::slint_windowrc_drop(&inner); }
WindowRc(const WindowRc &other) WindowRc(const WindowRc &other)
@ -223,7 +225,7 @@ public:
} }
private: private:
cbindgen_private::WindowRcOpaque inner; cbindgen_private::PlatformWindowRcOpaque inner;
}; };
constexpr inline ItemTreeNode make_item_node(uint32_t child_count, uint32_t child_index, constexpr inline ItemTreeNode make_item_node(uint32_t child_count, uint32_t child_index,

View file

@ -564,7 +564,7 @@ public:
/// such as the position on the screen. /// such as the position on the screen.
const slint::Window &window() const slint::Window &window()
{ {
const cbindgen_private::WindowRcOpaque *win_ptr = nullptr; const cbindgen_private::PlatformWindowRcOpaque *win_ptr = nullptr;
cbindgen_private::slint_interpreter_component_instance_window(inner(), &win_ptr); cbindgen_private::slint_interpreter_component_instance_window(inner(), &win_ptr);
return *reinterpret_cast<const slint::Window *>(win_ptr); return *reinterpret_cast<const slint::Window *>(win_ptr);
} }
@ -582,7 +582,7 @@ public:
/// it may return nullptr if the Qt backend is not used at runtime. /// it may return nullptr if the Qt backend is not used at runtime.
QWidget *qwidget() const QWidget *qwidget() const
{ {
const cbindgen_private::WindowRcOpaque *win_ptr = nullptr; const cbindgen_private::PlatformWindowRcOpaque *win_ptr = nullptr;
cbindgen_private::slint_interpreter_component_instance_window(inner(), &win_ptr); cbindgen_private::slint_interpreter_component_instance_window(inner(), &win_ptr);
auto wid = reinterpret_cast<QWidget *>(cbindgen_private::slint_qt_get_widget( auto wid = reinterpret_cast<QWidget *>(cbindgen_private::slint_qt_get_widget(
reinterpret_cast<const cbindgen_private::WindowRc *>(win_ptr))); reinterpret_cast<const cbindgen_private::WindowRc *>(win_ptr)));
@ -1010,7 +1010,7 @@ inline void send_keyboard_string_sequence(const slint::interpreter::ComponentIns
const slint::SharedString &str, const slint::SharedString &str,
KeyboardModifiers modifiers = {}) KeyboardModifiers modifiers = {})
{ {
const cbindgen_private::WindowRcOpaque *win_ptr = nullptr; const cbindgen_private::PlatformWindowRcOpaque *win_ptr = nullptr;
cbindgen_private::slint_interpreter_component_instance_window( cbindgen_private::slint_interpreter_component_instance_window(
reinterpret_cast<const cbindgen_private::ErasedComponentBox *>(component), &win_ptr); reinterpret_cast<const cbindgen_private::ErasedComponentBox *>(component), &win_ptr);
cbindgen_private::send_keyboard_string_sequence( cbindgen_private::send_keyboard_string_sequence(

View file

@ -5,8 +5,7 @@
use core::ffi::c_void; use core::ffi::c_void;
use i_slint_backend_selector::backend; use i_slint_backend_selector::backend;
use i_slint_core::api::Window; use i_slint_core::window::{ffi::PlatformWindowRcOpaque, PlatformWindowRc};
use i_slint_core::window::{ffi::WindowRcOpaque, WindowRc};
#[doc(hidden)] #[doc(hidden)]
#[cold] #[cold]
@ -18,9 +17,12 @@ pub fn use_modules() -> usize {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_init(out: *mut WindowRcOpaque) { pub unsafe extern "C" fn slint_windowrc_init(out: *mut PlatformWindowRcOpaque) {
assert_eq!(core::mem::size_of::<Window>(), core::mem::size_of::<WindowRcOpaque>()); assert_eq!(
core::ptr::write(out as *mut Window, crate::backend().create_window()); core::mem::size_of::<PlatformWindowRc>(),
core::mem::size_of::<PlatformWindowRcOpaque>()
);
core::ptr::write(out as *mut PlatformWindowRc, crate::backend().create_window());
} }
#[no_mangle] #[no_mangle]
@ -63,14 +65,17 @@ pub unsafe extern "C" fn slint_quit_event_loop() {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_register_font_from_path( pub unsafe extern "C" fn slint_register_font_from_path(
win: *const WindowRcOpaque, win: *const PlatformWindowRcOpaque,
path: &i_slint_core::SharedString, path: &i_slint_core::SharedString,
error_str: *mut i_slint_core::SharedString, error_str: *mut i_slint_core::SharedString,
) { ) {
let window = &*(win as *const WindowRc); let platform_window = &*(win as *const PlatformWindowRc);
core::ptr::write( core::ptr::write(
error_str, error_str,
match window.renderer().register_font_from_path(std::path::Path::new(path.as_str())) { match platform_window
.renderer()
.register_font_from_path(std::path::Path::new(path.as_str()))
{
Ok(()) => Default::default(), Ok(()) => Default::default(),
Err(err) => err.to_string().into(), Err(err) => err.to_string().into(),
}, },
@ -79,14 +84,14 @@ pub unsafe extern "C" fn slint_register_font_from_path(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_register_font_from_data( pub unsafe extern "C" fn slint_register_font_from_data(
win: *const WindowRcOpaque, win: *const PlatformWindowRcOpaque,
data: i_slint_core::slice::Slice<'static, u8>, data: i_slint_core::slice::Slice<'static, u8>,
error_str: *mut i_slint_core::SharedString, error_str: *mut i_slint_core::SharedString,
) { ) {
let window = &*(win as *const WindowRc); let platform_window = &*(win as *const PlatformWindowRc);
core::ptr::write( core::ptr::write(
error_str, error_str,
match window.renderer().register_font_from_memory(data.as_slice()) { match platform_window.renderer().register_font_from_memory(data.as_slice()) {
Ok(()) => Default::default(), Ok(()) => Default::default(),
Err(err) => err.to_string().into(), Err(err) => err.to_string().into(),
}, },

View file

@ -284,7 +284,7 @@ pub mod re_exports {
pub use i_slint_core::model::*; pub use i_slint_core::model::*;
pub use i_slint_core::properties::{set_state_binding, Property, PropertyTracker, StateInfo}; pub use i_slint_core::properties::{set_state_binding, Property, PropertyTracker, StateInfo};
pub use i_slint_core::slice::Slice; pub use i_slint_core::slice::Slice;
pub use i_slint_core::window::{WindowHandleAccess, WindowInner, WindowRc}; pub use i_slint_core::window::{PlatformWindowRc, WindowHandleAccess, WindowInner};
pub use i_slint_core::Color; pub use i_slint_core::Color;
pub use i_slint_core::ComponentVTable_static; pub use i_slint_core::ComponentVTable_static;
pub use i_slint_core::Coord; pub use i_slint_core::Coord;
@ -435,9 +435,8 @@ pub mod internal {
/// Creates a new window to render components in. /// Creates a new window to render components in.
#[doc(hidden)] #[doc(hidden)]
pub fn create_window() -> re_exports::WindowRc { pub fn create_window() -> re_exports::PlatformWindowRc {
use i_slint_core::window::WindowHandleAccess; i_slint_backend_selector::backend().create_window()
i_slint_backend_selector::backend().create_window().window_handle().clone()
} }
/// Enters the main event loop. This is necessary in order to receive /// Enters the main event loop. This is necessary in order to receive
@ -478,7 +477,7 @@ pub mod testing {
) { ) {
let rc = component.clone_strong().into(); let rc = component.clone_strong().into();
let dyn_rc = vtable::VRc::into_dyn(rc.clone()); let dyn_rc = vtable::VRc::into_dyn(rc.clone());
i_slint_core::tests::slint_send_mouse_click(&dyn_rc, x, y, &rc.window_handle().clone()); i_slint_core::tests::slint_send_mouse_click(&dyn_rc, x, y, rc.window_handle());
} }
/// Simulate a change in keyboard modifiers being pressed /// Simulate a change in keyboard modifiers being pressed
@ -506,7 +505,7 @@ pub mod testing {
i_slint_core::tests::send_keyboard_string_sequence( i_slint_core::tests::send_keyboard_string_sequence(
&super::SharedString::from(sequence), &super::SharedString::from(sequence),
KEYBOARD_MODIFIERS.with(|x| x.get()), KEYBOARD_MODIFIERS.with(|x| x.get()),
&component.window_handle().clone(), component.window_handle(),
) )
} }

View file

@ -113,21 +113,21 @@ mod the_backend {
use alloc::rc::{Rc, Weak}; use alloc::rc::{Rc, Weak};
use alloc::string::String; use alloc::string::String;
use core::cell::RefCell; use core::cell::RefCell;
use i_slint_core::window::WindowInner; use i_slint_core::api::Window;
use i_slint_core::window::{PlatformWindow, WindowRc}; use i_slint_core::window::{PlatformWindow, PlatformWindowRc, WindowHandleAccess};
thread_local! { static WINDOWS: RefCell<Option<Rc<McuWindow>>> = RefCell::new(None) } thread_local! { static WINDOWS: RefCell<Option<Rc<McuWindow>>> = RefCell::new(None) }
thread_local! { static EVENT_QUEUE: RefCell<VecDeque<McuEvent>> = Default::default() } thread_local! { static EVENT_QUEUE: RefCell<VecDeque<McuEvent>> = Default::default() }
pub struct McuWindow { pub struct McuWindow {
window_inner_weak: Weak<WindowInner>, window: Window,
self_weak: Weak<Self>, self_weak: Weak<Self>,
renderer: crate::renderer::SoftwareRenderer, renderer: crate::renderer::SoftwareRenderer,
} }
impl PlatformWindow for McuWindow { impl PlatformWindow for McuWindow {
fn show(&self) { fn show(&self) {
let w = self.window_inner_weak.upgrade().unwrap(); let w = self.window.window_handle();
w.set_scale_factor( w.set_scale_factor(
option_env!("SLINT_SCALE_FACTOR").and_then(|x| x.parse().ok()).unwrap_or(1.), option_env!("SLINT_SCALE_FACTOR").and_then(|x| x.parse().ok()).unwrap_or(1.),
); );
@ -149,8 +149,8 @@ mod the_backend {
self self
} }
fn window(&self) -> WindowRc { fn window(&self) -> &Window {
self.window_inner_weak.upgrade().unwrap() &self.window
} }
} }
@ -189,7 +189,7 @@ mod the_backend {
} }
fn draw(&self, window: Rc<McuWindow>) { fn draw(&self, window: Rc<McuWindow>) {
let runtime_window = window.window_inner_weak.upgrade().unwrap(); let runtime_window = window.window.window_handle();
runtime_window.update_window_properties(); runtime_window.update_window_properties();
DEVICES.with(|devices| { DEVICES.with(|devices| {
@ -202,11 +202,7 @@ mod the_backend {
runtime_window.set_window_item_geometry(size.width as _, size.height as _); runtime_window.set_window_item_geometry(size.width as _, size.height as _);
if let Some(buffer) = devices.get_buffer() { if let Some(buffer) = devices.get_buffer() {
window.renderer.render( window.renderer.render(&window.window, buffer, screen_size.width_length());
&runtime_window.into(),
buffer,
screen_size.width_length(),
);
devices.flush_frame(); devices.flush_frame();
frame_profiler.stop_profiling(&mut **devices, "=> frame total"); frame_profiler.stop_profiling(&mut **devices, "=> frame total");
@ -263,24 +259,21 @@ mod the_backend {
devices: &mut **devices, devices: &mut **devices,
}; };
window.renderer.render_by_line(&runtime_window.into(), buffer_provider); window.renderer.render_by_line(&window.window, buffer_provider);
frame_profiler.stop_profiling(&mut **devices, "=> frame total"); frame_profiler.stop_profiling(&mut **devices, "=> frame total");
}); });
} }
} }
impl i_slint_core::backend::Backend for MCUBackend { impl i_slint_core::backend::Backend for MCUBackend {
fn create_window(&self) -> i_slint_core::api::Window { fn create_window(&self) -> PlatformWindowRc {
i_slint_core::window::WindowInner::new(|window| { Rc::new_cyclic(|self_weak| McuWindow {
Rc::new_cyclic(|self_weak| McuWindow { window: Window::new(self_weak.clone() as _),
window_inner_weak: window.clone(), self_weak: self_weak.clone(),
self_weak: self_weak.clone(), renderer: crate::renderer::SoftwareRenderer::new(
renderer: crate::renderer::SoftwareRenderer::new( crate::renderer::DirtyTracking::DoubleBuffer,
crate::renderer::DirtyTracking::DoubleBuffer, ),
),
})
}) })
.into()
} }
fn run_event_loop(&self, behavior: i_slint_core::backend::EventLoopQuitBehavior) { fn run_event_loop(&self, behavior: i_slint_core::backend::EventLoopQuitBehavior) {
@ -302,7 +295,7 @@ mod the_backend {
let e = devices.borrow_mut().as_mut().unwrap().read_touch_event(); let e = devices.borrow_mut().as_mut().unwrap().read_touch_event();
if let Some(mut event) = e { if let Some(mut event) = e {
if let Some(window) = WINDOWS.with(|x| x.borrow().clone()) { if let Some(window) = WINDOWS.with(|x| x.borrow().clone()) {
let w = window.window_inner_weak.upgrade().unwrap(); let w = window.window.window_handle();
// scale the event by the scale factor: // scale the event by the scale factor:
if let Some(p) = event.position() { if let Some(p) = event.position() {
event.translate((p.cast() / w.scale_factor()).cast() - p); event.translate((p.cast() / w.scale_factor()).cast() - p);

View file

@ -65,16 +65,13 @@ thread_local! { static WINDOW: RefCell<Option<Rc<PicoWindow>>> = RefCell::new(No
struct PicoBackend; struct PicoBackend;
impl i_slint_core::backend::Backend for PicoBackend { impl i_slint_core::backend::Backend for PicoBackend {
fn create_window(&self) -> i_slint_core::api::Window { fn create_window(&self) -> i_slint_core::window::PlatformWindowRc {
i_slint_core::window::WindowInner::new(|window| { Rc::new_cyclic(|self_weak| PicoWindow {
Rc::new_cyclic(|self_weak| PicoWindow { window: i_slint_core::api::Window::new(self_weak.clone() as _),
window_inner_weak: window.clone(), self_weak: self_weak.clone(),
self_weak: self_weak.clone(), renderer: renderer::SoftwareRenderer::new(renderer::DirtyTracking::SingleBuffer),
renderer: renderer::SoftwareRenderer::new(renderer::DirtyTracking::SingleBuffer), needs_redraw: Default::default(),
needs_redraw: Default::default(),
})
}) })
.into()
} }
fn run_event_loop(&self, _behavior: i_slint_core::backend::EventLoopQuitBehavior) { fn run_event_loop(&self, _behavior: i_slint_core::backend::EventLoopQuitBehavior) {
@ -200,11 +197,8 @@ fn run_event_loop() -> ! {
i_slint_core::timers::update_timers(); i_slint_core::timers::update_timers();
if let Some(window) = WINDOW.with(|x| x.borrow().clone()) { if let Some(window) = WINDOW.with(|x| x.borrow().clone()) {
let runtime_window =
i_slint_core::api::Window::from(window.window_inner_weak.upgrade().unwrap());
if window.needs_redraw.replace(false) { if window.needs_redraw.replace(false) {
window.renderer.render_by_line(&runtime_window, &mut buffer_provider); window.renderer.render_by_line(&window.window, &mut buffer_provider);
buffer_provider.flush_frame(); buffer_provider.flush_frame();
} }
@ -217,7 +211,7 @@ fn run_event_loop() -> ! {
.map(|point| { .map(|point| {
let size = DISPLAY_SIZE.to_f32(); let size = DISPLAY_SIZE.to_f32();
let position = euclid::point2(point.x * size.width, point.y * size.height) let position = euclid::point2(point.x * size.width, point.y * size.height)
/ runtime_window.scale_factor(); / window.window.scale_factor().get();
match last_touch.replace(position) { match last_touch.replace(position) {
Some(_) => PointerEvent::Moved { position }, Some(_) => PointerEvent::Moved { position },
None => PointerEvent::Pressed { position, button }, None => PointerEvent::Pressed { position, button },
@ -227,7 +221,7 @@ fn run_event_loop() -> ! {
last_touch.take().map(|position| PointerEvent::Released { position, button }) last_touch.take().map(|position| PointerEvent::Released { position, button })
}) })
{ {
runtime_window.dispatch_pointer_event(event); window.window.dispatch_pointer_event(event);
// Don't go to sleep after a touch event that forces a redraw // Don't go to sleep after a touch event that forces a redraw
continue; continue;
} }
@ -287,7 +281,7 @@ impl<TO: WriteTarget<TransmittedWord = u8> + FullDuplex<u8>, CH: SingleChannel>
} }
struct PicoWindow { struct PicoWindow {
window_inner_weak: Weak<i_slint_core::window::WindowInner>, window: i_slint_core::api::Window,
self_weak: Weak<Self>, self_weak: Weak<Self>,
renderer: crate::renderer::SoftwareRenderer, renderer: crate::renderer::SoftwareRenderer,
needs_redraw: Cell<bool>, needs_redraw: Cell<bool>,
@ -295,9 +289,7 @@ struct PicoWindow {
impl i_slint_core::window::PlatformWindow for PicoWindow { impl i_slint_core::window::PlatformWindow for PicoWindow {
fn show(&self) { fn show(&self) {
let runtime_window = self.window.set_size(DISPLAY_SIZE.cast());
i_slint_core::api::Window::from(self.window_inner_weak.upgrade().unwrap());
runtime_window.set_size(DISPLAY_SIZE.cast());
WINDOW.with(|x| *x.borrow_mut() = Some(self.self_weak.upgrade().unwrap())) WINDOW.with(|x| *x.borrow_mut() = Some(self.self_weak.upgrade().unwrap()))
} }
fn hide(&self) { fn hide(&self) {
@ -315,8 +307,8 @@ impl i_slint_core::window::PlatformWindow for PicoWindow {
self self
} }
fn window(&self) -> i_slint_core::window::WindowRc { fn window(&self) -> &i_slint_core::api::Window {
self.window_inner_weak.upgrade().unwrap() &self.window
} }
} }

View file

@ -12,7 +12,7 @@ use i_slint_core::api::{euclid, PhysicalPx};
use i_slint_core::component::ComponentRc; use i_slint_core::component::ComponentRc;
use i_slint_core::input::KeyboardModifiers; use i_slint_core::input::KeyboardModifiers;
use i_slint_core::layout::Orientation; use i_slint_core::layout::Orientation;
use i_slint_core::window::{PlatformWindow, WindowRc}; use i_slint_core::window::{PlatformWindow, PlatformWindowRc, WindowHandleAccess};
use i_slint_core::Coord; use i_slint_core::Coord;
use rgb::FromSlice; use rgb::FromSlice;
@ -27,7 +27,7 @@ use glcontext::*;
use i_slint_core::swrenderer::SoftwareRenderer; use i_slint_core::swrenderer::SoftwareRenderer;
pub struct SimulatorWindow { pub struct SimulatorWindow {
window_inner_weak: Weak<i_slint_core::window::WindowInner>, window: i_slint_core::api::Window,
self_weak: Weak<Self>, self_weak: Weak<Self>,
keyboard_modifiers: std::cell::Cell<KeyboardModifiers>, keyboard_modifiers: std::cell::Cell<KeyboardModifiers>,
currently_pressed_key_code: std::cell::Cell<Option<winit::event::VirtualKeyCode>>, currently_pressed_key_code: std::cell::Cell<Option<winit::event::VirtualKeyCode>>,
@ -40,7 +40,7 @@ pub struct SimulatorWindow {
} }
impl SimulatorWindow { impl SimulatorWindow {
pub(crate) fn new(window_weak: &Weak<i_slint_core::window::WindowInner>) -> Rc<Self> { pub(crate) fn new() -> Rc<Self> {
let window_builder = winit::window::WindowBuilder::new().with_visible(false); let window_builder = winit::window::WindowBuilder::new().with_visible(false);
let opengl_context = OpenGLContext::new_context(window_builder); let opengl_context = OpenGLContext::new_context(window_builder);
@ -56,7 +56,7 @@ impl SimulatorWindow {
let canvas = Rc::new(RefCell::new(canvas)); let canvas = Rc::new(RefCell::new(canvas));
let window_rc = Rc::new_cyclic(|self_weak| Self { let window_rc = Rc::new_cyclic(|self_weak| Self {
window_inner_weak: window_weak.clone(), window: i_slint_core::api::Window::new(self_weak.clone() as _),
self_weak: self_weak.clone(), self_weak: self_weak.clone(),
keyboard_modifiers: Default::default(), keyboard_modifiers: Default::default(),
currently_pressed_key_code: Default::default(), currently_pressed_key_code: Default::default(),
@ -68,7 +68,7 @@ impl SimulatorWindow {
renderer: Default::default(), renderer: Default::default(),
}); });
let runtime_window = window_weak.upgrade().unwrap(); let runtime_window = window_rc.window.window_handle();
runtime_window.set_scale_factor(window_rc.opengl_context.window().scale_factor() as _); runtime_window.set_scale_factor(window_rc.opengl_context.window().scale_factor() as _);
window_rc window_rc
@ -89,7 +89,7 @@ impl PlatformWindow for SimulatorWindow {
self.visible.set(true); self.visible.set(true);
let runtime_window = self.window(); let runtime_window = self.window.window_handle();
let component_rc = runtime_window.component(); let component_rc = runtime_window.component();
let component = ComponentRc::borrow_pin(&component_rc); let component = ComponentRc::borrow_pin(&component_rc);
@ -178,8 +178,8 @@ impl PlatformWindow for SimulatorWindow {
unimplemented!() unimplemented!()
} }
fn window(&self) -> WindowRc { fn window(&self) -> &i_slint_core::api::Window {
self.window_inner_weak.upgrade().unwrap() &self.window
} }
} }
@ -193,8 +193,6 @@ impl WinitWindow for SimulatorWindow {
} }
fn draw(&self) { fn draw(&self) {
let runtime_window = self.window_inner_weak.upgrade().unwrap();
let size = self.opengl_context.window().inner_size(); let size = self.opengl_context.window().inner_size();
self.opengl_context.with_current_context(|opengl_context| { self.opengl_context.with_current_context(|opengl_context| {
@ -237,8 +235,7 @@ impl WinitWindow for SimulatorWindow {
}); });
} }
} }
self.renderer self.renderer.render_by_line(&self.window, BufferProvider { devices: display });
.render_by_line(&runtime_window.into(), BufferProvider { devices: display });
let output_image = display let output_image = display
.to_rgb_output_image(&embedded_graphics_simulator::OutputSettings::default()); .to_rgb_output_image(&embedded_graphics_simulator::OutputSettings::default());
@ -301,8 +298,8 @@ impl WinitWindow for SimulatorWindow {
pub struct SimulatorBackend; pub struct SimulatorBackend;
impl i_slint_core::backend::Backend for SimulatorBackend { impl i_slint_core::backend::Backend for SimulatorBackend {
fn create_window(&self) -> i_slint_core::api::Window { fn create_window(&self) -> PlatformWindowRc {
i_slint_core::window::WindowInner::new(|window| SimulatorWindow::new(window)).into() SimulatorWindow::new()
} }
fn run_event_loop(&self, behavior: i_slint_core::backend::EventLoopQuitBehavior) { fn run_event_loop(&self, behavior: i_slint_core::backend::EventLoopQuitBehavior) {

View file

@ -38,7 +38,7 @@ pub fn use_modules() -> usize {
mod ffi { mod ffi {
#[no_mangle] #[no_mangle]
pub extern "C" fn slint_qt_get_widget( pub extern "C" fn slint_qt_get_widget(
_: &i_slint_core::window::WindowRc, _: &i_slint_core::window::PlatformWindowRc,
) -> *mut std::ffi::c_void { ) -> *mut std::ffi::c_void {
std::ptr::null_mut() std::ptr::null_mut()
} }
@ -122,6 +122,7 @@ pub type NativeGlobals = ();
pub const HAS_NATIVE_STYLE: bool = cfg!(not(no_qt)); pub const HAS_NATIVE_STYLE: bool = cfg!(not(no_qt));
use i_slint_core::window::PlatformWindowRc;
#[cfg(not(no_qt))] #[cfg(not(no_qt))]
pub use qt_widgets::{native_style_metrics_deinit, native_style_metrics_init}; pub use qt_widgets::{native_style_metrics_deinit, native_style_metrics_init};
#[cfg(no_qt)] #[cfg(no_qt)]
@ -135,12 +136,12 @@ pub fn native_style_metrics_deinit(_: core::pin::Pin<&mut native_widgets::Native
pub struct Backend; pub struct Backend;
impl i_slint_core::backend::Backend for Backend { impl i_slint_core::backend::Backend for Backend {
fn create_window(&self) -> i_slint_core::api::Window { fn create_window(&self) -> PlatformWindowRc {
#[cfg(no_qt)] #[cfg(no_qt)]
panic!("The Qt backend needs Qt"); panic!("The Qt backend needs Qt");
#[cfg(not(no_qt))] #[cfg(not(no_qt))]
{ {
i_slint_core::window::WindowInner::new(|window| qt_window::QtWindow::new(window)).into() qt_window::QtWindow::new()
} }
} }

View file

@ -8,6 +8,7 @@ use crate::accessible_generated::*;
use i_slint_core::accessibility::AccessibleStringProperty; use i_slint_core::accessibility::AccessibleStringProperty;
use i_slint_core::item_tree::{ItemRc, ItemWeak}; use i_slint_core::item_tree::{ItemRc, ItemWeak};
use i_slint_core::properties::{PropertyDirtyHandler, PropertyTracker}; use i_slint_core::properties::{PropertyDirtyHandler, PropertyTracker};
use i_slint_core::window::WindowHandleAccess;
use i_slint_core::SharedVector; use i_slint_core::SharedVector;
use cpp::*; use cpp::*;
@ -327,9 +328,9 @@ cpp! {{
}; };
void *root_item_for_window(void *rustWindow) { void *root_item_for_window(void *rustWindow) {
return rust!(root_item_for_window_ [rustWindow: &i_slint_core::window::WindowInner as "void*"] return rust!(root_item_for_window_ [rustWindow: &std::rc::Weak<crate::qt_window::QtWindow> as "void*"]
-> *mut c_void as "void*" { -> *mut c_void as "void*" {
let root_item = Box::new(ItemRc::new(rustWindow.component(), 0).downgrade()); let root_item = Box::new(ItemRc::new(rustWindow.upgrade().unwrap().window.window_handle().component(), 0).downgrade());
Box::into_raw(root_item) as _ Box::into_raw(root_item) as _
}); });
} }

View file

@ -31,7 +31,7 @@ use i_slint_core::items::{Item, ItemConsts, ItemRc, ItemVTable, RenderingResult,
use i_slint_core::layout::{LayoutInfo, Orientation}; use i_slint_core::layout::{LayoutInfo, Orientation};
#[cfg(feature = "rtti")] #[cfg(feature = "rtti")]
use i_slint_core::rtti::*; use i_slint_core::rtti::*;
use i_slint_core::window::WindowInner; use i_slint_core::window::{WindowHandleAccess, WindowInner};
use i_slint_core::{ use i_slint_core::{
declare_item_vtable, Callback, ItemVTable_static, Property, SharedString, SharedVector, declare_item_vtable, Callback, ItemVTable_static, Property, SharedString, SharedVector,
}; };
@ -59,7 +59,7 @@ macro_rules! fn_render {
let $dpr: f32 = backend.scale_factor(); let $dpr: f32 = backend.scale_factor();
let window = backend.window(); let window = backend.window();
let active: bool = window.active(); let active: bool = window.window_handle().active();
// This should include self.enabled() as well, but not every native widget // This should include self.enabled() as well, but not every native widget
// has that property right now. // has that property right now.
let $initial_state = cpp!(unsafe [ active as "bool" ] -> i32 as "int" { let $initial_state = cpp!(unsafe [ active as "bool" ] -> i32 as "int" {

View file

@ -20,7 +20,7 @@ use i_slint_core::items::{
PointerEventButton, RenderingResult, TextOverflow, TextWrap, PointerEventButton, RenderingResult, TextOverflow, TextWrap,
}; };
use i_slint_core::layout::Orientation; use i_slint_core::layout::Orientation;
use i_slint_core::window::{PlatformWindow, WindowRc}; use i_slint_core::window::{PlatformWindow, PlatformWindowRc, WindowHandleAccess};
use i_slint_core::{ImageInner, PathData, Property, SharedString}; use i_slint_core::{ImageInner, PathData, Property, SharedString};
use items::{ImageFit, TextHorizontalAlignment, TextVerticalAlignment}; use items::{ImageFit, TextHorizontalAlignment, TextVerticalAlignment};
@ -189,7 +189,7 @@ cpp! {{
void customEvent(QEvent *event) override { void customEvent(QEvent *event) override {
if (event->type() == QEvent::User) { if (event->type() == QEvent::User) {
rust!(Slint_updateWindowProps [rust_window: &QtWindow as "void*"] { rust!(Slint_updateWindowProps [rust_window: &QtWindow as "void*"] {
if let Some(window) = rust_window.self_weak.upgrade() { window.update_window_properties() } rust_window.window.window_handle().update_window_properties()
}); });
} else { } else {
QWidget::customEvent(event); QWidget::customEvent(event);
@ -200,7 +200,7 @@ cpp! {{
if (event->type() == QEvent::ActivationChange) { if (event->type() == QEvent::ActivationChange) {
bool active = isActiveWindow(); bool active = isActiveWindow();
rust!(Slint_updateWindowActivation [rust_window: &QtWindow as "void*", active: bool as "bool"] { rust!(Slint_updateWindowActivation [rust_window: &QtWindow as "void*", active: bool as "bool"] {
if let Some(window) = rust_window.self_weak.upgrade() { window.set_active(active) } rust_window.window.window_handle().set_active(active)
}); });
} }
QWidget::changeEvent(event); QWidget::changeEvent(event);
@ -208,10 +208,7 @@ cpp! {{
void closeEvent(QCloseEvent *event) override { void closeEvent(QCloseEvent *event) override {
bool accepted = rust!(Slint_requestClose [rust_window: &QtWindow as "void*"] -> bool as "bool" { bool accepted = rust!(Slint_requestClose [rust_window: &QtWindow as "void*"] -> bool as "bool" {
if let Some(window) = rust_window.self_weak.upgrade() { return rust_window.window.window_handle().request_close();
return window.request_close();
}
true
}); });
if (accepted) { if (accepted) {
event->accept(); event->accept();
@ -222,7 +219,7 @@ cpp! {{
QSize sizeHint() const override { QSize sizeHint() const override {
auto preferred_size = rust!(Slint_sizeHint [rust_window: &QtWindow as "void*"] -> qttypes::QSize as "QSize" { auto preferred_size = rust!(Slint_sizeHint [rust_window: &QtWindow as "void*"] -> qttypes::QSize as "QSize" {
let component_rc = rust_window.self_weak.upgrade().unwrap().component(); let component_rc = rust_window.window.window_handle().component();
let component = ComponentRc::borrow_pin(&component_rc); let component = ComponentRc::borrow_pin(&component_rc);
let layout_info_h = component.as_ref().layout_info(Orientation::Horizontal); let layout_info_h = component.as_ref().layout_info(Orientation::Horizontal);
let layout_info_v = component.as_ref().layout_info(Orientation::Vertical); let layout_info_v = component.as_ref().layout_info(Orientation::Vertical);
@ -451,7 +448,7 @@ fn adjust_rect_and_border_for_inner_drawing(rect: &mut qttypes::QRectF, border_w
struct QtItemRenderer<'a> { struct QtItemRenderer<'a> {
painter: QPainterPtr, painter: QPainterPtr,
cache: &'a ItemCache<qttypes::QPixmap>, cache: &'a ItemCache<qttypes::QPixmap>,
window: WindowRc, window: &'a i_slint_core::api::Window,
metrics: RenderingMetrics, metrics: RenderingMetrics,
} }
@ -516,7 +513,7 @@ impl ItemRenderer for QtItemRenderer<'_> {
let rect: qttypes::QRectF = get_geometry!(items::Text, text); let rect: qttypes::QRectF = get_geometry!(items::Text, text);
let fill_brush: qttypes::QBrush = into_qbrush(text.color(), rect.width, rect.height); let fill_brush: qttypes::QBrush = into_qbrush(text.color(), rect.width, rect.height);
let mut string: qttypes::QString = text.text().as_str().into(); let mut string: qttypes::QString = text.text().as_str().into();
let font: QFont = get_font(text.font_request(&self.window)); let font: QFont = get_font(text.font_request(self.window.window_handle()));
let flags = match text.horizontal_alignment() { let flags = match text.horizontal_alignment() {
TextHorizontalAlignment::Left => key_generated::Qt_AlignmentFlag_AlignLeft, TextHorizontalAlignment::Left => key_generated::Qt_AlignmentFlag_AlignLeft,
TextHorizontalAlignment::Center => key_generated::Qt_AlignmentFlag_AlignHCenter, TextHorizontalAlignment::Center => key_generated::Qt_AlignmentFlag_AlignHCenter,
@ -607,7 +604,7 @@ impl ItemRenderer for QtItemRenderer<'_> {
}} }}
} }
let font: QFont = get_font(text_input.font_request(&self.window)); let font: QFont = get_font(text_input.font_request(self.window.window_handle()));
let flags = match text_input.horizontal_alignment() { let flags = match text_input.horizontal_alignment() {
TextHorizontalAlignment::Left => key_generated::Qt_AlignmentFlag_AlignLeft, TextHorizontalAlignment::Left => key_generated::Qt_AlignmentFlag_AlignLeft,
TextHorizontalAlignment::Center => key_generated::Qt_AlignmentFlag_AlignHCenter, TextHorizontalAlignment::Center => key_generated::Qt_AlignmentFlag_AlignHCenter,
@ -925,8 +922,8 @@ impl ItemRenderer for QtItemRenderer<'_> {
}} }}
} }
fn window(&self) -> WindowRc { fn window(&self) -> &i_slint_core::api::Window {
self.window.clone() &self.window
} }
fn as_any(&mut self) -> Option<&mut dyn std::any::Any> { fn as_any(&mut self) -> Option<&mut dyn std::any::Any> {
@ -1202,7 +1199,8 @@ cpp_class!(unsafe struct QWidgetPtr as "std::unique_ptr<QWidget>");
pub struct QtWindow { pub struct QtWindow {
widget_ptr: QWidgetPtr, widget_ptr: QWidgetPtr,
pub(crate) self_weak: Weak<i_slint_core::window::WindowInner>, pub(crate) window: i_slint_core::api::Window,
self_weak: Weak<Self>,
rendering_metrics_collector: RefCell<Option<Rc<RenderingMetricsCollector>>>, rendering_metrics_collector: RefCell<Option<Rc<RenderingMetricsCollector>>>,
@ -1212,31 +1210,34 @@ pub struct QtWindow {
} }
impl QtWindow { impl QtWindow {
pub fn new(window_weak: &Weak<i_slint_core::window::WindowInner>) -> Rc<Self> { pub fn new() -> Rc<Self> {
let window_ptr = window_weak.clone().into_raw(); let rc = Rc::new_cyclic(|self_weak| {
let widget_ptr = cpp! {unsafe [window_ptr as "void*"] -> QWidgetPtr as "std::unique_ptr<QWidget>" { let window_ptr = self_weak.clone().into_raw();
ensure_initialized(true); let widget_ptr = cpp! {unsafe [window_ptr as "void*"] -> QWidgetPtr as "std::unique_ptr<QWidget>" {
auto widget = std::make_unique<SlintWidget>(); ensure_initialized(true);
auto widget = std::make_unique<SlintWidget>();
auto accessibility = new Slint_accessible_window(widget.get(), window_ptr); auto accessibility = new Slint_accessible_window(widget.get(), window_ptr);
QAccessible::registerAccessibleInterface(accessibility); QAccessible::registerAccessibleInterface(accessibility);
return widget; return widget;
}}; }};
let rc = Rc::new(QtWindow {
widget_ptr, QtWindow {
self_weak: window_weak.clone(), widget_ptr,
rendering_metrics_collector: Default::default(), window: i_slint_core::api::Window::new(self_weak.clone() as _),
cache: Default::default(), self_weak: self_weak.clone(),
tree_structure_changed: RefCell::new(false), rendering_metrics_collector: Default::default(),
cache: Default::default(),
tree_structure_changed: RefCell::new(false),
}
}); });
let self_weak = Rc::downgrade(&rc);
let widget_ptr = rc.widget_ptr(); let widget_ptr = rc.widget_ptr();
let rust_window = Rc::as_ptr(&rc); let rust_window = Rc::as_ptr(&rc);
cpp! {unsafe [widget_ptr as "SlintWidget*", rust_window as "void*"] { cpp! {unsafe [widget_ptr as "SlintWidget*", rust_window as "void*"] {
widget_ptr->rust_window = rust_window; widget_ptr->rust_window = rust_window;
}}; }};
ALL_WINDOWS.with(|aw| aw.borrow_mut().push(self_weak)); ALL_WINDOWS.with(|aw| aw.borrow_mut().push(rc.self_weak.clone()));
rc rc
} }
@ -1246,13 +1247,13 @@ impl QtWindow {
} }
fn paint_event(&self, painter: QPainterPtr) { fn paint_event(&self, painter: QPainterPtr) {
let runtime_window = self.self_weak.upgrade().unwrap(); let runtime_window = self.window.window_handle();
runtime_window.clone().draw_contents(|components| { runtime_window.draw_contents(|components| {
i_slint_core::animations::update_animations(); i_slint_core::animations::update_animations();
let mut renderer = QtItemRenderer { let mut renderer = QtItemRenderer {
painter, painter,
cache: &self.cache, cache: &self.cache,
window: runtime_window, window: &self.window,
metrics: RenderingMetrics { layers_created: Some(0) }, metrics: RenderingMetrics { layers_created: Some(0) },
}; };
@ -1295,12 +1296,11 @@ impl QtWindow {
} }
fn resize_event(&self, size: qttypes::QSize) { fn resize_event(&self, size: qttypes::QSize) {
i_slint_core::api::Window::from(self.self_weak.upgrade().unwrap()) self.window.set_size(euclid::size2(size.width, size.height));
.set_size(euclid::size2(size.width, size.height));
} }
fn mouse_event(&self, event: MouseEvent) { fn mouse_event(&self, event: MouseEvent) {
self.self_weak.upgrade().unwrap().process_mouse_input(event); self.window.window_handle().process_mouse_input(event);
timer_event(); timer_event();
} }
@ -1321,13 +1321,13 @@ impl QtWindow {
text, text,
modifiers, modifiers,
}; };
self.self_weak.upgrade().unwrap().process_key_input(&event); self.window.window_handle().process_key_input(&event);
timer_event(); timer_event();
} }
fn close_popup(&self) { fn close_popup(&self) {
self.self_weak.upgrade().unwrap().close_popup(); self.window.window_handle().close_popup();
} }
fn free_graphics_resources(&self, component: ComponentRef) { fn free_graphics_resources(&self, component: ComponentRef) {
@ -1339,7 +1339,7 @@ impl QtWindow {
#[allow(unused)] #[allow(unused)]
impl PlatformWindow for QtWindow { impl PlatformWindow for QtWindow {
fn show(&self) { fn show(&self) {
let component_rc = self.self_weak.upgrade().unwrap().component(); let component_rc = self.window.window_handle().component();
let component = ComponentRc::borrow_pin(&component_rc); let component = ComponentRc::borrow_pin(&component_rc);
let root_item = component.as_ref().get_item_ref(0); let root_item = component.as_ref().get_item_ref(0);
if let Some(window_item) = ItemRef::downcast_pin(root_item) { if let Some(window_item) = ItemRef::downcast_pin(root_item) {
@ -1478,12 +1478,8 @@ impl PlatformWindow for QtWindow {
self.tree_structure_changed.replace(true); self.tree_structure_changed.replace(true);
} }
fn create_popup(&self, geometry: Rect) -> Option<i_slint_core::api::Window> { fn create_popup(&self, geometry: Rect) -> Option<PlatformWindowRc> {
let window = i_slint_core::window::WindowInner::new(|window| QtWindow::new(window)); let popup_window = QtWindow::new();
let popup_window: &QtWindow =
<dyn std::any::Any>::downcast_ref(window.as_ref().as_any()).unwrap();
let runtime_window = self.self_weak.upgrade().unwrap();
let size = qttypes::QSize { width: geometry.width() as _, height: geometry.height() as _ }; let size = qttypes::QSize { width: geometry.width() as _, height: geometry.height() as _ };
@ -1495,7 +1491,7 @@ impl PlatformWindow for QtWindow {
popup_ptr->setGeometry(QRect(pos + widget_ptr->mapToGlobal(QPoint(0,0)), size)); popup_ptr->setGeometry(QRect(pos + widget_ptr->mapToGlobal(QPoint(0,0)), size));
popup_ptr->show(); popup_ptr->show();
}}; }};
Some(window.into()) Some(popup_window as _)
} }
fn set_mouse_cursor(&self, cursor: MouseCursor) { fn set_mouse_cursor(&self, cursor: MouseCursor) {
@ -1583,8 +1579,8 @@ impl PlatformWindow for QtWindow {
}}; }};
} }
fn window(&self) -> WindowRc { fn window(&self) -> &i_slint_core::api::Window {
self.self_weak.upgrade().unwrap() &self.window
} }
} }
@ -1609,8 +1605,7 @@ impl Renderer for QtWindow {
} }
let rect: qttypes::QRectF = get_geometry!(items::TextInput, text_input); let rect: qttypes::QRectF = get_geometry!(items::TextInput, text_input);
let pos = qttypes::QPointF { x: pos.x as _, y: pos.y as _ }; let pos = qttypes::QPointF { x: pos.x as _, y: pos.y as _ };
let runtime_window = self.self_weak.upgrade().unwrap(); let font: QFont = get_font(text_input.font_request(self.window.window_handle()));
let font: QFont = get_font(text_input.font_request(&runtime_window));
let string = qttypes::QString::from(text_input.text().as_str()); let string = qttypes::QString::from(text_input.text().as_str());
let flags = match text_input.horizontal_alignment() { let flags = match text_input.horizontal_alignment() {
TextHorizontalAlignment::Left => key_generated::Qt_AlignmentFlag_AlignLeft, TextHorizontalAlignment::Left => key_generated::Qt_AlignmentFlag_AlignLeft,
@ -1665,8 +1660,7 @@ impl Renderer for QtWindow {
byte_offset: usize, byte_offset: usize,
) -> Rect { ) -> Rect {
let rect: qttypes::QRectF = get_geometry!(items::TextInput, text_input); let rect: qttypes::QRectF = get_geometry!(items::TextInput, text_input);
let runtime_window = self.self_weak.upgrade().unwrap(); let font: QFont = get_font(text_input.font_request(self.window.window_handle()));
let font: QFont = get_font(text_input.font_request(&runtime_window));
let text = text_input.text(); let text = text_input.text();
let mut string = qttypes::QString::from(text.as_str()); let mut string = qttypes::QString::from(text.as_str());
let offset: u32 = utf8_byte_offset_to_utf16_units(text.as_str(), byte_offset) as _; let offset: u32 = utf8_byte_offset_to_utf16_units(text.as_str(), byte_offset) as _;
@ -1943,8 +1937,10 @@ pub(crate) mod ffi {
use super::QtWindow; use super::QtWindow;
#[no_mangle] #[no_mangle]
pub extern "C" fn slint_qt_get_widget(window: &i_slint_core::window::WindowRc) -> *mut c_void { pub extern "C" fn slint_qt_get_widget(
<dyn std::any::Any>::downcast_ref(window.as_any()) platform_window: &i_slint_core::window::PlatformWindowRc,
) -> *mut c_void {
<dyn std::any::Any>::downcast_ref(platform_window.as_any())
.map_or(std::ptr::null_mut(), |win: &QtWindow| { .map_or(std::ptr::null_mut(), |win: &QtWindow| {
win.widget_ptr().cast::<c_void>().as_ptr() win.widget_ptr().cast::<c_void>().as_ptr()
}) })

View file

@ -6,14 +6,12 @@
use i_slint_core::api::euclid; use i_slint_core::api::euclid;
use i_slint_core::api::PhysicalPx; use i_slint_core::api::PhysicalPx;
use i_slint_core::api::Window;
use i_slint_core::graphics::{Point, Rect, Size}; use i_slint_core::graphics::{Point, Rect, Size};
use i_slint_core::renderer::Renderer; use i_slint_core::renderer::Renderer;
use i_slint_core::window::WindowRc; use i_slint_core::window::PlatformWindow;
use i_slint_core::window::{PlatformWindow, WindowInner}; use i_slint_core::window::PlatformWindowRc;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
use std::rc::Weak;
use std::sync::Mutex; use std::sync::Mutex;
#[derive(Default)] #[derive(Default)]
@ -22,9 +20,10 @@ pub struct TestingBackend {
} }
impl i_slint_core::backend::Backend for TestingBackend { impl i_slint_core::backend::Backend for TestingBackend {
fn create_window(&self) -> Window { fn create_window(&self) -> PlatformWindowRc {
WindowInner::new(|window_weak| Rc::new(TestingWindow { self_weak: window_weak.clone() })) Rc::new_cyclic(|self_weak| TestingWindow {
.into() window: i_slint_core::api::Window::new(self_weak.clone() as _),
})
} }
fn run_event_loop(&self, _behavior: i_slint_core::backend::EventLoopQuitBehavior) { fn run_event_loop(&self, _behavior: i_slint_core::backend::EventLoopQuitBehavior) {
@ -52,7 +51,7 @@ impl i_slint_core::backend::Backend for TestingBackend {
} }
pub struct TestingWindow { pub struct TestingWindow {
self_weak: Weak<i_slint_core::window::WindowInner>, window: i_slint_core::api::Window,
} }
impl PlatformWindow for TestingWindow { impl PlatformWindow for TestingWindow {
@ -104,8 +103,8 @@ impl PlatformWindow for TestingWindow {
unimplemented!() unimplemented!()
} }
fn window(&self) -> WindowRc { fn window(&self) -> &i_slint_core::api::Window {
self.self_weak.upgrade().unwrap() &self.window
} }
} }

View file

@ -57,7 +57,7 @@ pub trait WinitWindow: PlatformWindow {
let max_width = constraints_horizontal.max.max(constraints_horizontal.min) as f32; let max_width = constraints_horizontal.max.max(constraints_horizontal.min) as f32;
let max_height = constraints_vertical.max.max(constraints_vertical.min) as f32; let max_height = constraints_vertical.max.max(constraints_vertical.min) as f32;
let sf = self.window().scale_factor(); let sf = self.window().scale_factor().get();
winit_window.set_resizable(true); winit_window.set_resizable(true);
winit_window.set_min_inner_size(if min_width > 0. || min_height > 0. { winit_window.set_min_inner_size(if min_width > 0. || min_height > 0. {
@ -123,7 +123,7 @@ pub trait WinitWindow: PlatformWindow {
must_resize = true; must_resize = true;
let winit_size = let winit_size =
winit_window.inner_size().to_logical(self.window().scale_factor() as f64); winit_window.inner_size().to_logical(self.window().scale_factor().get() as f64);
if width <= 0. { if width <= 0. {
width = winit_size.width; width = winit_size.width;
@ -133,7 +133,8 @@ pub trait WinitWindow: PlatformWindow {
} }
} }
let existing_size: LogicalSize = self.inner_size().cast() / self.window().scale(); let existing_size: LogicalSize =
self.inner_size().cast() / self.window().scale_factor();
if (existing_size.width as f32 - width).abs() > 1. if (existing_size.width as f32 - width).abs() > 1.
|| (existing_size.height as f32 - height).abs() > 1. || (existing_size.height as f32 - height).abs() > 1.
@ -148,7 +149,7 @@ pub trait WinitWindow: PlatformWindow {
}); });
if must_resize { if must_resize {
let win = i_slint_core::api::Window::from(self.window()); let win = self.window();
let f = win.scale_factor().0; let f = win.scale_factor().0;
win.set_size(euclid::size2((width as f32 * f) as _, (height as f32 * f) as _)); win.set_size(euclid::size2((width as f32 * f) as _, (height as f32 * f) as _));
} }
@ -380,7 +381,7 @@ fn process_window_event(
event event
} }
let runtime_window = window.window(); let runtime_window = window.window().window_handle();
match event { match event {
WindowEvent::Resized(size) => { WindowEvent::Resized(size) => {
window.resize_event(size); window.resize_event(size);
@ -651,7 +652,7 @@ pub fn run(quit_behavior: i_slint_core::backend::EventLoopQuitBehavior) {
.drain(..) .drain(..)
.flat_map(|window_id| window_by_id(window_id)) .flat_map(|window_id| window_by_id(window_id))
{ {
window.window().update_window_properties(); window.window().window_handle().update_window_properties();
} }
} }

View file

@ -17,7 +17,7 @@ use corelib::component::ComponentRc;
use corelib::input::KeyboardModifiers; use corelib::input::KeyboardModifiers;
use corelib::items::{ItemRef, MouseCursor}; use corelib::items::{ItemRef, MouseCursor};
use corelib::layout::Orientation; use corelib::layout::Orientation;
use corelib::window::{PlatformWindow, WindowRc}; use corelib::window::{PlatformWindow, PlatformWindowRc, WindowHandleAccess};
use corelib::Property; use corelib::Property;
use corelib::{graphics::*, Coord}; use corelib::{graphics::*, Coord};
use i_slint_core as corelib; use i_slint_core as corelib;
@ -26,7 +26,7 @@ use winit::dpi::LogicalSize;
/// GraphicsWindow is an implementation of the [PlatformWindow][`crate::eventloop::PlatformWindow`] trait. This is /// GraphicsWindow is an implementation of the [PlatformWindow][`crate::eventloop::PlatformWindow`] trait. This is
/// typically instantiated by entry factory functions of the different graphics back ends. /// typically instantiated by entry factory functions of the different graphics back ends.
pub(crate) struct GLWindow<Renderer: WinitCompatibleRenderer + 'static> { pub(crate) struct GLWindow<Renderer: WinitCompatibleRenderer + 'static> {
window_inner_weak: Weak<corelib::window::WindowInner>, window: corelib::api::Window,
self_weak: Weak<Self>, self_weak: Weak<Self>,
map_state: RefCell<GraphicsWindowBackendState<Renderer>>, map_state: RefCell<GraphicsWindowBackendState<Renderer>>,
keyboard_modifiers: std::cell::Cell<KeyboardModifiers>, keyboard_modifiers: std::cell::Cell<KeyboardModifiers>,
@ -38,19 +38,16 @@ pub(crate) struct GLWindow<Renderer: WinitCompatibleRenderer + 'static> {
virtual_keyboard_helper: RefCell<Option<super::wasm_input_helper::WasmInputHelper>>, virtual_keyboard_helper: RefCell<Option<super::wasm_input_helper::WasmInputHelper>>,
} }
impl<Renderer: WinitCompatibleRenderer> GLWindow<Renderer> { impl<Renderer: WinitCompatibleRenderer + 'static> GLWindow<Renderer> {
/// Creates a new reference-counted instance. /// Creates a new reference-counted instance.
/// ///
/// Arguments: /// Arguments:
/// * `graphics_backend_factory`: The factor function stored in the GraphicsWindow that's called when the state /// * `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 /// of the window changes to mapped. The event loop and window builder parameters can be used to create a
/// backing window. /// backing window.
pub(crate) fn new( pub(crate) fn new(#[cfg(target_arch = "wasm32")] canvas_id: String) -> PlatformWindowRc {
window_weak: &Weak<corelib::window::WindowInner>, let self_rc = Rc::new_cyclic(|self_weak| Self {
#[cfg(target_arch = "wasm32")] canvas_id: String, window: corelib::api::Window::new(self_weak.clone() as _),
) -> Rc<Self> {
Rc::new_cyclic(|self_weak| Self {
window_inner_weak: window_weak.clone(),
self_weak: self_weak.clone(), self_weak: self_weak.clone(),
map_state: RefCell::new(GraphicsWindowBackendState::Unmapped { map_state: RefCell::new(GraphicsWindowBackendState::Unmapped {
requested_position: None, requested_position: None,
@ -59,13 +56,14 @@ impl<Renderer: WinitCompatibleRenderer> GLWindow<Renderer> {
keyboard_modifiers: Default::default(), keyboard_modifiers: Default::default(),
currently_pressed_key_code: Default::default(), currently_pressed_key_code: Default::default(),
renderer: Renderer::new( renderer: Renderer::new(
&window_weak, &(self_weak.clone() as _),
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
canvas_id, canvas_id,
), ),
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
virtual_keyboard_helper: Default::default(), virtual_keyboard_helper: Default::default(),
}) });
self_rc as _
} }
fn is_mapped(&self) -> bool { fn is_mapped(&self) -> bool {
@ -192,8 +190,7 @@ impl<Renderer: WinitCompatibleRenderer + 'static> WinitWindow for GLWindow<Rende
fn resize_event(&self, size: winit::dpi::PhysicalSize<u32>) { fn resize_event(&self, size: winit::dpi::PhysicalSize<u32>) {
if let Some(mapped_window) = self.borrow_mapped_window() { if let Some(mapped_window) = self.borrow_mapped_window() {
i_slint_core::api::Window::from(self.window()) self.window().set_size(euclid::size2(size.width, size.height));
.set_size(euclid::size2(size.width, size.height));
mapped_window.canvas.resize_event() mapped_window.canvas.resize_event()
} }
} }
@ -270,7 +267,7 @@ impl<Renderer: WinitCompatibleRenderer + 'static> PlatformWindow for GLWindow<Re
GraphicsWindowBackendState::Mapped(_) => return, GraphicsWindowBackendState::Mapped(_) => return,
}; };
let runtime_window = self.window(); let runtime_window = self.window().window_handle();
let component_rc = runtime_window.component(); let component_rc = runtime_window.component();
let component = ComponentRc::borrow_pin(&component_rc); let component = ComponentRc::borrow_pin(&component_rc);
@ -345,12 +342,11 @@ impl<Renderer: WinitCompatibleRenderer + 'static> PlatformWindow for GLWindow<Re
let canvas = self.renderer.create_canvas(window_builder); let canvas = self.renderer.create_canvas(window_builder);
let id = canvas.with_window_handle(|window| { let id = canvas.with_window_handle(|winit_window| {
let runtime_window = self.window_inner_weak.upgrade().unwrap(); self.window.window_handle().set_scale_factor(
runtime_window.set_scale_factor( scale_factor_override.unwrap_or_else(|| winit_window.scale_factor()) as _,
scale_factor_override.unwrap_or_else(|| window.scale_factor()) as _,
); );
window.id() winit_window.id()
}); });
self.map_state.replace(GraphicsWindowBackendState::Mapped(MappedWindow { self.map_state.replace(GraphicsWindowBackendState::Mapped(MappedWindow {
@ -483,8 +479,8 @@ impl<Renderer: WinitCompatibleRenderer + 'static> PlatformWindow for GLWindow<Re
} }
} }
fn window(&self) -> WindowRc { fn window(&self) -> &corelib::api::Window {
self.window_inner_weak.upgrade().unwrap() &self.window
} }
} }

View file

@ -18,13 +18,14 @@ mod glcontext;
use glcontext::*; use glcontext::*;
pub(crate) mod event_loop; pub(crate) mod event_loop;
mod renderer { mod renderer {
use std::rc::Weak;
use i_slint_core::window::PlatformWindowWeak;
pub(crate) trait WinitCompatibleRenderer: i_slint_core::renderer::Renderer { pub(crate) trait WinitCompatibleRenderer: i_slint_core::renderer::Renderer {
type Canvas: WinitCompatibleCanvas; type Canvas: WinitCompatibleCanvas;
fn new( fn new(
window_weak: &Weak<i_slint_core::window::WindowInner>, platform_window_weak: &PlatformWindowWeak,
#[cfg(target_arch = "wasm32")] canvas_id: String, #[cfg(target_arch = "wasm32")] canvas_id: String,
) -> Self; ) -> Self;
@ -57,11 +58,8 @@ pub(crate) mod wasm_input_helper;
mod stylemetrics; mod stylemetrics;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
pub fn create_gl_window_with_canvas_id(canvas_id: String) -> i_slint_core::api::Window { pub fn create_gl_window_with_canvas_id(canvas_id: String) -> PlatformWindowRc {
i_slint_core::window::WindowInner::new(|window| { GLWindow::<crate::renderer::femtovg::FemtoVGRenderer>::new(canvas_id)
GLWindow::<crate::renderer::femtovg::FemtoVGRenderer>::new(window, canvas_id)
})
.into()
} }
#[doc(hidden)] #[doc(hidden)]
@ -76,60 +74,45 @@ pub mod native_widgets {
} }
pub const HAS_NATIVE_STYLE: bool = false; pub const HAS_NATIVE_STYLE: bool = false;
use i_slint_core::window::PlatformWindowRc;
pub use stylemetrics::native_style_metrics_deinit; pub use stylemetrics::native_style_metrics_deinit;
pub use stylemetrics::native_style_metrics_init; pub use stylemetrics::native_style_metrics_init;
pub struct Backend { pub struct Backend {
window_factory_fn: Mutex<Box<dyn Fn() -> i_slint_core::api::Window + Send>>, window_factory_fn: Mutex<Box<dyn Fn() -> PlatformWindowRc + Send>>,
} }
impl Backend { impl Backend {
pub fn new(renderer_name: Option<&str>) -> Self { pub fn new(renderer_name: Option<&str>) -> Self {
#[cfg(feature = "renderer-femtovg")] #[cfg(feature = "renderer-femtovg")]
let (default_renderer, default_renderer_factory) = ("FemtoVG", || { let (default_renderer, default_renderer_factory) = ("FemtoVG", || {
i_slint_core::window::WindowInner::new(|window| { GLWindow::<renderer::femtovg::FemtoVGRenderer>::new(
GLWindow::<renderer::femtovg::FemtoVGRenderer>::new( #[cfg(target_arch = "wasm32")]
window, "canvas".into(),
#[cfg(target_arch = "wasm32")] )
"canvas".into(),
)
})
.into()
}); });
#[cfg(all(not(feature = "renderer-femtovg"), feature = "renderer-skia"))] #[cfg(all(not(feature = "renderer-femtovg"), feature = "renderer-skia"))]
let (default_renderer, default_renderer_factory) = ("Skia", || { let (default_renderer, default_renderer_factory) = ("Skia", || {
i_slint_core::window::WindowInner::new(|window| { GLWindow::<renderer::skia::SkiaRenderer>::new(
GLWindow::<renderer::skia::SkiaRenderer>::new( #[cfg(target_arch = "wasm32")]
window, "canvas".into(),
#[cfg(target_arch = "wasm32")] )
"canvas".into(),
)
})
.into()
}); });
let factory_fn = match renderer_name { let factory_fn = match renderer_name {
#[cfg(feature = "renderer-femtovg")] #[cfg(feature = "renderer-femtovg")]
Some("gl") | Some("femtovg") => || { Some("gl") | Some("femtovg") => || {
i_slint_core::window::WindowInner::new(|window| { GLWindow::<renderer::femtovg::FemtoVGRenderer>::new(
GLWindow::<renderer::femtovg::FemtoVGRenderer>::new( #[cfg(target_arch = "wasm32")]
window, "canvas".into(),
#[cfg(target_arch = "wasm32")] )
"canvas".into(),
)
})
.into()
}, },
#[cfg(feature = "renderer-skia")] #[cfg(feature = "renderer-skia")]
Some("skia") => || { Some("skia") => || {
i_slint_core::window::WindowInner::new(|window| { GLWindow::<renderer::skia::SkiaRenderer>::new(
GLWindow::<renderer::skia::SkiaRenderer>::new( #[cfg(target_arch = "wasm32")]
window, "canvas".into(),
#[cfg(target_arch = "wasm32")] )
"canvas".into(),
)
})
.into()
}, },
None => default_renderer_factory, None => default_renderer_factory,
Some(renderer_name) => { Some(renderer_name) => {
@ -145,7 +128,7 @@ impl Backend {
} }
impl i_slint_core::backend::Backend for Backend { impl i_slint_core::backend::Backend for Backend {
fn create_window(&self) -> i_slint_core::api::Window { fn create_window(&self) -> PlatformWindowRc {
self.window_factory_fn.lock().unwrap()() self.window_factory_fn.lock().unwrap()()
} }

View file

@ -1,19 +1,17 @@
// Copyright © SixtyFPS GmbH <info@slint-ui.com> // Copyright © SixtyFPS GmbH <info@slint-ui.com>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
use std::{ use std::{cell::RefCell, pin::Pin, rc::Rc};
cell::RefCell,
pin::Pin,
rc::{Rc, Weak},
};
use i_slint_core::{ use i_slint_core::api::{
api::{euclid, GraphicsAPI, RenderingNotifier, RenderingState, SetRenderingNotifierError}, euclid, GraphicsAPI, RenderingNotifier, RenderingState, SetRenderingNotifierError,
graphics::rendering_metrics_collector::RenderingMetricsCollector,
graphics::{Point, Rect, Size},
renderer::Renderer,
Coord,
}; };
use i_slint_core::graphics::{
rendering_metrics_collector::RenderingMetricsCollector, Point, Rect, Size,
};
use i_slint_core::renderer::Renderer;
use i_slint_core::window::{PlatformWindowWeak, WindowHandleAccess};
use i_slint_core::Coord;
use crate::WindowSystemName; use crate::WindowSystemName;
@ -26,7 +24,7 @@ mod itemrenderer;
const PASSWORD_CHARACTER: &str = ""; const PASSWORD_CHARACTER: &str = "";
pub struct FemtoVGRenderer { pub struct FemtoVGRenderer {
window_weak: Weak<i_slint_core::window::WindowInner>, platform_window_weak: PlatformWindowWeak,
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
canvas_id: String, canvas_id: String,
rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>, rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>,
@ -36,11 +34,11 @@ impl super::WinitCompatibleRenderer for FemtoVGRenderer {
type Canvas = FemtoVGCanvas; type Canvas = FemtoVGCanvas;
fn new( fn new(
window_weak: &Weak<i_slint_core::window::WindowInner>, platform_window_weak: &PlatformWindowWeak,
#[cfg(target_arch = "wasm32")] canvas_id: String, #[cfg(target_arch = "wasm32")] canvas_id: String,
) -> Self { ) -> Self {
Self { Self {
window_weak: window_weak.clone(), platform_window_weak: platform_window_weak.clone(),
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
canvas_id, canvas_id,
rendering_notifier: Default::default(), rendering_notifier: Default::default(),
@ -55,7 +53,7 @@ impl super::WinitCompatibleRenderer for FemtoVGRenderer {
); );
let rendering_metrics_collector = RenderingMetricsCollector::new( let rendering_metrics_collector = RenderingMetricsCollector::new(
self.window_weak.clone(), self.platform_window_weak.clone(),
&format!( &format!(
"FemtoVG renderer (windowing system: {})", "FemtoVG renderer (windowing system: {})",
opengl_context.window().winsys_name() opengl_context.window().winsys_name()
@ -125,7 +123,7 @@ impl super::WinitCompatibleRenderer for FemtoVGRenderer {
} }
fn render(&self, canvas: &FemtoVGCanvas) { fn render(&self, canvas: &FemtoVGCanvas) {
let window = match self.window_weak.upgrade() { let platform_window = match self.platform_window_weak.upgrade() {
Some(window) => window, Some(window) => window,
None => return, None => return,
}; };
@ -136,6 +134,8 @@ impl super::WinitCompatibleRenderer for FemtoVGRenderer {
canvas.opengl_context.make_current(); canvas.opengl_context.make_current();
let window = platform_window.window().window_handle();
window.draw_contents(|components| { window.draw_contents(|components| {
{ {
let mut femtovg_canvas = canvas.canvas.as_ref().borrow_mut(); let mut femtovg_canvas = canvas.canvas.as_ref().borrow_mut();
@ -170,8 +170,12 @@ impl super::WinitCompatibleRenderer for FemtoVGRenderer {
.with_graphics_api(|api| callback.notify(RenderingState::BeforeRendering, &api)) .with_graphics_api(|api| callback.notify(RenderingState::BeforeRendering, &api))
} }
let mut item_renderer = let mut item_renderer = self::itemrenderer::GLItemRenderer::new(
self::itemrenderer::GLItemRenderer::new(canvas, &window, width, height); canvas,
platform_window.window(),
width,
height,
);
for (component, origin) in components { for (component, origin) in components {
i_slint_core::item_rendering::render_component_items( i_slint_core::item_rendering::render_component_items(
@ -218,11 +222,13 @@ impl Renderer for FemtoVGRenderer {
text_input: Pin<&i_slint_core::items::TextInput>, text_input: Pin<&i_slint_core::items::TextInput>,
pos: Point, pos: Point,
) -> usize { ) -> usize {
let window = match self.window_weak.upgrade() { let platform_window = match self.platform_window_weak.upgrade() {
Some(window) => window, Some(window) => window,
None => return 0, None => return 0,
}; };
let window = platform_window.window().window_handle();
let scale_factor = window.scale_factor(); let scale_factor = window.scale_factor();
let pos = pos * scale_factor; let pos = pos * scale_factor;
let text = text_input.text(); let text = text_input.text();
@ -295,11 +301,13 @@ impl Renderer for FemtoVGRenderer {
text_input: Pin<&i_slint_core::items::TextInput>, text_input: Pin<&i_slint_core::items::TextInput>,
byte_offset: usize, byte_offset: usize,
) -> Rect { ) -> Rect {
let window = match self.window_weak.upgrade() { let platform_window = match self.platform_window_weak.upgrade() {
Some(window) => window, Some(window) => window,
None => return Default::default(), None => return Default::default(),
}; };
let window = platform_window.window().window_handle();
let text = text_input.text(); let text = text_input.text();
let scale_factor = window.scale_factor(); let scale_factor = window.scale_factor();

View file

@ -14,7 +14,7 @@ use i_slint_core::items::{
self, Clip, FillRule, ImageFit, ImageRendering, InputType, Item, ItemRc, Layer, Opacity, self, Clip, FillRule, ImageFit, ImageRendering, InputType, Item, ItemRc, Layer, Opacity,
RenderingResult, RenderingResult,
}; };
use i_slint_core::window::WindowRc; use i_slint_core::window::WindowHandleAccess;
use i_slint_core::{Brush, Color, ImageInner, Property, SharedString}; use i_slint_core::{Brush, Color, ImageInner, Property, SharedString};
use super::fonts; use super::fonts;
@ -66,7 +66,7 @@ pub struct GLItemRenderer<'a> {
// because that can only happen after calling `flush`. Otherwise femtovg ends up processing // because that can only happen after calling `flush`. Otherwise femtovg ends up processing
// `set_render_target` commands with image ids that have been deleted. // `set_render_target` commands with image ids that have been deleted.
layer_images_to_delete_after_flush: Vec<Rc<super::images::Texture>>, layer_images_to_delete_after_flush: Vec<Rc<super::images::Texture>>,
window: Rc<i_slint_core::window::WindowInner>, window: &'a i_slint_core::api::Window,
scale_factor: f32, scale_factor: f32,
/// track the state manually since femtovg don't have accessor for its state /// track the state manually since femtovg don't have accessor for its state
state: Vec<State>, state: Vec<State>,
@ -240,7 +240,7 @@ impl<'a> ItemRenderer for GLItemRenderer<'a> {
let string = string.as_str(); let string = string.as_str();
let font = fonts::FONT_CACHE.with(|cache| { let font = fonts::FONT_CACHE.with(|cache| {
cache.borrow_mut().font( cache.borrow_mut().font(
text.font_request(&self.window), text.font_request(self.window.window_handle()),
self.scale_factor, self.scale_factor,
&text.text(), &text.text(),
) )
@ -278,7 +278,7 @@ impl<'a> ItemRenderer for GLItemRenderer<'a> {
let font = fonts::FONT_CACHE.with(|cache| { let font = fonts::FONT_CACHE.with(|cache| {
cache.borrow_mut().font( cache.borrow_mut().font(
text_input.font_request(&self.window), text_input.font_request(self.window.window_handle()),
self.scale_factor, self.scale_factor,
&text_input.text(), &text_input.text(),
) )
@ -819,8 +819,8 @@ impl<'a> ItemRenderer for GLItemRenderer<'a> {
canvas.fill_text(0., 0., string, paint).unwrap(); canvas.fill_text(0., 0., string, paint).unwrap();
} }
fn window(&self) -> WindowRc { fn window(&self) -> &i_slint_core::api::Window {
self.window.clone() self.window
} }
fn as_any(&mut self) -> Option<&mut dyn std::any::Any> { fn as_any(&mut self) -> Option<&mut dyn std::any::Any> {
@ -873,17 +873,17 @@ impl<'a> ItemRenderer for GLItemRenderer<'a> {
impl<'a> GLItemRenderer<'a> { impl<'a> GLItemRenderer<'a> {
pub fn new( pub fn new(
canvas: &'a super::FemtoVGCanvas, canvas: &'a super::FemtoVGCanvas,
window: &Rc<i_slint_core::window::WindowInner>, window: &'a i_slint_core::api::Window,
width: u32, width: u32,
height: u32, height: u32,
) -> Self { ) -> Self {
let scale_factor = window.scale_factor(); let scale_factor = window.scale_factor().get();
Self { Self {
graphics_cache: &canvas.graphics_cache, graphics_cache: &canvas.graphics_cache,
texture_cache: &canvas.texture_cache, texture_cache: &canvas.texture_cache,
canvas: canvas.canvas.clone(), canvas: canvas.canvas.clone(),
layer_images_to_delete_after_flush: Default::default(), layer_images_to_delete_after_flush: Default::default(),
window: window.clone(), window,
scale_factor, scale_factor,
state: vec![State { state: vec![State {
scissor: Rect::new( scissor: Rect::new(
@ -1112,7 +1112,7 @@ impl<'a> GLItemRenderer<'a> {
let target_size_for_scalable_source = matches!(image_inner, ImageInner::Svg(..)) let target_size_for_scalable_source = matches!(image_inner, ImageInner::Svg(..))
.then(|| { .then(|| {
// get the scale factor as a property again, to ensure the cache is invalidated when the scale factor changes // get the scale factor as a property again, to ensure the cache is invalidated when the scale factor changes
let scale_factor = self.window.scale_factor(); let scale_factor = self.window.scale_factor().get();
[ [
(target_width.get() * scale_factor) as u32, (target_width.get() * scale_factor) as u32,
(target_height.get() * scale_factor) as u32, (target_height.get() * scale_factor) as u32,

View file

@ -1,16 +1,14 @@
// Copyright © SixtyFPS GmbH <info@slint-ui.com> // Copyright © SixtyFPS GmbH <info@slint-ui.com>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
use std::{ use std::{cell::RefCell, rc::Rc};
cell::RefCell,
rc::{Rc, Weak},
};
use i_slint_core::{ use i_slint_core::api::{
api::{GraphicsAPI, RenderingNotifier, RenderingState, SetRenderingNotifierError}, GraphicsAPI, RenderingNotifier, RenderingState, SetRenderingNotifierError,
graphics::rendering_metrics_collector::RenderingMetricsCollector,
item_rendering::ItemCache,
}; };
use i_slint_core::graphics::rendering_metrics_collector::RenderingMetricsCollector;
use i_slint_core::item_rendering::ItemCache;
use i_slint_core::window::{PlatformWindowWeak, WindowHandleAccess};
use crate::WindowSystemName; use crate::WindowSystemName;
@ -38,22 +36,25 @@ cfg_if::cfg_if! {
} }
pub struct SkiaRenderer { pub struct SkiaRenderer {
window_weak: Weak<i_slint_core::window::WindowInner>, platform_window_weak: PlatformWindowWeak,
rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>, rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>,
} }
impl super::WinitCompatibleRenderer for SkiaRenderer { impl super::WinitCompatibleRenderer for SkiaRenderer {
type Canvas = SkiaCanvas<DefaultSurface>; type Canvas = SkiaCanvas<DefaultSurface>;
fn new(window_weak: &std::rc::Weak<i_slint_core::window::WindowInner>) -> Self { fn new(platform_window_weak: &PlatformWindowWeak) -> Self {
Self { window_weak: window_weak.clone(), rendering_notifier: Default::default() } Self {
platform_window_weak: platform_window_weak.clone(),
rendering_notifier: Default::default(),
}
} }
fn create_canvas(&self, window_builder: winit::window::WindowBuilder) -> Self::Canvas { fn create_canvas(&self, window_builder: winit::window::WindowBuilder) -> Self::Canvas {
let surface = DefaultSurface::new(window_builder); let surface = DefaultSurface::new(window_builder);
let rendering_metrics_collector = RenderingMetricsCollector::new( let rendering_metrics_collector = RenderingMetricsCollector::new(
self.window_weak.clone(), self.platform_window_weak.clone(),
&format!( &format!(
"Skia renderer (windowing system: {}; skia backend {})", "Skia renderer (windowing system: {}; skia backend {})",
surface.with_window_handle(|winit_window| winit_window.winsys_name()), surface.with_window_handle(|winit_window| winit_window.winsys_name()),
@ -82,11 +83,13 @@ impl super::WinitCompatibleRenderer for SkiaRenderer {
} }
fn render(&self, canvas: &Self::Canvas) { fn render(&self, canvas: &Self::Canvas) {
let window = match self.window_weak.upgrade() { let platform_window = match self.platform_window_weak.upgrade() {
Some(window) => window, Some(window) => window,
None => return, None => return,
}; };
let window = platform_window.window().window_handle();
canvas.surface.render(|skia_canvas, gr_context| { canvas.surface.render(|skia_canvas, gr_context| {
window.draw_contents(|components| { window.draw_contents(|components| {
if let Some(window_item) = window.window_item() { if let Some(window_item) = window.window_item() {
@ -105,8 +108,11 @@ impl super::WinitCompatibleRenderer for SkiaRenderer {
}) })
} }
let mut item_renderer = let mut item_renderer = itemrenderer::SkiaRenderer::new(
itemrenderer::SkiaRenderer::new(skia_canvas, &window, &canvas.image_cache); skia_canvas,
platform_window.window(),
&canvas.image_cache,
);
for (component, origin) in components { for (component, origin) in components {
i_slint_core::item_rendering::render_component_items( i_slint_core::item_rendering::render_component_items(

View file

@ -2,11 +2,11 @@
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc;
use i_slint_core::graphics::euclid; use i_slint_core::graphics::euclid;
use i_slint_core::item_rendering::{ItemCache, ItemRenderer}; use i_slint_core::item_rendering::{ItemCache, ItemRenderer};
use i_slint_core::items::{ImageFit, ImageRendering, ItemRc, Layer, Opacity, RenderingResult}; use i_slint_core::items::{ImageFit, ImageRendering, ItemRc, Layer, Opacity, RenderingResult};
use i_slint_core::window::WindowHandleAccess;
use i_slint_core::{items, Brush, Color, Property}; use i_slint_core::{items, Brush, Color, Property};
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -16,8 +16,8 @@ struct RenderState {
pub struct SkiaRenderer<'a> { pub struct SkiaRenderer<'a> {
pub canvas: &'a mut skia_safe::Canvas, pub canvas: &'a mut skia_safe::Canvas,
pub window: Rc<i_slint_core::window::WindowInner>,
pub scale_factor: f32, pub scale_factor: f32,
pub window: &'a i_slint_core::api::Window,
state_stack: Vec<RenderState>, state_stack: Vec<RenderState>,
current_state: RenderState, current_state: RenderState,
image_cache: &'a ItemCache<Option<skia_safe::Image>>, image_cache: &'a ItemCache<Option<skia_safe::Image>>,
@ -26,13 +26,13 @@ pub struct SkiaRenderer<'a> {
impl<'a> SkiaRenderer<'a> { impl<'a> SkiaRenderer<'a> {
pub fn new( pub fn new(
canvas: &'a mut skia_safe::Canvas, canvas: &'a mut skia_safe::Canvas,
window: &Rc<i_slint_core::window::WindowInner>, window: &'a i_slint_core::api::Window,
image_cache: &'a ItemCache<Option<skia_safe::Image>>, image_cache: &'a ItemCache<Option<skia_safe::Image>>,
) -> Self { ) -> Self {
Self { Self {
canvas, canvas,
window: window.clone(), scale_factor: window.scale_factor().get(),
scale_factor: window.scale_factor(), window,
state_stack: vec![], state_stack: vec![],
current_state: RenderState { alpha: 1.0 }, current_state: RenderState { alpha: 1.0 },
image_cache, image_cache,
@ -351,7 +351,7 @@ impl<'a> ItemRenderer for SkiaRenderer<'a> {
let string = text.text(); let string = text.text();
let string = string.as_str(); let string = string.as_str();
let font_request = text.font_request(&self.window); let font_request = text.font_request(self.window.window_handle());
let paint = match self.brush_to_paint(text.color(), max_width, max_height) { let paint = match self.brush_to_paint(text.color(), max_width, max_height) {
Some(paint) => paint, Some(paint) => paint,
@ -599,8 +599,8 @@ impl<'a> ItemRenderer for SkiaRenderer<'a> {
); );
} }
fn window(&self) -> i_slint_core::window::WindowRc { fn window(&self) -> &i_slint_core::api::Window {
self.window.clone() self.window
} }
fn as_any(&mut self) -> Option<&mut dyn core::any::Any> { fn as_any(&mut self) -> Option<&mut dyn core::any::Any> {

View file

@ -18,9 +18,10 @@
//! we just simulate a few backspaces. //! we just simulate a few backspaces.
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::{Rc, Weak}; use std::rc::Rc;
use i_slint_core::input::{KeyEvent, KeyEventType, KeyboardModifiers}; use i_slint_core::input::{KeyEvent, KeyEventType, KeyboardModifiers};
use i_slint_core::window::{PlatformWindowWeak, WindowHandleAccess};
use i_slint_core::SharedString; use i_slint_core::SharedString;
use wasm_bindgen::closure::Closure; use wasm_bindgen::closure::Closure;
use wasm_bindgen::convert::FromWasmAbi; use wasm_bindgen::convert::FromWasmAbi;
@ -65,10 +66,7 @@ impl WasmInputState {
impl WasmInputHelper { impl WasmInputHelper {
#[allow(unused)] #[allow(unused)]
pub fn new( pub fn new(platform_window: PlatformWindowWeak, canvas: web_sys::HtmlCanvasElement) -> Self {
window: Weak<i_slint_core::window::WindowInner>,
canvas: web_sys::HtmlCanvasElement,
) -> Self {
let input = web_sys::window() let input = web_sys::window()
.unwrap() .unwrap()
.document() .document()
@ -91,23 +89,24 @@ impl WasmInputHelper {
let shared_state = Rc::new(RefCell::new(WasmInputState::default())); let shared_state = Rc::new(RefCell::new(WasmInputState::default()));
let win = window.clone(); let win = platform_window.clone();
h.add_event_listener("blur", move |_: web_sys::Event| { h.add_event_listener("blur", move |_: web_sys::Event| {
// Make sure that the window gets marked as unfocused when the focus leaves the input // Make sure that the window gets marked as unfocused when the focus leaves the input
if let Some(window) = win.upgrade() { if let Some(platform_window) = win.upgrade() {
let window = platform_window.window().window_handle();
if !canvas.matches(":focus").unwrap_or(false) { if !canvas.matches(":focus").unwrap_or(false) {
window.set_active(false); window.set_active(false);
window.set_focus(false); window.set_focus(false);
} }
} }
}); });
let win = window.clone(); let win = platform_window.clone();
let shared_state2 = shared_state.clone(); let shared_state2 = shared_state.clone();
h.add_event_listener("keydown", move |e: web_sys::KeyboardEvent| { h.add_event_listener("keydown", move |e: web_sys::KeyboardEvent| {
if let (Some(window), Some(text)) = (win.upgrade(), event_text(&e)) { if let (Some(platform_window), Some(text)) = (win.upgrade(), event_text(&e)) {
e.prevent_default(); e.prevent_default();
shared_state2.borrow_mut().has_key_down = true; shared_state2.borrow_mut().has_key_down = true;
window.process_key_input(&KeyEvent { platform_window.window().window_handle().process_key_input(&KeyEvent {
modifiers: modifiers(&e), modifiers: modifiers(&e),
text, text,
event_type: KeyEventType::KeyPressed, event_type: KeyEventType::KeyPressed,
@ -115,13 +114,13 @@ impl WasmInputHelper {
} }
}); });
let win = window.clone(); let win = platform_window.clone();
let shared_state2 = shared_state.clone(); let shared_state2 = shared_state.clone();
h.add_event_listener("keyup", move |e: web_sys::KeyboardEvent| { h.add_event_listener("keyup", move |e: web_sys::KeyboardEvent| {
if let (Some(window), Some(text)) = (win.upgrade(), event_text(&e)) { if let (Some(platform_window), Some(text)) = (win.upgrade(), event_text(&e)) {
e.prevent_default(); e.prevent_default();
shared_state2.borrow_mut().has_key_down = false; shared_state2.borrow_mut().has_key_down = false;
window.process_key_input(&KeyEvent { platform_window.window().window_handle().process_key_input(&KeyEvent {
modifiers: modifiers(&e), modifiers: modifiers(&e),
text, text,
event_type: KeyEventType::KeyReleased, event_type: KeyEventType::KeyReleased,
@ -129,13 +128,14 @@ impl WasmInputHelper {
} }
}); });
let win = window.clone(); let win = platform_window.clone();
let shared_state2 = shared_state.clone(); let shared_state2 = shared_state.clone();
let input = h.input.clone(); let input = h.input.clone();
h.add_event_listener("input", move |e: web_sys::InputEvent| { h.add_event_listener("input", move |e: web_sys::InputEvent| {
if let (Some(window), Some(data)) = (win.upgrade(), e.data()) { if let (Some(platform_window), Some(data)) = (win.upgrade(), e.data()) {
if !e.is_composing() && e.input_type() != "insertCompositionText" { if !e.is_composing() && e.input_type() != "insertCompositionText" {
if !shared_state2.borrow_mut().has_key_down { if !shared_state2.borrow_mut().has_key_down {
let window = platform_window.window().window_handle();
let text = SharedString::from(data.as_str()); let text = SharedString::from(data.as_str());
window.process_key_input(&KeyEvent { window.process_key_input(&KeyEvent {
modifiers: Default::default(), modifiers: Default::default(),
@ -155,11 +155,12 @@ impl WasmInputHelper {
}); });
for event in ["compositionend", "compositionupdate"] { for event in ["compositionend", "compositionupdate"] {
let win = window.clone(); let win = platform_window.clone();
let shared_state2 = shared_state.clone(); let shared_state2 = shared_state.clone();
let input = h.input.clone(); let input = h.input.clone();
h.add_event_listener(event, move |e: web_sys::CompositionEvent| { h.add_event_listener(event, move |e: web_sys::CompositionEvent| {
if let (Some(window), Some(data)) = (win.upgrade(), e.data()) { if let (Some(platform_window), Some(data)) = (win.upgrade(), e.data()) {
let window = platform_window.window().window_handle();
let is_end = event == "compositionend"; let is_end = event == "compositionend";
let (text, to_delete) = let (text, to_delete) =
shared_state2.borrow_mut().text_from_compose(data, is_end); shared_state2.borrow_mut().text_from_compose(data, is_end);

View file

@ -6,10 +6,9 @@ This module contains types that are public and re-exported in the slint-rs as we
*/ */
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::rc::Rc;
use crate::component::ComponentVTable; use crate::component::ComponentVTable;
use crate::window::WindowRc; use crate::window::WindowInner;
pub use crate::lengths::LogicalPx; pub use crate::lengths::LogicalPx;
pub use crate::lengths::PhysicalPx; pub use crate::lengths::PhysicalPx;
@ -97,14 +96,7 @@ pub enum SetRenderingNotifierError {
/// scene of a component. It provides API to control windowing system specific aspects such /// scene of a component. It provides API to control windowing system specific aspects such
/// as the position on the screen. /// as the position on the screen.
#[repr(transparent)] #[repr(transparent)]
pub struct Window(WindowRc); pub struct Window(WindowInner);
#[doc(hidden)]
impl From<WindowRc> for Window {
fn from(window: WindowRc) -> Self {
Self(window)
}
}
/// This enum describes whether a Window is allowed to be hidden when the user tries to close the window. /// This enum describes whether a Window is allowed to be hidden when the user tries to close the window.
/// It is the return type of the callback provided to [Window::on_close_requested]. /// It is the return type of the callback provided to [Window::on_close_requested].
@ -122,6 +114,10 @@ impl Default for CloseRequestResponse {
} }
impl Window { impl Window {
pub fn new(platform_window_weak: alloc::rc::Weak<dyn crate::window::PlatformWindow>) -> Self {
Self(WindowInner::new(platform_window_weak))
}
/// Registers the window with the windowing system in order to make it visible on the screen. /// Registers the window with the windowing system in order to make it visible on the screen.
pub fn show(&self) { pub fn show(&self) {
self.0.show(); self.0.show();
@ -138,7 +134,7 @@ impl Window {
&self, &self,
callback: impl FnMut(RenderingState, &GraphicsAPI) + 'static, callback: impl FnMut(RenderingState, &GraphicsAPI) + 'static,
) -> Result<(), SetRenderingNotifierError> { ) -> Result<(), SetRenderingNotifierError> {
self.0.renderer().set_rendering_notifier(Box::new(callback)) self.0.platform_window().renderer().set_rendering_notifier(Box::new(callback))
} }
/// This function allows registering a callback that's invoked when the user tries to close a window. /// This function allows registering a callback that's invoked when the user tries to close a window.
@ -149,7 +145,7 @@ impl Window {
/// This function issues a request to the windowing system to redraw the contents of the window. /// This function issues a request to the windowing system to redraw the contents of the window.
pub fn request_redraw(&self) { pub fn request_redraw(&self) {
self.0.request_redraw(); self.0.platform_window().request_redraw();
// When this function is called by the user, we want it to translate to a requestAnimationFrame() // When this function is called by the user, we want it to translate to a requestAnimationFrame()
// on the web. If called through the rendering notifier (so from within the event loop processing), // on the web. If called through the rendering notifier (so from within the event loop processing),
@ -169,14 +165,14 @@ impl Window {
/// Returns the position of the window on the screen, in physical screen coordinates and including /// Returns the position of the window on the screen, in physical screen coordinates and including
/// a window frame (if present). /// a window frame (if present).
pub fn position(&self) -> euclid::Point2D<i32, PhysicalPx> { pub fn position(&self) -> euclid::Point2D<i32, PhysicalPx> {
self.0.position() self.0.platform_window().position()
} }
/// Sets the position of the window on the screen, in physical screen coordinates and including /// Sets the position of the window on the screen, in physical screen coordinates and including
/// a window frame (if present). /// a window frame (if present).
/// Note that on some windowing systems, such as Wayland, this functionality is not available. /// Note that on some windowing systems, such as Wayland, this functionality is not available.
pub fn set_position(&self, position: euclid::Point2D<i32, PhysicalPx>) { pub fn set_position(&self, position: euclid::Point2D<i32, PhysicalPx>) {
self.0.set_position(position) self.0.platform_window().set_position(position)
} }
/// Returns the size of the window on the screen, in physical screen coordinates and excluding /// Returns the size of the window on the screen, in physical screen coordinates and excluding
@ -194,7 +190,7 @@ impl Window {
let l = size.cast() / self.scale_factor(); let l = size.cast() / self.scale_factor();
self.0.set_window_item_geometry(l.width as _, l.height as _); self.0.set_window_item_geometry(l.width as _, l.height as _);
self.0.set_inner_size(size) self.0.platform_window().set_inner_size(size)
} }
/// Dispatch a pointer event (touch or mouse) to the window /// Dispatch a pointer event (touch or mouse) to the window
@ -204,12 +200,12 @@ impl Window {
/// Note: This function is usually called by the Slint backend. You should only call this function /// Note: This function is usually called by the Slint backend. You should only call this function
/// if implementing your own backend or for testing purposes. /// if implementing your own backend or for testing purposes.
pub fn dispatch_pointer_event(&self, event: PointerEvent) { pub fn dispatch_pointer_event(&self, event: PointerEvent) {
self.0.clone().process_mouse_input(event.into()) self.0.process_mouse_input(event.into())
} }
} }
impl crate::window::WindowHandleAccess for Window { impl crate::window::WindowHandleAccess for Window {
fn window_handle(&self) -> &Rc<crate::window::WindowInner> { fn window_handle(&self) -> &crate::window::WindowInner {
&self.0 &self.0
} }
} }

View file

@ -13,6 +13,7 @@ use once_cell::sync::OnceCell;
#[cfg(all(not(feature = "std"), feature = "unsafe_single_core"))] #[cfg(all(not(feature = "std"), feature = "unsafe_single_core"))]
use crate::unsafe_single_core::OnceCell; use crate::unsafe_single_core::OnceCell;
use crate::window::PlatformWindowRc;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
/// Behavior describing how the event loop should terminate. /// Behavior describing how the event loop should terminate.
@ -26,7 +27,7 @@ pub enum EventLoopQuitBehavior {
/// Interface implemented by back-ends /// Interface implemented by back-ends
pub trait Backend: Send + Sync { pub trait Backend: Send + Sync {
/// Instantiate a window for a component. /// Instantiate a window for a component.
fn create_window(&self) -> crate::api::Window; fn create_window(&self) -> PlatformWindowRc;
/// Spins an event loop and renders the visible windows. /// Spins an event loop and renders the visible windows.
fn run_event_loop(&self, _behavior: EventLoopQuitBehavior) { fn run_event_loop(&self, _behavior: EventLoopQuitBehavior) {

View file

@ -12,7 +12,7 @@ use crate::item_tree::{
use crate::items::{AccessibleRole, ItemVTable}; use crate::items::{AccessibleRole, ItemVTable};
use crate::layout::{LayoutInfo, Orientation}; use crate::layout::{LayoutInfo, Orientation};
use crate::slice::Slice; use crate::slice::Slice;
use crate::window::WindowInner; use crate::window::{PlatformWindowRc, WindowHandleAccess};
use crate::SharedString; use crate::SharedString;
use vtable::*; use vtable::*;
@ -114,10 +114,12 @@ pub type ComponentWeak = vtable::VWeak<ComponentVTable, Dyn>;
pub fn register_component<Base>( pub fn register_component<Base>(
base: core::pin::Pin<&Base>, base: core::pin::Pin<&Base>,
item_array: &[vtable::VOffset<Base, ItemVTable, vtable::AllowPin>], item_array: &[vtable::VOffset<Base, ItemVTable, vtable::AllowPin>],
window: &WindowInner, platform_window: &PlatformWindowRc,
) { ) {
item_array.iter().for_each(|item| item.apply_pin(base).as_ref().init(window)); item_array.iter().for_each(|item| {
window.register_component(); item.apply_pin(base).as_ref().init(platform_window.window().window_handle())
});
platform_window.register_component();
} }
/// Free the backend graphics resources allocated by the component's items. /// Free the backend graphics resources allocated by the component's items.
@ -125,30 +127,32 @@ pub fn unregister_component<Base>(
base: core::pin::Pin<&Base>, base: core::pin::Pin<&Base>,
component: ComponentRef, component: ComponentRef,
item_array: &[vtable::VOffset<Base, ItemVTable, vtable::AllowPin>], item_array: &[vtable::VOffset<Base, ItemVTable, vtable::AllowPin>],
window: &WindowInner, platform_window: &PlatformWindowRc,
) { ) {
window.unregister_component(component, &mut item_array.iter().map(|item| item.apply_pin(base))); platform_window
.unregister_component(component, &mut item_array.iter().map(|item| item.apply_pin(base)));
} }
#[cfg(feature = "ffi")] #[cfg(feature = "ffi")]
pub(crate) mod ffi { pub(crate) mod ffi {
#![allow(unsafe_code)] #![allow(unsafe_code)]
use crate::window::PlatformWindowRc;
use super::*; use super::*;
use crate::window::WindowRc;
/// Call init() on the ItemVTable of each item in the item array. /// Call init() on the ItemVTable of each item in the item array.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_register_component( pub unsafe extern "C" fn slint_register_component(
component: ComponentRefPin, component: ComponentRefPin,
item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>, item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>,
window_handle: *const crate::window::ffi::WindowRcOpaque, window_handle: *const crate::window::ffi::PlatformWindowRcOpaque,
) { ) {
let window = &*(window_handle as *const WindowRc); let platform_window = &*(window_handle as *const PlatformWindowRc);
super::register_component( super::register_component(
core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)), core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
item_array.as_slice(), item_array.as_slice(),
window, platform_window,
) )
} }
@ -157,14 +161,14 @@ pub(crate) mod ffi {
pub unsafe extern "C" fn slint_unregister_component( pub unsafe extern "C" fn slint_unregister_component(
component: ComponentRefPin, component: ComponentRefPin,
item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>, item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>,
window_handle: *const crate::window::ffi::WindowRcOpaque, window_handle: *const crate::window::ffi::PlatformWindowRcOpaque,
) { ) {
let window = &*(window_handle as *const WindowRc); let platform_window = &*(window_handle as *const PlatformWindowRc);
super::unregister_component( super::unregister_component(
core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)), core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
core::pin::Pin::into_inner(component), core::pin::Pin::into_inner(component),
item_array.as_slice(), item_array.as_slice(),
window, platform_window,
) )
} }
} }

View file

@ -6,9 +6,10 @@ This module contains a simple helper type to measure the average number of frame
*/ */
use crate::timers::*; use crate::timers::*;
use crate::window::PlatformWindowWeak;
use std::cell::RefCell; use std::cell::RefCell;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::rc::{Rc, Weak}; use std::rc::Rc;
enum RefreshMode { enum RefreshMode {
Lazy, // render only when necessary (default) Lazy, // render only when necessary (default)
@ -59,7 +60,7 @@ pub struct RenderingMetricsCollector {
refresh_mode: RefreshMode, refresh_mode: RefreshMode,
output_console: bool, output_console: bool,
output_overlay: bool, output_overlay: bool,
window: Weak<crate::window::WindowInner>, platform_window: PlatformWindowWeak,
} }
impl RenderingMetricsCollector { impl RenderingMetricsCollector {
@ -72,7 +73,7 @@ impl RenderingMetricsCollector {
/// ///
/// If enabled, this will also print out some system information such as whether /// If enabled, this will also print out some system information such as whether
/// this is a debug or release build, as well as the provided winsys_info string. /// this is a debug or release build, as well as the provided winsys_info string.
pub fn new(window: Weak<crate::window::WindowInner>, winsys_info: &str) -> Option<Rc<Self>> { pub fn new(platform_window: PlatformWindowWeak, winsys_info: &str) -> Option<Rc<Self>> {
let options = match std::env::var("SLINT_DEBUG_PERFORMANCE") { let options = match std::env::var("SLINT_DEBUG_PERFORMANCE") {
Ok(var) => var, Ok(var) => var,
_ => return None, _ => return None,
@ -101,7 +102,7 @@ impl RenderingMetricsCollector {
refresh_mode, refresh_mode,
output_console, output_console,
output_overlay, output_overlay,
window, platform_window,
}); });
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -170,7 +171,7 @@ impl RenderingMetricsCollector {
.borrow_mut() .borrow_mut()
.push(FrameData { timestamp: instant::Instant::now(), metrics: renderer.metrics() }); .push(FrameData { timestamp: instant::Instant::now(), metrics: renderer.metrics() });
if matches!(self.refresh_mode, RefreshMode::FullSpeed) { if matches!(self.refresh_mode, RefreshMode::FullSpeed) {
if let Some(window) = self.window.upgrade() { if let Some(window) = self.platform_window.upgrade() {
window.request_redraw(); window.request_redraw();
} }
crate::animations::CURRENT_ANIMATION_DRIVER crate::animations::CURRENT_ANIMATION_DRIVER

View file

@ -345,7 +345,7 @@ pub trait ItemRenderer {
(self.get_current_clip().intersects(&item_geometry), item_geometry) (self.get_current_clip().intersects(&item_geometry), item_geometry)
} }
fn window(&self) -> crate::window::WindowRc; fn window(&self) -> &crate::api::Window;
/// Return the internal renderer /// Return the internal renderer
fn as_any(&mut self) -> Option<&mut dyn core::any::Any>; fn as_any(&mut self) -> Option<&mut dyn core::any::Any>;
@ -547,7 +547,7 @@ impl<'a, T: ItemRenderer> ItemRenderer for PartialRenderer<'a, T> {
self.actual_renderer.draw_string(string, color) self.actual_renderer.draw_string(string, color)
} }
fn window(&self) -> crate::window::WindowRc { fn window(&self) -> &crate::api::Window {
self.actual_renderer.window() self.actual_renderer.window()
} }

View file

@ -382,7 +382,7 @@ impl Item for TouchArea {
let hovering = !matches!(event, MouseEvent::Exit); let hovering = !matches!(event, MouseEvent::Exit);
Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(hovering); Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(hovering);
if hovering { if hovering {
window.set_mouse_cursor(self.mouse_cursor()); window.platform_window().set_mouse_cursor(self.mouse_cursor());
} }
InputEventFilterResult::ForwardAndInterceptGrab InputEventFilterResult::ForwardAndInterceptGrab
} }
@ -395,7 +395,7 @@ impl Item for TouchArea {
) -> InputEventResult { ) -> InputEventResult {
if matches!(event, MouseEvent::Exit) { if matches!(event, MouseEvent::Exit) {
Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(false); Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(false);
window.set_mouse_cursor(MouseCursor::Default); window.platform_window().set_mouse_cursor(MouseCursor::Default);
} }
if !self.enabled() { if !self.enabled() {
return InputEventResult::EventIgnored; return InputEventResult::EventIgnored;

View file

@ -62,8 +62,9 @@ impl Item for Text {
} }
fn layout_info(self: Pin<&Self>, orientation: Orientation, window: &WindowInner) -> LayoutInfo { fn layout_info(self: Pin<&Self>, orientation: Orientation, window: &WindowInner) -> LayoutInfo {
let platform_window = window.platform_window();
let implicit_size = |max_width| { let implicit_size = |max_width| {
window.renderer().text_size( platform_window.renderer().text_size(
self.font_request(window), self.font_request(window),
self.text().as_str(), self.text().as_str(),
max_width, max_width,
@ -79,7 +80,7 @@ impl Item for Text {
let implicit_size = implicit_size(None); let implicit_size = implicit_size(None);
let min = match self.overflow() { let min = match self.overflow() {
TextOverflow::Elide => implicit_size.width.min( TextOverflow::Elide => implicit_size.width.min(
window platform_window
.renderer() .renderer()
.text_size(self.font_request(window), "", None, window.scale_factor()) .text_size(self.font_request(window), "", None, window.scale_factor())
.width, .width,
@ -231,7 +232,7 @@ impl Item for TextInput {
fn layout_info(self: Pin<&Self>, orientation: Orientation, window: &WindowInner) -> LayoutInfo { fn layout_info(self: Pin<&Self>, orientation: Orientation, window: &WindowInner) -> LayoutInfo {
let text = self.text(); let text = self.text();
let implicit_size = |max_width| { let implicit_size = |max_width| {
window.renderer().text_size( window.platform_window().renderer().text_size(
self.font_request(window), self.font_request(window),
{ {
if text.is_empty() { if text.is_empty() {
@ -290,10 +291,12 @@ impl Item for TextInput {
if !self.enabled() { if !self.enabled() {
return InputEventResult::EventIgnored; return InputEventResult::EventIgnored;
} }
let platform_window = window.platform_window();
match event { match event {
MouseEvent::Pressed { position, button: PointerEventButton::Left } => { MouseEvent::Pressed { position, button: PointerEventButton::Left } => {
let clicked_offset = let clicked_offset =
window.renderer().text_input_byte_offset_for_position(self, position) as i32; platform_window.renderer().text_input_byte_offset_for_position(self, position)
as i32;
self.as_ref().pressed.set(true); self.as_ref().pressed.set(true);
self.as_ref().anchor_position.set(clicked_offset); self.as_ref().anchor_position.set(clicked_offset);
self.set_cursor_position(clicked_offset, true, window); self.set_cursor_position(clicked_offset, true, window);
@ -306,9 +309,10 @@ impl Item for TextInput {
} }
MouseEvent::Moved { position } => { MouseEvent::Moved { position } => {
if self.as_ref().pressed.get() { if self.as_ref().pressed.get() {
let clicked_offset = let clicked_offset = platform_window
window.renderer().text_input_byte_offset_for_position(self, position) .renderer()
as i32; .text_input_byte_offset_for_position(self, position)
as i32;
self.set_cursor_position(clicked_offset, true, window); self.set_cursor_position(clicked_offset, true, window);
} }
} }
@ -445,12 +449,12 @@ impl Item for TextInput {
FocusEvent::FocusIn | FocusEvent::WindowReceivedFocus => { FocusEvent::FocusIn | FocusEvent::WindowReceivedFocus => {
self.has_focus.set(true); self.has_focus.set(true);
self.show_cursor(window); self.show_cursor(window);
window.show_virtual_keyboard(self.input_type()); window.platform_window().show_virtual_keyboard(self.input_type());
} }
FocusEvent::FocusOut | FocusEvent::WindowLostFocus => { FocusEvent::FocusOut | FocusEvent::WindowLostFocus => {
self.has_focus.set(false); self.has_focus.set(false);
self.hide_cursor(); self.hide_cursor();
window.hide_virtual_keyboard(); window.platform_window().hide_virtual_keyboard();
} }
} }
FocusEventResult::FocusAccepted FocusEventResult::FocusAccepted
@ -544,15 +548,16 @@ impl TextInput {
return false; return false;
} }
let platform_window = window.platform_window();
let renderer = platform_window.renderer();
let last_cursor_pos = (self.cursor_position() as usize).max(0).min(text.len()); let last_cursor_pos = (self.cursor_position() as usize).max(0).min(text.len());
let mut grapheme_cursor = let mut grapheme_cursor =
unicode_segmentation::GraphemeCursor::new(last_cursor_pos, text.len(), true); unicode_segmentation::GraphemeCursor::new(last_cursor_pos, text.len(), true);
let font_height = window let font_height =
.renderer() renderer.text_size(self.font_request(window), " ", None, window.scale_factor()).height;
.text_size(self.font_request(window), " ", None, window.scale_factor())
.height;
let mut reset_preferred_x_pos = true; let mut reset_preferred_x_pos = true;
@ -567,23 +572,23 @@ impl TextInput {
reset_preferred_x_pos = false; reset_preferred_x_pos = false;
let cursor_rect = let cursor_rect =
window.renderer().text_input_cursor_rect_for_byte_offset(self, last_cursor_pos); renderer.text_input_cursor_rect_for_byte_offset(self, last_cursor_pos);
let mut cursor_xy_pos = cursor_rect.center(); let mut cursor_xy_pos = cursor_rect.center();
cursor_xy_pos.y += font_height; cursor_xy_pos.y += font_height;
cursor_xy_pos.x = self.preferred_x_pos.get(); cursor_xy_pos.x = self.preferred_x_pos.get();
window.renderer().text_input_byte_offset_for_position(self, cursor_xy_pos) renderer.text_input_byte_offset_for_position(self, cursor_xy_pos)
} }
TextCursorDirection::PreviousLine => { TextCursorDirection::PreviousLine => {
reset_preferred_x_pos = false; reset_preferred_x_pos = false;
let cursor_rect = let cursor_rect =
window.renderer().text_input_cursor_rect_for_byte_offset(self, last_cursor_pos); renderer.text_input_cursor_rect_for_byte_offset(self, last_cursor_pos);
let mut cursor_xy_pos = cursor_rect.center(); let mut cursor_xy_pos = cursor_rect.center();
cursor_xy_pos.y -= font_height; cursor_xy_pos.y -= font_height;
cursor_xy_pos.x = self.preferred_x_pos.get(); cursor_xy_pos.x = self.preferred_x_pos.get();
window.renderer().text_input_byte_offset_for_position(self, cursor_xy_pos) renderer.text_input_byte_offset_for_position(self, cursor_xy_pos)
} }
TextCursorDirection::PreviousCharacter => { TextCursorDirection::PreviousCharacter => {
let mut i = last_cursor_pos; let mut i = last_cursor_pos;
@ -615,19 +620,19 @@ impl TextInput {
} }
TextCursorDirection::StartOfLine => { TextCursorDirection::StartOfLine => {
let cursor_rect = let cursor_rect =
window.renderer().text_input_cursor_rect_for_byte_offset(self, last_cursor_pos); renderer.text_input_cursor_rect_for_byte_offset(self, last_cursor_pos);
let mut cursor_xy_pos = cursor_rect.center(); let mut cursor_xy_pos = cursor_rect.center();
cursor_xy_pos.x = 0 as Coord; cursor_xy_pos.x = 0 as Coord;
window.renderer().text_input_byte_offset_for_position(self, cursor_xy_pos) renderer.text_input_byte_offset_for_position(self, cursor_xy_pos)
} }
TextCursorDirection::EndOfLine => { TextCursorDirection::EndOfLine => {
let cursor_rect = let cursor_rect =
window.renderer().text_input_cursor_rect_for_byte_offset(self, last_cursor_pos); renderer.text_input_cursor_rect_for_byte_offset(self, last_cursor_pos);
let mut cursor_xy_pos = cursor_rect.center(); let mut cursor_xy_pos = cursor_rect.center();
cursor_xy_pos.x = Coord::MAX; cursor_xy_pos.x = Coord::MAX;
window.renderer().text_input_byte_offset_for_position(self, cursor_xy_pos) renderer.text_input_byte_offset_for_position(self, cursor_xy_pos)
} }
TextCursorDirection::StartOfParagraph => text TextCursorDirection::StartOfParagraph => text
.as_bytes() .as_bytes()
@ -674,6 +679,7 @@ impl TextInput {
self.cursor_position.set(new_position); self.cursor_position.set(new_position);
if new_position >= 0 { if new_position >= 0 {
let pos = window let pos = window
.platform_window()
.renderer() .renderer()
.text_input_cursor_rect_for_byte_offset(self, new_position as usize) .text_input_cursor_rect_for_byte_offset(self, new_position as usize)
.origin; .origin;

View file

@ -14,9 +14,8 @@ use crate::lengths::{
}; };
use crate::renderer::Renderer; use crate::renderer::Renderer;
use crate::textlayout::{FontMetrics as _, TextParagraphLayout}; use crate::textlayout::{FontMetrics as _, TextParagraphLayout};
use crate::window::WindowHandleAccess; use crate::window::{WindowHandleAccess, WindowInner};
use crate::{Color, Coord, ImageInner, StaticTextures}; use crate::{Color, Coord, ImageInner, StaticTextures};
use alloc::rc::Rc;
use alloc::{vec, vec::Vec}; use alloc::{vec, vec::Vec};
use core::cell::{Cell, RefCell}; use core::cell::{Cell, RefCell};
use core::pin::Pin; use core::pin::Pin;
@ -105,7 +104,7 @@ impl SoftwareRenderer {
buffer: &mut [impl TargetPixel], buffer: &mut [impl TargetPixel],
buffer_stride: PhysicalLength, buffer_stride: PhysicalLength,
) { ) {
let window = window.window_handle().clone(); let window = window.window_handle();
let factor = ScaleFactor::new(window.scale_factor()); let factor = ScaleFactor::new(window.scale_factor());
let (size, background) = if let Some(window_item) = let (size, background) = if let Some(window_item) =
window.window_item().as_ref().map(|item| item.as_pin_ref()) window.window_item().as_ref().map(|item| item.as_pin_ref())
@ -127,7 +126,7 @@ impl SoftwareRenderer {
let buffer_renderer = SceneBuilder::new( let buffer_renderer = SceneBuilder::new(
size, size,
factor, factor,
window.clone(), window,
RenderToBuffer { buffer, stride: buffer_stride }, RenderToBuffer { buffer, stride: buffer_stride },
); );
let mut renderer = crate::item_rendering::PartialRenderer::new( let mut renderer = crate::item_rendering::PartialRenderer::new(
@ -234,13 +233,13 @@ impl Renderer for SoftwareRenderer {
} }
fn render_window_frame_by_line( fn render_window_frame_by_line(
runtime_window: Rc<crate::window::WindowInner>, window: &WindowInner,
background: Color, background: Color,
size: PhysicalSize, size: PhysicalSize,
renderer: &SoftwareRenderer, renderer: &SoftwareRenderer,
mut line_buffer: impl LineBufferProvider, mut line_buffer: impl LineBufferProvider,
) { ) {
let mut scene = prepare_scene(runtime_window, size, renderer); let mut scene = prepare_scene(window, size, renderer);
let dirty_region = scene.dirty_region; let dirty_region = scene.dirty_region;
@ -556,14 +555,9 @@ struct RoundedRectangle {
bottom_clip: PhysicalLength, bottom_clip: PhysicalLength,
} }
fn prepare_scene( fn prepare_scene(window: &WindowInner, size: PhysicalSize, swrenderer: &SoftwareRenderer) -> Scene {
runtime_window: Rc<crate::window::WindowInner>, let factor = ScaleFactor::new(window.scale_factor());
size: PhysicalSize, let prepare_scene = SceneBuilder::new(size, factor, window, PrepareScene::default());
swrenderer: &SoftwareRenderer,
) -> Scene {
let factor = ScaleFactor::new(runtime_window.scale_factor());
let prepare_scene =
SceneBuilder::new(size, factor, runtime_window.clone(), PrepareScene::default());
let mut renderer = crate::item_rendering::PartialRenderer::new( let mut renderer = crate::item_rendering::PartialRenderer::new(
&swrenderer.partial_cache, &swrenderer.partial_cache,
swrenderer.force_dirty.take(), swrenderer.force_dirty.take(),
@ -571,7 +565,7 @@ fn prepare_scene(
); );
let mut dirty_region = PhysicalRect::default(); let mut dirty_region = PhysicalRect::default();
runtime_window.draw_contents(|components| { window.draw_contents(|components| {
for (component, origin) in components { for (component, origin) in components {
renderer.compute_dirty_regions(component, *origin); renderer.compute_dirty_regions(component, *origin);
} }
@ -717,19 +711,19 @@ impl ProcessScene for PrepareScene {
} }
} }
struct SceneBuilder<T> { struct SceneBuilder<'a, T> {
processor: T, processor: T,
state_stack: Vec<RenderState>, state_stack: Vec<RenderState>,
current_state: RenderState, current_state: RenderState,
scale_factor: ScaleFactor, scale_factor: ScaleFactor,
window: Rc<crate::window::WindowInner>, window: &'a WindowInner,
} }
impl<T: ProcessScene> SceneBuilder<T> { impl<'a, T: ProcessScene> SceneBuilder<'a, T> {
fn new( fn new(
size: PhysicalSize, size: PhysicalSize,
scale_factor: ScaleFactor, scale_factor: ScaleFactor,
window: Rc<crate::window::WindowInner>, window: &'a WindowInner,
processor: T, processor: T,
) -> Self { ) -> Self {
Self { Self {
@ -900,7 +894,7 @@ struct RenderState {
clip: LogicalRect, clip: LogicalRect,
} }
impl<T: ProcessScene> crate::item_rendering::ItemRenderer for SceneBuilder<T> { impl<'a, T: ProcessScene> crate::item_rendering::ItemRenderer for SceneBuilder<'a, T> {
fn draw_rectangle(&mut self, rect: Pin<&crate::items::Rectangle>, _: &ItemRc) { fn draw_rectangle(&mut self, rect: Pin<&crate::items::Rectangle>, _: &ItemRc) {
let geom = LogicalRect::new(LogicalPoint::default(), rect.logical_geometry().size_length()); let geom = LogicalRect::new(LogicalPoint::default(), rect.logical_geometry().size_length());
if self.should_draw(&geom) { if self.should_draw(&geom) {
@ -1060,7 +1054,7 @@ impl<T: ProcessScene> crate::item_rendering::ItemRenderer for SceneBuilder<T> {
return; return;
} }
let font_request = text.font_request(&self.window); let font_request = text.font_request(self.window);
let font = fonts::match_font(&font_request, self.scale_factor); let font = fonts::match_font(&font_request, self.scale_factor);
let layout = fonts::text_layout_for_font(&font, &font_request, self.scale_factor); let layout = fonts::text_layout_for_font(&font, &font_request, self.scale_factor);
@ -1199,7 +1193,7 @@ impl<T: ProcessScene> crate::item_rendering::ItemRenderer for SceneBuilder<T> {
todo!() todo!()
} }
fn window(&self) -> crate::window::WindowRc { fn window(&self) -> &crate::api::Window {
unreachable!("this backend don't query the window") unreachable!("this backend don't query the window")
} }

View file

@ -6,7 +6,6 @@
#![allow(unsafe_code)] #![allow(unsafe_code)]
use crate::input::{KeyEvent, KeyEventType, KeyboardModifiers, MouseEvent}; use crate::input::{KeyEvent, KeyEventType, KeyboardModifiers, MouseEvent};
use crate::window::WindowRc;
use crate::Coord; use crate::Coord;
use crate::SharedString; use crate::SharedString;
@ -29,7 +28,7 @@ pub extern "C" fn slint_send_mouse_click(
component: &crate::component::ComponentRc, component: &crate::component::ComponentRc,
x: Coord, x: Coord,
y: Coord, y: Coord,
window: &WindowRc, window: &crate::window::WindowInner,
) { ) {
let mut state = crate::input::MouseInputState::default(); let mut state = crate::input::MouseInputState::default();
let position = euclid::point2(x, y); let position = euclid::point2(x, y);
@ -60,7 +59,7 @@ pub extern "C" fn slint_send_mouse_click(
pub extern "C" fn send_keyboard_string_sequence( pub extern "C" fn send_keyboard_string_sequence(
sequence: &crate::SharedString, sequence: &crate::SharedString,
modifiers: KeyboardModifiers, modifiers: KeyboardModifiers,
window: &WindowRc, window: &crate::window::WindowInner,
) { ) {
for ch in sequence.chars() { for ch in sequence.chars() {
let mut modifiers = modifiers; let mut modifiers = modifiers;

View file

@ -62,7 +62,7 @@ pub trait PlatformWindow {
/// ///
/// If this function return None (the default implementation), then the /// If this function return None (the default implementation), then the
/// popup will be rendered within the window itself. /// popup will be rendered within the window itself.
fn create_popup(&self, _geometry: Rect) -> Option<Window> { fn create_popup(&self, _geometry: Rect) -> Option<PlatformWindowRc> {
None None
} }
@ -117,9 +117,8 @@ pub trait PlatformWindow {
/// Return the renderer /// Return the renderer
fn renderer(&self) -> &dyn Renderer; fn renderer(&self) -> &dyn Renderer;
/// Temporary function to provide access to the WindowInner. This should, in the future, return /// Returns the window API.
/// a &Window fn window(&self) -> &Window;
fn window(&self) -> WindowRc;
} }
struct WindowPropertiesTracker { struct WindowPropertiesTracker {
@ -149,7 +148,7 @@ impl crate::properties::PropertyDirtyHandler for WindowRedrawTracker {
/// This enum describes the different ways a popup can be rendered by the back-end. /// This enum describes the different ways a popup can be rendered by the back-end.
pub enum PopupWindowLocation { pub enum PopupWindowLocation {
/// The popup is rendered in its own top-level window that is know to the windowing system. /// The popup is rendered in its own top-level window that is know to the windowing system.
TopLevel(Window), TopLevel(PlatformWindowRc),
/// The popup is rendered as an embedded child window at the given position. /// The popup is rendered as an embedded child window at the given position.
ChildWindow(Point), ChildWindow(Point),
} }
@ -165,13 +164,11 @@ pub struct PopupWindow {
/// Inner datastructure for the [`crate::api::Window`] /// Inner datastructure for the [`crate::api::Window`]
pub struct WindowInner { pub struct WindowInner {
/// FIXME! use Box instead; platform_window_weak: Weak<dyn PlatformWindow>,
platform_window: once_cell::unsync::OnceCell<Rc<dyn PlatformWindow>>,
component: RefCell<ComponentWeak>, component: RefCell<ComponentWeak>,
mouse_input_state: Cell<MouseInputState>, mouse_input_state: Cell<MouseInputState>,
redraw_tracker: once_cell::unsync::OnceCell<Pin<Box<PropertyTracker<WindowRedrawTracker>>>>, redraw_tracker: Pin<Box<PropertyTracker<WindowRedrawTracker>>>,
window_properties_tracker: window_properties_tracker: Pin<Box<PropertyTracker<WindowPropertiesTracker>>>,
once_cell::unsync::OnceCell<Pin<Box<PropertyTracker<WindowPropertiesTracker>>>>,
/// Gets dirty when the layout restrictions, or some other property of the windows change /// Gets dirty when the layout restrictions, or some other property of the windows change
meta_properties_tracker: Pin<Rc<PropertyTracker>>, meta_properties_tracker: Pin<Rc<PropertyTracker>>,
@ -197,35 +194,16 @@ impl Drop for WindowInner {
impl WindowInner { impl WindowInner {
/// Create a new instance of the window, given the platform_window factory fn /// Create a new instance of the window, given the platform_window factory fn
pub fn new( pub fn new(platform_window_weak: Weak<dyn PlatformWindow>) -> Self {
platform_window_fn: impl FnOnce(&Weak<WindowInner>) -> Rc<dyn PlatformWindow>,
) -> Rc<Self> {
#![allow(unused_mut)] #![allow(unused_mut)]
let window = Rc::new(Self {
platform_window: Default::default(),
component: Default::default(),
mouse_input_state: Default::default(),
redraw_tracker: Default::default(),
window_properties_tracker: Default::default(),
meta_properties_tracker: Rc::pin(Default::default()),
focus_item: Default::default(),
cursor_blinker: Default::default(),
scale_factor: Box::pin(Property::new_named(1., "i_slint_core::Window::scale_factor")),
active: Box::pin(Property::new_named(false, "i_slint_core::Window::active")),
active_popup: Default::default(),
close_requested: Default::default(),
inner_size: Default::default(),
});
let window_weak = Rc::downgrade(&window);
window.platform_window.set(platform_window_fn(&window_weak)).ok().unwrap();
let mut window_properties_tracker = let mut window_properties_tracker =
PropertyTracker::new_with_dirty_handler(WindowPropertiesTracker { PropertyTracker::new_with_dirty_handler(WindowPropertiesTracker {
platform_window_weak: Rc::downgrade(&window.platform_window.get().unwrap()), platform_window_weak: platform_window_weak.clone(),
}); });
let mut redraw_tracker = PropertyTracker::new_with_dirty_handler(WindowRedrawTracker { let mut redraw_tracker = PropertyTracker::new_with_dirty_handler(WindowRedrawTracker {
platform_window_weak: Rc::downgrade(&window.platform_window.get().unwrap()), platform_window_weak: platform_window_weak.clone(),
}); });
#[cfg(slint_debug_property)] #[cfg(slint_debug_property)]
@ -235,10 +213,21 @@ impl WindowInner {
redraw_tracker.set_debug_name("i_slint_core::Window::redraw_tracker".into()); redraw_tracker.set_debug_name("i_slint_core::Window::redraw_tracker".into());
} }
// We need to use a OnceCell only so we can have a cycle with the Weak. let window = Self {
// Rust 1.60's Rc::new_cyclic would allow to avoid that. platform_window_weak,
window.window_properties_tracker.set(Box::pin(window_properties_tracker)).ok().unwrap(); component: Default::default(),
window.redraw_tracker.set(Box::pin(redraw_tracker)).ok().unwrap(); mouse_input_state: Default::default(),
redraw_tracker: Box::pin(redraw_tracker),
window_properties_tracker: Box::pin(window_properties_tracker),
meta_properties_tracker: Rc::pin(Default::default()),
focus_item: Default::default(),
cursor_blinker: Default::default(),
scale_factor: Box::pin(Property::new_named(1., "i_slint_core::Window::scale_factor")),
active: Box::pin(Property::new_named(false, "i_slint_core::Window::active")),
active_popup: Default::default(),
close_requested: Default::default(),
inner_size: Default::default(),
};
window window
} }
@ -251,8 +240,9 @@ impl WindowInner {
self.mouse_input_state.replace(Default::default()); self.mouse_input_state.replace(Default::default());
self.component.replace(ComponentRc::downgrade(component)); self.component.replace(ComponentRc::downgrade(component));
self.meta_properties_tracker.set_dirty(); // component changed, layout constraints for sure must be re-calculated self.meta_properties_tracker.set_dirty(); // component changed, layout constraints for sure must be re-calculated
self.request_window_properties_update(); let platform_window = self.platform_window();
self.request_redraw(); platform_window.request_window_properties_update();
platform_window.request_redraw();
} }
/// return the component. /// return the component.
@ -314,7 +304,7 @@ impl WindowInner {
self.mouse_input_state.set(crate::input::process_mouse_input( self.mouse_input_state.set(crate::input::process_mouse_input(
component, component,
event, event,
&self.window_rc(), self,
self.mouse_input_state.take(), self.mouse_input_state.take(),
)); ));
@ -339,7 +329,7 @@ impl WindowInner {
// Reset the focus... not great, but better than keeping it. // Reset the focus... not great, but better than keeping it.
self.take_focus_item(); self.take_focus_item();
} else { } else {
if focus_item.borrow().as_ref().key_event(event, &self.window_rc()) if focus_item.borrow().as_ref().key_event(event, self)
== crate::input::KeyEventResult::EventAccepted == crate::input::KeyEventResult::EventAccepted
{ {
return; return;
@ -377,7 +367,7 @@ impl WindowInner {
pub fn set_focus_item(&self, focus_item: &ItemRc) { pub fn set_focus_item(&self, focus_item: &ItemRc) {
let old = self.take_focus_item(); let old = self.take_focus_item();
let new = self.clone().move_focus(focus_item.clone(), next_focus_item); let new = self.clone().move_focus(focus_item.clone(), next_focus_item);
self.platform_window.get().unwrap().handle_focus_change(old, new); self.platform_window().handle_focus_change(old, new);
} }
/// Sets the focus on the window to true or false, depending on the have_focus argument. /// Sets the focus on the window to true or false, depending on the have_focus argument.
@ -390,7 +380,7 @@ impl WindowInner {
}; };
if let Some(focus_item) = self.focus_item.borrow().upgrade() { if let Some(focus_item) = self.focus_item.borrow().upgrade() {
focus_item.borrow().as_ref().focus_event(&event, &self.window_rc()); focus_item.borrow().as_ref().focus_event(&event, self);
} }
} }
@ -401,10 +391,7 @@ impl WindowInner {
let focus_item = self.focus_item.take(); let focus_item = self.focus_item.take();
if let Some(focus_item_rc) = focus_item.upgrade() { if let Some(focus_item_rc) = focus_item.upgrade() {
focus_item_rc focus_item_rc.borrow().as_ref().focus_event(&crate::input::FocusEvent::FocusOut, self);
.borrow()
.as_ref()
.focus_event(&crate::input::FocusEvent::FocusOut, &self.window_rc());
Some(focus_item_rc) Some(focus_item_rc)
} else { } else {
None None
@ -418,9 +405,7 @@ impl WindowInner {
match item { match item {
Some(item) => { Some(item) => {
*self.focus_item.borrow_mut() = item.downgrade(); *self.focus_item.borrow_mut() = item.downgrade();
item.borrow() item.borrow().as_ref().focus_event(&crate::input::FocusEvent::FocusIn, self)
.as_ref()
.focus_event(&crate::input::FocusEvent::FocusIn, &self.window_rc())
} }
None => { None => {
*self.focus_item.borrow_mut() = Default::default(); *self.focus_item.borrow_mut() = Default::default();
@ -457,7 +442,7 @@ impl WindowInner {
.map(next_focus_item) .map(next_focus_item)
.unwrap_or_else(|| ItemRc::new(component, 0)); .unwrap_or_else(|| ItemRc::new(component, 0));
let end_item = self.move_focus(start_item.clone(), next_focus_item); let end_item = self.move_focus(start_item.clone(), next_focus_item);
self.platform_window.get().unwrap().handle_focus_change(Some(start_item), end_item); self.platform_window().handle_focus_change(Some(start_item), end_item);
} }
/// Move keyboard focus to the previous item. /// Move keyboard focus to the previous item.
@ -467,7 +452,7 @@ impl WindowInner {
self.take_focus_item().unwrap_or_else(|| ItemRc::new(component, 0)), self.take_focus_item().unwrap_or_else(|| ItemRc::new(component, 0)),
); );
let end_item = self.move_focus(start_item.clone(), previous_focus_item); let end_item = self.move_focus(start_item.clone(), previous_focus_item);
self.platform_window.get().unwrap().handle_focus_change(Some(start_item), end_item); self.platform_window().handle_focus_change(Some(start_item), end_item);
} }
/// Marks the window to be the active window. This typically coincides with the keyboard /// Marks the window to be the active window. This typically coincides with the keyboard
@ -486,18 +471,13 @@ impl WindowInner {
/// If the component's root item is a Window element, then this function synchronizes its properties, such as the title /// If the component's root item is a Window element, then this function synchronizes its properties, such as the title
/// for example, with the properties known to the windowing system. /// for example, with the properties known to the windowing system.
pub fn update_window_properties(&self) { pub fn update_window_properties(&self) {
if let Some(window_properties_tracker) = self.window_properties_tracker.get() { // No `if !dirty { return; }` check here because the backend window may be newly mapped and not up-to-date, so force
// No `if !dirty { return; }` check here because the backend window may be newly mapped and not up-to-date, so force // an evaluation.
// an evaluation. self.window_properties_tracker.as_ref().evaluate_as_dependency_root(|| {
window_properties_tracker.as_ref().evaluate_as_dependency_root(|| { if let Some(window_item) = self.window_item() {
if let Some(window_item) = self.window_item() { self.platform_window().apply_window_properties(window_item.as_pin_ref());
self.platform_window }
.get() });
.unwrap()
.apply_window_properties(window_item.as_pin_ref());
}
});
}
} }
/// Calls the render_components to render the main component and any sub-window components, tracked by a /// Calls the render_components to render the main component and any sub-window components, tracked by a
@ -508,7 +488,7 @@ impl WindowInner {
let component = ComponentRc::borrow_pin(&component_rc); let component = ComponentRc::borrow_pin(&component_rc);
self.meta_properties_tracker.as_ref().evaluate_if_dirty(|| { self.meta_properties_tracker.as_ref().evaluate_if_dirty(|| {
self.apply_geometry_constraint( self.platform_window().apply_geometry_constraint(
component.as_ref().layout_info(crate::layout::Orientation::Horizontal), component.as_ref().layout_info(crate::layout::Orientation::Horizontal),
component.as_ref().layout_info(crate::layout::Orientation::Vertical), component.as_ref().layout_info(crate::layout::Orientation::Vertical),
); );
@ -532,23 +512,19 @@ impl WindowInner {
} }
}; };
if let Some(redraw_tracker) = self.redraw_tracker.get() { self.redraw_tracker.as_ref().evaluate_as_dependency_root(draw_fn)
redraw_tracker.as_ref().evaluate_as_dependency_root(draw_fn)
} else {
draw_fn()
}
} }
/// Registers the window with the windowing system, in order to render the component's items and react /// Registers the window with the windowing system, in order to render the component's items and react
/// to input events once the event loop spins. /// to input events once the event loop spins.
pub fn show(&self) { pub fn show(&self) {
self.platform_window.get().unwrap().clone().show(); self.platform_window().show();
self.update_window_properties(); self.update_window_properties();
} }
/// De-registers the window with the windowing system. /// De-registers the window with the windowing system.
pub fn hide(&self) { pub fn hide(&self) {
self.platform_window.get().unwrap().clone().hide(); self.platform_window().hide();
} }
/// Show a popup at the given position relative to the item /// Show a popup at the given position relative to the item
@ -603,18 +579,17 @@ impl WindowInner {
height_property.set(size.height); height_property.set(size.height);
}; };
let location = let location = match self.platform_window().create_popup(Rect::new(position, size)) {
match self.platform_window.get().unwrap().create_popup(Rect::new(position, size)) { None => {
None => { self.meta_properties_tracker.set_dirty();
self.meta_properties_tracker.set_dirty(); PopupWindowLocation::ChildWindow(position)
PopupWindowLocation::ChildWindow(position) }
}
Some(window) => { Some(platform_window) => {
window.window_handle().set_component(popup_componentrc); platform_window.window().window_handle().set_component(popup_componentrc);
PopupWindowLocation::TopLevel(window) PopupWindowLocation::TopLevel(platform_window)
} }
}; };
self.active_popup self.active_popup
.replace(Some(PopupWindow { location, component: popup_componentrc.clone() })); .replace(Some(PopupWindow { location, component: popup_componentrc.clone() }));
@ -632,8 +607,9 @@ impl WindowInner {
.translate(offset.to_vector()); .translate(offset.to_vector());
if !popup_region.is_empty() { if !popup_region.is_empty() {
self.renderer().mark_dirty_region(popup_region.to_box2d()); let platform_window = self.platform_window();
self.request_redraw(); platform_window.renderer().mark_dirty_region(popup_region.to_box2d());
platform_window.request_redraw();
} }
} }
} }
@ -696,29 +672,22 @@ impl WindowInner {
} }
} }
/// Temporary function to turn an `&WindowInner` into an `Rc<WindowInner>` for use with the item vtable functions. /// Returns the upgraded rlatform window.
pub fn window_rc(&self) -> WindowRc { pub fn platform_window(&self) -> PlatformWindowRc {
self.platform_window.get().unwrap().as_ref().window() self.platform_window_weak.upgrade().unwrap()
}
}
impl core::ops::Deref for WindowInner {
type Target = dyn PlatformWindow;
fn deref(&self) -> &Self::Target {
self.platform_window.get().unwrap().as_ref()
} }
} }
/// Internal trait used by generated code to access window internals. /// Internal trait used by generated code to access window internals.
pub trait WindowHandleAccess { pub trait WindowHandleAccess {
/// Returns a reference to the window implementation. /// Returns a reference to the window implementation.
fn window_handle(&self) -> &Rc<WindowInner>; fn window_handle(&self) -> &WindowInner;
} }
/// Internal alias for Rc<Window> so that it can be used in the vtable /// Internal alias for Rc<dyn PlatformWindow>.
/// functions and generate a good signature. pub type PlatformWindowRc = Rc<dyn PlatformWindow>;
pub type WindowRc = Rc<WindowInner>; /// Internal convenience alias for Weak<dyn PlatformWindow>.
pub type PlatformWindowWeak = Weak<dyn PlatformWindow>;
/// This module contains the functions needed to interface with the event loop and window traits /// This module contains the functions needed to interface with the event loop and window traits
/// from outside the Rust language. /// from outside the Rust language.
@ -742,101 +711,112 @@ pub mod ffi {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
type c_void = (); type c_void = ();
/// Same layout as WindowRc /// Same layout as PlatformWindowRc
#[repr(C)] #[repr(C)]
pub struct WindowRcOpaque(*const c_void); pub struct PlatformWindowRcOpaque(*const c_void, *const c_void);
/// Releases the reference to the windowrc held by handle. /// Releases the reference to the windowrc held by handle.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_drop(handle: *mut WindowRcOpaque) { pub unsafe extern "C" fn slint_windowrc_drop(handle: *mut PlatformWindowRcOpaque) {
assert_eq!(core::mem::size_of::<WindowRc>(), core::mem::size_of::<WindowRcOpaque>()); assert_eq!(
core::ptr::read(handle as *mut WindowRc); core::mem::size_of::<PlatformWindowRc>(),
core::mem::size_of::<PlatformWindowRcOpaque>()
);
core::ptr::read(handle as *mut PlatformWindowRc);
} }
/// Releases the reference to the component window held by handle. /// Releases the reference to the component window held by handle.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_clone( pub unsafe extern "C" fn slint_windowrc_clone(
source: *const WindowRcOpaque, source: *const PlatformWindowRcOpaque,
target: *mut WindowRcOpaque, target: *mut PlatformWindowRcOpaque,
) { ) {
assert_eq!(core::mem::size_of::<WindowRc>(), core::mem::size_of::<WindowRcOpaque>()); assert_eq!(
let window = &*(source as *const WindowRc); core::mem::size_of::<PlatformWindowRc>(),
core::ptr::write(target as *mut WindowRc, window.clone()); core::mem::size_of::<PlatformWindowRcOpaque>()
);
let window = &*(source as *const PlatformWindowRc);
core::ptr::write(target as *mut PlatformWindowRc, window.clone());
} }
/// Spins an event loop and renders the items of the provided component in this window. /// Spins an event loop and renders the items of the provided component in this window.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_show(handle: *const WindowRcOpaque) { pub unsafe extern "C" fn slint_windowrc_show(handle: *const PlatformWindowRcOpaque) {
let window = &*(handle as *const WindowRc); let platform_window = &*(handle as *const PlatformWindowRc);
window.show(); platform_window.show();
} }
/// Spins an event loop and renders the items of the provided component in this window. /// Spins an event loop and renders the items of the provided component in this window.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_hide(handle: *const WindowRcOpaque) { pub unsafe extern "C" fn slint_windowrc_hide(handle: *const PlatformWindowRcOpaque) {
let window = &*(handle as *const WindowRc); let window = &*(handle as *const PlatformWindowRc);
window.hide(); window.hide();
} }
/// Returns the window scale factor. /// Returns the window scale factor.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_get_scale_factor(handle: *const WindowRcOpaque) -> f32 { pub unsafe extern "C" fn slint_windowrc_get_scale_factor(
assert_eq!(core::mem::size_of::<WindowRc>(), core::mem::size_of::<WindowRcOpaque>()); handle: *const PlatformWindowRcOpaque,
let window = &*(handle as *const WindowRc); ) -> f32 {
window.scale_factor() assert_eq!(
core::mem::size_of::<PlatformWindowRc>(),
core::mem::size_of::<PlatformWindowRcOpaque>()
);
let platform_window = &*(handle as *const PlatformWindowRc);
platform_window.window().window_handle().scale_factor()
} }
/// Sets the window scale factor, merely for testing purposes. /// Sets the window scale factor, merely for testing purposes.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_set_scale_factor( pub unsafe extern "C" fn slint_windowrc_set_scale_factor(
handle: *const WindowRcOpaque, handle: *const PlatformWindowRcOpaque,
value: f32, value: f32,
) { ) {
let window = &*(handle as *const WindowRc); let platform_window = &*(handle as *const PlatformWindowRc);
window.set_scale_factor(value) platform_window.window().window_handle().set_scale_factor(value)
} }
/// Sets the focus item. /// Sets the focus item.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_set_focus_item( pub unsafe extern "C" fn slint_windowrc_set_focus_item(
handle: *const WindowRcOpaque, handle: *const PlatformWindowRcOpaque,
focus_item: &ItemRc, focus_item: &ItemRc,
) { ) {
let window = &*(handle as *const WindowRc); let platform_window = &*(handle as *const PlatformWindowRc);
window.set_focus_item(focus_item) platform_window.window().window_handle().set_focus_item(focus_item)
} }
/// Associates the window with the given component. /// Associates the window with the given component.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_set_component( pub unsafe extern "C" fn slint_windowrc_set_component(
handle: *const WindowRcOpaque, handle: *const PlatformWindowRcOpaque,
component: &ComponentRc, component: &ComponentRc,
) { ) {
let window = &*(handle as *const WindowRc); let platform_window = &*(handle as *const PlatformWindowRc);
window.set_component(component) platform_window.window().window_handle().set_component(component)
} }
/// Show a popup. /// Show a popup.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_show_popup( pub unsafe extern "C" fn slint_windowrc_show_popup(
handle: *const WindowRcOpaque, handle: *const PlatformWindowRcOpaque,
popup: &ComponentRc, popup: &ComponentRc,
position: crate::graphics::Point, position: crate::graphics::Point,
parent_item: &ItemRc, parent_item: &ItemRc,
) { ) {
let window = &*(handle as *const WindowRc); let platform_window = &*(handle as *const PlatformWindowRc);
window.show_popup(popup, position, parent_item); platform_window.window().window_handle().show_popup(popup, position, parent_item);
} }
/// Close the current popup /// Close the current popup
pub unsafe extern "C" fn slint_windowrc_close_popup(handle: *const WindowRcOpaque) { pub unsafe extern "C" fn slint_windowrc_close_popup(handle: *const PlatformWindowRcOpaque) {
let window = &*(handle as *const WindowRc); let platform_window = &*(handle as *const PlatformWindowRc);
window.close_popup(); platform_window.window().window_handle().close_popup();
} }
/// C binding to the set_rendering_notifier() API of Window /// C binding to the set_rendering_notifier() API of Window
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_set_rendering_notifier( pub unsafe extern "C" fn slint_windowrc_set_rendering_notifier(
handle: *const WindowRcOpaque, handle: *const PlatformWindowRcOpaque,
callback: extern "C" fn( callback: extern "C" fn(
rendering_state: RenderingState, rendering_state: RenderingState,
graphics_api: GraphicsAPI, graphics_api: GraphicsAPI,
@ -872,7 +852,7 @@ pub mod ffi {
} }
} }
let window = &*(handle as *const WindowRc); let window = &*(handle as *const PlatformWindowRc);
match window.renderer().set_rendering_notifier(Box::new(CNotifier { match window.renderer().set_rendering_notifier(Box::new(CNotifier {
callback, callback,
drop_user_data, drop_user_data,
@ -889,7 +869,7 @@ pub mod ffi {
/// C binding to the on_close_requested() API of Window /// C binding to the on_close_requested() API of Window
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_on_close_requested( pub unsafe extern "C" fn slint_windowrc_on_close_requested(
handle: *const WindowRcOpaque, handle: *const PlatformWindowRcOpaque,
callback: extern "C" fn(user_data: *mut c_void) -> CloseRequestResponse, callback: extern "C" fn(user_data: *mut c_void) -> CloseRequestResponse,
drop_user_data: extern "C" fn(user_data: *mut c_void), drop_user_data: extern "C" fn(user_data: *mut c_void),
user_data: *mut c_void, user_data: *mut c_void,
@ -914,26 +894,26 @@ pub mod ffi {
let with_user_data = WithUserData { callback, drop_user_data, user_data }; let with_user_data = WithUserData { callback, drop_user_data, user_data };
let window = &*(handle as *const WindowRc); let platform_window = &*(handle as *const PlatformWindowRc);
window.on_close_requested(move || with_user_data.call()); platform_window.window().on_close_requested(move || with_user_data.call());
} }
/// This function issues a request to the windowing system to redraw the contents of the window. /// This function issues a request to the windowing system to redraw the contents of the window.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_request_redraw(handle: *const WindowRcOpaque) { pub unsafe extern "C" fn slint_windowrc_request_redraw(handle: *const PlatformWindowRcOpaque) {
let window = &*(handle as *const WindowRc); let platform_window = &*(handle as *const PlatformWindowRc);
window.request_redraw(); platform_window.request_redraw();
} }
/// Returns the position of the window on the screen, in physical screen coordinates and including /// Returns the position of the window on the screen, in physical screen coordinates and including
/// a window frame (if present). /// a window frame (if present).
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_position( pub unsafe extern "C" fn slint_windowrc_position(
handle: *const WindowRcOpaque, handle: *const PlatformWindowRcOpaque,
pos: &mut euclid::default::Point2D<i32>, pos: &mut euclid::default::Point2D<i32>,
) { ) {
let window = &*(handle as *const WindowRc); let platform_window = &*(handle as *const PlatformWindowRc);
*pos = window.position().to_untyped() *pos = platform_window.position().to_untyped()
} }
/// Sets the position of the window on the screen, in physical screen coordinates and including /// Sets the position of the window on the screen, in physical screen coordinates and including
@ -941,29 +921,29 @@ pub mod ffi {
/// Note that on some windowing systems, such as Wayland, this functionality is not available. /// Note that on some windowing systems, such as Wayland, this functionality is not available.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_set_position( pub unsafe extern "C" fn slint_windowrc_set_position(
handle: *const WindowRcOpaque, handle: *const PlatformWindowRcOpaque,
pos: &euclid::default::Point2D<i32>, pos: &euclid::default::Point2D<i32>,
) { ) {
let window = &*(handle as *const WindowRc); let platform_window = &*(handle as *const PlatformWindowRc);
window.set_position(euclid::Point2D::from_untyped(*pos)); platform_window.set_position(euclid::Point2D::from_untyped(*pos));
} }
/// Returns the size of the window on the screen, in physical screen coordinates and excluding /// Returns the size of the window on the screen, in physical screen coordinates and excluding
/// a window frame (if present). /// a window frame (if present).
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_size(handle: *const WindowRcOpaque) -> IntSize { pub unsafe extern "C" fn slint_windowrc_size(handle: *const PlatformWindowRcOpaque) -> IntSize {
let window = &*(handle as *const WindowRc); let platform_window = &*(handle as *const PlatformWindowRc);
window.inner_size.get().to_untyped() platform_window.window().window_handle().inner_size.get().to_untyped().cast()
} }
/// Resizes the window to the specified size on the screen, in physical pixels and excluding /// Resizes the window to the specified size on the screen, in physical pixels and excluding
/// a window frame (if present). /// a window frame (if present).
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_windowrc_set_size( pub unsafe extern "C" fn slint_windowrc_set_size(
handle: *const WindowRcOpaque, handle: *const PlatformWindowRcOpaque,
size: &IntSize, size: &IntSize,
) { ) {
let window = &*(handle as *const WindowRc); let platform_window = &*(handle as *const PlatformWindowRc);
window.set_inner_size([size.width, size.height].into()); platform_window.set_inner_size([size.width, size.height].into());
} }
} }

View file

@ -560,11 +560,11 @@ pub extern "C" fn slint_interpreter_component_instance_show(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_interpreter_component_instance_window( pub unsafe extern "C" fn slint_interpreter_component_instance_window(
inst: &ErasedComponentBox, inst: &ErasedComponentBox,
out: *mut *const i_slint_core::window::ffi::WindowRcOpaque, out: *mut *const i_slint_core::window::ffi::PlatformWindowRcOpaque,
) { ) {
assert_eq!( assert_eq!(
core::mem::size_of::<WindowRc>(), core::mem::size_of::<WindowRc>(),
core::mem::size_of::<i_slint_core::window::ffi::WindowRcOpaque>() core::mem::size_of::<i_slint_core::window::ffi::PlatformWindowRcOpaque>()
); );
core::ptr::write(out as *mut *const WindowRc, inst.window().window_handle() as *const _) core::ptr::write(out as *mut *const WindowRc, inst.window().window_handle() as *const _)
} }