diff --git a/api/cpp/include/slint.h b/api/cpp/include/slint.h index 2477663d38..84e1acff39 100644 --- a/api/cpp/include/slint.h +++ b/api/cpp/include/slint.h @@ -3,11 +3,6 @@ #pragma once -#if defined(__GNUC__) || defined(__clang__) -// In C++17, it is conditionally supported, but still valid for all compiler we care -# pragma GCC diagnostic ignored "-Winvalid-offsetof" -#endif - #include "slint_internal.h" #include "slint_platform_internal.h" #include "slint_qt_internal.h" @@ -44,23 +39,16 @@ inline cbindgen_private::Rect convert_anonymous_rect(std::tuple(ptr), layout.size, - static_cast(layout.align)); -#elif !defined(__APPLE__) || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 - ::operator delete(reinterpret_cast(ptr), static_cast(layout.align)); -#else - ::operator delete(reinterpret_cast(ptr)); -#endif + vtable::dealloc(vtable, ptr, layout); } template inline vtable::Layout drop_in_place(ItemTreeRef item_tree) { - reinterpret_cast(item_tree.instance)->~T(); - return vtable::Layout { sizeof(T), alignof(T) }; + return vtable::drop_in_place(item_tree); } #if !defined(DOXYGEN) @@ -184,6 +172,19 @@ item_layout_info(VT *itemvtable, ItemType *item_ptr, cbindgen_private::Orientati namespace private_api { +template +union MaybeUninitialized { + T value; + ~MaybeUninitialized() { } + MaybeUninitialized() { } + T take() + { + T result = std::move(value); + value.~T(); + return result; + } +}; + inline void setup_popup_menu_from_menu_item_tree( const ItemTreeRc &menu_item_tree, Property>> &entries, @@ -193,26 +194,23 @@ inline void setup_popup_menu_from_menu_item_tree( { using cbindgen_private::MenuEntry; using cbindgen_private::MenuVTable; - auto shared = std::make_shared>(nullptr, nullptr); - cbindgen_private::slint_menus_create_wrapper(&menu_item_tree, &*shared); + MaybeUninitialized> maybe; + cbindgen_private::slint_menus_create_wrapper(&menu_item_tree, &maybe.value); + auto shared = maybe.take(); entries.set_binding([shared] { - vtable::VRefMut ref { shared->vtable, shared->instance }; SharedVector entries_sv; - shared->vtable->sub_menu(ref, nullptr, &entries_sv); + shared.vtable()->sub_menu(shared.borrow(), nullptr, &entries_sv); std::vector entries_vec(entries_sv.begin(), entries_sv.end()); return std::make_shared>(std::move(entries_vec)); }); sub_menu.set_handler([shared](const auto &entry) { - vtable::VRefMut ref { shared->vtable, shared->instance }; SharedVector entries_sv; - shared->vtable->sub_menu(ref, &entry, &entries_sv); + shared.vtable()->sub_menu(shared.borrow(), &entry, &entries_sv); std::vector entries_vec(entries_sv.begin(), entries_sv.end()); return std::make_shared>(std::move(entries_vec)); }); - activated.set_handler([shared](const auto &entry) { - vtable::VRefMut ref { shared->vtable, shared->instance }; - shared->vtable->activate(ref, &entry); - }); + activated.set_handler( + [shared](const auto &entry) { shared.vtable()->activate(shared.borrow(), &entry); }); } inline SharedString translate(const SharedString &original, const SharedString &context, diff --git a/api/cpp/include/slint_window.h b/api/cpp/include/slint_window.h index 5ab15f8133..68e568bc9c 100644 --- a/api/cpp/include/slint_window.h +++ b/api/cpp/include/slint_window.h @@ -17,6 +17,39 @@ namespace private_api { using ItemTreeRc = vtable::VRc; using slint::LogicalPosition; +template +struct MenuWrapper +{ + Component component; + SubMenu submenu; + Activated activated; + static cbindgen_private::MenuVTable static_vtable; +}; + +template +inline cbindgen_private::MenuVTable MenuWrapper::static_vtable { + .sub_menu = + [](auto data, const cbindgen_private::MenuEntry *entry, + slint::SharedVector *result) { + auto wrapper = reinterpret_cast(data.instance); + auto model = wrapper->submenu(wrapper->component, entry); + result->clear(); + if (model) { + auto count = model->row_count(); + for (size_t i = 0; i < count; ++i) { + result->push_back(*model->row_data(i)); + } + } + }, + .activate = + [](auto data, const cbindgen_private::MenuEntry *entry) { + auto wrapper = reinterpret_cast(data.instance); + wrapper->activated(wrapper->component, *entry); + }, + .drop_in_place = vtable::drop_in_place, + .dealloc = vtable::dealloc, +}; + class WindowAdapterRc { public: @@ -62,35 +95,10 @@ public: if (!supports_native_menu_bar()) { return; } - struct MenuWrapper - { - Component component; - SubMenu submenu; - Activated activated; - }; - static cbindgen_private::MenuVTable menu_vtable = { - .drop = [](auto data) { delete reinterpret_cast(data.instance); }, - .sub_menu = - [](auto data, const cbindgen_private::MenuEntry *entry, - slint::SharedVector *result) { - auto wrapper = reinterpret_cast(data.instance); - auto model = wrapper->submenu(wrapper->component, entry); - result->clear(); - if (model) { - auto count = model->row_count(); - for (size_t i = 0; i < count; ++i) { - result->push_back(*model->row_data(i)); - } - } - }, - .activate = - [](auto data, const cbindgen_private::MenuEntry *entry) { - auto wrapper = reinterpret_cast(data.instance); - wrapper->activated(wrapper->component, *entry); - }, - }; - auto instance = new MenuWrapper { component, std::move(submenu), std::move(activated) }; - cbindgen_private::slint_windowrc_setup_native_menu_bar(&inner, &menu_vtable, instance); + using Wrapper = MenuWrapper; + auto instance = vtable::VRc::make( + Wrapper { component, std::move(submenu), std::move(activated) }); + cbindgen_private::slint_windowrc_setup_native_menu_bar(&inner, &instance.into_dyn()); } bool text_input_focused() const { return slint_windowrc_get_text_input_focused(&inner); } diff --git a/api/cpp/include/vtable.h b/api/cpp/include/vtable.h index 9204e6cb8f..a7a9bd3648 100644 --- a/api/cpp/include/vtable.h +++ b/api/cpp/include/vtable.h @@ -13,6 +13,11 @@ # include #endif +#if defined(__GNUC__) || defined(__clang__) +// In C++17, it is conditionally supported, but still valid for all compiler we care +# pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif + namespace vtable { template @@ -242,4 +247,24 @@ public: } }; +template +inline void dealloc(const VTable *, uint8_t *ptr, [[maybe_unused]] Layout layout) +{ +#ifdef __cpp_sized_deallocation + ::operator delete(reinterpret_cast(ptr), layout.size, + static_cast(layout.align)); +#elif !defined(__APPLE__) || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 + ::operator delete(reinterpret_cast(ptr), static_cast(layout.align)); +#else + ::operator delete(reinterpret_cast(ptr)); +#endif +} + +template +inline Layout drop_in_place(VRefMut item_tree) +{ + reinterpret_cast(item_tree.instance)->~T(); + return vtable::Layout { sizeof(T), alignof(T) }; +} + } // namespace vtable diff --git a/internal/compiler/generator/cpp.rs b/internal/compiler/generator/cpp.rs index 2380d58595..62b9954f86 100644 --- a/internal/compiler/generator/cpp.rs +++ b/internal/compiler/generator/cpp.rs @@ -3737,12 +3737,10 @@ fn compile_builtin_function_call( if ({window}.supports_native_menu_bar()) {{ auto item_tree = {item_tree_id}::create(self); auto item_tree_dyn = item_tree.into_dyn(); - vtable::VBox box{{}}; - slint::cbindgen_private::slint_menus_create_wrapper(&item_tree_dyn, &box); - slint::cbindgen_private::slint_windowrc_setup_native_menu_bar(&{window}.handle(), const_cast(box.vtable), box.instance); - // The ownership of the VBox is transferred to slint_windowrc_setup_native_menu_bar - box.instance = nullptr; - box.vtable = nullptr; + slint::private_api::MaybeUninitialized> maybe; + slint::cbindgen_private::slint_menus_create_wrapper(&item_tree_dyn, &maybe.value); + auto vrc = maybe.take(); + slint::cbindgen_private::slint_windowrc_setup_native_menu_bar(&{window}.handle(), &vrc); }} else {{ auto item_tree = {item_tree_id}::create(self); auto item_tree_dyn = item_tree.into_dyn(); diff --git a/internal/core/menus.rs b/internal/core/menus.rs index e90344c38e..f54beca738 100644 --- a/internal/core/menus.rs +++ b/internal/core/menus.rs @@ -27,8 +27,6 @@ use vtable::{VRef, VRefMut}; #[vtable::vtable] #[repr(C)] pub struct MenuVTable { - /// destructor - drop: extern "C" fn(VRefMut), /// Return the list of items for the sub menu (or the main menu of parent is None) sub_menu: extern "C" fn(VRef, Option<&MenuEntry>, &mut SharedVector), /// Handler when the menu entry is activated @@ -243,9 +241,9 @@ pub mod ffi { #[unsafe(no_mangle)] pub unsafe extern "C" fn slint_menus_create_wrapper( menu_tree: &ItemTreeRc, - result: *mut vtable::VBox, + result: *mut vtable::VRc, ) { - let b = vtable::VBox::::new(MenuFromItemTree::new(menu_tree.clone())); - core::ptr::write(result, b); + let vrc = vtable::VRc::into_dyn(vtable::VRc::new(MenuFromItemTree::new(menu_tree.clone()))); + core::ptr::write(result, vrc); } } diff --git a/internal/core/window.rs b/internal/core/window.rs index a396fa15c0..81a8e0e0fe 100644 --- a/internal/core/window.rs +++ b/internal/core/window.rs @@ -1494,7 +1494,6 @@ pub mod ffi { use crate::graphics::Size; use crate::graphics::{IntSize, Rgba8Pixel}; use crate::SharedVector; - use core::ptr::NonNull; /// This enum describes a low-level access to specific graphics APIs used /// by the renderer. @@ -1847,13 +1846,12 @@ pub mod ffi { #[unsafe(no_mangle)] pub unsafe extern "C" fn slint_windowrc_setup_native_menu_bar( handle: *const WindowAdapterRcOpaque, - vtable: NonNull, - menu_instance: NonNull, + menu_instance: &vtable::VRc, ) { let window_adapter = &*(handle as *const Rc); window_adapter .internal(crate::InternalToken) - .map(|x| x.setup_menubar(vtable::VBox::from_raw(vtable, menu_instance.cast()))); + .map(|x| x.setup_menubar(menu_instance.clone())); } /// Return the default-font-size property of the WindowItem