aboutsummaryrefslogtreecommitdiff
path: root/include/cru/ui/controls
diff options
context:
space:
mode:
authorYuqian Yang <crupest@crupest.life>2025-11-17 13:52:52 +0800
committerYuqian Yang <crupest@crupest.life>2025-11-17 13:52:52 +0800
commitf7c4d19df66c602d74795e98ce2ee4390d06fbb4 (patch)
tree5d91dc18ae8129652d4c5b88234d0bb7b93dcf13 /include/cru/ui/controls
parentc9f31440d65a867e2316e9a19ee3f5db2d0e53a7 (diff)
downloadcru-f7c4d19df66c602d74795e98ce2ee4390d06fbb4.tar.gz
cru-f7c4d19df66c602d74795e98ce2ee4390d06fbb4.tar.bz2
cru-f7c4d19df66c602d74795e98ce2ee4390d06fbb4.zip
Harden delete after free.
Diffstat (limited to 'include/cru/ui/controls')
-rw-r--r--include/cru/ui/controls/Control.h13
-rw-r--r--include/cru/ui/controls/Window.h33
2 files changed, 35 insertions, 11 deletions
diff --git a/include/cru/ui/controls/Control.h b/include/cru/ui/controls/Control.h
index 684bc960..94de4cdc 100644
--- a/include/cru/ui/controls/Control.h
+++ b/include/cru/ui/controls/Control.h
@@ -1,12 +1,14 @@
#pragma once
#include "../Base.h"
#include "../DeleteLater.h"
+#include "../events/KeyEventArgs.h"
+#include "../events/MouseWheelEventArgs.h"
#include "../events/UiEvents.h"
+#include "../render/MeasureRequirement.h"
#include "../render/RenderObject.h"
#include "../style/StyleRuleSet.h"
-#include "cru/ui/events/KeyEventArgs.h"
-#include "cru/ui/events/MouseWheelEventArgs.h"
-#include "cru/ui/render/MeasureRequirement.h"
+
+#include <cru/base/SelfResolvable.h>
namespace cru::ui::controls {
@@ -19,7 +21,9 @@ namespace cru::ui::controls {
* - RemoveChild(Control* child)
* The last two methods are totally for convenient control tree management.
*/
-class CRU_UI_API Control : public Object, public DeleteLaterImpl {
+class CRU_UI_API Control : public Object,
+ public DeleteLaterImpl,
+ public SelfResolvable<Control> {
friend class RootControl;
CRU_DEFINE_CLASS_LOG_TAG("Control")
@@ -41,6 +45,7 @@ class CRU_UI_API Control : public Object, public DeleteLaterImpl {
Control* GetParent() const { return parent_; }
void SetParent(Control* parent);
+ bool HasAncestor(Control* control);
virtual void ForEachChild(const std::function<void(Control*)>& predicate) = 0;
diff --git a/include/cru/ui/controls/Window.h b/include/cru/ui/controls/Window.h
index e25694ba..88320219 100644
--- a/include/cru/ui/controls/Window.h
+++ b/include/cru/ui/controls/Window.h
@@ -13,6 +13,8 @@ namespace cru::ui::controls {
class CRU_UI_API Window
: public LayoutControl<render::StackLayoutRenderObject> {
CRU_DEFINE_CLASS_LOG_TAG("cru::ui::controls::Window")
+ friend Control;
+
public:
static constexpr std::string_view kControlType = "Window";
@@ -58,7 +60,6 @@ class CRU_UI_API Window
void SetOverrideCursor(std::shared_ptr<platform::gui::ICursor> cursor);
bool IsInEventHandling();
- void UpdateCursor();
CRU_DEFINE_EVENT(AfterLayout, std::nullptr_t)
@@ -104,7 +105,8 @@ class CRU_UI_API Window
if (original_sender == nullptr || original_sender == last_receiver) return;
std::string log = "Begin dispatching routed event " +
- (original_sender->*event_ptr)()->GetName() + ":\n\tTunnel:";
+ (original_sender->*event_ptr)()->GetName() +
+ ":\n\tTunnel:";
Guard logging_guard([&] {
log += "\nEnd dispatching routed event " +
@@ -112,11 +114,11 @@ class CRU_UI_API Window
CRU_LOG_TAG_DEBUG("{}", log);
});
- std::vector<Control*> receive_list;
+ std::vector<ObjectResolver<Control>> receive_list;
auto parent = original_sender;
while (parent != last_receiver) {
- receive_list.push_back(parent);
+ receive_list.push_back(parent->CreateResolver());
parent = parent->GetParent();
}
@@ -124,8 +126,12 @@ class CRU_UI_API Window
// tunnel
for (auto i = receive_list.crbegin(); i != receive_list.crend(); ++i) {
- auto control = *i;
+ auto control = i->Resolve();
log += " ";
+ if (!control) {
+ log += "(deleted)";
+ continue;
+ }
log += control->GetDebugId();
EventArgs event_args(control, original_sender,
std::forward<Args>(args)...);
@@ -140,8 +146,13 @@ class CRU_UI_API Window
// bubble
if (!handled) {
log += "\n\tBubble:";
- for (auto control : receive_list) {
+ for (auto resolver : receive_list) {
+ auto control = resolver.Resolve();
log += " ";
+ if (!control) {
+ log += "(deleted)";
+ continue;
+ }
log += control->GetDebugId();
EventArgs event_args(control, original_sender,
std::forward<Args>(args)...);
@@ -155,8 +166,13 @@ class CRU_UI_API Window
log += "\n\tDirect:";
// direct
- for (auto control : receive_list) {
+ for (auto resolver : receive_list) {
+ auto control = resolver.Resolve();
log += " ";
+ if (!control) {
+ log += "(deleted)";
+ continue;
+ }
log += control->GetDebugId();
EventArgs event_args(control, original_sender,
std::forward<Args>(args)...);
@@ -164,6 +180,9 @@ class CRU_UI_API Window
}
}
+ void UpdateCursor();
+ void NotifyControlDestroyed(Control* control);
+
private:
int event_handling_count_;