Add window_adapter to ComponentVTable

Make it duplicate as `maybe_window_adapter` with a boolean `do_create`
parameter.
This commit is contained in:
Tobias Hunger 2023-07-06 20:14:42 +02:00 committed by Olivier Goffart
parent de96455dda
commit a362b7a1ae
7 changed files with 148 additions and 58 deletions

View file

@ -1292,6 +1292,21 @@ fn generate_item_tree(
}),
));
target_struct.members.push((
Access::Private,
Declaration::Function(Function {
name: "window_adapter".into(),
signature:
"([[maybe_unused]] slint::private_api::ComponentRef component, [[maybe_unused]] bool do_create, [[maybe_unused]] slint::cbindgen_private::Option<slint::private_api::WindowAdapterRc>* result) -> void"
.into(),
is_static: true,
statements: Some(vec![format!(
"/* TODO: implement this! */",
)]),
..Default::default()
}),
));
target_struct.members.push((
Access::Public,
Declaration::Var(Var {
@ -1307,7 +1322,7 @@ fn generate_item_tree(
init: Some(format!(
"{{ visit_children, get_item_ref, get_subtree_range, get_subtree_component, \
get_item_tree, parent_node, embed_component, subtree_index, layout_info, \
accessible_role, accessible_string_property, \
accessible_role, accessible_string_property, window_adapter, \
slint::private_api::drop_in_place<{}>, slint::private_api::dealloc }}",
item_tree_class_name
)),

View file

@ -1256,16 +1256,16 @@ fn generate_item_tree(
(
quote!(
#[allow(unused)]
fn window_adapter(&self) -> Rc<dyn sp::WindowAdapter> {
self.root.get().unwrap().upgrade().unwrap().window_adapter()
fn window_adapter_impl(&self) -> Rc<dyn sp::WindowAdapter> {
self.root.get().unwrap().upgrade().unwrap().window_adapter_impl()
}
#[allow(unused)]
fn maybe_window_adapter(&self) -> Option<Rc<dyn sp::WindowAdapter>> {
fn maybe_window_adapter_impl(&self) -> Option<Rc<dyn sp::WindowAdapter>> {
self.root
.get()
.and_then(|root_weak| root_weak.upgrade())
.and_then(|root| root.maybe_window_adapter())
.and_then(|root| root.maybe_window_adapter_impl())
}
),
quote!(vtable::VRc<sp::ComponentVTable, Self>),
@ -1283,7 +1283,7 @@ fn generate_item_tree(
(
quote!(
#[allow(unused)]
fn window_adapter(&self) -> Rc<dyn sp::WindowAdapter> {
fn window_adapter_impl(&self) -> Rc<dyn sp::WindowAdapter> {
Rc::clone(self.window_adapter_ref().unwrap())
}
@ -1300,7 +1300,7 @@ fn generate_item_tree(
}
#[allow(unused)]
fn maybe_window_adapter(&self) -> Option<Rc<dyn sp::WindowAdapter>> {
fn maybe_window_adapter_impl(&self) -> Option<Rc<dyn sp::WindowAdapter>> {
self.window_adapter_.get().cloned()
}
),
@ -1392,7 +1392,7 @@ fn generate_item_tree(
#(_self.parent = parent.clone() as #parent_component_type;)*
let self_rc = VRc::new(_self);
let self_dyn_rc = vtable::VRc::into_dyn(self_rc.clone());
sp::register_component(&self_dyn_rc, (*#root_token).maybe_window_adapter());
sp::register_component(&self_dyn_rc, (*#root_token).maybe_window_adapter_impl());
Self::init(sp::VRc::map(self_rc.clone(), |x| x), #root_token, 0, 1);
#new_end
}
@ -1418,7 +1418,7 @@ fn generate_item_tree(
use slint::private_unstable_api::re_exports::*;
ComponentVTable_static!(static VT for self::#inner_component_id);
new_vref!(let vref : VRef<ComponentVTable> for Component = self.as_ref().get_ref());
if let Some(wa) = self.maybe_window_adapter() {
if let Some(wa) = self.maybe_window_adapter_impl() {
sp::unregister_component(self.as_ref(), vref, Self::item_array(), &wa);
}
}
@ -1493,6 +1493,18 @@ fn generate_item_tree(
) {
*result = self.accessible_string_property(index, what);
}
fn window_adapter(
self: ::core::pin::Pin<&Self>,
do_create: bool,
result: &mut Option<Rc<dyn WindowAdapter>>,
) {
if do_create {
*result = Some(self.window_adapter_impl());
} else {
*result = self.maybe_window_adapter_impl();
}
}
}
@ -1798,7 +1810,7 @@ fn follow_sub_component_path<'a>(
fn access_window_adapter_field(ctx: &EvaluationContext) -> TokenStream {
let root = &ctx.generator_state;
quote!((&#root.window_adapter()))
quote!((&#root.window_adapter_impl()))
}
/// Given a property reference to a native item (eg, the property name is empty)

View file

@ -12,9 +12,8 @@ use crate::item_tree::{
use crate::items::{AccessibleRole, ItemRc, ItemVTable};
use crate::layout::{LayoutInfo, Orientation};
use crate::slice::Slice;
use crate::window::WindowAdapter;
use crate::window::WindowAdapterRc;
use crate::SharedString;
use alloc::rc::Rc;
use vtable::*;
#[repr(C)]
@ -111,6 +110,13 @@ pub struct ComponentVTable {
result: &mut SharedString,
),
/// Returns a Window, creating a fresh one if `do_create` is true.
pub window_adapter: extern "C" fn(
core::pin::Pin<VRef<ComponentVTable>>,
do_create: bool,
result: &mut Option<WindowAdapterRc>,
),
/// in-place destructor (for VRc)
pub drop_in_place: unsafe fn(VRefMut<ComponentVTable>) -> vtable::Layout,
/// dealloc function (for VRc)
@ -133,10 +139,7 @@ pub type ComponentRc = vtable::VRc<ComponentVTable, Dyn>;
pub type ComponentWeak = vtable::VWeak<ComponentVTable, Dyn>;
/// Call init() on the ItemVTable for each item of the component.
pub fn register_component(
component_rc: &ComponentRc,
window_adapter: Option<Rc<dyn WindowAdapter>>,
) {
pub fn register_component(component_rc: &ComponentRc, window_adapter: Option<WindowAdapterRc>) {
let c = vtable::VRc::borrow_pin(component_rc);
let item_tree = c.as_ref().get_item_tree();
item_tree.iter().enumerate().for_each(|(tree_index, node)| {
@ -155,7 +158,7 @@ pub fn unregister_component<Base>(
base: core::pin::Pin<&Base>,
component: ComponentRef,
item_array: &[vtable::VOffset<Base, ItemVTable, vtable::AllowPin>],
window_adapter: &Rc<dyn WindowAdapter>,
window_adapter: &WindowAdapterRc,
) {
window_adapter.renderer().free_graphics_resources(
component,
@ -170,7 +173,7 @@ pub fn unregister_component<Base>(
pub(crate) mod ffi {
#![allow(unsafe_code)]
use crate::window::WindowAdapter;
use crate::window::WindowAdapterRc;
use super::*;
@ -180,7 +183,7 @@ pub(crate) mod ffi {
component_rc: &ComponentRc,
window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
) {
let window_adapter = (window_handle as *const Rc<dyn WindowAdapter>).as_ref().cloned();
let window_adapter = (window_handle as *const WindowAdapterRc).as_ref().cloned();
super::register_component(component_rc, window_adapter)
}
@ -191,7 +194,7 @@ pub(crate) mod ffi {
item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>,
window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
) {
let window_adapter = &*(window_handle as *const Rc<dyn WindowAdapter>);
let window_adapter = &*(window_handle as *const WindowAdapterRc);
super::unregister_component(
core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
core::pin::Pin::into_inner(component),

View file

@ -850,10 +850,13 @@ mod tests {
use crate::items::AccessibleRole;
use crate::layout::{LayoutInfo, Orientation};
use crate::slice::Slice;
use crate::window::WindowAdapter;
use crate::SharedString;
use vtable::VRc;
use alloc::rc::Rc;
struct TestComponent {
parent_component: Option<ComponentRc>,
item_tree: Vec<ItemTreeNode>,
@ -931,6 +934,14 @@ mod tests {
_: &mut SharedString,
) {
}
fn window_adapter(
self: Pin<&Self>,
_do_create: bool,
_result: &mut Option<Rc<dyn WindowAdapter>>,
) {
unimplemented!("Not needed for this test")
}
}
crate::component::ComponentVTable_static!(static TEST_COMPONENT_VT for TestComponent);

View file

@ -1097,11 +1097,11 @@ impl ComponentHandle for ComponentInstance {
}
fn show(&self) -> Result<(), PlatformError> {
self.inner.window_adapter()?.window().show()
self.inner.window_adapter_ref()?.window().show()
}
fn hide(&self) -> Result<(), PlatformError> {
self.inner.window_adapter()?.window().hide()
self.inner.window_adapter_ref()?.window().hide()
}
fn run(&self) -> Result<(), PlatformError> {
@ -1111,7 +1111,7 @@ impl ComponentHandle for ComponentInstance {
}
fn window(&self) -> &Window {
self.inner.window_adapter().unwrap().window()
self.inner.window_adapter_ref().unwrap().window()
}
fn global<'a, T: Global<'a, Self>>(&'a self) -> T

View file

@ -59,9 +59,12 @@ impl<'id> ComponentBox<'id> {
InstanceRef { instance: self.instance.as_pin_ref(), component_type: &self.component_type }
}
pub fn window_adapter(&self) -> Result<&Rc<dyn WindowAdapter>, PlatformError> {
pub fn window_adapter_ref(&self) -> Result<&Rc<dyn WindowAdapter>, PlatformError> {
let root_weak = vtable::VWeak::into_dyn(self.borrow_instance().root_weak().clone());
InstanceRef::get_or_init_window_adapter_ref(
&self.component_type,
root_weak,
true,
self.instance.as_pin_ref().get_ref(),
)
}
@ -220,6 +223,14 @@ impl Component for ErasedComponentBox {
) {
self.borrow().as_ref().accessible_string_property(index, what, result)
}
fn window_adapter(
self: Pin<&Self>,
do_create: bool,
result: &mut Option<Rc<dyn WindowAdapter>>,
) {
self.borrow().as_ref().window_adapter(do_create, result);
}
}
i_slint_core::ComponentVTable_static!(static COMPONENT_BOX_VT for ErasedComponentBox);
@ -229,6 +240,7 @@ impl<'id> Drop for ErasedComponentBox {
generativity::make_guard!(guard);
let unerase = self.unerase(guard);
let instance_ref = unerase.borrow_instance();
// Do not walk out of our component here:
if let Some(window_adapter) = instance_ref.maybe_window_adapter() {
i_slint_core::component::unregister_component(
instance_ref.instance,
@ -1130,6 +1142,7 @@ pub(crate) fn generate_component<'id>(
subtree_index,
accessible_role,
accessible_string_property,
window_adapter,
drop_in_place,
dealloc,
};
@ -1266,17 +1279,17 @@ pub fn instantiate(
instance_ref.self_weak().set(self_weak.clone()).ok();
let component_type = comp.description();
let root = root
.or_else(|| instance_ref.parent_instance().map(|parent| parent.root_weak().clone()))
.unwrap_or_else(|| self_weak.clone());
component_type.root_offset.apply(instance_ref.as_ref()).set(root).ok().unwrap();
if !component_type.original.is_global() {
let maybe_window_adapter =
if let Some(WindowOptions::UseExistingWindow(adapter)) = window_options.as_ref() {
Some(adapter.clone())
} else {
root.as_ref().and_then(|root| root.upgrade()).and_then(|root| {
generativity::make_guard!(guard);
let comp = root.unerase(guard);
let instance = comp.borrow_instance();
instance.maybe_window_adapter()
})
instance_ref.maybe_window_adapter()
};
let component_rc = vtable::VRc::into_dyn(self_rc.clone());
@ -1318,11 +1331,6 @@ pub fn instantiate(
}
}
let root = root
.or_else(|| instance_ref.parent_instance().map(|parent| parent.root_weak().clone()))
.unwrap_or_else(|| self_weak.clone());
component_type.root_offset.apply(instance_ref.as_ref()).set(root).ok().unwrap();
match &window_options {
Some(WindowOptions::UseExistingWindow(existing_adapter))
| Some(WindowOptions::EmbedIntoExistingWindow(existing_adapter)) => {
@ -1543,12 +1551,8 @@ impl ErasedComponentBox {
self.0.borrow()
}
pub fn window_adapter(&self) -> Result<&Rc<dyn WindowAdapter>, PlatformError> {
self.0.window_adapter()
}
pub fn maybe_window_adapter(&self) -> Option<Rc<dyn WindowAdapter>> {
self.0.borrow_instance().maybe_window_adapter()
pub fn window_adapter_ref(&self) -> Result<&Rc<dyn WindowAdapter>, PlatformError> {
self.0.window_adapter_ref()
}
pub fn run_setup_code(&self) {
@ -1776,6 +1780,7 @@ extern "C" fn accessible_role(component: ComponentRefPin, item_index: usize) ->
None => AccessibleRole::default(),
}
}
extern "C" fn accessible_string_property(
component: ComponentRefPin,
item_index: usize,
@ -1802,6 +1807,20 @@ extern "C" fn accessible_string_property(
}
}
extern "C" fn window_adapter(
component: ComponentRefPin,
do_create: bool,
result: &mut Option<Rc<dyn WindowAdapter>>,
) {
generativity::make_guard!(guard);
let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
if do_create {
*result = Some(instance_ref.window_adapter());
} else {
*result = instance_ref.maybe_window_adapter();
}
}
unsafe extern "C" fn drop_in_place(component: vtable::VRefMut<ComponentVTable>) -> vtable::Layout {
let instance_ptr = component.as_ptr() as *mut Instance<'static>;
let layout = (*instance_ptr).type_info().layout();
@ -1860,45 +1879,75 @@ impl<'a, 'id> InstanceRef<'a, 'id> {
}
pub fn window_adapter(&self) -> Rc<dyn WindowAdapter> {
let root_weak = vtable::VWeak::into_dyn(self.root_weak().clone());
let root = self.root_weak().upgrade().unwrap();
generativity::make_guard!(guard);
let comp = root.unerase(guard);
Self::get_or_init_window_adapter_ref(
&comp.component_type,
root_weak,
true,
comp.instance.as_pin_ref().get_ref(),
)
.unwrap()
.clone()
}
// Call this only on root components!
pub fn get_or_init_window_adapter_ref<'b, 'id2>(
component_type: &'b ComponentDescription<'id2>,
root_weak: ComponentWeak,
do_create: bool,
instance: &'b Instance<'id2>,
) -> Result<&'b Rc<dyn WindowAdapter>, PlatformError> {
// We are the actual root: Generate and store a window_adapter if necessary
component_type.window_adapter_offset.apply(instance).get_or_try_init(|| {
let extra_data = component_type.extra_data_offset.apply(instance);
let window_adapter = i_slint_backend_selector::with_platform(|_b| {
#[cfg(not(target_arch = "wasm32"))]
return _b.create_window_adapter();
#[cfg(target_arch = "wasm32")]
i_slint_backend_winit::create_gl_window_with_canvas_id(
extra_data.canvas_id.get().map_or("canvas", |s| s.as_str()),
)
})?;
let comp_rc = extra_data.self_weak.get().unwrap().upgrade().unwrap();
WindowInner::from_pub(window_adapter.window())
.set_component(&vtable::VRc::into_dyn(comp_rc));
Ok(window_adapter)
let mut parent_node = ItemWeak::default();
if let Some(rc) = vtable::VWeak::upgrade(&root_weak) {
vtable::VRc::borrow_pin(&rc).as_ref().parent_node(&mut parent_node);
}
if let Some(parent) = parent_node.upgrade() {
// We are embedded: Get window adapter from our parent
let mut result = None;
vtable::VRc::borrow_pin(parent.component())
.as_ref()
.window_adapter(do_create, &mut result);
result.ok_or(PlatformError::NoPlatform)
} else if do_create {
let window_adapter = // We are the root: Create a window adapter
i_slint_backend_selector::with_platform(|_b| {
#[cfg(not(target_arch = "wasm32"))]
return _b.create_window_adapter();
#[cfg(target_arch = "wasm32")]
i_slint_backend_winit::create_gl_window_with_canvas_id(
extra_data.canvas_id.get().map_or("canvas", |s| s.as_str()),
)
})?;
let extra_data = component_type.extra_data_offset.apply(instance);
let comp_rc = extra_data.self_weak.get().unwrap().upgrade().unwrap();
WindowInner::from_pub(window_adapter.window())
.set_component(&vtable::VRc::into_dyn(comp_rc));
Ok(window_adapter)
} else {
Err(PlatformError::NoPlatform)
}
})
}
pub fn maybe_window_adapter(&self) -> Option<Rc<dyn WindowAdapter>> {
let root_weak = vtable::VWeak::into_dyn(self.root_weak().clone());
let root = self.root_weak().upgrade()?;
generativity::make_guard!(guard);
let comp = root.unerase(guard);
let instance = comp.borrow_instance();
instance.component_type.window_adapter_offset.apply(instance.as_ref()).get().cloned()
Self::get_or_init_window_adapter_ref(
&comp.component_type,
root_weak,
false,
comp.instance.as_pin_ref().get_ref(),
)
.ok()
.cloned()
}
pub fn access_window<R>(

View file

@ -579,7 +579,7 @@ pub unsafe extern "C" fn slint_interpreter_component_instance_window(
);
core::ptr::write(
out as *mut *const Rc<dyn WindowAdapter>,
inst.window_adapter().unwrap() as *const _,
inst.window_adapter_ref().unwrap() as *const _,
)
}