Start a new sixtyfps::Window API for Rust, C++, the interpreters and JS

The generated component now provides access to a Window type
via the window() accessor function.

This is part of #333
This commit is contained in:
Simon Hausmann 2021-07-21 18:38:05 +02:00 committed by Simon Hausmann
parent 5fd63b63f1
commit 66891a299c
14 changed files with 200 additions and 50 deletions

View file

@ -13,6 +13,8 @@ This class will have the following public member functions:
and react to user input, it's still necessary to spin the event loop, by calling {cpp:func}`sixtyfps::run_event_loop()` and react to user input, it's still necessary to spin the event loop, by calling {cpp:func}`sixtyfps::run_event_loop()`
or using the convenience `fun` function in this class. or using the convenience `fun` function in this class.
* A `hide` function, which de-registers the component from the windowing system. * A `hide` function, which de-registers the component from the windowing system.
* A `window` function that provides access to the {cpp:class}`sixtyfps::Window`, allow for further customization
towards the windowing system.
* A `run` convenience function, which will show the component and starts the event loop. * A `run` convenience function, which will show the component and starts the event loop.
* for each properties: * for each properties:
* A getter `get_<property_name>` returning the property type. * A getter `get_<property_name>` returning the property type.

View file

@ -82,6 +82,7 @@ using cbindgen_private::KeyEvent;
class WindowRc class WindowRc
{ {
public: public:
explicit WindowRc(cbindgen_private::WindowRcOpaque adopted_inner) : inner(adopted_inner) { }
WindowRc() { cbindgen_private::sixtyfps_windowrc_init(&inner); } WindowRc() { cbindgen_private::sixtyfps_windowrc_init(&inner); }
~WindowRc() { cbindgen_private::sixtyfps_windowrc_drop(&inner); } ~WindowRc() { cbindgen_private::sixtyfps_windowrc_drop(&inner); }
WindowRc(const WindowRc &other) WindowRc(const WindowRc &other)
@ -89,7 +90,15 @@ public:
cbindgen_private::sixtyfps_windowrc_clone(&other.inner, &inner); cbindgen_private::sixtyfps_windowrc_clone(&other.inner, &inner);
} }
WindowRc(WindowRc &&) = delete; WindowRc(WindowRc &&) = delete;
WindowRc &operator=(const WindowRc &) = delete; WindowRc &operator=(WindowRc &&) = delete;
WindowRc &operator=(const WindowRc &other)
{
if (this != &other) {
cbindgen_private::sixtyfps_windowrc_drop(&inner);
cbindgen_private::sixtyfps_windowrc_clone(&other.inner, &inner);
}
return *this;
}
void show() const { sixtyfps_windowrc_show(&inner); } void show() const { sixtyfps_windowrc_show(&inner); }
void hide() const { sixtyfps_windowrc_hide(&inner); } void hide() const { sixtyfps_windowrc_hide(&inner); }
@ -257,6 +266,40 @@ public:
} }
}; };
/// This class represents a window towards the windowing system, that's used to render the
/// scene of a component. It provides API to control windowing system specific aspects such
/// as the position on the screen.
class Window
{
public:
/// \private
/// Internal function used by the generated code to construct a new instance of this
/// public API wrapper.
explicit Window(const private_api::WindowRc &windowrc) : inner(windowrc) { }
/// Copy-constructs a new window from \a other. Window instances are explicitly
/// shared and reference counted. Creating a copy will not create a second window
/// on the screen.
Window(const Window &other) = default;
/// Copy-constructs the window \a other to this and returns a reference to this.
/// Window instances are explicitly shared and reference counted. Creating a copy
/// will not create a second window on the screen.
Window &operator=(const Window &other) = default;
Window(Window &&other) = delete;
Window &operator=(Window &&other) = delete;
/// Destroys this window. Window instances are explicitly shared and reference counted.
/// If this window instance is the last one referencing the window towards the windowing
/// system, then it will also become hidden and destroyed.
~Window() = default;
/// Registers the window with the windowing system in order to make it visible on the screen.
void show() const { inner.show(); }
/// De-registers the window from the windowing system, therefore hiding it.
void hide() const { inner.hide(); }
private:
private_api::WindowRc inner;
};
/// A Timer that can call a callback at repeated interval /// A Timer that can call a callback at repeated interval
/// ///
/// Use the static single_shot function to make a single shot timer /// Use the static single_shot function to make a single shot timer

View file

@ -585,6 +585,15 @@ public:
{ {
cbindgen_private::sixtyfps_interpreter_component_instance_show(inner(), false); cbindgen_private::sixtyfps_interpreter_component_instance_show(inner(), false);
} }
/// Returns the Window associated with this component. The window API can be used
/// to control different aspects of the integration into the windowing system,
/// such as the position on the screen.
sixtyfps::Window window() const
{
cbindgen_private::WindowRcOpaque win;
cbindgen_private::sixtyfps_interpreter_component_instance_window(inner(), &win);
return sixtyfps::Window(sixtyfps::private_api::WindowRc(win));
}
/// This is a convenience function that first calls show(), followed by /// This is a convenience function that first calls show(), followed by
/// sixtyfps::run_event_loop() and hide(). /// sixtyfps::run_event_loop() and hide().
void run() const void run() const

View file

@ -13,7 +13,8 @@ LICENSE END */
namespace sixtyfps::testing { namespace sixtyfps::testing {
inline void init() { inline void init()
{
cbindgen_private::sixtyfps_testing_init_backend(); cbindgen_private::sixtyfps_testing_init_backend();
} }
@ -25,7 +26,7 @@ template<typename Component>
inline void send_mouse_click(const Component *component, float x, float y) inline void send_mouse_click(const Component *component, float x, float y)
{ {
auto crc = *component->self_weak.into_dyn().lock(); auto crc = *component->self_weak.into_dyn().lock();
cbindgen_private::sixtyfps_send_mouse_click(&crc, x, y, &component->window); cbindgen_private::sixtyfps_send_mouse_click(&crc, x, y, &component->window_);
} }
template<typename Component> template<typename Component>
@ -33,7 +34,7 @@ inline void send_keyboard_string_sequence(const Component *component,
const sixtyfps::SharedString &str, const sixtyfps::SharedString &str,
cbindgen_private::KeyboardModifiers modifiers = {}) cbindgen_private::KeyboardModifiers modifiers = {})
{ {
cbindgen_private::send_keyboard_string_sequence(&str, modifiers, &component->window); cbindgen_private::send_keyboard_string_sequence(&str, modifiers, &component->window_);
} }
#define assert_eq(A, B) \ #define assert_eq(A, B) \

View file

@ -41,11 +41,15 @@ class Component {
} }
show() { show() {
this.comp.show(); this.window.show();
} }
hide() { hide() {
this.comp.hide(); this.window.hide()
}
get window(): Window {
return this.comp.window();
} }
send_mouse_click(x: number, y: number) { send_mouse_click(x: number, y: number) {
@ -57,6 +61,11 @@ class Component {
} }
} }
interface Window {
show(): void;
hide(): void;
}
/** /**
* @hidden * @hidden
*/ */

View file

@ -18,6 +18,7 @@ mod persistent_context;
struct WrappedComponentType(Option<sixtyfps_interpreter::ComponentDefinition>); struct WrappedComponentType(Option<sixtyfps_interpreter::ComponentDefinition>);
struct WrappedComponentRc(Option<sixtyfps_interpreter::ComponentInstance>); struct WrappedComponentRc(Option<sixtyfps_interpreter::ComponentInstance>);
struct WrappedWindow(Option<sixtyfps_interpreter::Window>);
/// We need to do some gymnastic with closures to pass the ExecuteContext with the right lifetime /// We need to do some gymnastic with closures to pass the ExecuteContext with the right lifetime
type GlobalContextCallback<'c> = type GlobalContextCallback<'c> =
@ -344,25 +345,14 @@ declare_types! {
})?; })?;
Ok(JsUndefined::new().as_value(&mut cx)) Ok(JsUndefined::new().as_value(&mut cx))
} }
method show(mut cx) { method window(mut cx) {
let this = cx.this(); let this = cx.this();
let component = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone_strong())); let component = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone_strong()));
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?; let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
run_scoped(&mut cx,this.downcast().unwrap(), || { let window = component.window();
component.show(); let mut obj = SixtyFpsWindow::new::<_, JsValue, _>(&mut cx, std::iter::empty())?;
Ok(()) cx.borrow_mut(&mut obj, |mut obj| obj.0 = Some(window));
})?; Ok(obj.as_value(&mut cx))
Ok(JsUndefined::new().as_value(&mut cx))
}
method hide(mut cx) {
let this = cx.this();
let component = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone_strong()));
let component = component.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
run_scoped(&mut cx,this.downcast().unwrap(), || {
component.hide();
Ok(())
})?;
Ok(JsUndefined::new().as_value(&mut cx))
} }
method get_property(mut cx) { method get_property(mut cx) {
let prop_name = cx.argument::<JsString>(0)?.value(); let prop_name = cx.argument::<JsString>(0)?.value();
@ -485,6 +475,28 @@ declare_types! {
Ok(JsUndefined::new().as_value(&mut cx)) Ok(JsUndefined::new().as_value(&mut cx))
} }
} }
class SixtyFpsWindow for WrappedWindow {
init(_) {
Ok(WrappedWindow(None))
}
method show(mut cx) {
let this = cx.this();
let window = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone()));
let window = window.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
window.show();
Ok(JsUndefined::new().as_value(&mut cx))
}
method hide(mut cx) {
let this = cx.this();
let window = cx.borrow(&this, |x| x.0.as_ref().map(|c| c.clone()));
let window = window.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
window.hide();
Ok(JsUndefined::new().as_value(&mut cx))
}
}
} }
fn singleshot_timer_property(id: u32) -> String { fn singleshot_timer_property(id: u32) -> String {

View file

@ -56,6 +56,7 @@ pub mod generated_code {
use crate::re_exports; use crate::re_exports;
use crate::ComponentHandle; use crate::ComponentHandle;
use crate::Weak; use crate::Weak;
use crate::Window;
/// This an example of the API that is generated for a component in `.60` design markup. This may help you understand /// This an example of the API that is generated for a component in `.60` design markup. This may help you understand
/// what functions you can call and how you can pass data in and out. /// what functions you can call and how you can pass data in and out.
@ -146,6 +147,13 @@ pub mod generated_code {
unimplemented!(); unimplemented!();
} }
/// Returns the Window associated with this component. The window API can be used
/// to control different aspects of the integration into the windowing system,
/// such as the position on the screen.
fn window(&self) -> Window {
unimplemented!()
}
/// This is a convenience function that first calls [`Self::show`], followed by [`crate::run_event_loop()`] /// This is a convenience function that first calls [`Self::show`], followed by [`crate::run_event_loop()`]
/// and [`Self::hide`]. /// and [`Self::hide`].
fn run(&self) { fn run(&self) {

View file

@ -450,6 +450,11 @@ pub trait ComponentHandle {
/// the window from the windowing system and it will not receive any further events. /// the window from the windowing system and it will not receive any further events.
fn hide(&self); fn hide(&self);
/// Returns the Window associated with this component. The window API can be used
/// to control different aspects of the integration into the windowing system,
/// such as the position on the screen.
fn window(&self) -> Window;
/// This is a convenience function that first calls [`Self::show`], followed by [`crate::run_event_loop()`] /// This is a convenience function that first calls [`Self::show`], followed by [`crate::run_event_loop()`]
/// and [`Self::hide`]. /// and [`Self::hide`].
fn run(&self); fn run(&self);
@ -554,6 +559,8 @@ mod weak_handle {
pub use weak_handle::*; pub use weak_handle::*;
pub use sixtyfps_corelib::window::api::Window;
/// This module contains functions useful for unit tests /// This module contains functions useful for unit tests
pub mod testing { pub mod testing {
use core::cell::Cell; use core::cell::Cell;

View file

@ -90,6 +90,7 @@
"untracked", "untracked",
"vtable", "vtable",
"wasm", "wasm",
"windowrc", // used in sixtyfps_windowrc_foo FFI functions
"xtask" "xtask"
], ],
"ignorePaths": [ "ignorePaths": [

View file

@ -901,7 +901,7 @@ fn generate_component(
Access::Private, Access::Private,
Declaration::Var(Var { Declaration::Var(Var {
ty: "sixtyfps::private_api::WindowRc".into(), ty: "sixtyfps::private_api::WindowRc".into(),
name: "window".into(), name: "window_".into(),
..Var::default() ..Var::default()
}), }),
)); ));
@ -910,7 +910,7 @@ fn generate_component(
Access::Public, // FIXME: many of the different component bindings need to access this Access::Public, // FIXME: many of the different component bindings need to access this
Declaration::Var(Var { Declaration::Var(Var {
ty: "sixtyfps::private_api::WindowRc".into(), ty: "sixtyfps::private_api::WindowRc".into(),
name: "window".into(), name: "window_".into(),
..Var::default() ..Var::default()
}), }),
)); ));
@ -932,7 +932,7 @@ fn generate_component(
Declaration::Function(Function { Declaration::Function(Function {
name: "show".into(), name: "show".into(),
signature: "() const".into(), signature: "() const".into(),
statements: Some(vec!["window.show();".into()]), statements: Some(vec!["window_.show();".into()]),
..Default::default() ..Default::default()
}), }),
)); ));
@ -942,7 +942,17 @@ fn generate_component(
Declaration::Function(Function { Declaration::Function(Function {
name: "hide".into(), name: "hide".into(),
signature: "() const".into(), signature: "() const".into(),
statements: Some(vec!["window.hide();".into()]), statements: Some(vec!["window_.hide();".into()]),
..Default::default()
}),
));
component_struct.members.push((
Access::Public,
Declaration::Function(Function {
name: "window".into(),
signature: "() const -> sixtyfps::Window".into(),
statements: Some(vec!["return sixtyfps::Window(window_);".into()]),
..Default::default() ..Default::default()
}), }),
)); ));
@ -961,7 +971,7 @@ fn generate_component(
}), }),
)); ));
init.push("self->window.init_items(this, item_tree());".into()); init.push("self->window_.init_items(this, item_tree());".into());
component_struct.friends.push("sixtyfps::private_api::WindowRc".into()); component_struct.friends.push("sixtyfps::private_api::WindowRc".into());
} }
@ -976,7 +986,7 @@ fn generate_component(
]; ];
if component.parent_element.upgrade().is_none() { if component.parent_element.upgrade().is_none() {
create_code.push("self->window.set_component(**self->self_weak.lock());".into()); create_code.push("self->window_.set_component(**self->self_weak.lock());".into());
} }
create_code.extend( create_code.extend(
@ -1088,7 +1098,7 @@ fn generate_component(
is_constructor_or_destructor: true, is_constructor_or_destructor: true,
statements: Some(init), statements: Some(init),
constructor_member_initializers: if !component.is_global() && !is_root { constructor_member_initializers: if !component.is_global() && !is_root {
vec!["window(parent->window)".into()] vec!["window_(parent->window_)".into()]
} else { } else {
vec![] vec![]
}, },
@ -1117,7 +1127,7 @@ fn generate_component(
.join(","), .join(","),
); );
destructor.push("};".into()); destructor.push("};".into());
destructor.push("window.free_graphics_resources(sixtyfps::Slice<sixtyfps::private_api::ItemRef>{items, std::size(items)});".into()); destructor.push("window_.free_graphics_resources(sixtyfps::Slice<sixtyfps::private_api::ItemRef>{items, std::size(items)});".into());
} }
component_struct.members.push(( component_struct.members.push((
@ -1404,7 +1414,7 @@ fn compile_expression(
), ),
Expression::BuiltinFunctionReference(funcref, _) => match funcref { Expression::BuiltinFunctionReference(funcref, _) => match funcref {
BuiltinFunction::GetWindowScaleFactor => { BuiltinFunction::GetWindowScaleFactor => {
"self->window.scale_factor".into() "self->window_.scale_factor".into()
} }
BuiltinFunction::Debug => { BuiltinFunction::Debug => {
"[](auto... args){ (std::cout << ... << args) << std::endl; return nullptr; }" "[](auto... args){ (std::cout << ... << args) << std::endl; return nullptr; }"
@ -1423,10 +1433,10 @@ fn compile_expression(
BuiltinFunction::ACos => format!("[](float a){{ return std::acos(a) / {}; }}", std::f32::consts::PI / 180.), BuiltinFunction::ACos => format!("[](float a){{ return std::acos(a) / {}; }}", std::f32::consts::PI / 180.),
BuiltinFunction::ATan => format!("[](float a){{ return std::atan(a) / {}; }}", std::f32::consts::PI / 180.), BuiltinFunction::ATan => format!("[](float a){{ return std::atan(a) / {}; }}", std::f32::consts::PI / 180.),
BuiltinFunction::SetFocusItem => { BuiltinFunction::SetFocusItem => {
"self->window.set_focus_item".into() "self->window_.set_focus_item".into()
} }
BuiltinFunction::ShowPopupWindow => { BuiltinFunction::ShowPopupWindow => {
"self->window.show_popup".into() "self->window_.show_popup".into()
} }
/* std::from_chars is unfortunately not yet implemented in gcc /* std::from_chars is unfortunately not yet implemented in gcc
@ -1562,7 +1572,7 @@ fn compile_expression(
if let Expression::ElementReference(focus_item) = &arguments[0] { if let Expression::ElementReference(focus_item) = &arguments[0] {
let focus_item = focus_item.upgrade().unwrap(); let focus_item = focus_item.upgrade().unwrap();
let focus_item = focus_item.borrow(); let focus_item = focus_item.borrow();
format!("self->window.set_focus_item(self->self_weak.lock()->into_dyn(), {});", focus_item.item_index.get().unwrap()) format!("self->window_.set_focus_item(self->self_weak.lock()->into_dyn(), {});", focus_item.item_index.get().unwrap())
} else { } else {
panic!("internal error: argument to SetFocusItem must be an element") panic!("internal error: argument to SetFocusItem must be an element")
} }
@ -1580,7 +1590,7 @@ fn compile_expression(
let popup = popup_list.iter().find(|p| Rc::ptr_eq(&p.component, &pop_comp)).unwrap(); let popup = popup_list.iter().find(|p| Rc::ptr_eq(&p.component, &pop_comp)).unwrap();
let x = access_named_reference(&popup.x, component, "self"); let x = access_named_reference(&popup.x, component, "self");
let y = access_named_reference(&popup.y, component, "self"); let y = access_named_reference(&popup.y, component, "self");
format!("self->window.show_popup<{}>(self, {{ {}.get(), {}.get() }} );", popup_window_id, x, y) format!("self->window_.show_popup<{}>(self, {{ {}.get(), {}.get() }} );", popup_window_id, x, y)
} else { } else {
panic!("internal error: argument to SetFocusItem must be an element") panic!("internal error: argument to SetFocusItem must be an element")
} }
@ -1593,7 +1603,7 @@ fn compile_expression(
let item = item.upgrade().unwrap(); let item = item.upgrade().unwrap();
let item = item.borrow(); let item = item.borrow();
let native_item = item.base_type.as_native(); let native_item = item.base_type.as_native();
format!("{vt}->layouting_info({{{vt}, const_cast<sixtyfps::cbindgen_private::{ty}*>(&self->{id})}}, {o}, &window)", format!("{vt}->layouting_info({{{vt}, const_cast<sixtyfps::cbindgen_private::{ty}*>(&self->{id})}}, {o}, &window_)",
vt = native_item.cpp_vtable_getter, vt = native_item.cpp_vtable_getter,
ty = native_item.class_name, ty = native_item.class_name,
id = item.id, id = item.id,
@ -2038,7 +2048,7 @@ fn get_layout_info(
format!("{}.get()", access_named_reference(layout_info_prop, component, "self")) format!("{}.get()", access_named_reference(layout_info_prop, component, "self"))
} else { } else {
format!( format!(
"{vt}->layouting_info({{{vt}, const_cast<sixtyfps::cbindgen_private::{ty}*>(&self->{id})}}, {o}, &self->window)", "{vt}->layouting_info({{{vt}, const_cast<sixtyfps::cbindgen_private::{ty}*>(&self->{id})}}, {o}, &self->window_)",
vt = elem.borrow().base_type.as_native().cpp_vtable_getter, vt = elem.borrow().base_type.as_native().cpp_vtable_getter,
ty = elem.borrow().base_type.as_native().class_name, ty = elem.borrow().base_type.as_native().class_name,
id = elem.borrow().id, id = elem.borrow().id,

View file

@ -849,11 +849,15 @@ fn generate_component(
} }
fn show(&self) { fn show(&self) {
vtable::VRc::as_pin_ref(&self.0).window.window_handle().show(); self.window().show();
} }
fn hide(&self) { fn hide(&self) {
vtable::VRc::as_pin_ref(&self.0).window.window_handle().hide(); self.window().hide()
}
fn window(&self) -> sixtyfps::Window {
vtable::VRc::as_pin_ref(&self.0).window.clone().into()
} }
} }
)) ))

View file

@ -339,6 +339,44 @@ impl WindowHandleAccess for WindowRc {
} }
} }
/// Internal module to define the public Window API, for re-export in the regular Rust crate
/// and the interpreter crate.
pub mod api {
/// This type represents a window towards the windowing system, that's used to render the
/// scene of a component. It provides API to control windowing system specific aspects such
/// as the position on the screen.
#[derive(Clone)]
pub struct Window(super::WindowRc);
#[doc(hidden)]
impl From<super::WindowRc> for Window {
fn from(window: super::WindowRc) -> Self {
Self(window)
}
}
impl Window {
/// Registers the window with the windowing system in order to make it visible on the screen.
pub fn show(&self) {
use super::WindowHandleAccess;
self.0.window_handle().show();
}
/// De-registers the window from the windowing system, therefore hiding it.
pub fn hide(&self) {
use super::WindowHandleAccess;
self.0.window_handle().hide();
}
}
#[doc(hidden)]
impl super::WindowHandleAccess for Window {
fn window_handle(&self) -> &std::rc::Rc<super::Window> {
self.0.window_handle()
}
}
}
/// This module contains the functions needed to interface with the event loop and window traits /// This module contains the functions needed to interface with the event loop and window traits
/// from outside the Rust language. /// from outside the Rust language.
#[cfg(feature = "ffi")] #[cfg(feature = "ffi")]

View file

@ -11,6 +11,7 @@ LICENSE END */
use core::convert::TryInto; use core::convert::TryInto;
use sixtyfps_compilerlib::langtype::Type as LangType; use sixtyfps_compilerlib::langtype::Type as LangType;
use sixtyfps_corelib::graphics::Image; use sixtyfps_corelib::graphics::Image;
use sixtyfps_corelib::window::WindowHandleAccess;
use sixtyfps_corelib::{Brush, PathData, SharedString, SharedVector}; use sixtyfps_corelib::{Brush, PathData, SharedString, SharedVector};
use std::collections::HashMap; use std::collections::HashMap;
use std::iter::FromIterator; use std::iter::FromIterator;
@ -20,6 +21,8 @@ use std::rc::Rc;
#[doc(inline)] #[doc(inline)]
pub use sixtyfps_compilerlib::diagnostics::{Diagnostic, DiagnosticLevel}; pub use sixtyfps_compilerlib::diagnostics::{Diagnostic, DiagnosticLevel};
pub use sixtyfps_corelib::window::api::Window;
/// This enum represents the different public variants of the [`Value`] enum, without /// This enum represents the different public variants of the [`Value`] enum, without
/// the contained values. /// the contained values.
// NOTE: The docs for ValueType are duplicated in sixtyfps_interpreter.h, for extraction by // NOTE: The docs for ValueType are duplicated in sixtyfps_interpreter.h, for extraction by
@ -578,13 +581,14 @@ impl ComponentDefinition {
/// Instantiate the component using an existing window. /// Instantiate the component using an existing window.
/// This method is internal because the Window is not a public type /// This method is internal because the Window is not a public type
#[doc(hidden)] #[doc(hidden)]
pub fn create_with_existing_window( pub fn create_with_existing_window(&self, window: Window) -> ComponentInstance {
&self,
window: Rc<sixtyfps_corelib::window::Window>,
) -> ComponentInstance {
generativity::make_guard!(guard); generativity::make_guard!(guard);
ComponentInstance { ComponentInstance {
inner: self.inner.unerase(guard).clone().create_with_existing_window(window), inner: self
.inner
.unerase(guard)
.clone()
.create_with_existing_window(window.window_handle().clone()),
} }
} }
@ -781,6 +785,7 @@ impl ComponentInstance {
let comp = self.inner.unerase(guard); let comp = self.inner.unerase(guard);
comp.window().hide(); comp.window().hide();
} }
/// This is a convenience function that first calls [`Self::show`], followed by [`crate::run_event_loop()`] /// This is a convenience function that first calls [`Self::show`], followed by [`crate::run_event_loop()`]
/// and [`Self::hide`]. /// and [`Self::hide`].
pub fn run(&self) { pub fn run(&self) {
@ -807,13 +812,14 @@ impl ComponentInstance {
WeakComponentInstance { inner: vtable::VRc::downgrade(&self.inner) } WeakComponentInstance { inner: vtable::VRc::downgrade(&self.inner) }
} }
/// Return the window. /// Returns the Window associated with this component. The window API can be used
/// This method is internal because the Window is not a public type /// to control different aspects of the integration into the windowing system,
#[doc(hidden)] /// such as the position on the screen.
pub fn window(&self) -> Rc<sixtyfps_corelib::window::Window> { pub fn window(&self) -> Window {
generativity::make_guard!(guard); generativity::make_guard!(guard);
let comp = self.inner.unerase(guard); let comp = self.inner.unerase(guard);
comp.window() let window_rc: sixtyfps_corelib::window::WindowRc = comp.window().into();
window_rc.into()
} }
} }

View file

@ -53,7 +53,7 @@ assert(instance.get_test_zero());
assert(instance.get_test()); assert(instance.get_test());
ratio = 2.; ratio = 2.;
instance.window.set_scale_factor(ratio); instance.window_.set_scale_factor(ratio);
assert_eq(instance.get_l1(), 12.); assert_eq(instance.get_l1(), 12.);
assert_eq(instance.get_l2(), 12. * ratio); assert_eq(instance.get_l2(), 12. * ratio);
assert_eq(instance.get_l3(), 100. + 12. * ratio); assert_eq(instance.get_l3(), 100. + 12. * ratio);