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 = [
"ComponentVTable",
"Slice",
"WindowRcOpaque",
"PlatformWindowRcOpaque",
"PropertyAnimation",
"EasingCurve",
"TextHorizontalAlignment",

View file

@ -86,7 +86,9 @@ inline void assert_main_thread()
class WindowRc
{
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_drop(&inner); }
WindowRc(const WindowRc &other)
@ -223,7 +225,7 @@ public:
}
private:
cbindgen_private::WindowRcOpaque inner;
cbindgen_private::PlatformWindowRcOpaque inner;
};
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.
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);
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.
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);
auto wid = reinterpret_cast<QWidget *>(cbindgen_private::slint_qt_get_widget(
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,
KeyboardModifiers modifiers = {})
{
const cbindgen_private::WindowRcOpaque *win_ptr = nullptr;
const cbindgen_private::PlatformWindowRcOpaque *win_ptr = nullptr;
cbindgen_private::slint_interpreter_component_instance_window(
reinterpret_cast<const cbindgen_private::ErasedComponentBox *>(component), &win_ptr);
cbindgen_private::send_keyboard_string_sequence(

View file

@ -5,8 +5,7 @@
use core::ffi::c_void;
use i_slint_backend_selector::backend;
use i_slint_core::api::Window;
use i_slint_core::window::{ffi::WindowRcOpaque, WindowRc};
use i_slint_core::window::{ffi::PlatformWindowRcOpaque, PlatformWindowRc};
#[doc(hidden)]
#[cold]
@ -18,9 +17,12 @@ pub fn use_modules() -> usize {
}
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_init(out: *mut WindowRcOpaque) {
assert_eq!(core::mem::size_of::<Window>(), core::mem::size_of::<WindowRcOpaque>());
core::ptr::write(out as *mut Window, crate::backend().create_window());
pub unsafe extern "C" fn slint_windowrc_init(out: *mut PlatformWindowRcOpaque) {
assert_eq!(
core::mem::size_of::<PlatformWindowRc>(),
core::mem::size_of::<PlatformWindowRcOpaque>()
);
core::ptr::write(out as *mut PlatformWindowRc, crate::backend().create_window());
}
#[no_mangle]
@ -63,14 +65,17 @@ pub unsafe extern "C" fn slint_quit_event_loop() {
#[no_mangle]
pub unsafe extern "C" fn slint_register_font_from_path(
win: *const WindowRcOpaque,
win: *const PlatformWindowRcOpaque,
path: &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(
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(),
Err(err) => err.to_string().into(),
},
@ -79,14 +84,14 @@ pub unsafe extern "C" fn slint_register_font_from_path(
#[no_mangle]
pub unsafe extern "C" fn slint_register_font_from_data(
win: *const WindowRcOpaque,
win: *const PlatformWindowRcOpaque,
data: i_slint_core::slice::Slice<'static, u8>,
error_str: *mut i_slint_core::SharedString,
) {
let window = &*(win as *const WindowRc);
let platform_window = &*(win as *const PlatformWindowRc);
core::ptr::write(
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(),
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::properties::{set_state_binding, Property, PropertyTracker, StateInfo};
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::ComponentVTable_static;
pub use i_slint_core::Coord;
@ -435,9 +435,8 @@ pub mod internal {
/// Creates a new window to render components in.
#[doc(hidden)]
pub fn create_window() -> re_exports::WindowRc {
use i_slint_core::window::WindowHandleAccess;
i_slint_backend_selector::backend().create_window().window_handle().clone()
pub fn create_window() -> re_exports::PlatformWindowRc {
i_slint_backend_selector::backend().create_window()
}
/// 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 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
@ -506,7 +505,7 @@ pub mod testing {
i_slint_core::tests::send_keyboard_string_sequence(
&super::SharedString::from(sequence),
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::string::String;
use core::cell::RefCell;
use i_slint_core::window::WindowInner;
use i_slint_core::window::{PlatformWindow, WindowRc};
use i_slint_core::api::Window;
use i_slint_core::window::{PlatformWindow, PlatformWindowRc, WindowHandleAccess};
thread_local! { static WINDOWS: RefCell<Option<Rc<McuWindow>>> = RefCell::new(None) }
thread_local! { static EVENT_QUEUE: RefCell<VecDeque<McuEvent>> = Default::default() }
pub struct McuWindow {
window_inner_weak: Weak<WindowInner>,
window: Window,
self_weak: Weak<Self>,
renderer: crate::renderer::SoftwareRenderer,
}
impl PlatformWindow for McuWindow {
fn show(&self) {
let w = self.window_inner_weak.upgrade().unwrap();
let w = self.window.window_handle();
w.set_scale_factor(
option_env!("SLINT_SCALE_FACTOR").and_then(|x| x.parse().ok()).unwrap_or(1.),
);
@ -149,8 +149,8 @@ mod the_backend {
self
}
fn window(&self) -> WindowRc {
self.window_inner_weak.upgrade().unwrap()
fn window(&self) -> &Window {
&self.window
}
}
@ -189,7 +189,7 @@ mod the_backend {
}
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();
DEVICES.with(|devices| {
@ -202,11 +202,7 @@ mod the_backend {
runtime_window.set_window_item_geometry(size.width as _, size.height as _);
if let Some(buffer) = devices.get_buffer() {
window.renderer.render(
&runtime_window.into(),
buffer,
screen_size.width_length(),
);
window.renderer.render(&window.window, buffer, screen_size.width_length());
devices.flush_frame();
frame_profiler.stop_profiling(&mut **devices, "=> frame total");
@ -263,24 +259,21 @@ mod the_backend {
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");
});
}
}
impl i_slint_core::backend::Backend for MCUBackend {
fn create_window(&self) -> i_slint_core::api::Window {
i_slint_core::window::WindowInner::new(|window| {
fn create_window(&self) -> PlatformWindowRc {
Rc::new_cyclic(|self_weak| McuWindow {
window_inner_weak: window.clone(),
window: Window::new(self_weak.clone() as _),
self_weak: self_weak.clone(),
renderer: crate::renderer::SoftwareRenderer::new(
crate::renderer::DirtyTracking::DoubleBuffer,
),
})
})
.into()
}
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();
if let Some(mut event) = e {
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:
if let Some(p) = event.position() {
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;
impl i_slint_core::backend::Backend for PicoBackend {
fn create_window(&self) -> i_slint_core::api::Window {
i_slint_core::window::WindowInner::new(|window| {
fn create_window(&self) -> i_slint_core::window::PlatformWindowRc {
Rc::new_cyclic(|self_weak| PicoWindow {
window_inner_weak: window.clone(),
window: i_slint_core::api::Window::new(self_weak.clone() as _),
self_weak: self_weak.clone(),
renderer: renderer::SoftwareRenderer::new(renderer::DirtyTracking::SingleBuffer),
needs_redraw: Default::default(),
})
})
.into()
}
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();
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) {
window.renderer.render_by_line(&runtime_window, &mut buffer_provider);
window.renderer.render_by_line(&window.window, &mut buffer_provider);
buffer_provider.flush_frame();
}
@ -217,7 +211,7 @@ fn run_event_loop() -> ! {
.map(|point| {
let size = DISPLAY_SIZE.to_f32();
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) {
Some(_) => PointerEvent::Moved { position },
None => PointerEvent::Pressed { position, button },
@ -227,7 +221,7 @@ fn run_event_loop() -> ! {
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
continue;
}
@ -287,7 +281,7 @@ impl<TO: WriteTarget<TransmittedWord = u8> + FullDuplex<u8>, CH: SingleChannel>
}
struct PicoWindow {
window_inner_weak: Weak<i_slint_core::window::WindowInner>,
window: i_slint_core::api::Window,
self_weak: Weak<Self>,
renderer: crate::renderer::SoftwareRenderer,
needs_redraw: Cell<bool>,
@ -295,9 +289,7 @@ struct PicoWindow {
impl i_slint_core::window::PlatformWindow for PicoWindow {
fn show(&self) {
let runtime_window =
i_slint_core::api::Window::from(self.window_inner_weak.upgrade().unwrap());
runtime_window.set_size(DISPLAY_SIZE.cast());
self.window.set_size(DISPLAY_SIZE.cast());
WINDOW.with(|x| *x.borrow_mut() = Some(self.self_weak.upgrade().unwrap()))
}
fn hide(&self) {
@ -315,8 +307,8 @@ impl i_slint_core::window::PlatformWindow for PicoWindow {
self
}
fn window(&self) -> i_slint_core::window::WindowRc {
self.window_inner_weak.upgrade().unwrap()
fn window(&self) -> &i_slint_core::api::Window {
&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::input::KeyboardModifiers;
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 rgb::FromSlice;
@ -27,7 +27,7 @@ use glcontext::*;
use i_slint_core::swrenderer::SoftwareRenderer;
pub struct SimulatorWindow {
window_inner_weak: Weak<i_slint_core::window::WindowInner>,
window: i_slint_core::api::Window,
self_weak: Weak<Self>,
keyboard_modifiers: std::cell::Cell<KeyboardModifiers>,
currently_pressed_key_code: std::cell::Cell<Option<winit::event::VirtualKeyCode>>,
@ -40,7 +40,7 @@ pub struct 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 opengl_context = OpenGLContext::new_context(window_builder);
@ -56,7 +56,7 @@ impl SimulatorWindow {
let canvas = Rc::new(RefCell::new(canvas));
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(),
keyboard_modifiers: Default::default(),
currently_pressed_key_code: Default::default(),
@ -68,7 +68,7 @@ impl SimulatorWindow {
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 _);
window_rc
@ -89,7 +89,7 @@ impl PlatformWindow for SimulatorWindow {
self.visible.set(true);
let runtime_window = self.window();
let runtime_window = self.window.window_handle();
let component_rc = runtime_window.component();
let component = ComponentRc::borrow_pin(&component_rc);
@ -178,8 +178,8 @@ impl PlatformWindow for SimulatorWindow {
unimplemented!()
}
fn window(&self) -> WindowRc {
self.window_inner_weak.upgrade().unwrap()
fn window(&self) -> &i_slint_core::api::Window {
&self.window
}
}
@ -193,8 +193,6 @@ impl WinitWindow for SimulatorWindow {
}
fn draw(&self) {
let runtime_window = self.window_inner_weak.upgrade().unwrap();
let size = self.opengl_context.window().inner_size();
self.opengl_context.with_current_context(|opengl_context| {
@ -237,8 +235,7 @@ impl WinitWindow for SimulatorWindow {
});
}
}
self.renderer
.render_by_line(&runtime_window.into(), BufferProvider { devices: display });
self.renderer.render_by_line(&self.window, BufferProvider { devices: display });
let output_image = display
.to_rgb_output_image(&embedded_graphics_simulator::OutputSettings::default());
@ -301,8 +298,8 @@ impl WinitWindow for SimulatorWindow {
pub struct SimulatorBackend;
impl i_slint_core::backend::Backend for SimulatorBackend {
fn create_window(&self) -> i_slint_core::api::Window {
i_slint_core::window::WindowInner::new(|window| SimulatorWindow::new(window)).into()
fn create_window(&self) -> PlatformWindowRc {
SimulatorWindow::new()
}
fn run_event_loop(&self, behavior: i_slint_core::backend::EventLoopQuitBehavior) {

View file

@ -38,7 +38,7 @@ pub fn use_modules() -> usize {
mod ffi {
#[no_mangle]
pub extern "C" fn slint_qt_get_widget(
_: &i_slint_core::window::WindowRc,
_: &i_slint_core::window::PlatformWindowRc,
) -> *mut std::ffi::c_void {
std::ptr::null_mut()
}
@ -122,6 +122,7 @@ pub type NativeGlobals = ();
pub const HAS_NATIVE_STYLE: bool = cfg!(not(no_qt));
use i_slint_core::window::PlatformWindowRc;
#[cfg(not(no_qt))]
pub use qt_widgets::{native_style_metrics_deinit, native_style_metrics_init};
#[cfg(no_qt)]
@ -135,12 +136,12 @@ pub fn native_style_metrics_deinit(_: core::pin::Pin<&mut native_widgets::Native
pub struct 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)]
panic!("The Qt backend needs 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::item_tree::{ItemRc, ItemWeak};
use i_slint_core::properties::{PropertyDirtyHandler, PropertyTracker};
use i_slint_core::window::WindowHandleAccess;
use i_slint_core::SharedVector;
use cpp::*;
@ -327,9 +328,9 @@ cpp! {{
};
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*" {
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 _
});
}

View file

@ -31,7 +31,7 @@ use i_slint_core::items::{Item, ItemConsts, ItemRc, ItemVTable, RenderingResult,
use i_slint_core::layout::{LayoutInfo, Orientation};
#[cfg(feature = "rtti")]
use i_slint_core::rtti::*;
use i_slint_core::window::WindowInner;
use i_slint_core::window::{WindowHandleAccess, WindowInner};
use i_slint_core::{
declare_item_vtable, Callback, ItemVTable_static, Property, SharedString, SharedVector,
};
@ -59,7 +59,7 @@ macro_rules! fn_render {
let $dpr: f32 = backend.scale_factor();
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
// has that property right now.
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,
};
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 items::{ImageFit, TextHorizontalAlignment, TextVerticalAlignment};
@ -189,7 +189,7 @@ cpp! {{
void customEvent(QEvent *event) override {
if (event->type() == QEvent::User) {
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 {
QWidget::customEvent(event);
@ -200,7 +200,7 @@ cpp! {{
if (event->type() == QEvent::ActivationChange) {
bool active = isActiveWindow();
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);
@ -208,10 +208,7 @@ cpp! {{
void closeEvent(QCloseEvent *event) override {
bool accepted = rust!(Slint_requestClose [rust_window: &QtWindow as "void*"] -> bool as "bool" {
if let Some(window) = rust_window.self_weak.upgrade() {
return window.request_close();
}
true
return rust_window.window.window_handle().request_close();
});
if (accepted) {
event->accept();
@ -222,7 +219,7 @@ cpp! {{
QSize sizeHint() const override {
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 layout_info_h = component.as_ref().layout_info(Orientation::Horizontal);
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> {
painter: QPainterPtr,
cache: &'a ItemCache<qttypes::QPixmap>,
window: WindowRc,
window: &'a i_slint_core::api::Window,
metrics: RenderingMetrics,
}
@ -516,7 +513,7 @@ impl ItemRenderer for QtItemRenderer<'_> {
let rect: qttypes::QRectF = get_geometry!(items::Text, text);
let fill_brush: qttypes::QBrush = into_qbrush(text.color(), rect.width, rect.height);
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() {
TextHorizontalAlignment::Left => key_generated::Qt_AlignmentFlag_AlignLeft,
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() {
TextHorizontalAlignment::Left => key_generated::Qt_AlignmentFlag_AlignLeft,
TextHorizontalAlignment::Center => key_generated::Qt_AlignmentFlag_AlignHCenter,
@ -925,8 +922,8 @@ impl ItemRenderer for QtItemRenderer<'_> {
}}
}
fn window(&self) -> WindowRc {
self.window.clone()
fn window(&self) -> &i_slint_core::api::Window {
&self.window
}
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 {
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>>>,
@ -1212,8 +1210,9 @@ pub struct QtWindow {
}
impl QtWindow {
pub fn new(window_weak: &Weak<i_slint_core::window::WindowInner>) -> Rc<Self> {
let window_ptr = window_weak.clone().into_raw();
pub fn new() -> Rc<Self> {
let rc = Rc::new_cyclic(|self_weak| {
let window_ptr = self_weak.clone().into_raw();
let widget_ptr = cpp! {unsafe [window_ptr as "void*"] -> QWidgetPtr as "std::unique_ptr<QWidget>" {
ensure_initialized(true);
auto widget = std::make_unique<SlintWidget>();
@ -1223,20 +1222,22 @@ impl QtWindow {
return widget;
}};
let rc = Rc::new(QtWindow {
QtWindow {
widget_ptr,
self_weak: window_weak.clone(),
window: i_slint_core::api::Window::new(self_weak.clone() as _),
self_weak: self_weak.clone(),
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 rust_window = Rc::as_ptr(&rc);
cpp! {unsafe [widget_ptr as "SlintWidget*", rust_window as "void*"] {
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
}
@ -1246,13 +1247,13 @@ impl QtWindow {
}
fn paint_event(&self, painter: QPainterPtr) {
let runtime_window = self.self_weak.upgrade().unwrap();
runtime_window.clone().draw_contents(|components| {
let runtime_window = self.window.window_handle();
runtime_window.draw_contents(|components| {
i_slint_core::animations::update_animations();
let mut renderer = QtItemRenderer {
painter,
cache: &self.cache,
window: runtime_window,
window: &self.window,
metrics: RenderingMetrics { layers_created: Some(0) },
};
@ -1295,12 +1296,11 @@ impl QtWindow {
}
fn resize_event(&self, size: qttypes::QSize) {
i_slint_core::api::Window::from(self.self_weak.upgrade().unwrap())
.set_size(euclid::size2(size.width, size.height));
self.window.set_size(euclid::size2(size.width, size.height));
}
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();
}
@ -1321,13 +1321,13 @@ impl QtWindow {
text,
modifiers,
};
self.self_weak.upgrade().unwrap().process_key_input(&event);
self.window.window_handle().process_key_input(&event);
timer_event();
}
fn close_popup(&self) {
self.self_weak.upgrade().unwrap().close_popup();
self.window.window_handle().close_popup();
}
fn free_graphics_resources(&self, component: ComponentRef) {
@ -1339,7 +1339,7 @@ impl QtWindow {
#[allow(unused)]
impl PlatformWindow for QtWindow {
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 root_item = component.as_ref().get_item_ref(0);
if let Some(window_item) = ItemRef::downcast_pin(root_item) {
@ -1478,12 +1478,8 @@ impl PlatformWindow for QtWindow {
self.tree_structure_changed.replace(true);
}
fn create_popup(&self, geometry: Rect) -> Option<i_slint_core::api::Window> {
let window = i_slint_core::window::WindowInner::new(|window| QtWindow::new(window));
let popup_window: &QtWindow =
<dyn std::any::Any>::downcast_ref(window.as_ref().as_any()).unwrap();
let runtime_window = self.self_weak.upgrade().unwrap();
fn create_popup(&self, geometry: Rect) -> Option<PlatformWindowRc> {
let popup_window = QtWindow::new();
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->show();
}};
Some(window.into())
Some(popup_window as _)
}
fn set_mouse_cursor(&self, cursor: MouseCursor) {
@ -1583,8 +1579,8 @@ impl PlatformWindow for QtWindow {
}};
}
fn window(&self) -> WindowRc {
self.self_weak.upgrade().unwrap()
fn window(&self) -> &i_slint_core::api::Window {
&self.window
}
}
@ -1609,8 +1605,7 @@ impl Renderer for QtWindow {
}
let rect: qttypes::QRectF = get_geometry!(items::TextInput, text_input);
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(&runtime_window));
let font: QFont = get_font(text_input.font_request(self.window.window_handle()));
let string = qttypes::QString::from(text_input.text().as_str());
let flags = match text_input.horizontal_alignment() {
TextHorizontalAlignment::Left => key_generated::Qt_AlignmentFlag_AlignLeft,
@ -1665,8 +1660,7 @@ impl Renderer for QtWindow {
byte_offset: usize,
) -> Rect {
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(&runtime_window));
let font: QFont = get_font(text_input.font_request(self.window.window_handle()));
let text = text_input.text();
let mut string = qttypes::QString::from(text.as_str());
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;
#[no_mangle]
pub extern "C" fn slint_qt_get_widget(window: &i_slint_core::window::WindowRc) -> *mut c_void {
<dyn std::any::Any>::downcast_ref(window.as_any())
pub extern "C" fn slint_qt_get_widget(
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| {
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::PhysicalPx;
use i_slint_core::api::Window;
use i_slint_core::graphics::{Point, Rect, Size};
use i_slint_core::renderer::Renderer;
use i_slint_core::window::WindowRc;
use i_slint_core::window::{PlatformWindow, WindowInner};
use i_slint_core::window::PlatformWindow;
use i_slint_core::window::PlatformWindowRc;
use std::pin::Pin;
use std::rc::Rc;
use std::rc::Weak;
use std::sync::Mutex;
#[derive(Default)]
@ -22,9 +20,10 @@ pub struct TestingBackend {
}
impl i_slint_core::backend::Backend for TestingBackend {
fn create_window(&self) -> Window {
WindowInner::new(|window_weak| Rc::new(TestingWindow { self_weak: window_weak.clone() }))
.into()
fn create_window(&self) -> PlatformWindowRc {
Rc::new_cyclic(|self_weak| TestingWindow {
window: i_slint_core::api::Window::new(self_weak.clone() as _),
})
}
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 {
self_weak: Weak<i_slint_core::window::WindowInner>,
window: i_slint_core::api::Window,
}
impl PlatformWindow for TestingWindow {
@ -104,8 +103,8 @@ impl PlatformWindow for TestingWindow {
unimplemented!()
}
fn window(&self) -> WindowRc {
self.self_weak.upgrade().unwrap()
fn window(&self) -> &i_slint_core::api::Window {
&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_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_min_inner_size(if min_width > 0. || min_height > 0. {
@ -123,7 +123,7 @@ pub trait WinitWindow: PlatformWindow {
must_resize = true;
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. {
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.
|| (existing_size.height as f32 - height).abs() > 1.
@ -148,7 +149,7 @@ pub trait WinitWindow: PlatformWindow {
});
if must_resize {
let win = i_slint_core::api::Window::from(self.window());
let win = self.window();
let f = win.scale_factor().0;
win.set_size(euclid::size2((width as f32 * f) as _, (height as f32 * f) as _));
}
@ -380,7 +381,7 @@ fn process_window_event(
event
}
let runtime_window = window.window();
let runtime_window = window.window().window_handle();
match event {
WindowEvent::Resized(size) => {
window.resize_event(size);
@ -651,7 +652,7 @@ pub fn run(quit_behavior: i_slint_core::backend::EventLoopQuitBehavior) {
.drain(..)
.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::items::{ItemRef, MouseCursor};
use corelib::layout::Orientation;
use corelib::window::{PlatformWindow, WindowRc};
use corelib::window::{PlatformWindow, PlatformWindowRc, WindowHandleAccess};
use corelib::Property;
use corelib::{graphics::*, Coord};
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
/// typically instantiated by entry factory functions of the different graphics back ends.
pub(crate) struct GLWindow<Renderer: WinitCompatibleRenderer + 'static> {
window_inner_weak: Weak<corelib::window::WindowInner>,
window: corelib::api::Window,
self_weak: Weak<Self>,
map_state: RefCell<GraphicsWindowBackendState<Renderer>>,
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>>,
}
impl<Renderer: WinitCompatibleRenderer> GLWindow<Renderer> {
impl<Renderer: WinitCompatibleRenderer + 'static> GLWindow<Renderer> {
/// Creates a new reference-counted instance.
///
/// Arguments:
/// * `graphics_backend_factory`: The factor function stored in the GraphicsWindow that's called when the state
/// of the window changes to mapped. The event loop and window builder parameters can be used to create a
/// backing window.
pub(crate) fn new(
window_weak: &Weak<corelib::window::WindowInner>,
#[cfg(target_arch = "wasm32")] canvas_id: String,
) -> Rc<Self> {
Rc::new_cyclic(|self_weak| Self {
window_inner_weak: window_weak.clone(),
pub(crate) fn new(#[cfg(target_arch = "wasm32")] canvas_id: String) -> PlatformWindowRc {
let self_rc = Rc::new_cyclic(|self_weak| Self {
window: corelib::api::Window::new(self_weak.clone() as _),
self_weak: self_weak.clone(),
map_state: RefCell::new(GraphicsWindowBackendState::Unmapped {
requested_position: None,
@ -59,13 +56,14 @@ impl<Renderer: WinitCompatibleRenderer> GLWindow<Renderer> {
keyboard_modifiers: Default::default(),
currently_pressed_key_code: Default::default(),
renderer: Renderer::new(
&window_weak,
&(self_weak.clone() as _),
#[cfg(target_arch = "wasm32")]
canvas_id,
),
#[cfg(target_arch = "wasm32")]
virtual_keyboard_helper: Default::default(),
})
});
self_rc as _
}
fn is_mapped(&self) -> bool {
@ -192,8 +190,7 @@ impl<Renderer: WinitCompatibleRenderer + 'static> WinitWindow for GLWindow<Rende
fn resize_event(&self, size: winit::dpi::PhysicalSize<u32>) {
if let Some(mapped_window) = self.borrow_mapped_window() {
i_slint_core::api::Window::from(self.window())
.set_size(euclid::size2(size.width, size.height));
self.window().set_size(euclid::size2(size.width, size.height));
mapped_window.canvas.resize_event()
}
}
@ -270,7 +267,7 @@ impl<Renderer: WinitCompatibleRenderer + 'static> PlatformWindow for GLWindow<Re
GraphicsWindowBackendState::Mapped(_) => return,
};
let runtime_window = self.window();
let runtime_window = self.window().window_handle();
let component_rc = runtime_window.component();
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 id = canvas.with_window_handle(|window| {
let runtime_window = self.window_inner_weak.upgrade().unwrap();
runtime_window.set_scale_factor(
scale_factor_override.unwrap_or_else(|| window.scale_factor()) as _,
let id = canvas.with_window_handle(|winit_window| {
self.window.window_handle().set_scale_factor(
scale_factor_override.unwrap_or_else(|| winit_window.scale_factor()) as _,
);
window.id()
winit_window.id()
});
self.map_state.replace(GraphicsWindowBackendState::Mapped(MappedWindow {
@ -483,8 +479,8 @@ impl<Renderer: WinitCompatibleRenderer + 'static> PlatformWindow for GLWindow<Re
}
}
fn window(&self) -> WindowRc {
self.window_inner_weak.upgrade().unwrap()
fn window(&self) -> &corelib::api::Window {
&self.window
}
}

View file

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

View file

@ -1,19 +1,17 @@
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
use std::{
cell::RefCell,
pin::Pin,
rc::{Rc, Weak},
};
use std::{cell::RefCell, pin::Pin, rc::Rc};
use i_slint_core::{
api::{euclid, GraphicsAPI, RenderingNotifier, RenderingState, SetRenderingNotifierError},
graphics::rendering_metrics_collector::RenderingMetricsCollector,
graphics::{Point, Rect, Size},
renderer::Renderer,
Coord,
use i_slint_core::api::{
euclid, GraphicsAPI, RenderingNotifier, RenderingState, SetRenderingNotifierError,
};
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;
@ -26,7 +24,7 @@ mod itemrenderer;
const PASSWORD_CHARACTER: &str = "";
pub struct FemtoVGRenderer {
window_weak: Weak<i_slint_core::window::WindowInner>,
platform_window_weak: PlatformWindowWeak,
#[cfg(target_arch = "wasm32")]
canvas_id: String,
rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>,
@ -36,11 +34,11 @@ impl super::WinitCompatibleRenderer for FemtoVGRenderer {
type Canvas = FemtoVGCanvas;
fn new(
window_weak: &Weak<i_slint_core::window::WindowInner>,
platform_window_weak: &PlatformWindowWeak,
#[cfg(target_arch = "wasm32")] canvas_id: String,
) -> Self {
Self {
window_weak: window_weak.clone(),
platform_window_weak: platform_window_weak.clone(),
#[cfg(target_arch = "wasm32")]
canvas_id,
rendering_notifier: Default::default(),
@ -55,7 +53,7 @@ impl super::WinitCompatibleRenderer for FemtoVGRenderer {
);
let rendering_metrics_collector = RenderingMetricsCollector::new(
self.window_weak.clone(),
self.platform_window_weak.clone(),
&format!(
"FemtoVG renderer (windowing system: {})",
opengl_context.window().winsys_name()
@ -125,7 +123,7 @@ impl super::WinitCompatibleRenderer for FemtoVGRenderer {
}
fn render(&self, canvas: &FemtoVGCanvas) {
let window = match self.window_weak.upgrade() {
let platform_window = match self.platform_window_weak.upgrade() {
Some(window) => window,
None => return,
};
@ -136,6 +134,8 @@ impl super::WinitCompatibleRenderer for FemtoVGRenderer {
canvas.opengl_context.make_current();
let window = platform_window.window().window_handle();
window.draw_contents(|components| {
{
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))
}
let mut item_renderer =
self::itemrenderer::GLItemRenderer::new(canvas, &window, width, height);
let mut item_renderer = self::itemrenderer::GLItemRenderer::new(
canvas,
platform_window.window(),
width,
height,
);
for (component, origin) in components {
i_slint_core::item_rendering::render_component_items(
@ -218,11 +222,13 @@ impl Renderer for FemtoVGRenderer {
text_input: Pin<&i_slint_core::items::TextInput>,
pos: Point,
) -> usize {
let window = match self.window_weak.upgrade() {
let platform_window = match self.platform_window_weak.upgrade() {
Some(window) => window,
None => return 0,
};
let window = platform_window.window().window_handle();
let scale_factor = window.scale_factor();
let pos = pos * scale_factor;
let text = text_input.text();
@ -295,11 +301,13 @@ impl Renderer for FemtoVGRenderer {
text_input: Pin<&i_slint_core::items::TextInput>,
byte_offset: usize,
) -> Rect {
let window = match self.window_weak.upgrade() {
let platform_window = match self.platform_window_weak.upgrade() {
Some(window) => window,
None => return Default::default(),
};
let window = platform_window.window().window_handle();
let text = text_input.text();
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,
RenderingResult,
};
use i_slint_core::window::WindowRc;
use i_slint_core::window::WindowHandleAccess;
use i_slint_core::{Brush, Color, ImageInner, Property, SharedString};
use super::fonts;
@ -66,7 +66,7 @@ pub struct GLItemRenderer<'a> {
// because that can only happen after calling `flush`. Otherwise femtovg ends up processing
// `set_render_target` commands with image ids that have been deleted.
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,
/// track the state manually since femtovg don't have accessor for its state
state: Vec<State>,
@ -240,7 +240,7 @@ impl<'a> ItemRenderer for GLItemRenderer<'a> {
let string = string.as_str();
let font = fonts::FONT_CACHE.with(|cache| {
cache.borrow_mut().font(
text.font_request(&self.window),
text.font_request(self.window.window_handle()),
self.scale_factor,
&text.text(),
)
@ -278,7 +278,7 @@ impl<'a> ItemRenderer for GLItemRenderer<'a> {
let font = fonts::FONT_CACHE.with(|cache| {
cache.borrow_mut().font(
text_input.font_request(&self.window),
text_input.font_request(self.window.window_handle()),
self.scale_factor,
&text_input.text(),
)
@ -819,8 +819,8 @@ impl<'a> ItemRenderer for GLItemRenderer<'a> {
canvas.fill_text(0., 0., string, paint).unwrap();
}
fn window(&self) -> WindowRc {
self.window.clone()
fn window(&self) -> &i_slint_core::api::Window {
self.window
}
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> {
pub fn new(
canvas: &'a super::FemtoVGCanvas,
window: &Rc<i_slint_core::window::WindowInner>,
window: &'a i_slint_core::api::Window,
width: u32,
height: u32,
) -> Self {
let scale_factor = window.scale_factor();
let scale_factor = window.scale_factor().get();
Self {
graphics_cache: &canvas.graphics_cache,
texture_cache: &canvas.texture_cache,
canvas: canvas.canvas.clone(),
layer_images_to_delete_after_flush: Default::default(),
window: window.clone(),
window,
scale_factor,
state: vec![State {
scissor: Rect::new(
@ -1112,7 +1112,7 @@ impl<'a> GLItemRenderer<'a> {
let target_size_for_scalable_source = matches!(image_inner, ImageInner::Svg(..))
.then(|| {
// 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_height.get() * scale_factor) as u32,

View file

@ -1,16 +1,14 @@
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
use std::{
cell::RefCell,
rc::{Rc, Weak},
};
use std::{cell::RefCell, rc::Rc};
use i_slint_core::{
api::{GraphicsAPI, RenderingNotifier, RenderingState, SetRenderingNotifierError},
graphics::rendering_metrics_collector::RenderingMetricsCollector,
item_rendering::ItemCache,
use i_slint_core::api::{
GraphicsAPI, RenderingNotifier, RenderingState, SetRenderingNotifierError,
};
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;
@ -38,22 +36,25 @@ cfg_if::cfg_if! {
}
pub struct SkiaRenderer {
window_weak: Weak<i_slint_core::window::WindowInner>,
platform_window_weak: PlatformWindowWeak,
rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>,
}
impl super::WinitCompatibleRenderer for SkiaRenderer {
type Canvas = SkiaCanvas<DefaultSurface>;
fn new(window_weak: &std::rc::Weak<i_slint_core::window::WindowInner>) -> Self {
Self { window_weak: window_weak.clone(), rendering_notifier: Default::default() }
fn new(platform_window_weak: &PlatformWindowWeak) -> Self {
Self {
platform_window_weak: platform_window_weak.clone(),
rendering_notifier: Default::default(),
}
}
fn create_canvas(&self, window_builder: winit::window::WindowBuilder) -> Self::Canvas {
let surface = DefaultSurface::new(window_builder);
let rendering_metrics_collector = RenderingMetricsCollector::new(
self.window_weak.clone(),
self.platform_window_weak.clone(),
&format!(
"Skia renderer (windowing system: {}; skia backend {})",
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) {
let window = match self.window_weak.upgrade() {
let platform_window = match self.platform_window_weak.upgrade() {
Some(window) => window,
None => return,
};
let window = platform_window.window().window_handle();
canvas.surface.render(|skia_canvas, gr_context| {
window.draw_contents(|components| {
if let Some(window_item) = window.window_item() {
@ -105,8 +108,11 @@ impl super::WinitCompatibleRenderer for SkiaRenderer {
})
}
let mut item_renderer =
itemrenderer::SkiaRenderer::new(skia_canvas, &window, &canvas.image_cache);
let mut item_renderer = itemrenderer::SkiaRenderer::new(
skia_canvas,
platform_window.window(),
&canvas.image_cache,
);
for (component, origin) in components {
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
use std::pin::Pin;
use std::rc::Rc;
use i_slint_core::graphics::euclid;
use i_slint_core::item_rendering::{ItemCache, ItemRenderer};
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};
#[derive(Clone, Copy)]
@ -16,8 +16,8 @@ struct RenderState {
pub struct SkiaRenderer<'a> {
pub canvas: &'a mut skia_safe::Canvas,
pub window: Rc<i_slint_core::window::WindowInner>,
pub scale_factor: f32,
pub window: &'a i_slint_core::api::Window,
state_stack: Vec<RenderState>,
current_state: RenderState,
image_cache: &'a ItemCache<Option<skia_safe::Image>>,
@ -26,13 +26,13 @@ pub struct SkiaRenderer<'a> {
impl<'a> SkiaRenderer<'a> {
pub fn new(
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>>,
) -> Self {
Self {
canvas,
window: window.clone(),
scale_factor: window.scale_factor(),
scale_factor: window.scale_factor().get(),
window,
state_stack: vec![],
current_state: RenderState { alpha: 1.0 },
image_cache,
@ -351,7 +351,7 @@ impl<'a> ItemRenderer for SkiaRenderer<'a> {
let string = text.text();
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) {
Some(paint) => paint,
@ -599,8 +599,8 @@ impl<'a> ItemRenderer for SkiaRenderer<'a> {
);
}
fn window(&self) -> i_slint_core::window::WindowRc {
self.window.clone()
fn window(&self) -> &i_slint_core::api::Window {
self.window
}
fn as_any(&mut self) -> Option<&mut dyn core::any::Any> {

View file

@ -18,9 +18,10 @@
//! we just simulate a few backspaces.
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::window::{PlatformWindowWeak, WindowHandleAccess};
use i_slint_core::SharedString;
use wasm_bindgen::closure::Closure;
use wasm_bindgen::convert::FromWasmAbi;
@ -65,10 +66,7 @@ impl WasmInputState {
impl WasmInputHelper {
#[allow(unused)]
pub fn new(
window: Weak<i_slint_core::window::WindowInner>,
canvas: web_sys::HtmlCanvasElement,
) -> Self {
pub fn new(platform_window: PlatformWindowWeak, canvas: web_sys::HtmlCanvasElement) -> Self {
let input = web_sys::window()
.unwrap()
.document()
@ -91,23 +89,24 @@ impl WasmInputHelper {
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| {
// 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) {
window.set_active(false);
window.set_focus(false);
}
}
});
let win = window.clone();
let win = platform_window.clone();
let shared_state2 = shared_state.clone();
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();
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),
text,
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();
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();
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),
text,
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 input = h.input.clone();
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 !shared_state2.borrow_mut().has_key_down {
let window = platform_window.window().window_handle();
let text = SharedString::from(data.as_str());
window.process_key_input(&KeyEvent {
modifiers: Default::default(),
@ -155,11 +155,12 @@ impl WasmInputHelper {
});
for event in ["compositionend", "compositionupdate"] {
let win = window.clone();
let win = platform_window.clone();
let shared_state2 = shared_state.clone();
let input = h.input.clone();
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 (text, to_delete) =
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::rc::Rc;
use crate::component::ComponentVTable;
use crate::window::WindowRc;
use crate::window::WindowInner;
pub use crate::lengths::LogicalPx;
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
/// as the position on the screen.
#[repr(transparent)]
pub struct Window(WindowRc);
#[doc(hidden)]
impl From<WindowRc> for Window {
fn from(window: WindowRc) -> Self {
Self(window)
}
}
pub struct Window(WindowInner);
/// 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].
@ -122,6 +114,10 @@ impl Default for CloseRequestResponse {
}
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.
pub fn show(&self) {
self.0.show();
@ -138,7 +134,7 @@ impl Window {
&self,
callback: impl FnMut(RenderingState, &GraphicsAPI) + 'static,
) -> 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.
@ -149,7 +145,7 @@ impl Window {
/// This function issues a request to the windowing system to redraw the contents of the window.
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()
// 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
/// a window frame (if present).
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
/// a window frame (if present).
/// Note that on some windowing systems, such as Wayland, this functionality is not available.
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
@ -194,7 +190,7 @@ impl Window {
let l = size.cast() / self.scale_factor();
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
@ -204,12 +200,12 @@ impl Window {
/// 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.
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 {
fn window_handle(&self) -> &Rc<crate::window::WindowInner> {
fn window_handle(&self) -> &crate::window::WindowInner {
&self.0
}
}

View file

@ -13,6 +13,7 @@ use once_cell::sync::OnceCell;
#[cfg(all(not(feature = "std"), feature = "unsafe_single_core"))]
use crate::unsafe_single_core::OnceCell;
use crate::window::PlatformWindowRc;
#[derive(Copy, Clone)]
/// Behavior describing how the event loop should terminate.
@ -26,7 +27,7 @@ pub enum EventLoopQuitBehavior {
/// Interface implemented by back-ends
pub trait Backend: Send + Sync {
/// 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.
fn run_event_loop(&self, _behavior: EventLoopQuitBehavior) {

View file

@ -12,7 +12,7 @@ use crate::item_tree::{
use crate::items::{AccessibleRole, ItemVTable};
use crate::layout::{LayoutInfo, Orientation};
use crate::slice::Slice;
use crate::window::WindowInner;
use crate::window::{PlatformWindowRc, WindowHandleAccess};
use crate::SharedString;
use vtable::*;
@ -114,10 +114,12 @@ pub type ComponentWeak = vtable::VWeak<ComponentVTable, Dyn>;
pub fn register_component<Base>(
base: core::pin::Pin<&Base>,
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));
window.register_component();
item_array.iter().for_each(|item| {
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.
@ -125,30 +127,32 @@ pub fn unregister_component<Base>(
base: core::pin::Pin<&Base>,
component: ComponentRef,
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")]
pub(crate) mod ffi {
#![allow(unsafe_code)]
use crate::window::PlatformWindowRc;
use super::*;
use crate::window::WindowRc;
/// Call init() on the ItemVTable of each item in the item array.
#[no_mangle]
pub unsafe extern "C" fn slint_register_component(
component: ComponentRefPin,
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(
core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
item_array.as_slice(),
window,
platform_window,
)
}
@ -157,14 +161,14 @@ pub(crate) mod ffi {
pub unsafe extern "C" fn slint_unregister_component(
component: ComponentRefPin,
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(
core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
core::pin::Pin::into_inner(component),
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::window::PlatformWindowWeak;
use std::cell::RefCell;
use std::convert::TryFrom;
use std::rc::{Rc, Weak};
use std::rc::Rc;
enum RefreshMode {
Lazy, // render only when necessary (default)
@ -59,7 +60,7 @@ pub struct RenderingMetricsCollector {
refresh_mode: RefreshMode,
output_console: bool,
output_overlay: bool,
window: Weak<crate::window::WindowInner>,
platform_window: PlatformWindowWeak,
}
impl RenderingMetricsCollector {
@ -72,7 +73,7 @@ impl RenderingMetricsCollector {
///
/// 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.
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") {
Ok(var) => var,
_ => return None,
@ -101,7 +102,7 @@ impl RenderingMetricsCollector {
refresh_mode,
output_console,
output_overlay,
window,
platform_window,
});
#[cfg(debug_assertions)]
@ -170,7 +171,7 @@ impl RenderingMetricsCollector {
.borrow_mut()
.push(FrameData { timestamp: instant::Instant::now(), metrics: renderer.metrics() });
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();
}
crate::animations::CURRENT_ANIMATION_DRIVER

View file

@ -345,7 +345,7 @@ pub trait ItemRenderer {
(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
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)
}
fn window(&self) -> crate::window::WindowRc {
fn window(&self) -> &crate::api::Window {
self.actual_renderer.window()
}

View file

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

View file

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

View file

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

View file

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

View file

@ -62,7 +62,7 @@ pub trait PlatformWindow {
///
/// If this function return None (the default implementation), then the
/// 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
}
@ -117,9 +117,8 @@ pub trait PlatformWindow {
/// Return the renderer
fn renderer(&self) -> &dyn Renderer;
/// Temporary function to provide access to the WindowInner. This should, in the future, return
/// a &Window
fn window(&self) -> WindowRc;
/// Returns the window API.
fn window(&self) -> &Window;
}
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.
pub enum PopupWindowLocation {
/// 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.
ChildWindow(Point),
}
@ -165,13 +164,11 @@ pub struct PopupWindow {
/// Inner datastructure for the [`crate::api::Window`]
pub struct WindowInner {
/// FIXME! use Box instead;
platform_window: once_cell::unsync::OnceCell<Rc<dyn PlatformWindow>>,
platform_window_weak: Weak<dyn PlatformWindow>,
component: RefCell<ComponentWeak>,
mouse_input_state: Cell<MouseInputState>,
redraw_tracker: once_cell::unsync::OnceCell<Pin<Box<PropertyTracker<WindowRedrawTracker>>>>,
window_properties_tracker:
once_cell::unsync::OnceCell<Pin<Box<PropertyTracker<WindowPropertiesTracker>>>>,
redraw_tracker: Pin<Box<PropertyTracker<WindowRedrawTracker>>>,
window_properties_tracker: Pin<Box<PropertyTracker<WindowPropertiesTracker>>>,
/// Gets dirty when the layout restrictions, or some other property of the windows change
meta_properties_tracker: Pin<Rc<PropertyTracker>>,
@ -197,35 +194,16 @@ impl Drop for WindowInner {
impl WindowInner {
/// Create a new instance of the window, given the platform_window factory fn
pub fn new(
platform_window_fn: impl FnOnce(&Weak<WindowInner>) -> Rc<dyn PlatformWindow>,
) -> Rc<Self> {
pub fn new(platform_window_weak: Weak<dyn PlatformWindow>) -> Self {
#![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 =
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 {
platform_window_weak: Rc::downgrade(&window.platform_window.get().unwrap()),
platform_window_weak: platform_window_weak.clone(),
});
#[cfg(slint_debug_property)]
@ -235,10 +213,21 @@ impl WindowInner {
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.
// Rust 1.60's Rc::new_cyclic would allow to avoid that.
window.window_properties_tracker.set(Box::pin(window_properties_tracker)).ok().unwrap();
window.redraw_tracker.set(Box::pin(redraw_tracker)).ok().unwrap();
let window = Self {
platform_window_weak,
component: Default::default(),
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
}
@ -251,8 +240,9 @@ impl WindowInner {
self.mouse_input_state.replace(Default::default());
self.component.replace(ComponentRc::downgrade(component));
self.meta_properties_tracker.set_dirty(); // component changed, layout constraints for sure must be re-calculated
self.request_window_properties_update();
self.request_redraw();
let platform_window = self.platform_window();
platform_window.request_window_properties_update();
platform_window.request_redraw();
}
/// return the component.
@ -314,7 +304,7 @@ impl WindowInner {
self.mouse_input_state.set(crate::input::process_mouse_input(
component,
event,
&self.window_rc(),
self,
self.mouse_input_state.take(),
));
@ -339,7 +329,7 @@ impl WindowInner {
// Reset the focus... not great, but better than keeping it.
self.take_focus_item();
} 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
{
return;
@ -377,7 +367,7 @@ impl WindowInner {
pub fn set_focus_item(&self, focus_item: &ItemRc) {
let old = self.take_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.
@ -390,7 +380,7 @@ impl WindowInner {
};
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();
if let Some(focus_item_rc) = focus_item.upgrade() {
focus_item_rc
.borrow()
.as_ref()
.focus_event(&crate::input::FocusEvent::FocusOut, &self.window_rc());
focus_item_rc.borrow().as_ref().focus_event(&crate::input::FocusEvent::FocusOut, self);
Some(focus_item_rc)
} else {
None
@ -418,9 +405,7 @@ impl WindowInner {
match item {
Some(item) => {
*self.focus_item.borrow_mut() = item.downgrade();
item.borrow()
.as_ref()
.focus_event(&crate::input::FocusEvent::FocusIn, &self.window_rc())
item.borrow().as_ref().focus_event(&crate::input::FocusEvent::FocusIn, self)
}
None => {
*self.focus_item.borrow_mut() = Default::default();
@ -457,7 +442,7 @@ impl WindowInner {
.map(next_focus_item)
.unwrap_or_else(|| ItemRc::new(component, 0));
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.
@ -467,7 +452,7 @@ impl WindowInner {
self.take_focus_item().unwrap_or_else(|| ItemRc::new(component, 0)),
);
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
@ -486,19 +471,14 @@ impl WindowInner {
/// 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.
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
// an evaluation.
window_properties_tracker.as_ref().evaluate_as_dependency_root(|| {
self.window_properties_tracker.as_ref().evaluate_as_dependency_root(|| {
if let Some(window_item) = self.window_item() {
self.platform_window
.get()
.unwrap()
.apply_window_properties(window_item.as_pin_ref());
self.platform_window().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
/// property dependency tracker.
@ -508,7 +488,7 @@ impl WindowInner {
let component = ComponentRc::borrow_pin(&component_rc);
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::Vertical),
);
@ -532,23 +512,19 @@ impl WindowInner {
}
};
if let Some(redraw_tracker) = self.redraw_tracker.get() {
redraw_tracker.as_ref().evaluate_as_dependency_root(draw_fn)
} else {
draw_fn()
}
self.redraw_tracker.as_ref().evaluate_as_dependency_root(draw_fn)
}
/// 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.
pub fn show(&self) {
self.platform_window.get().unwrap().clone().show();
self.platform_window().show();
self.update_window_properties();
}
/// De-registers the window with the windowing system.
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
@ -603,16 +579,15 @@ impl WindowInner {
height_property.set(size.height);
};
let location =
match self.platform_window.get().unwrap().create_popup(Rect::new(position, size)) {
let location = match self.platform_window().create_popup(Rect::new(position, size)) {
None => {
self.meta_properties_tracker.set_dirty();
PopupWindowLocation::ChildWindow(position)
}
Some(window) => {
window.window_handle().set_component(popup_componentrc);
PopupWindowLocation::TopLevel(window)
Some(platform_window) => {
platform_window.window().window_handle().set_component(popup_componentrc);
PopupWindowLocation::TopLevel(platform_window)
}
};
@ -632,8 +607,9 @@ impl WindowInner {
.translate(offset.to_vector());
if !popup_region.is_empty() {
self.renderer().mark_dirty_region(popup_region.to_box2d());
self.request_redraw();
let platform_window = self.platform_window();
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.
pub fn window_rc(&self) -> WindowRc {
self.platform_window.get().unwrap().as_ref().window()
}
}
impl core::ops::Deref for WindowInner {
type Target = dyn PlatformWindow;
fn deref(&self) -> &Self::Target {
self.platform_window.get().unwrap().as_ref()
/// Returns the upgraded rlatform window.
pub fn platform_window(&self) -> PlatformWindowRc {
self.platform_window_weak.upgrade().unwrap()
}
}
/// Internal trait used by generated code to access window internals.
pub trait WindowHandleAccess {
/// 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
/// functions and generate a good signature.
pub type WindowRc = Rc<WindowInner>;
/// Internal alias for Rc<dyn PlatformWindow>.
pub type PlatformWindowRc = Rc<dyn PlatformWindow>;
/// 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
/// from outside the Rust language.
@ -742,101 +711,112 @@ pub mod ffi {
#[allow(non_camel_case_types)]
type c_void = ();
/// Same layout as WindowRc
/// Same layout as PlatformWindowRc
#[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.
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_drop(handle: *mut WindowRcOpaque) {
assert_eq!(core::mem::size_of::<WindowRc>(), core::mem::size_of::<WindowRcOpaque>());
core::ptr::read(handle as *mut WindowRc);
pub unsafe extern "C" fn slint_windowrc_drop(handle: *mut PlatformWindowRcOpaque) {
assert_eq!(
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.
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_clone(
source: *const WindowRcOpaque,
target: *mut WindowRcOpaque,
source: *const PlatformWindowRcOpaque,
target: *mut PlatformWindowRcOpaque,
) {
assert_eq!(core::mem::size_of::<WindowRc>(), core::mem::size_of::<WindowRcOpaque>());
let window = &*(source as *const WindowRc);
core::ptr::write(target as *mut WindowRc, window.clone());
assert_eq!(
core::mem::size_of::<PlatformWindowRc>(),
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.
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_show(handle: *const WindowRcOpaque) {
let window = &*(handle as *const WindowRc);
window.show();
pub unsafe extern "C" fn slint_windowrc_show(handle: *const PlatformWindowRcOpaque) {
let platform_window = &*(handle as *const PlatformWindowRc);
platform_window.show();
}
/// Spins an event loop and renders the items of the provided component in this window.
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_hide(handle: *const WindowRcOpaque) {
let window = &*(handle as *const WindowRc);
pub unsafe extern "C" fn slint_windowrc_hide(handle: *const PlatformWindowRcOpaque) {
let window = &*(handle as *const PlatformWindowRc);
window.hide();
}
/// Returns the window scale factor.
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_get_scale_factor(handle: *const WindowRcOpaque) -> f32 {
assert_eq!(core::mem::size_of::<WindowRc>(), core::mem::size_of::<WindowRcOpaque>());
let window = &*(handle as *const WindowRc);
window.scale_factor()
pub unsafe extern "C" fn slint_windowrc_get_scale_factor(
handle: *const PlatformWindowRcOpaque,
) -> f32 {
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.
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_set_scale_factor(
handle: *const WindowRcOpaque,
handle: *const PlatformWindowRcOpaque,
value: f32,
) {
let window = &*(handle as *const WindowRc);
window.set_scale_factor(value)
let platform_window = &*(handle as *const PlatformWindowRc);
platform_window.window().window_handle().set_scale_factor(value)
}
/// Sets the focus item.
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_set_focus_item(
handle: *const WindowRcOpaque,
handle: *const PlatformWindowRcOpaque,
focus_item: &ItemRc,
) {
let window = &*(handle as *const WindowRc);
window.set_focus_item(focus_item)
let platform_window = &*(handle as *const PlatformWindowRc);
platform_window.window().window_handle().set_focus_item(focus_item)
}
/// Associates the window with the given component.
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_set_component(
handle: *const WindowRcOpaque,
handle: *const PlatformWindowRcOpaque,
component: &ComponentRc,
) {
let window = &*(handle as *const WindowRc);
window.set_component(component)
let platform_window = &*(handle as *const PlatformWindowRc);
platform_window.window().window_handle().set_component(component)
}
/// Show a popup.
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_show_popup(
handle: *const WindowRcOpaque,
handle: *const PlatformWindowRcOpaque,
popup: &ComponentRc,
position: crate::graphics::Point,
parent_item: &ItemRc,
) {
let window = &*(handle as *const WindowRc);
window.show_popup(popup, position, parent_item);
let platform_window = &*(handle as *const PlatformWindowRc);
platform_window.window().window_handle().show_popup(popup, position, parent_item);
}
/// Close the current popup
pub unsafe extern "C" fn slint_windowrc_close_popup(handle: *const WindowRcOpaque) {
let window = &*(handle as *const WindowRc);
window.close_popup();
pub unsafe extern "C" fn slint_windowrc_close_popup(handle: *const PlatformWindowRcOpaque) {
let platform_window = &*(handle as *const PlatformWindowRc);
platform_window.window().window_handle().close_popup();
}
/// C binding to the set_rendering_notifier() API of Window
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_set_rendering_notifier(
handle: *const WindowRcOpaque,
handle: *const PlatformWindowRcOpaque,
callback: extern "C" fn(
rendering_state: RenderingState,
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 {
callback,
drop_user_data,
@ -889,7 +869,7 @@ pub mod ffi {
/// C binding to the on_close_requested() API of Window
#[no_mangle]
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,
drop_user_data: extern "C" fn(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 window = &*(handle as *const WindowRc);
window.on_close_requested(move || with_user_data.call());
let platform_window = &*(handle as *const PlatformWindowRc);
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.
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_request_redraw(handle: *const WindowRcOpaque) {
let window = &*(handle as *const WindowRc);
window.request_redraw();
pub unsafe extern "C" fn slint_windowrc_request_redraw(handle: *const PlatformWindowRcOpaque) {
let platform_window = &*(handle as *const PlatformWindowRc);
platform_window.request_redraw();
}
/// Returns the position of the window on the screen, in physical screen coordinates and including
/// a window frame (if present).
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_position(
handle: *const WindowRcOpaque,
handle: *const PlatformWindowRcOpaque,
pos: &mut euclid::default::Point2D<i32>,
) {
let window = &*(handle as *const WindowRc);
*pos = window.position().to_untyped()
let platform_window = &*(handle as *const PlatformWindowRc);
*pos = platform_window.position().to_untyped()
}
/// 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.
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_set_position(
handle: *const WindowRcOpaque,
handle: *const PlatformWindowRcOpaque,
pos: &euclid::default::Point2D<i32>,
) {
let window = &*(handle as *const WindowRc);
window.set_position(euclid::Point2D::from_untyped(*pos));
let platform_window = &*(handle as *const PlatformWindowRc);
platform_window.set_position(euclid::Point2D::from_untyped(*pos));
}
/// Returns the size of the window on the screen, in physical screen coordinates and excluding
/// a window frame (if present).
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_size(handle: *const WindowRcOpaque) -> IntSize {
let window = &*(handle as *const WindowRc);
window.inner_size.get().to_untyped()
pub unsafe extern "C" fn slint_windowrc_size(handle: *const PlatformWindowRcOpaque) -> IntSize {
let platform_window = &*(handle as *const PlatformWindowRc);
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
/// a window frame (if present).
#[no_mangle]
pub unsafe extern "C" fn slint_windowrc_set_size(
handle: *const WindowRcOpaque,
handle: *const PlatformWindowRcOpaque,
size: &IntSize,
) {
let window = &*(handle as *const WindowRc);
window.set_inner_size([size.width, size.height].into());
let platform_window = &*(handle as *const PlatformWindowRc);
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]
pub unsafe extern "C" fn slint_interpreter_component_instance_window(
inst: &ErasedComponentBox,
out: *mut *const i_slint_core::window::ffi::WindowRcOpaque,
out: *mut *const i_slint_core::window::ffi::PlatformWindowRcOpaque,
) {
assert_eq!(
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 _)
}