From 04d243699cbde40fe69472f4c4df38c36f7942ef Mon Sep 17 00:00:00 2001 From: Yuqian Yang Date: Tue, 18 Nov 2025 17:31:23 +0800 Subject: Move delete later to platform::gui. --- include/cru/platform/gui/DeleteLater.h | 41 ++++++++++++++++++++++ include/cru/platform/gui/UiApplication.h | 14 ++++++++ include/cru/platform/gui/win/UiApplication.h | 3 ++ include/cru/ui/DeleteLater.h | 40 --------------------- include/cru/ui/components/Component.h | 7 ++-- include/cru/ui/controls/Control.h | 4 +-- src/ThemeBuilder/components/StyleRuleSetEditor.cpp | 19 +++++----- src/ThemeBuilder/components/StyleRuleSetEditor.h | 6 ++-- .../conditions/CompoundConditionEditor.cpp | 6 ++-- .../conditions/CompoundConditionEditor.h | 2 +- .../components/stylers/CompoundStylerEditor.cpp | 6 ++-- .../components/stylers/CompoundStylerEditor.h | 4 +-- src/platform/gui/UiApplication.cpp | 18 ++++++++-- src/platform/gui/win/UiApplication.cpp | 6 ++++ src/ui/CMakeLists.txt | 1 - src/ui/DeleteLater.cpp | 23 ------------ test/platform/CMakeLists.txt | 1 + test/platform/DeleteLaterTest.cpp | 17 +++++++++ test/ui/CMakeLists.txt | 6 ---- test/ui/DeleteLaterTest.cpp | 17 --------- 20 files changed, 127 insertions(+), 114 deletions(-) create mode 100644 include/cru/platform/gui/DeleteLater.h delete mode 100644 include/cru/ui/DeleteLater.h delete mode 100644 src/ui/DeleteLater.cpp create mode 100644 test/platform/DeleteLaterTest.cpp delete mode 100644 test/ui/DeleteLaterTest.cpp diff --git a/include/cru/platform/gui/DeleteLater.h b/include/cru/platform/gui/DeleteLater.h new file mode 100644 index 00000000..c0578974 --- /dev/null +++ b/include/cru/platform/gui/DeleteLater.h @@ -0,0 +1,41 @@ +#pragma once +#include "UiApplication.h" + +#include +#include +#include + +namespace cru::platform::gui { +template +class DeleteLaterImpl { + CRU_DEFINE_CLASS_LOG_TAG("cru::platform::gui::DeleteLaterImpl") + + public: + virtual ~DeleteLaterImpl() {} + + void DeleteLater() { + IUiApplication::GetInstance()->DeleteLater(static_cast(this)); + } +}; + +namespace details { +template +struct DeleteLaterPtrDeleter { + void operator()(T* p) const noexcept { p->DeleteLater(); } +}; +} // namespace details + +template +using DeleteLaterPtr = std::unique_ptr>; + +template +DeleteLaterPtr ToDeleteLaterPtr(std::unique_ptr&& p) { + return DeleteLaterPtr(p.release()); +} + +template +DeleteLaterPtr MakeDeleteLater(Args&&... args) { + return DeleteLaterPtr(new T(std::forward(args)...)); +} + +} // namespace cru::platform::gui diff --git a/include/cru/platform/gui/UiApplication.h b/include/cru/platform/gui/UiApplication.h index 84011275..c4454b2e 100644 --- a/include/cru/platform/gui/UiApplication.h +++ b/include/cru/platform/gui/UiApplication.h @@ -16,6 +16,18 @@ struct INativeWindow; struct IInputMethodContext; struct IClipboard; +class CRU_PLATFORM_GUI_API DeleteLaterPool : public Object { + public: + void Add(Object* object); + + void Clean(); + + private: + // May contain duplicate object pointer. When performing deleting, use a set + // to record deleted objects to avoid double delete. + std::vector pool_; +}; + // The entry point of a ui application. struct CRU_PLATFORM_GUI_API IUiApplication : public virtual IPlatformResource { public: @@ -51,6 +63,8 @@ struct CRU_PLATFORM_GUI_API IUiApplication : public virtual IPlatformResource { // result in no-op. virtual void CancelTimer(long long id) = 0; + virtual void DeleteLater(Object* object) = 0; + virtual std::vector GetAllWindow() = 0; virtual INativeWindow* CreateWindow() = 0; diff --git a/include/cru/platform/gui/win/UiApplication.h b/include/cru/platform/gui/win/UiApplication.h index b2d1f39b..c5057c4b 100644 --- a/include/cru/platform/gui/win/UiApplication.h +++ b/include/cru/platform/gui/win/UiApplication.h @@ -48,6 +48,8 @@ class CRU_WIN_GUI_API WinUiApplication : public WinNativeResource, std::function action) override; void CancelTimer(long long id) override; + void DeleteLater(Object* object) override; + std::vector GetAllWindow() override; INativeWindow* CreateWindow() override; @@ -79,6 +81,7 @@ class CRU_WIN_GUI_API WinUiApplication : public WinNativeResource, graph_factory_; TimerRegistry> timers_; + DeleteLaterPool delete_later_pool_; std::unique_ptr general_window_class_; std::vector windows_; diff --git a/include/cru/ui/DeleteLater.h b/include/cru/ui/DeleteLater.h deleted file mode 100644 index 95301bc0..00000000 --- a/include/cru/ui/DeleteLater.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include "Base.h" - -#include -#include -#include - -namespace cru::ui { -class CRU_UI_API DeleteLaterImpl { - CRU_DEFINE_CLASS_LOG_TAG("cru::ui::DeleteLaterImpl") - public: - DeleteLaterImpl(); - virtual ~DeleteLaterImpl(); - void DeleteLater(); - - private: - bool delete_later_scheduled_; -}; - -namespace details { -template -struct DeleteLaterPtrDeleter { - void operator()(T* p) const noexcept { p->DeleteLater(); } -}; -} // namespace details - -template -using DeleteLaterPtr = std::unique_ptr>; - -template -DeleteLaterPtr ToDeleteLaterPtr(std::unique_ptr&& p) { - return DeleteLaterPtr(p.release()); -} - -template -DeleteLaterPtr MakeDeleteLater(Args&&... args) { - return DeleteLaterPtr(new T(std::forward(args)...)); -} - -} // namespace cru::ui diff --git a/include/cru/ui/components/Component.h b/include/cru/ui/components/Component.h index d8966a89..1e002e5f 100644 --- a/include/cru/ui/components/Component.h +++ b/include/cru/ui/components/Component.h @@ -1,6 +1,7 @@ #pragma once #include "../Base.h" -#include "../DeleteLater.h" + +#include namespace cru::ui::components { /** @@ -8,7 +9,9 @@ namespace cru::ui::components { * \remarks Component should respect children's Component::IsDeleteByParent * value and decide whether to delete it. */ -class CRU_UI_API Component : public Object, public DeleteLaterImpl { +class CRU_UI_API Component + : public Object, + public cru::platform::gui::DeleteLaterImpl { public: virtual controls::Control* GetRootControl() = 0; diff --git a/include/cru/ui/controls/Control.h b/include/cru/ui/controls/Control.h index 9e5e86b8..6a85d25a 100644 --- a/include/cru/ui/controls/Control.h +++ b/include/cru/ui/controls/Control.h @@ -1,6 +1,5 @@ #pragma once #include "../Base.h" -#include "../DeleteLater.h" #include "../events/KeyEventArgs.h" #include "../events/MouseWheelEventArgs.h" #include "../events/UiEvents.h" @@ -9,6 +8,7 @@ #include "../style/StyleRuleSet.h" #include +#include namespace cru::ui::controls { @@ -22,7 +22,7 @@ namespace cru::ui::controls { * The last two methods are totally for convenient control tree management. */ class CRU_UI_API Control : public Object, - public DeleteLaterImpl, + public cru::platform::gui::DeleteLaterImpl, public SelfResolvable { friend class ControlHost; diff --git a/src/ThemeBuilder/components/StyleRuleSetEditor.cpp b/src/ThemeBuilder/components/StyleRuleSetEditor.cpp index fd159a44..9159e966 100644 --- a/src/ThemeBuilder/components/StyleRuleSetEditor.cpp +++ b/src/ThemeBuilder/components/StyleRuleSetEditor.cpp @@ -1,5 +1,5 @@ #include "StyleRuleSetEditor.h" -#include "cru/ui/DeleteLater.h" +#include "cru/platform/gui/DeleteLater.h" #include "cru/ui/ThemeManager.h" #include "cru/ui/controls/FlexLayout.h" #include "cru/ui/model/IListChangeNotify.h" @@ -49,11 +49,11 @@ void StyleRuleSetEditor::BindStyleRuleSet( } Index StyleRuleSetEditor::IndexOfRuleEditor(StyleRuleEditor* editor) { - auto iter = - std::find_if(style_rule_editors_.cbegin(), style_rule_editors_.cend(), - [editor](const ui::DeleteLaterPtr& p) { - return p.get() == editor; - }); + auto iter = std::find_if( + style_rule_editors_.cbegin(), style_rule_editors_.cend(), + [editor](const platform::gui::DeleteLaterPtr& p) { + return p.get() == editor; + }); return iter - style_rule_editors_.cbegin(); } @@ -66,7 +66,8 @@ void StyleRuleSetEditor::UpdateView( for (auto i = change->position; i < change->position + change->count; ++i) { const auto& rule = style_rule_set->GetStyleRule(i); - auto style_rule_editor = ui::MakeDeleteLater(); + auto style_rule_editor = + platform::gui::MakeDeleteLater(); style_rule_editor->SetValue(rule, false); style_rule_editor->RemoveEvent()->AddSpyOnlyHandler( [this, editor = style_rule_editor.get()] { @@ -80,8 +81,8 @@ void StyleRuleSetEditor::UpdateView( }); style_rule_editors_.insert(style_rule_editors_.cbegin() + i, std::move(style_rule_editor)); - rules_layout_.InsertChildAt(style_rule_editors_.back()->GetRootControl(), - i); + rules_layout_.InsertChildAt( + style_rule_editors_.back()->GetRootControl(), i); } break; } diff --git a/src/ThemeBuilder/components/StyleRuleSetEditor.h b/src/ThemeBuilder/components/StyleRuleSetEditor.h index 03148889..36ac8626 100644 --- a/src/ThemeBuilder/components/StyleRuleSetEditor.h +++ b/src/ThemeBuilder/components/StyleRuleSetEditor.h @@ -1,8 +1,8 @@ #pragma once #include "StyleRuleEditor.h" -#include "cru/ui/DeleteLater.h" +#include "cru/platform/gui/DeleteLater.h" #include "cru/ui/components/Component.h" -#include "cru/ui/controls/Button.h" +#include "cru/ui/controls/IconButton.h" #include "cru/ui/controls/Control.h" #include "cru/ui/controls/FlexLayout.h" #include "cru/ui/controls/ScrollView.h" @@ -36,7 +36,7 @@ class StyleRuleSetEditor : public ui::components::Component { ui::controls::ScrollView scroll_view_; ui::controls::FlexLayout container_; ui::controls::FlexLayout rules_layout_; - std::vector> style_rule_editors_; + std::vector> style_rule_editors_; ui::controls::IconButton add_button_; bool suppress_next_set_ = false; diff --git a/src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp b/src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp index d7324350..8501d7cd 100644 --- a/src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp +++ b/src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp @@ -7,7 +7,7 @@ #include "cru/base/ClonePtr.h" #include "cru/platform/Color.h" #include "cru/ui/Base.h" -#include "cru/ui/DeleteLater.h" +#include "cru/platform/gui/DeleteLater.h" #include "cru/ui/ThemeManager.h" #include "cru/ui/controls/FlexLayout.h" #include "cru/ui/style/Condition.h" @@ -69,7 +69,7 @@ CompoundConditionEditor::CompoundConditionEditor() { this->children_container_.RemoveChildAt(index); RaiseChangeEvent(); }); - children_.push_back(ui::ToDeleteLaterPtr(std::move(editor))); + children_.push_back(platform::gui::ToDeleteLaterPtr(std::move(editor))); children_container_.AddChild(children_.back()->GetRootControl()); RaiseChangeEvent(); } @@ -100,7 +100,7 @@ void CompoundConditionEditor::SetChildren( this->children_container_.RemoveChildAt(index); RaiseChangeEvent(); }); - children_.push_back(ui::ToDeleteLaterPtr(std::move(editor))); + children_.push_back(platform::gui::ToDeleteLaterPtr(std::move(editor))); children_container_.AddChild(children_.back()->GetRootControl()); } if (trigger_change) { diff --git a/src/ThemeBuilder/components/conditions/CompoundConditionEditor.h b/src/ThemeBuilder/components/conditions/CompoundConditionEditor.h index af632758..c0f0891a 100644 --- a/src/ThemeBuilder/components/conditions/CompoundConditionEditor.h +++ b/src/ThemeBuilder/components/conditions/CompoundConditionEditor.h @@ -23,7 +23,7 @@ class CompoundConditionEditor : public ConditionEditor { private: ui::components::PopupMenuIconButton add_child_button_; ui::controls::FlexLayout children_container_; - std::vector> children_; + std::vector> children_; }; class AndConditionEditor : public CompoundConditionEditor { diff --git a/src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp b/src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp index 90d19a68..698cc699 100644 --- a/src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp +++ b/src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp @@ -7,7 +7,7 @@ #include "PaddingStylerEditor.h" #include "PreferredSizeStylerEditor.h" #include "cru/base/ClonePtr.h" -#include "cru/ui/DeleteLater.h" +#include "cru/platform/gui/DeleteLater.h" #include "cru/ui/ThemeManager.h" #include "cru/ui/style/Styler.h" @@ -71,7 +71,7 @@ CompoundStylerEditor::CompoundStylerEditor() { this->children_container_.RemoveChildAt(index); RaiseChangeEvent(); }); - children_.push_back(ui::ToDeleteLaterPtr(std::move(editor))); + children_.push_back(platform::gui::ToDeleteLaterPtr(std::move(editor))); children_container_.AddChild(editor->GetRootControl()); RaiseChangeEvent(); } @@ -100,7 +100,7 @@ void CompoundStylerEditor::SetValue(ui::style::CompoundStyler* value, this->children_container_.RemoveChildAt(index); RaiseChangeEvent(); }); - children_.push_back(ui::ToDeleteLaterPtr(std::move(editor))); + children_.push_back(platform::gui::ToDeleteLaterPtr(std::move(editor))); children_container_.AddChild(children_.back()->GetRootControl()); } } diff --git a/src/ThemeBuilder/components/stylers/CompoundStylerEditor.h b/src/ThemeBuilder/components/stylers/CompoundStylerEditor.h index f9265fbf..454b3622 100644 --- a/src/ThemeBuilder/components/stylers/CompoundStylerEditor.h +++ b/src/ThemeBuilder/components/stylers/CompoundStylerEditor.h @@ -1,7 +1,7 @@ #pragma once #include "StylerEditor.h" #include "cru/base/ClonePtr.h" -#include "cru/ui/DeleteLater.h" +#include "cru/platform/gui/DeleteLater.h" #include "cru/ui/components/PopupButton.h" #include "cru/ui/controls/FlexLayout.h" #include "cru/ui/style/Styler.h" @@ -24,7 +24,7 @@ class CompoundStylerEditor : public StylerEditor { private: ui::controls::FlexLayout children_container_; - std::vector> children_; + std::vector> children_; ui::components::PopupMenuIconButton add_child_button_; }; } // namespace cru::theme_builder::components::stylers diff --git a/src/platform/gui/UiApplication.cpp b/src/platform/gui/UiApplication.cpp index f035224f..56570125 100644 --- a/src/platform/gui/UiApplication.cpp +++ b/src/platform/gui/UiApplication.cpp @@ -1,9 +1,23 @@ #include "cru/platform/gui/UiApplication.h" - #include "cru/base/Base.h" +#include + namespace cru::platform::gui { +void DeleteLaterPool::Add(Object* object) { pool_.push_back(object); } + +void DeleteLaterPool::Clean() { + std::unordered_set deleted; + for (auto object : pool_) { + if (!deleted.contains(object)) { + deleted.insert(object); + delete object; + } + } + pool_.clear(); +} + namespace { IUiApplication* instance = nullptr; } @@ -12,7 +26,7 @@ IUiApplication* IUiApplication::GetInstance() { return instance; } IUiApplication::IUiApplication() { if (instance) { - throw std::runtime_error("An ui application has already been created."); + throw Exception("A ui application has already been created."); } instance = this; diff --git a/src/platform/gui/win/UiApplication.cpp b/src/platform/gui/win/UiApplication.cpp index eb85ef90..e1c21d59 100644 --- a/src/platform/gui/win/UiApplication.cpp +++ b/src/platform/gui/win/UiApplication.cpp @@ -71,6 +71,8 @@ int WinUiApplication::Run() { break; } } + + delete_later_pool_.Clean(); } for (const auto& handler : quit_handlers_) handler(); @@ -103,6 +105,10 @@ long long WinUiApplication::SetInterval(std::chrono::milliseconds milliseconds, void WinUiApplication::CancelTimer(long long id) { timers_.Remove(id); } +void WinUiApplication::DeleteLater(Object* object) { + delete_later_pool_.Add(object); +} + std::vector WinUiApplication::GetAllWindow() { std::vector result; for (const auto w : windows_) { diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index e931b678..d2188e0b 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -1,5 +1,4 @@ add_library(CruUi - DeleteLater.cpp Helper.cpp ThemeManager.cpp ThemeResourceDictionary.cpp diff --git a/src/ui/DeleteLater.cpp b/src/ui/DeleteLater.cpp deleted file mode 100644 index 90b07b71..00000000 --- a/src/ui/DeleteLater.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "cru/ui/DeleteLater.h" - -#include "Helper.h" -#include "cru/base/log/Logger.h" -#include "cru/platform/gui/UiApplication.h" - -namespace cru::ui { - -DeleteLaterImpl::DeleteLaterImpl() : delete_later_scheduled_(false) {} - -DeleteLaterImpl::~DeleteLaterImpl() { - CRU_LOG_TAG_DEBUG("Delete later object being deleted {}.", - static_cast(this)); -} - -void DeleteLaterImpl::DeleteLater() { - if (!delete_later_scheduled_) { - CRU_LOG_TAG_DEBUG("Schedule delete later {}.", static_cast(this)); - GetUiApplication()->SetImmediate([this] { delete this; }); - delete_later_scheduled_ = true; - } -} -} // namespace cru::ui diff --git a/test/platform/CMakeLists.txt b/test/platform/CMakeLists.txt index e4237cd3..ea6493c4 100644 --- a/test/platform/CMakeLists.txt +++ b/test/platform/CMakeLists.txt @@ -1,5 +1,6 @@ add_executable(CruPlatformBaseTest ColorTest.cpp + DeleteLaterTest.cpp MatrixTest.cpp ) target_link_libraries(CruPlatformBaseTest PRIVATE CruPlatformBase CruTestBase) diff --git a/test/platform/DeleteLaterTest.cpp b/test/platform/DeleteLaterTest.cpp new file mode 100644 index 00000000..932ac357 --- /dev/null +++ b/test/platform/DeleteLaterTest.cpp @@ -0,0 +1,17 @@ +#include "cru/platform/gui/DeleteLater.h" + +#include + +struct MockDeleteLater { + bool triggered = false; + + void DeleteLater() { triggered = true; } +}; + +TEST_CASE("DeleteLaterPtr should work.", "[delete-later]") { + auto ptr = cru::platform::gui::MakeDeleteLater(); + auto p = ptr.get(); + ptr.reset(); + REQUIRE(p->triggered); + delete p; +} diff --git a/test/ui/CMakeLists.txt b/test/ui/CMakeLists.txt index 66a7cd27..e69de29b 100644 --- a/test/ui/CMakeLists.txt +++ b/test/ui/CMakeLists.txt @@ -1,6 +0,0 @@ -add_executable(CruUiTest - DeleteLaterTest.cpp -) -target_link_libraries(CruUiTest PRIVATE CruUi CruTestBase) - -cru_catch_discover_tests(CruUiTest) diff --git a/test/ui/DeleteLaterTest.cpp b/test/ui/DeleteLaterTest.cpp deleted file mode 100644 index c9d600de..00000000 --- a/test/ui/DeleteLaterTest.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "cru/ui/DeleteLater.h" - -#include - -struct MockDeleteLater { - bool triggered = false; - - void DeleteLater() { triggered = true; } -}; - -TEST_CASE("DeleteLaterPtr should work.", "[delete-later]") { - auto ptr = cru::ui::MakeDeleteLater(); - auto p = ptr.get(); - ptr.reset(); - REQUIRE(p->triggered); - delete p; -} -- cgit v1.2.3