diff --git a/api/sixtyfps-cpp/include/sixtyfps.h b/api/sixtyfps-cpp/include/sixtyfps.h index ef8b199a5..76aeca3b8 100644 --- a/api/sixtyfps-cpp/include/sixtyfps.h +++ b/api/sixtyfps-cpp/include/sixtyfps.h @@ -62,6 +62,7 @@ using ComponentRef = vtable::VRef; using ItemRef = vtable::VRef; using ItemVisitorRefMut = vtable::VRefMut; } +using cbindgen_private::ComponentRc; using cbindgen_private::EasingCurve; using cbindgen_private::PropertyAnimation; using cbindgen_private::Slice; @@ -174,7 +175,7 @@ using cbindgen_private::MouseEvent; using cbindgen_private::sixtyfps_visit_item_tree; namespace private_api { template -inline InputEventResult process_input_event(ComponentRef component, int64_t &mouse_grabber, +inline InputEventResult process_input_event(const ComponentRc &component_rc, int64_t &mouse_grabber, MouseEvent mouse_event, Slice tree, GetDynamic get_dynamic, const ComponentWindow *window, const ComponentRef *app_component) @@ -182,7 +183,8 @@ inline InputEventResult process_input_event(ComponentRef component, int64_t &mou if (mouse_grabber != -1) { auto item_index = mouse_grabber & 0xffffffff; auto rep_index = mouse_grabber >> 32; - auto offset = cbindgen_private::sixtyfps_item_offset(component, tree, item_index); + auto offset = + cbindgen_private::sixtyfps_item_offset(component_rc.borrow(), tree, item_index); mouse_event.pos = { mouse_event.pos.x - offset.x, mouse_event.pos.y - offset.y }; const auto &item_node = tree.ptr[item_index]; InputEventResult result = InputEventResult::EventIgnored; @@ -191,7 +193,7 @@ inline InputEventResult process_input_event(ComponentRef component, int64_t &mou result = item_node.item.item.vtable->input_event( { item_node.item.item.vtable, - reinterpret_cast(component.instance) + reinterpret_cast(component_rc.borrow().instance) + item_node.item.item.offset, }, mouse_event, window, *app_component); @@ -207,7 +209,7 @@ inline InputEventResult process_input_event(ComponentRef component, int64_t &mou return result; } else { return cbindgen_private::sixtyfps_process_ungrabbed_mouse_event( - component, mouse_event, window, *app_component, &mouse_grabber); + &component_rc, mouse_event, window, *app_component, &mouse_grabber); } } template @@ -238,14 +240,14 @@ inline KeyEventResult process_key_event(ComponentRef component, int64_t focus_it } template -inline FocusEventResult process_focus_event(ComponentRef component, int64_t &focus_item, +inline FocusEventResult process_focus_event(const ComponentRc &component_rc, int64_t &focus_item, const FocusEvent *event, Slice tree, GetDynamic get_dynamic, const ComponentWindow *window) { switch (event->tag) { case FocusEvent::Tag::FocusIn: - return cbindgen_private::sixtyfps_locate_and_activate_focus_item(component, event, window, - &focus_item); + return cbindgen_private::sixtyfps_locate_and_activate_focus_item(&component_rc, event, + window, &focus_item); case FocusEvent::Tag::FocusOut: [[fallthrough]]; case FocusEvent::Tag::WindowReceivedFocus: @@ -260,7 +262,7 @@ inline FocusEventResult process_focus_event(ComponentRef component, int64_t &foc item_node.item.item.vtable->focus_event( { item_node.item.item.vtable, - reinterpret_cast(component.instance) + reinterpret_cast(component_rc.borrow().instance) + item_node.item.item.offset, }, event, window); diff --git a/api/sixtyfps-cpp/include/vtable.h b/api/sixtyfps-cpp/include/vtable.h index 9d520ad4c..17f64c072 100644 --- a/api/sixtyfps-cpp/include/vtable.h +++ b/api/sixtyfps-cpp/include/vtable.h @@ -74,6 +74,8 @@ private: X data; Layout layout; }; + + void *data_ptr() { return reinterpret_cast(this) + data_offset; } }; struct Dyn {}; @@ -120,6 +122,8 @@ public: } VRc into_dyn() const { return *reinterpret_cast *>(this); } + + VRef borrow() const { return { inner->vtable, inner->data_ptr() }; } }; template diff --git a/sixtyfps_compiler/generator/cpp.rs b/sixtyfps_compiler/generator/cpp.rs index 4c20f56be..d1576bda7 100644 --- a/sixtyfps_compiler/generator/cpp.rs +++ b/sixtyfps_compiler/generator/cpp.rs @@ -1020,7 +1020,8 @@ fn generate_component( format!(" [[maybe_unused]] auto self = reinterpret_cast(base);", component_id), format!(" switch(dyn_index) {{ {} }};", children_visitor_cases.join("")), " std::abort();\n};".to_owned(), - "return sixtyfps::sixtyfps_visit_item_tree(component, item_tree() , index, order, visitor, dyn_visit);".to_owned(), + format!("auto self_rc = reinterpret_cast(component.instance)->self_weak.lock()->into_dyn();", component_id), + "return sixtyfps::sixtyfps_visit_item_tree(&self_rc, item_tree() , index, order, visitor, dyn_visit);".to_owned(), ]), ..Default::default() }), @@ -1072,8 +1073,9 @@ fn generate_component( .into(), is_static: true, statements: Some(vec![ - format!(" auto self = reinterpret_cast<{}*>(component.instance);", component_id), - "return sixtyfps::private_api::process_input_event(component, self->mouse_grabber, mouse_event, item_tree(), [self](int dyn_index, [[maybe_unused]] int rep_index) {".into(), + format!("auto self = reinterpret_cast<{}*>(component.instance);", component_id), + "auto self_rc = self->self_weak.lock()->into_dyn();".into(), + "return sixtyfps::private_api::process_input_event(self_rc, self->mouse_grabber, mouse_event, item_tree(), [self](int dyn_index, [[maybe_unused]] int rep_index) {".into(), " (void)self;".into(), format!(" switch(dyn_index) {{ {} }};", repeated_input_branch.join("")), " return sixtyfps::private_api::ComponentRef{nullptr, nullptr};\n}, window, app_component);".into(), @@ -1118,8 +1120,9 @@ fn generate_component( .into(), is_static: true, statements: Some(vec![ - format!(" auto self = reinterpret_cast<{}*>(component.instance);", component_id), - "return sixtyfps::private_api::process_focus_event(component, self->focus_item, focus_event, item_tree(), [self](int dyn_index, [[maybe_unused]] int rep_index) {".into(), + format!("auto self = reinterpret_cast<{}*>(component.instance);", component_id), + "auto self_rc = self->self_weak.lock()->into_dyn();".into(), + "return sixtyfps::private_api::process_focus_event(self_rc, self->focus_item, focus_event, item_tree(), [self](int dyn_index, [[maybe_unused]] int rep_index) {".into(), " (void)self;".into(), format!(" switch(dyn_index) {{ {} }};", repeated_input_branch.join("")), " return sixtyfps::private_api::ComponentRef{nullptr, nullptr};\n}, window);".into(), diff --git a/sixtyfps_compiler/generator/rust.rs b/sixtyfps_compiler/generator/rust.rs index 33c5cdfd3..0236dc564 100644 --- a/sixtyfps_compiler/generator/rust.rs +++ b/sixtyfps_compiler/generator/rust.rs @@ -651,7 +651,7 @@ fn generate_component( -> sixtyfps::re_exports::VisitChildrenResult { use sixtyfps::re_exports::*; - return sixtyfps::re_exports::visit_item_tree(self, VRef::new_pin(self), Self::item_tree(), index, order, visitor, visit_dynamic); + return sixtyfps::re_exports::visit_item_tree(self, &VRc::into_dyn(self.as_ref().self_weak.get().unwrap().upgrade().unwrap()), Self::item_tree(), index, order, visitor, visit_dynamic); #[allow(unused)] fn visit_dynamic(self_pinned: ::core::pin::Pin<&#component_id>, order: sixtyfps::re_exports::TraversalOrder, visitor: ItemVisitorRefMut, dyn_index: usize) -> VisitChildrenResult { let _self = self_pinned; @@ -688,7 +688,7 @@ fn generate_component( _ => (res, VisitChildrenResult::CONTINUE), } } else { - process_ungrabbed_mouse_event(VRef::new_pin(self), mouse_event, window, app_component.clone()) + process_ungrabbed_mouse_event(&VRc::into_dyn(self.as_ref().self_weak.get().unwrap().upgrade().unwrap()), mouse_event, window, app_component.clone()) }; self.mouse_grabber.set(new_grab); status @@ -722,7 +722,7 @@ fn generate_component( #[allow(unused)] match event { FocusEvent::FocusIn(_) => { - let (event_result, visit_result) = locate_and_activate_focus_item(VRef::new_pin(self), event, window); + let (event_result, visit_result) = locate_and_activate_focus_item(&VRc::into_dyn(self.as_ref().self_weak.get().unwrap().upgrade().unwrap()), event, window); if event_result == FocusEventResult::FocusItemFound { self.focus_item.set(visit_result) } diff --git a/sixtyfps_runtime/corelib/graphics.rs b/sixtyfps_runtime/corelib/graphics.rs index 3ccfca747..61eb150a8 100644 --- a/sixtyfps_runtime/corelib/graphics.rs +++ b/sixtyfps_runtime/corelib/graphics.rs @@ -609,8 +609,8 @@ impl crate::eventloop::GenericWindow for GraphicsWindo } fn draw(self: Rc) { - let component = self.component.borrow().upgrade().unwrap(); - let component = ComponentRc::borrow_pin(&component); + let component_rc = self.component.borrow().upgrade().unwrap(); + let component = ComponentRc::borrow_pin(&component_rc); { if self.layout_listener.as_ref().is_dirty() { @@ -629,7 +629,7 @@ impl crate::eventloop::GenericWindow for GraphicsWindo // Generate cached rendering data once crate::item_tree::visit_items( - component, + &component_rc, crate::item_tree::TraversalOrder::BackToFront, |_, item, _| { crate::item_rendering::update_item_rendering_data( @@ -656,7 +656,7 @@ impl crate::eventloop::GenericWindow for GraphicsWindo &ARGBColor { red: 255 as u8, green: 255, blue: 255, alpha: 255 }.into(), ); crate::item_rendering::render_component_items( - component, + &component_rc, &mut frame, &window.rendering_cache, &self, diff --git a/sixtyfps_runtime/corelib/input.rs b/sixtyfps_runtime/corelib/input.rs index f8f9eb712..941b5abba 100644 --- a/sixtyfps_runtime/corelib/input.rs +++ b/sixtyfps_runtime/corelib/input.rs @@ -11,7 +11,7 @@ LICENSE END */ */ #![warn(missing_docs)] -use crate::component::ComponentRefPin; +use crate::component::{ComponentRc, ComponentRefPin}; use crate::graphics::Point; use crate::item_tree::{ItemVisitorResult, VisitChildrenResult}; use euclid::default::Vector2D; @@ -480,7 +480,7 @@ pub enum FocusEventResult { /// the focus_event (assuming it is of type FocusIn). Once located, the focus in /// even will also be dispatched to the item itself. pub fn locate_and_activate_focus_item( - component: ComponentRefPin, + component: &ComponentRc, focus_event: &FocusEvent, window: &crate::eventloop::ComponentWindow, ) -> (FocusEventResult, VisitChildrenResult) { @@ -522,7 +522,7 @@ pub fn locate_and_activate_focus_item( /// * `component`: The component to deliver the event to. /// * `event`: The mouse event to deliver. pub fn process_ungrabbed_mouse_event( - component: ComponentRefPin, + component: &ComponentRc, event: MouseEvent, window: &crate::eventloop::ComponentWindow, app_component: ComponentRefPin, @@ -596,7 +596,7 @@ pub(crate) mod ffi { #[no_mangle] pub extern "C" fn sixtyfps_process_ungrabbed_mouse_event( - component: core::pin::Pin, + component: &ComponentRc, event: MouseEvent, window: &crate::eventloop::ComponentWindow, app_component: core::pin::Pin, @@ -620,7 +620,7 @@ pub(crate) mod ffi { #[no_mangle] pub extern "C" fn sixtyfps_locate_and_activate_focus_item( - component: core::pin::Pin, + component: &ComponentRc, event: &FocusEvent, window: &crate::eventloop::ComponentWindow, new_focus_item: &mut crate::item_tree::VisitChildrenResult, diff --git a/sixtyfps_runtime/corelib/item_rendering.rs b/sixtyfps_runtime/corelib/item_rendering.rs index 04aefbb56..2585834a0 100644 --- a/sixtyfps_runtime/corelib/item_rendering.rs +++ b/sixtyfps_runtime/corelib/item_rendering.rs @@ -14,8 +14,10 @@ use super::graphics::{ Frame, GraphicsBackend, GraphicsWindow, RenderingCache, RenderingPrimitivesBuilder, }; use super::items::ItemRef; +use crate::component::ComponentRc; +use crate::eventloop::ComponentWindow; use crate::item_tree::ItemVisitorResult; -use crate::{eventloop::ComponentWindow, slice::Slice}; +use crate::slice::Slice; use cgmath::{Matrix4, SquareMatrix, Vector3}; use std::cell::{Cell, RefCell}; @@ -80,7 +82,7 @@ pub(crate) fn update_item_rendering_data( } pub(crate) fn render_component_items( - component: crate::component::ComponentRefPin, + component: &ComponentRc, frame: &mut Backend::Frame, rendering_cache: &RefCell>, window: &std::rc::Rc>, diff --git a/sixtyfps_runtime/corelib/item_tree.rs b/sixtyfps_runtime/corelib/item_tree.rs index 4bd094993..dd04582ea 100644 --- a/sixtyfps_runtime/corelib/item_tree.rs +++ b/sixtyfps_runtime/corelib/item_tree.rs @@ -7,7 +7,7 @@ This file is also available under commercial licensing terms. Please contact info@sixtyfps.io for more information. LICENSE END */ -use crate::component::{ComponentRefPin, ComponentVTable}; +use crate::component::{ComponentRc, ComponentVTable}; use crate::graphics::Point; use crate::items::{ItemRef, ItemVTable}; use core::pin::Pin; @@ -106,7 +106,7 @@ pub struct ItemVisitorVTable { /// and `item` is a reference to the item itself visit_item: fn( VRefMut, - component: Pin>, + component: &VRc, index: isize, item: Pin>, ) -> VisitChildrenResult, @@ -117,12 +117,10 @@ pub struct ItemVisitorVTable { /// Type alias to `vtable::VRefMut` pub type ItemVisitorRefMut<'a> = vtable::VRefMut<'a, ItemVisitorVTable>; -impl) -> VisitChildrenResult> - ItemVisitor for T -{ +impl) -> VisitChildrenResult> ItemVisitor for T { fn visit_item( &mut self, - component: crate::component::ComponentRefPin, + component: &ComponentRc, index: isize, item: Pin, ) -> VisitChildrenResult { @@ -140,9 +138,9 @@ pub enum ItemVisitorResult { /// /// Returns the index of the item that cancelled, or -1 if nobody cancelled pub fn visit_items( - component: ComponentRefPin, + component: &ComponentRc, order: TraversalOrder, - mut visitor: impl FnMut(ComponentRefPin, Pin, &State) -> ItemVisitorResult, + mut visitor: impl FnMut(&ComponentRc, Pin, &State) -> ItemVisitorResult, state: State, ) -> VisitChildrenResult { visit_internal( @@ -161,33 +159,33 @@ pub fn visit_items( /// /// Returns the index of the item that cancelled, or -1 if nobody cancelled pub fn visit_items_with_post_visit( - component: ComponentRefPin, + component: &ComponentRc, order: TraversalOrder, mut visitor: impl FnMut( - ComponentRefPin, + &ComponentRc, Pin, &State, ) -> (ItemVisitorResult, PostVisitState), - mut post_visitor: impl FnMut(ComponentRefPin, Pin, PostVisitState), + mut post_visitor: impl FnMut(&ComponentRc, Pin, PostVisitState), state: State, ) -> VisitChildrenResult { visit_internal(component, order, &mut visitor, &mut post_visitor, -1, &state) } fn visit_internal( - component: ComponentRefPin, + component: &ComponentRc, order: TraversalOrder, visitor: &mut impl FnMut( - ComponentRefPin, + &ComponentRc, Pin, &State, ) -> (ItemVisitorResult, PostVisitState), - post_visitor: &mut impl FnMut(ComponentRefPin, Pin, PostVisitState), + post_visitor: &mut impl FnMut(&ComponentRc, Pin, PostVisitState), index: isize, state: &State, ) -> VisitChildrenResult { let mut actual_visitor = - |component: ComponentRefPin, index: isize, item: Pin| -> VisitChildrenResult { + |component: &ComponentRc, index: isize, item: Pin| -> VisitChildrenResult { match visitor(component, item, state) { (ItemVisitorResult::Continue(state), post_visit_state) => { let result = @@ -199,7 +197,7 @@ fn visit_internal( } }; vtable::new_vref!(let mut actual_visitor : VRefMut for ItemVisitor = &mut actual_visitor); - component.as_ref().visit_children_item(index, order, actual_visitor) + VRc::borrow_pin(component).as_ref().visit_children_item(index, order, actual_visitor) } /// Visit the children within an array of ItemTreeNode @@ -212,7 +210,7 @@ fn visit_internal( /// Possibly we should generate code that directly call the visitor instead pub fn visit_item_tree( base: Pin<&Base>, - component: ComponentRefPin, + component: &ComponentRc, item_tree: &[ItemTreeNode], index: isize, order: TraversalOrder, @@ -307,7 +305,7 @@ pub(crate) mod ffi { /// Safety: Assume a correct implementation of the item_tree array #[no_mangle] pub unsafe extern "C" fn sixtyfps_visit_item_tree( - component: Pin>, + component: &ComponentRc, item_tree: Slice>, index: isize, order: TraversalOrder, @@ -320,7 +318,7 @@ pub(crate) mod ffi { ) -> VisitChildrenResult, ) -> VisitChildrenResult { crate::item_tree::visit_item_tree( - Pin::new_unchecked(&*(component.as_ptr() as *const u8)), + Pin::new_unchecked(&*(&**component as *const Dyn as *const u8)), component, item_tree.as_slice(), index, diff --git a/sixtyfps_runtime/interpreter/dynamic_component.rs b/sixtyfps_runtime/interpreter/dynamic_component.rs index 0c6f89eaf..02b96acb5 100644 --- a/sixtyfps_runtime/interpreter/dynamic_component.rs +++ b/sixtyfps_runtime/interpreter/dynamic_component.rs @@ -336,9 +336,10 @@ extern "C" fn visit_children_item( ) -> VisitChildrenResult { generativity::make_guard!(guard); let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) }; + let comp_rc = instance_ref.self_weak().get().unwrap().upgrade().unwrap(); sixtyfps_corelib::item_tree::visit_item_tree( instance_ref.instance, - component, + &vtable::VRc::into_dyn(comp_rc), instance_ref.component_type.item_tree.as_slice().into(), index, order, @@ -1014,6 +1015,7 @@ pub fn instantiate<'id>( ); } } + comp_rc } @@ -1459,8 +1461,12 @@ extern "C" fn input_event( _ => (res, VisitChildrenResult::CONTINUE), } } else { + generativity::make_guard!(guard); + let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) }; + let comp_rc = instance_ref.self_weak().get().unwrap().upgrade().unwrap(); + sixtyfps_corelib::input::process_ungrabbed_mouse_event( - component, + &vtable::VRc::into_dyn(comp_rc), mouse_event, window, app_component.clone(), @@ -1508,8 +1514,16 @@ extern "C" fn focus_event( match event { FocusEvent::FocusIn(_) => { + generativity::make_guard!(guard); + let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) }; + let comp_rc = instance_ref.self_weak().get().unwrap().upgrade().unwrap(); + let (event_result, visit_result) = - sixtyfps_corelib::input::locate_and_activate_focus_item(component, event, window); + sixtyfps_corelib::input::locate_and_activate_focus_item( + &vtable::VRc::into_dyn(comp_rc), + event, + window, + ); if event_result == FocusEventResult::FocusItemFound { extra_data.focus_item.set(visit_result) }