1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 07:27:45 +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:
Andreas Kling 2019-09-22 00:17:53 +02:00
parent 0c72e0c09f
commit bc319d9e88
45 changed files with 174 additions and 233 deletions

View file

@ -20,7 +20,7 @@
#include <sys/uio.h>
#include <unistd.h>
HashMap<int, WSClientConnection*>* s_connections;
HashMap<int, NonnullRefPtr<WSClientConnection>>* s_connections;
void WSClientConnection::for_each_client(Function<void(WSClientConnection&)> callback)
{
@ -38,24 +38,20 @@ WSClientConnection* WSClientConnection::from_client_id(int client_id)
auto it = s_connections->find(client_id);
if (it == s_connections->end())
return nullptr;
return (*it).value;
return (*it).value.ptr();
}
WSClientConnection::WSClientConnection(CLocalSocket& client_socket, int client_id)
: Connection(client_socket, client_id)
{
if (!s_connections)
s_connections = new HashMap<int, WSClientConnection*>;
s_connections->set(client_id, this);
s_connections = new HashMap<int, NonnullRefPtr<WSClientConnection>>;
s_connections->set(client_id, *this);
}
WSClientConnection::~WSClientConnection()
{
// NOTE: Move the windows out of 'm_windows' before teardown. This prevents code
// that runs in response to window destruction from trying to iterate over
// a partially destroyed window list.
auto windows = move(m_windows);
s_connections->remove(client_id());
}
void WSClientConnection::send_greeting()
@ -68,6 +64,11 @@ void WSClientConnection::send_greeting()
post_message(message);
}
void WSClientConnection::die()
{
s_connections->remove(client_id());
}
void WSClientConnection::post_error(const String& error_message)
{
dbgprintf("WSClientConnection::post_error: client_id=%d: %s\n", client_id(), error_message.characters());
@ -370,7 +371,7 @@ void WSClientConnection::handle_request(const WSAPIDestroyMenubarRequest& reques
void WSClientConnection::handle_request(const WSAPICreateMenuRequest& request)
{
int menu_id = m_next_menu_id++;
auto menu = make<WSMenu>(this, menu_id, request.text());
auto menu = WSMenu::construct(this, menu_id, request.text());
m_menus.set(menu_id, move(menu));
WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidCreateMenu;
@ -389,6 +390,7 @@ void WSClientConnection::handle_request(const WSAPIDestroyMenuRequest& request)
auto& menu = *(*it).value;
WSWindowManager::the().close_menu(menu);
m_menus.remove(it);
remove_child(menu);
WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidDestroyMenu;
response.menu.menu_id = menu_id;
@ -738,7 +740,7 @@ void WSClientConnection::handle_request(const WSAPIGetClipboardContentsRequest&)
void WSClientConnection::handle_request(const WSAPICreateWindowRequest& request)
{
int window_id = m_next_window_id++;
auto window = make<WSWindow>(*this, request.window_type(), window_id, request.is_modal(), request.is_resizable(), request.is_fullscreen());
auto window = WSWindow::construct(*this, request.window_type(), window_id, request.is_modal(), request.is_resizable(), request.is_fullscreen());
window->set_background_color(request.background_color());
window->set_has_alpha_channel(request.has_alpha_channel());
window->set_title(request.title());
@ -766,11 +768,15 @@ void WSClientConnection::handle_request(const WSAPIDestroyWindowRequest& request
}
auto& window = *(*it).value;
WSWindowManager::the().invalidate(window);
m_windows.remove(it);
WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidDestroyWindow;
response.window_id = window.window_id();
post_message(response);
dbg() << *this << " removing window child " << window << " refs: " << window.ref_count() << " parent: " << window.parent();
remove_child(window);
ASSERT(it->value.ptr() == &window);
m_windows.remove(window_id);
}
void WSClientConnection::post_paint_message(WSWindow& window)

View file

@ -17,9 +17,9 @@ class WSMenuBar;
class WSClientConnection final : public IPC::Server::Connection<WSAPI_ServerMessage, WSAPI_ClientMessage> {
C_OBJECT(WSClientConnection)
public:
explicit WSClientConnection(CLocalSocket&, int client_id);
~WSClientConnection() override;
void send_greeting() override;
virtual void send_greeting() override;
virtual void die() override;
bool handle_message(const WSAPI_ClientMessage&, const ByteBuffer&& = {}) override;
static WSClientConnection* from_client_id(int client_id);
@ -40,11 +40,14 @@ public:
WSMenu* find_menu_by_id(int menu_id)
{
// FIXME: Remove this const_cast when Optional knows how to vend a non-const fallback value somehow.
return const_cast<WSMenu*>(m_menus.get(menu_id).value_or(nullptr));
auto menu = m_menus.get(menu_id);
if (!menu.has_value())
return nullptr;
return const_cast<WSMenu*>(menu.value().ptr());
}
private:
explicit WSClientConnection(CLocalSocket&, int client_id);
virtual void event(CEvent&) override;
void on_request(const WSAPIClientRequest&);
@ -88,9 +91,9 @@ private:
void post_error(const String&);
HashMap<int, NonnullOwnPtr<WSWindow>> m_windows;
HashMap<int, NonnullRefPtr<WSWindow>> m_windows;
HashMap<int, NonnullOwnPtr<WSMenuBar>> m_menubars;
HashMap<int, NonnullOwnPtr<WSMenu>> m_menus;
HashMap<int, NonnullRefPtr<WSMenu>> m_menus;
WeakPtr<WSMenuBar> m_app_menubar;
int m_next_menubar_id { 10000 };

View file

@ -116,7 +116,7 @@ WSWindow& WSMenu::ensure_menu_window()
next_item_location.move_by(0, height);
}
auto window = make<WSWindow>(*this, WSWindowType::Menu);
auto window = WSWindow::construct(*this, WSWindowType::Menu);
window->set_rect(0, 0, width, height());
m_menu_window = move(window);
draw();

View file

@ -88,5 +88,5 @@ private:
WSMenuBar* m_menubar { nullptr };
WSMenuItem* m_hovered_item { nullptr };
NonnullOwnPtrVector<WSMenuItem> m_items;
OwnPtr<WSWindow> m_menu_window;
RefPtr<WSWindow> m_menu_window;
};

View file

@ -27,7 +27,7 @@ WSMenuManager::~WSMenuManager()
void WSMenuManager::setup()
{
m_window = make<WSWindow>(*this, WSWindowType::Menubar);
m_window = WSWindow::construct(*this, WSWindowType::Menubar);
m_window->set_rect(WSWindowManager::the().menubar_rect());
}

View file

@ -30,7 +30,7 @@ private:
void draw();
void tick_clock();
OwnPtr<WSWindow> m_window;
RefPtr<WSWindow> m_window;
WSCPUMonitor m_cpu_monitor;
String m_username;
ObjectPtr<CTimer> m_timer;

View file

@ -328,7 +328,7 @@ void WSWindow::request_update(const Rect& rect)
void WSWindow::popup_window_menu(const Point& position)
{
if (!m_window_menu) {
m_window_menu = make<WSMenu>(nullptr, -1, "(Window Menu)");
m_window_menu = WSMenu::construct(nullptr, -1, "(Window Menu)");
m_window_menu->add_item(make<WSMenuItem>(*m_window_menu, 1, "Minimize"));
m_window_menu->add_item(make<WSMenuItem>(*m_window_menu, 2, "Unminimize"));
m_window_menu->add_item(make<WSMenuItem>(*m_window_menu, WSMenuItem::Type::Separator));

View file

@ -182,5 +182,5 @@ private:
unsigned m_wm_event_mask { 0 };
DisjointRectSet m_pending_paint_rects;
Rect m_unmaximized_rect;
OwnPtr<WSMenu> m_window_menu;
RefPtr<WSMenu> m_window_menu;
};

View file

@ -57,7 +57,7 @@ WSWindowManager::WSWindowManager()
};
u8 system_menu_name[] = { 0xc3, 0xb8, 0 };
m_system_menu = make<WSMenu>(nullptr, -1, String((const char*)system_menu_name));
m_system_menu = WSMenu::construct(nullptr, -1, String((const char*)system_menu_name));
int appIndex = 1;
for (const auto& app : apps) {

View file

@ -248,7 +248,7 @@ private:
u8 m_keyboard_modifiers { 0 };
OwnPtr<WSMenu> m_system_menu;
RefPtr<WSMenu> m_system_menu;
Color m_menu_selection_color;
WeakPtr<WSMenuBar> m_current_menubar;
WeakPtr<WSMenu> m_current_menu;

View file

@ -135,7 +135,7 @@ void WSWindowSwitcher::refresh()
m_rect.set_height(window_count * item_height() + padding() * 2);
m_rect.center_within(WSScreen::the().rect());
if (!m_switcher_window)
m_switcher_window = make<WSWindow>(*this, WSWindowType::WindowSwitcher);
m_switcher_window = WSWindow::construct(*this, WSWindowType::WindowSwitcher);
m_switcher_window->set_rect(m_rect);
draw();
}

View file

@ -41,7 +41,7 @@ public:
WSWindow* switcher_window() { return m_switcher_window.ptr(); }
private:
OwnPtr<WSWindow> m_switcher_window;
RefPtr<WSWindow> m_switcher_window;
Rect m_rect;
bool m_visible { false };
Vector<WeakPtr<WSWindow>> m_windows;

View file

@ -24,7 +24,7 @@ int main(int, char**)
WSScreen screen(wm_config->read_num_entry("Screen", "Width", 1024),
wm_config->read_num_entry("Screen", "Height", 768));
WSCompositor::the();
WSWindowManager window_manager;
auto wm = WSWindowManager::construct();
dbgprintf("Entering WindowServer main loop.\n");
loop.exec();