Skip to content

Commit

Permalink
LibCore: Make CObject reference-counted
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
awesomekling committed Sep 21, 2019
1 parent 0c72e0c commit bc319d9
Show file tree
Hide file tree
Showing 45 changed files with 174 additions and 233 deletions.
6 changes: 3 additions & 3 deletions Applications/DisplayProperties/DisplayProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ void DisplayPropertiesWidget::create_frame()
auto background_splitter = GSplitter::construct(Orientation::Vertical, nullptr);
tab_widget->add_widget("Wallpaper", background_splitter);

auto background_content = GWidget::construct(background_splitter);
auto background_content = GWidget::construct(background_splitter.ptr());
background_content->set_layout(make<GBoxLayout>(Orientation::Vertical));
background_content->layout()->set_margins({ 4, 4, 4, 4 });

Expand All @@ -120,7 +120,7 @@ void DisplayPropertiesWidget::create_frame()
auto settings_splitter = GSplitter::construct(Orientation::Vertical, nullptr);
tab_widget->add_widget("Settings", settings_splitter);

auto settings_content = GWidget::construct(settings_splitter);
auto settings_content = GWidget::construct(settings_splitter.ptr());
settings_content->set_layout(make<GBoxLayout>(Orientation::Vertical));
settings_content->layout()->set_margins({ 4, 4, 4, 4 });

Expand All @@ -135,7 +135,7 @@ void DisplayPropertiesWidget::create_frame()
settings_content->layout()->add_spacer();

// Add the apply and cancel buttons
auto bottom_widget = GWidget::construct(m_root_widget);
auto bottom_widget = GWidget::construct(m_root_widget.ptr());
bottom_widget->set_layout(make<GBoxLayout>(Orientation::Horizontal));
bottom_widget->layout()->add_spacer();
bottom_widget->set_size_policy(Orientation::Vertical, SizePolicy::Fixed);
Expand Down
2 changes: 1 addition & 1 deletion Applications/IRCClient/IRCAppWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ void IRCAppWindow::setup_widgets()
toolbar->add_action(*m_open_query_action);
toolbar->add_action(*m_close_query_action);

auto outer_container = GWidget::construct(widget);
auto outer_container = GWidget::construct(widget.ptr());
outer_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
outer_container->layout()->set_margins({ 2, 0, 2, 2 });

Expand Down
4 changes: 2 additions & 2 deletions Applications/PaintBrush/ColorDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ void ColorDialog::build()
horizontal_container->layout()->set_margins({ 4, 4, 4, 4 });
set_main_widget(horizontal_container);

auto left_vertical_container = GWidget::construct(horizontal_container);
auto left_vertical_container = GWidget::construct(horizontal_container.ptr());
left_vertical_container->set_layout(make<GBoxLayout>(Orientation::Vertical));

auto right_vertical_container = GWidget::construct(horizontal_container);
auto right_vertical_container = GWidget::construct(horizontal_container.ptr());
right_vertical_container->set_layout(make<GBoxLayout>(Orientation::Vertical));

enum RGBComponent {
Expand Down
4 changes: 2 additions & 2 deletions Applications/PaintBrush/PaletteWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ PaletteWidget::PaletteWidget(PaintableWidget& paintable_widget, GWidget* parent)
color_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
color_container->layout()->set_spacing(1);

auto top_color_container = GWidget::construct(color_container);
auto top_color_container = GWidget::construct(color_container.ptr());
top_color_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
top_color_container->layout()->set_spacing(1);

auto bottom_color_container = GWidget::construct(color_container);
auto bottom_color_container = GWidget::construct(color_container.ptr());
bottom_color_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
bottom_color_container->layout()->set_spacing(1);

Expand Down
4 changes: 2 additions & 2 deletions Applications/PaintBrush/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ int main(int argc, char** argv)
window->set_title("PaintBrush");
window->set_rect(100, 100, 640, 480);

auto horizontal_container = GWidget::construct(nullptr);
auto horizontal_container = GWidget::construct();
window->set_main_widget(horizontal_container);
horizontal_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
horizontal_container->layout()->set_spacing(0);

new ToolboxWidget(horizontal_container);

auto vertical_container = GWidget::construct(horizontal_container);
auto vertical_container = GWidget::construct(horizontal_container.ptr());
vertical_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
vertical_container->layout()->set_spacing(0);

Expand Down
4 changes: 2 additions & 2 deletions Applications/Piano/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
int main(int argc, char** argv)
{
GApplication app(argc, argv);
AClientConnection audio_connection;
audio_connection.handshake();
auto audio_client = AClientConnection::construct();
audio_client->handshake();

auto window = GWindow::construct();
window->set_title("Piano");
Expand Down
6 changes: 3 additions & 3 deletions Applications/SoundPlayer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ int main(int argc, char** argv)
return 1;
}

AClientConnection audio_client;
audio_client.handshake();
auto audio_client = AClientConnection::construct();
audio_client->handshake();

auto window = GWindow::construct();
window->set_title("SoundPlayer");
Expand Down Expand Up @@ -57,7 +57,7 @@ int main(int argc, char** argv)
sample_widget->set_buffer(nullptr);
return;
}
bool enqueued = audio_client.try_enqueue(*next_sample_buffer);
bool enqueued = audio_client->try_enqueue(*next_sample_buffer);
if (!enqueued)
return;
sample_widget->set_buffer(next_sample_buffer);
Expand Down
4 changes: 2 additions & 2 deletions Applications/SystemMonitor/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ int main(int argc, char** argv)
auto process_container_splitter = GSplitter::construct(Orientation::Vertical, nullptr);
tabwidget->add_widget("Processes", process_container_splitter);

auto process_table_container = GWidget::construct(process_container_splitter);
auto process_table_container = GWidget::construct(process_container_splitter.ptr());

auto graphs_container = GWidget::construct();
graphs_container->set_fill_with_background_color(true);
Expand Down Expand Up @@ -301,7 +301,7 @@ ObjectPtr<GWidget> build_file_systems_tab()

ObjectPtr<GWidget> build_pci_devices_tab()
{
auto pci_widget = GWidget::construct(nullptr);
auto pci_widget = GWidget::construct();
pci_widget->set_layout(make<GBoxLayout>(Orientation::Vertical));
pci_widget->layout()->set_margins({ 4, 4, 4, 4 });
auto pci_table_view = GTableView::construct(pci_widget);
Expand Down
2 changes: 1 addition & 1 deletion Applications/Taskbar/TaskbarWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ void TaskbarWindow::on_screen_rect_change(const Rect& rect)
set_rect(new_rect);
}

GButton* TaskbarWindow::create_button(const WindowIdentifier& identifier)
NonnullRefPtr<GButton> TaskbarWindow::create_button(const WindowIdentifier& identifier)
{
auto button = TaskbarButton::construct(identifier, main_widget());
button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
Expand Down
2 changes: 1 addition & 1 deletion Applications/Taskbar/TaskbarWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class TaskbarWindow final : public GWindow {

private:
void on_screen_rect_change(const Rect&);
GButton* create_button(const WindowIdentifier&);
NonnullRefPtr<GButton> create_button(const WindowIdentifier&);

virtual void wm_event(GWMEvent&) override;
};
5 changes: 2 additions & 3 deletions Applications/Taskbar/WindowList.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ class Window {

~Window()
{
delete m_button;
}

WindowIdentifier identifier() const { return m_identifier; }
Expand All @@ -41,7 +40,7 @@ class Window {
WindowIdentifier m_identifier;
String m_title;
Rect m_rect;
GButton* m_button { nullptr };
RefPtr<GButton> m_button;
RefPtr<GraphicsBitmap> m_icon;
bool m_active { false };
bool m_minimized { false };
Expand All @@ -62,7 +61,7 @@ class WindowList {
Window& ensure_window(const WindowIdentifier&);
void remove_window(const WindowIdentifier&);

Function<GButton*(const WindowIdentifier&)> aid_create_button;
Function<NonnullRefPtr<GButton>(const WindowIdentifier&)> aid_create_button;

private:
HashMap<WindowIdentifier, NonnullOwnPtr<Window>> m_windows;
Expand Down
8 changes: 4 additions & 4 deletions Applications/Welcome/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ int main(int argc, char** argv)
// header
//

auto header = GLabel::construct(background);
auto header = GLabel::construct(background.ptr());
header->set_font(Font::default_bold_font());
header->set_text("Welcome to Serenity");
header->set_text_alignment(TextAlignment::CenterLeft);
Expand All @@ -94,13 +94,13 @@ int main(int argc, char** argv)
// main section
//

auto main_section = GWidget::construct(background);
auto main_section = GWidget::construct(background.ptr());
main_section->set_layout(make<GBoxLayout>(Orientation::Horizontal));
main_section->layout()->set_margins({ 0, 0, 0, 0 });
main_section->layout()->set_spacing(8);
main_section->set_size_policy(SizePolicy::Fill, SizePolicy::Fill);

auto menu = GWidget::construct(main_section);
auto menu = GWidget::construct(main_section.ptr());
menu->set_layout(make<GBoxLayout>(Orientation::Vertical));
menu->layout()->set_margins({ 0, 0, 0, 0 });
menu->layout()->set_spacing(8);
Expand All @@ -111,7 +111,7 @@ int main(int argc, char** argv)
stack->set_size_policy(SizePolicy::Fill, SizePolicy::Fill);

for (auto& page : pages) {
auto content = GWidget::construct(stack);
auto content = GWidget::construct(stack.ptr());
content->set_layout(make<GBoxLayout>(Orientation::Vertical));
content->layout()->set_margins({ 0, 0, 0, 0 });
content->layout()->set_spacing(8);
Expand Down
2 changes: 1 addition & 1 deletion Demos/WidgetGallery/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ int main(int argc, char** argv)
auto spinbox2 = GSpinBox::construct(main_widget);
spinbox2->set_enabled(false);

auto vertical_slider_container = GWidget::construct(main_widget);
auto vertical_slider_container = GWidget::construct(main_widget.ptr());
vertical_slider_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
vertical_slider_container->set_preferred_size(0, 100);
vertical_slider_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
Expand Down
2 changes: 1 addition & 1 deletion Games/Minesweeper/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ int main(int argc, char** argv)
widget->set_layout(make<GBoxLayout>(Orientation::Vertical));
widget->layout()->set_spacing(0);

auto container = GWidget::construct(widget);
auto container = GWidget::construct(widget.ptr());
container->set_fill_with_background_color(true);
container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
container->set_preferred_size(0, 36);
Expand Down
1 change: 0 additions & 1 deletion Libraries/LibCore/CEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ class CEvent {
Timer,
NotifierRead,
NotifierWrite,
DeferredDestroy,
DeferredInvoke,
ChildAdded,
ChildRemoved,
Expand Down
16 changes: 12 additions & 4 deletions Libraries/LibCore/CEventLoop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class RPCClient : public CObject {
int nread = m_socket->read((u8*)&length, sizeof(length));
if (nread == 0) {
dbg() << "RPC client disconnected";
delete_later();
shutdown();
return;
}
ASSERT(nread == sizeof(length));
Expand All @@ -52,7 +52,7 @@ class RPCClient : public CObject {
auto request_json = JsonValue::from_string(request);
if (!request_json.is_object()) {
dbg() << "RPC client sent invalid request";
delete_later();
shutdown();
return;
}

Expand Down Expand Up @@ -111,11 +111,17 @@ class RPCClient : public CObject {
}

if (type == "Disconnect") {
delete_later();
shutdown();
return;
}
}

void shutdown()
{
// FIXME: This is quite a hackish way to clean ourselves up.
delete this;
}

private:
ObjectPtr<CLocalSocket> m_socket;
};
Expand Down Expand Up @@ -148,7 +154,8 @@ CEventLoop::CEventLoop()
s_rpc_server->on_ready_to_accept = [&] {
auto client_socket = s_rpc_server->accept();
ASSERT(client_socket);
new RPCClient(move(client_socket));
// NOTE: RPCClient will delete itself in RPCClient::shutdown().
(void)RPCClient::construct(move(client_socket)).leak_ref();
};
}

Expand Down Expand Up @@ -246,6 +253,7 @@ void CEventLoop::pump(WaitMode mode)
#endif
static_cast<CDeferredInvocationEvent&>(event).m_invokee(*receiver);
} else {
NonnullRefPtr<CObject> protector(*receiver);
receiver->dispatch_event(event);
}

Expand Down
30 changes: 16 additions & 14 deletions Libraries/LibCore/CObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,25 @@ 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)
{
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));
Expand All @@ -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&)
Expand Down Expand Up @@ -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) {
Expand Down
Loading

0 comments on commit bc319d9

Please sign in to comment.