mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 05:18:12 +00:00
LibCore: Make CObject reference-counted
Okay, I've spent a whole day on this now, and it finally kinda works! With this patch, CObject and all of its derived classes are reference counted instead of tree-owned. The previous, Qt-like model was nice and familiar, but ultimately also outdated and difficult to reason about. CObject-derived types should now be stored in RefPtr/NonnullRefPtr and each class can be constructed using the forwarding construct() helper: auto widget = GWidget::construct(parent_widget); Note that construct() simply forwards all arguments to an existing constructor. It is inserted into each class by the C_OBJECT macro, see CObject.h to understand how that works. CObject::delete_later() disappears in this patch, as there is no longer a single logical owner of a CObject.
This commit is contained in:
parent
0c72e0c09f
commit
bc319d9e88
45 changed files with 174 additions and 233 deletions
|
@ -23,13 +23,18 @@ CObject::CObject(CObject* parent, bool is_widget)
|
|||
|
||||
CObject::~CObject()
|
||||
{
|
||||
// NOTE: We move our children out to a stack vector to prevent other
|
||||
// code from trying to iterate over them.
|
||||
auto children = move(m_children);
|
||||
// NOTE: We also unparent the children, so that they won't try to unparent
|
||||
// themselves in their own destructors.
|
||||
for (auto& child : children)
|
||||
child.m_parent = nullptr;
|
||||
|
||||
all_objects().remove(*this);
|
||||
stop_timer();
|
||||
if (m_parent)
|
||||
m_parent->remove_child(*this);
|
||||
auto children_to_delete = move(m_children);
|
||||
for (auto* child : children_to_delete)
|
||||
delete child;
|
||||
}
|
||||
|
||||
void CObject::event(CEvent& event)
|
||||
|
@ -37,9 +42,6 @@ void CObject::event(CEvent& event)
|
|||
switch (event.type()) {
|
||||
case CEvent::Timer:
|
||||
return timer_event(static_cast<CTimerEvent&>(event));
|
||||
case CEvent::DeferredDestroy:
|
||||
delete this;
|
||||
break;
|
||||
case CEvent::ChildAdded:
|
||||
case CEvent::ChildRemoved:
|
||||
return child_event(static_cast<CChildEvent&>(event));
|
||||
|
@ -58,19 +60,24 @@ void CObject::add_child(CObject& object)
|
|||
// FIXME: Should we support reparenting objects?
|
||||
ASSERT(!object.parent() || object.parent() == this);
|
||||
object.m_parent = this;
|
||||
m_children.append(&object);
|
||||
m_children.append(object);
|
||||
event(*make<CChildEvent>(CEvent::ChildAdded, object));
|
||||
}
|
||||
|
||||
void CObject::remove_child(CObject& object)
|
||||
{
|
||||
for (ssize_t i = 0; i < m_children.size(); ++i) {
|
||||
if (m_children[i] == &object) {
|
||||
for (int i = 0; i < m_children.size(); ++i) {
|
||||
dbg() << i << "] " << m_children.at(i);
|
||||
if (m_children.ptr_at(i).ptr() == &object) {
|
||||
// NOTE: We protect the child so it survives the handling of ChildRemoved.
|
||||
NonnullRefPtr<CObject> protector = object;
|
||||
object.m_parent = nullptr;
|
||||
m_children.remove(i);
|
||||
event(*make<CChildEvent>(CEvent::ChildRemoved, object));
|
||||
return;
|
||||
}
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void CObject::timer_event(CTimerEvent&)
|
||||
|
@ -104,11 +111,6 @@ void CObject::stop_timer()
|
|||
m_timer_id = 0;
|
||||
}
|
||||
|
||||
void CObject::delete_later()
|
||||
{
|
||||
CEventLoop::current().post_event(*this, make<CEvent>(CEvent::DeferredDestroy));
|
||||
}
|
||||
|
||||
void CObject::dump_tree(int indent)
|
||||
{
|
||||
for (int i = 0; i < indent; ++i) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue