1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 18:28: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:
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

@ -97,7 +97,7 @@ void DisplayPropertiesWidget::create_frame()
auto background_splitter = GSplitter::construct(Orientation::Vertical, nullptr); auto background_splitter = GSplitter::construct(Orientation::Vertical, nullptr);
tab_widget->add_widget("Wallpaper", background_splitter); 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->set_layout(make<GBoxLayout>(Orientation::Vertical));
background_content->layout()->set_margins({ 4, 4, 4, 4 }); background_content->layout()->set_margins({ 4, 4, 4, 4 });
@ -120,7 +120,7 @@ void DisplayPropertiesWidget::create_frame()
auto settings_splitter = GSplitter::construct(Orientation::Vertical, nullptr); auto settings_splitter = GSplitter::construct(Orientation::Vertical, nullptr);
tab_widget->add_widget("Settings", settings_splitter); 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->set_layout(make<GBoxLayout>(Orientation::Vertical));
settings_content->layout()->set_margins({ 4, 4, 4, 4 }); settings_content->layout()->set_margins({ 4, 4, 4, 4 });
@ -135,7 +135,7 @@ void DisplayPropertiesWidget::create_frame()
settings_content->layout()->add_spacer(); settings_content->layout()->add_spacer();
// Add the apply and cancel buttons // 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->set_layout(make<GBoxLayout>(Orientation::Horizontal));
bottom_widget->layout()->add_spacer(); bottom_widget->layout()->add_spacer();
bottom_widget->set_size_policy(Orientation::Vertical, SizePolicy::Fixed); bottom_widget->set_size_policy(Orientation::Vertical, SizePolicy::Fixed);

View file

@ -171,7 +171,7 @@ void IRCAppWindow::setup_widgets()
toolbar->add_action(*m_open_query_action); toolbar->add_action(*m_open_query_action);
toolbar->add_action(*m_close_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->set_layout(make<GBoxLayout>(Orientation::Vertical));
outer_container->layout()->set_margins({ 2, 0, 2, 2 }); outer_container->layout()->set_margins({ 2, 0, 2, 2 });

View file

@ -25,10 +25,10 @@ void ColorDialog::build()
horizontal_container->layout()->set_margins({ 4, 4, 4, 4 }); horizontal_container->layout()->set_margins({ 4, 4, 4, 4 });
set_main_widget(horizontal_container); 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)); 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)); right_vertical_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
enum RGBComponent { enum RGBComponent {

View file

@ -87,11 +87,11 @@ PaletteWidget::PaletteWidget(PaintableWidget& paintable_widget, GWidget* parent)
color_container->set_layout(make<GBoxLayout>(Orientation::Vertical)); color_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
color_container->layout()->set_spacing(1); 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->set_layout(make<GBoxLayout>(Orientation::Horizontal));
top_color_container->layout()->set_spacing(1); 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->set_layout(make<GBoxLayout>(Orientation::Horizontal));
bottom_color_container->layout()->set_spacing(1); bottom_color_container->layout()->set_spacing(1);

View file

@ -19,14 +19,14 @@ int main(int argc, char** argv)
window->set_title("PaintBrush"); window->set_title("PaintBrush");
window->set_rect(100, 100, 640, 480); window->set_rect(100, 100, 640, 480);
auto horizontal_container = GWidget::construct(nullptr); auto horizontal_container = GWidget::construct();
window->set_main_widget(horizontal_container); window->set_main_widget(horizontal_container);
horizontal_container->set_layout(make<GBoxLayout>(Orientation::Horizontal)); horizontal_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
horizontal_container->layout()->set_spacing(0); horizontal_container->layout()->set_spacing(0);
new ToolboxWidget(horizontal_container); 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->set_layout(make<GBoxLayout>(Orientation::Vertical));
vertical_container->layout()->set_spacing(0); vertical_container->layout()->set_spacing(0);

View file

@ -14,8 +14,8 @@
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
GApplication app(argc, argv); GApplication app(argc, argv);
AClientConnection audio_connection; auto audio_client = AClientConnection::construct();
audio_connection.handshake(); audio_client->handshake();
auto window = GWindow::construct(); auto window = GWindow::construct();
window->set_title("Piano"); window->set_title("Piano");

View file

@ -27,8 +27,8 @@ int main(int argc, char** argv)
return 1; return 1;
} }
AClientConnection audio_client; auto audio_client = AClientConnection::construct();
audio_client.handshake(); audio_client->handshake();
auto window = GWindow::construct(); auto window = GWindow::construct();
window->set_title("SoundPlayer"); window->set_title("SoundPlayer");
@ -57,7 +57,7 @@ int main(int argc, char** argv)
sample_widget->set_buffer(nullptr); sample_widget->set_buffer(nullptr);
return; return;
} }
bool enqueued = audio_client.try_enqueue(*next_sample_buffer); bool enqueued = audio_client->try_enqueue(*next_sample_buffer);
if (!enqueued) if (!enqueued)
return; return;
sample_widget->set_buffer(next_sample_buffer); sample_widget->set_buffer(next_sample_buffer);

View file

@ -58,7 +58,7 @@ int main(int argc, char** argv)
auto process_container_splitter = GSplitter::construct(Orientation::Vertical, nullptr); auto process_container_splitter = GSplitter::construct(Orientation::Vertical, nullptr);
tabwidget->add_widget("Processes", process_container_splitter); 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(); auto graphs_container = GWidget::construct();
graphs_container->set_fill_with_background_color(true); graphs_container->set_fill_with_background_color(true);
@ -301,7 +301,7 @@ ObjectPtr<GWidget> build_file_systems_tab()
ObjectPtr<GWidget> build_pci_devices_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->set_layout(make<GBoxLayout>(Orientation::Vertical));
pci_widget->layout()->set_margins({ 4, 4, 4, 4 }); pci_widget->layout()->set_margins({ 4, 4, 4, 4 });
auto pci_table_view = GTableView::construct(pci_widget); auto pci_table_view = GTableView::construct(pci_widget);

View file

@ -46,7 +46,7 @@ void TaskbarWindow::on_screen_rect_change(const Rect& rect)
set_rect(new_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()); auto button = TaskbarButton::construct(identifier, main_widget());
button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed); button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);

View file

@ -12,7 +12,7 @@ public:
private: private:
void on_screen_rect_change(const Rect&); void on_screen_rect_change(const Rect&);
GButton* create_button(const WindowIdentifier&); NonnullRefPtr<GButton> create_button(const WindowIdentifier&);
virtual void wm_event(GWMEvent&) override; virtual void wm_event(GWMEvent&) override;
}; };

View file

@ -15,7 +15,6 @@ public:
~Window() ~Window()
{ {
delete m_button;
} }
WindowIdentifier identifier() const { return m_identifier; } WindowIdentifier identifier() const { return m_identifier; }
@ -41,7 +40,7 @@ private:
WindowIdentifier m_identifier; WindowIdentifier m_identifier;
String m_title; String m_title;
Rect m_rect; Rect m_rect;
GButton* m_button { nullptr }; RefPtr<GButton> m_button;
RefPtr<GraphicsBitmap> m_icon; RefPtr<GraphicsBitmap> m_icon;
bool m_active { false }; bool m_active { false };
bool m_minimized { false }; bool m_minimized { false };
@ -62,7 +61,7 @@ public:
Window& ensure_window(const WindowIdentifier&); Window& ensure_window(const WindowIdentifier&);
void remove_window(const WindowIdentifier&); void remove_window(const WindowIdentifier&);
Function<GButton*(const WindowIdentifier&)> aid_create_button; Function<NonnullRefPtr<GButton>(const WindowIdentifier&)> aid_create_button;
private: private:
HashMap<WindowIdentifier, NonnullOwnPtr<Window>> m_windows; HashMap<WindowIdentifier, NonnullOwnPtr<Window>> m_windows;

View file

@ -83,7 +83,7 @@ int main(int argc, char** argv)
// header // header
// //
auto header = GLabel::construct(background); auto header = GLabel::construct(background.ptr());
header->set_font(Font::default_bold_font()); header->set_font(Font::default_bold_font());
header->set_text("Welcome to Serenity"); header->set_text("Welcome to Serenity");
header->set_text_alignment(TextAlignment::CenterLeft); header->set_text_alignment(TextAlignment::CenterLeft);
@ -94,13 +94,13 @@ int main(int argc, char** argv)
// main section // 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->set_layout(make<GBoxLayout>(Orientation::Horizontal));
main_section->layout()->set_margins({ 0, 0, 0, 0 }); main_section->layout()->set_margins({ 0, 0, 0, 0 });
main_section->layout()->set_spacing(8); main_section->layout()->set_spacing(8);
main_section->set_size_policy(SizePolicy::Fill, SizePolicy::Fill); 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->set_layout(make<GBoxLayout>(Orientation::Vertical));
menu->layout()->set_margins({ 0, 0, 0, 0 }); menu->layout()->set_margins({ 0, 0, 0, 0 });
menu->layout()->set_spacing(8); menu->layout()->set_spacing(8);
@ -111,7 +111,7 @@ int main(int argc, char** argv)
stack->set_size_policy(SizePolicy::Fill, SizePolicy::Fill); stack->set_size_policy(SizePolicy::Fill, SizePolicy::Fill);
for (auto& page : pages) { for (auto& page : pages) {
auto content = GWidget::construct(stack); auto content = GWidget::construct(stack.ptr());
content->set_layout(make<GBoxLayout>(Orientation::Vertical)); content->set_layout(make<GBoxLayout>(Orientation::Vertical));
content->layout()->set_margins({ 0, 0, 0, 0 }); content->layout()->set_margins({ 0, 0, 0, 0 });
content->layout()->set_spacing(8); content->layout()->set_spacing(8);

View file

@ -66,7 +66,7 @@ int main(int argc, char** argv)
auto spinbox2 = GSpinBox::construct(main_widget); auto spinbox2 = GSpinBox::construct(main_widget);
spinbox2->set_enabled(false); 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_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
vertical_slider_container->set_preferred_size(0, 100); vertical_slider_container->set_preferred_size(0, 100);
vertical_slider_container->set_layout(make<GBoxLayout>(Orientation::Horizontal)); vertical_slider_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));

View file

@ -24,7 +24,7 @@ int main(int argc, char** argv)
widget->set_layout(make<GBoxLayout>(Orientation::Vertical)); widget->set_layout(make<GBoxLayout>(Orientation::Vertical));
widget->layout()->set_spacing(0); 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_fill_with_background_color(true);
container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
container->set_preferred_size(0, 36); container->set_preferred_size(0, 36);

View file

@ -15,7 +15,6 @@ public:
Timer, Timer,
NotifierRead, NotifierRead,
NotifierWrite, NotifierWrite,
DeferredDestroy,
DeferredInvoke, DeferredInvoke,
ChildAdded, ChildAdded,
ChildRemoved, ChildRemoved,

View file

@ -43,7 +43,7 @@ public:
int nread = m_socket->read((u8*)&length, sizeof(length)); int nread = m_socket->read((u8*)&length, sizeof(length));
if (nread == 0) { if (nread == 0) {
dbg() << "RPC client disconnected"; dbg() << "RPC client disconnected";
delete_later(); shutdown();
return; return;
} }
ASSERT(nread == sizeof(length)); ASSERT(nread == sizeof(length));
@ -52,7 +52,7 @@ public:
auto request_json = JsonValue::from_string(request); auto request_json = JsonValue::from_string(request);
if (!request_json.is_object()) { if (!request_json.is_object()) {
dbg() << "RPC client sent invalid request"; dbg() << "RPC client sent invalid request";
delete_later(); shutdown();
return; return;
} }
@ -111,11 +111,17 @@ public:
} }
if (type == "Disconnect") { if (type == "Disconnect") {
delete_later(); shutdown();
return; return;
} }
} }
void shutdown()
{
// FIXME: This is quite a hackish way to clean ourselves up.
delete this;
}
private: private:
ObjectPtr<CLocalSocket> m_socket; ObjectPtr<CLocalSocket> m_socket;
}; };
@ -148,7 +154,8 @@ CEventLoop::CEventLoop()
s_rpc_server->on_ready_to_accept = [&] { s_rpc_server->on_ready_to_accept = [&] {
auto client_socket = s_rpc_server->accept(); auto client_socket = s_rpc_server->accept();
ASSERT(client_socket); ASSERT(client_socket);
new RPCClient(move(client_socket)); // NOTE: RPCClient will delete itself in RPCClient::shutdown().
(void)RPCClient::construct(move(client_socket)).leak_ref();
}; };
} }
@ -246,6 +253,7 @@ void CEventLoop::pump(WaitMode mode)
#endif #endif
static_cast<CDeferredInvocationEvent&>(event).m_invokee(*receiver); static_cast<CDeferredInvocationEvent&>(event).m_invokee(*receiver);
} else { } else {
NonnullRefPtr<CObject> protector(*receiver);
receiver->dispatch_event(event); receiver->dispatch_event(event);
} }

View file

@ -23,13 +23,18 @@ CObject::CObject(CObject* parent, bool is_widget)
CObject::~CObject() 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); all_objects().remove(*this);
stop_timer(); stop_timer();
if (m_parent) if (m_parent)
m_parent->remove_child(*this); 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) void CObject::event(CEvent& event)
@ -37,9 +42,6 @@ void CObject::event(CEvent& event)
switch (event.type()) { switch (event.type()) {
case CEvent::Timer: case CEvent::Timer:
return timer_event(static_cast<CTimerEvent&>(event)); return timer_event(static_cast<CTimerEvent&>(event));
case CEvent::DeferredDestroy:
delete this;
break;
case CEvent::ChildAdded: case CEvent::ChildAdded:
case CEvent::ChildRemoved: case CEvent::ChildRemoved:
return child_event(static_cast<CChildEvent&>(event)); return child_event(static_cast<CChildEvent&>(event));
@ -58,19 +60,24 @@ void CObject::add_child(CObject& object)
// FIXME: Should we support reparenting objects? // FIXME: Should we support reparenting objects?
ASSERT(!object.parent() || object.parent() == this); ASSERT(!object.parent() || object.parent() == this);
object.m_parent = this; object.m_parent = this;
m_children.append(&object); m_children.append(object);
event(*make<CChildEvent>(CEvent::ChildAdded, object)); event(*make<CChildEvent>(CEvent::ChildAdded, object));
} }
void CObject::remove_child(CObject& object) void CObject::remove_child(CObject& object)
{ {
for (ssize_t i = 0; i < m_children.size(); ++i) { for (int i = 0; i < m_children.size(); ++i) {
if (m_children[i] == &object) { 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); m_children.remove(i);
event(*make<CChildEvent>(CEvent::ChildRemoved, object)); event(*make<CChildEvent>(CEvent::ChildRemoved, object));
return; return;
} }
} }
ASSERT_NOT_REACHED();
} }
void CObject::timer_event(CTimerEvent&) void CObject::timer_event(CTimerEvent&)
@ -104,11 +111,6 @@ void CObject::stop_timer()
m_timer_id = 0; m_timer_id = 0;
} }
void CObject::delete_later()
{
CEventLoop::current().post_event(*this, make<CEvent>(CEvent::DeferredDestroy));
}
void CObject::dump_tree(int indent) void CObject::dump_tree(int indent)
{ {
for (int i = 0; i < indent; ++i) { for (int i = 0; i < indent; ++i) {

View file

@ -2,6 +2,8 @@
#include <AK/Function.h> #include <AK/Function.h>
#include <AK/IntrusiveList.h> #include <AK/IntrusiveList.h>
#include <AK/Noncopyable.h>
#include <AK/NonnullRefPtrVector.h>
#include <AK/StdLibExtras.h> #include <AK/StdLibExtras.h>
#include <AK/String.h> #include <AK/String.h>
#include <AK/Vector.h> #include <AK/Vector.h>
@ -21,13 +23,18 @@ class CTimerEvent;
public: \ public: \
virtual const char* class_name() const override { return #klass; } \ virtual const char* class_name() const override { return #klass; } \
template<class... Args> \ template<class... Args> \
static inline ObjectPtr<klass> construct(Args&&... args) \ static inline NonnullRefPtr<klass> construct(Args&&... args) \
{ \ { \
return ObjectPtr<klass>(new klass(forward<Args>(args)...)); \ return adopt(*new klass(forward<Args>(args)...)); \
} }
class CObject : public Weakable<CObject> { class CObject
: public RefCounted<CObject>
, public Weakable<CObject> {
// NOTE: No C_OBJECT macro for CObject itself. // NOTE: No C_OBJECT macro for CObject itself.
AK_MAKE_NONCOPYABLE(CObject)
AK_MAKE_NONMOVABLE(CObject)
public: public:
IntrusiveListNode m_all_objects_list_node; IntrusiveListNode m_all_objects_list_node;
@ -39,14 +46,14 @@ public:
const String& name() const { return m_name; } const String& name() const { return m_name; }
void set_name(const StringView& name) { m_name = name; } void set_name(const StringView& name) { m_name = name; }
Vector<CObject*>& children() { return m_children; } NonnullRefPtrVector<CObject>& children() { return m_children; }
const Vector<CObject*>& children() const { return m_children; } const NonnullRefPtrVector<CObject>& children() const { return m_children; }
template<typename Callback> template<typename Callback>
void for_each_child(Callback callback) void for_each_child(Callback callback)
{ {
for (auto* child : m_children) { for (auto& child : m_children) {
if (callback(*child) == IterationDecision::Break) if (callback(child) == IterationDecision::Break)
return; return;
} }
} }
@ -66,8 +73,6 @@ public:
void add_child(CObject&); void add_child(CObject&);
void remove_child(CObject&); void remove_child(CObject&);
void delete_later();
void dump_tree(int indent = 0); void dump_tree(int indent = 0);
void deferred_invoke(Function<void(CObject&)>); void deferred_invoke(Function<void(CObject&)>);
@ -95,7 +100,7 @@ private:
String m_name; String m_name;
int m_timer_id { 0 }; int m_timer_id { 0 };
bool m_widget { false }; bool m_widget { false };
Vector<CObject*> m_children; NonnullRefPtrVector<CObject> m_children;
}; };
template<typename T> template<typename T>

View file

@ -49,22 +49,22 @@ namespace Server {
}; };
template<typename T, class... Args> template<typename T, class... Args>
T* new_connection_for_client(Args&&... args) NonnullRefPtr<T> new_connection_for_client(Args&&... args)
{ {
auto conn = new T(AK::forward<Args>(args)...) /* arghs */; auto conn = T::construct(forward<Args>(args)...);
conn->send_greeting(); conn->send_greeting();
return conn; return conn;
} }
template<typename T, class... Args> template<typename T, class... Args>
T* new_connection_ng_for_client(Args&&... args) NonnullRefPtr<T> new_connection_ng_for_client(Args&&... args)
{ {
return new T(AK::forward<Args>(args)...) /* arghs */; return T::construct(forward<Args>(args)...) /* arghs */;
} }
template<typename ServerMessage, typename ClientMessage> template<typename ServerMessage, typename ClientMessage>
class Connection : public CObject { class Connection : public CObject {
public: protected:
Connection(CLocalSocket& socket, int client_id) Connection(CLocalSocket& socket, int client_id)
: m_socket(socket) : m_socket(socket)
, m_client_id(client_id) , m_client_id(client_id)
@ -76,6 +76,7 @@ namespace Server {
#endif #endif
} }
public:
~Connection() ~Connection()
{ {
#if defined(CIPC_DEBUG) #if defined(CIPC_DEBUG)
@ -108,14 +109,12 @@ namespace Server {
switch (errno) { switch (errno) {
case EPIPE: case EPIPE:
dbgprintf("Connection::post_message: Disconnected from peer.\n"); dbgprintf("Connection::post_message: Disconnected from peer.\n");
delete_later(); shutdown();
return; return;
break;
case EAGAIN: case EAGAIN:
dbgprintf("Connection::post_message: Client buffer overflowed.\n"); dbgprintf("Connection::post_message: Client buffer overflowed.\n");
did_misbehave(); did_misbehave();
return; return;
break;
default: default:
perror("Connection::post_message writev"); perror("Connection::post_message writev");
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
@ -134,7 +133,6 @@ namespace Server {
ssize_t nread = recv(m_socket->fd(), &message, sizeof(ClientMessage), MSG_DONTWAIT); ssize_t nread = recv(m_socket->fd(), &message, sizeof(ClientMessage), MSG_DONTWAIT);
if (nread == 0 || (nread == -1 && errno == EAGAIN)) { if (nread == 0 || (nread == -1 && errno == EAGAIN)) {
if (!messages_received) { if (!messages_received) {
// TODO: is delete_later() sufficient?
CEventLoop::current().post_event(*this, make<DisconnectedEvent>(client_id())); CEventLoop::current().post_event(*this, make<DisconnectedEvent>(client_id()));
} }
break; break;
@ -171,8 +169,13 @@ namespace Server {
void did_misbehave() void did_misbehave()
{ {
dbgprintf("Connection{%p} (id=%d, pid=%d) misbehaved, disconnecting.\n", this, client_id(), m_client_pid); dbgprintf("Connection{%p} (id=%d, pid=%d) misbehaved, disconnecting.\n", this, client_id(), m_client_pid);
shutdown();
}
void shutdown()
{
m_socket->close(); m_socket->close();
delete_later(); die();
} }
int client_id() const { return m_client_id; } int client_id() const { return m_client_id; }
@ -182,13 +185,15 @@ namespace Server {
// ### having this public is sad // ### having this public is sad
virtual void send_greeting() = 0; virtual void send_greeting() = 0;
virtual void die() = 0;
protected: protected:
void event(CEvent& event) void event(CEvent& event)
{ {
if (event.type() == Event::Disconnected) { if (event.type() == Event::Disconnected) {
int client_id = static_cast<const DisconnectedEvent&>(event).client_id(); int client_id = static_cast<const DisconnectedEvent&>(event).client_id();
dbgprintf("Connection: Client disconnected: %d\n", client_id); dbgprintf("Connection: Client disconnected: %d\n", client_id);
delete this; die();
return; return;
} }
@ -228,13 +233,12 @@ namespace Server {
switch (errno) { switch (errno) {
case EPIPE: case EPIPE:
dbg() << "Connection::post_message: Disconnected from peer"; dbg() << "Connection::post_message: Disconnected from peer";
delete_later(); shutdown();
return; return;
case EAGAIN: case EAGAIN:
dbg() << "Connection::post_message: Client buffer overflowed."; dbg() << "Connection::post_message: Client buffer overflowed.";
did_misbehave(); did_misbehave();
return; return;
break;
default: default:
perror("Connection::post_message write"); perror("Connection::post_message write");
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
@ -252,7 +256,6 @@ namespace Server {
ssize_t nread = recv(m_socket->fd(), buffer, sizeof(buffer), MSG_DONTWAIT); ssize_t nread = recv(m_socket->fd(), buffer, sizeof(buffer), MSG_DONTWAIT);
if (nread == 0 || (nread == -1 && errno == EAGAIN)) { if (nread == 0 || (nread == -1 && errno == EAGAIN)) {
if (!messages_received) { if (!messages_received) {
// TODO: is delete_later() sufficient?
CEventLoop::current().post_event(*this, make<DisconnectedEvent>(client_id())); CEventLoop::current().post_event(*this, make<DisconnectedEvent>(client_id()));
} }
break; break;
@ -278,21 +281,28 @@ namespace Server {
void did_misbehave() void did_misbehave()
{ {
dbg() << "Connection{" << this << "} (id=" << m_client_id << ", pid=" << m_client_pid << ") misbehaved, disconnecting."; dbg() << "Connection{" << this << "} (id=" << m_client_id << ", pid=" << m_client_pid << ") misbehaved, disconnecting.";
shutdown();
}
void shutdown()
{
m_socket->close(); m_socket->close();
delete_later(); die();
} }
int client_id() const { return m_client_id; } int client_id() const { return m_client_id; }
pid_t client_pid() const { return m_client_pid; } pid_t client_pid() const { return m_client_pid; }
void set_client_pid(pid_t pid) { m_client_pid = pid; } void set_client_pid(pid_t pid) { m_client_pid = pid; }
virtual void die() = 0;
protected: protected:
void event(CEvent& event) override void event(CEvent& event) override
{ {
if (event.type() == Event::Disconnected) { if (event.type() == Event::Disconnected) {
int client_id = static_cast<const DisconnectedEvent&>(event).client_id(); int client_id = static_cast<const DisconnectedEvent&>(event).client_id();
dbgprintf("Connection: Client disconnected: %d\n", client_id); dbgprintf("Connection: Client disconnected: %d\n", client_id);
delete this; die();
return; return;
} }

View file

@ -1,99 +1,3 @@
#pragma once #pragma once
#include <AK/StdLibExtras.h> #define ObjectPtr RefPtr
// This is a stopgap pointer. It's not meant to stick around forever.
template<typename T>
class ObjectPtr {
public:
ObjectPtr() {}
ObjectPtr(T* ptr)
: m_ptr(ptr)
{
}
ObjectPtr(T& ptr)
: m_ptr(&ptr)
{
}
~ObjectPtr()
{
clear();
}
void clear()
{
if (m_ptr && !m_ptr->parent())
delete m_ptr;
m_ptr = nullptr;
}
ObjectPtr& operator=(std::nullptr_t)
{
clear();
return *this;
}
template<typename U>
ObjectPtr(U* ptr)
: m_ptr(static_cast<T*>(ptr))
{
}
ObjectPtr(const ObjectPtr& other)
: m_ptr(other.m_ptr)
{
}
template<typename U>
ObjectPtr(const ObjectPtr<U>& other)
: m_ptr(static_cast<T*>(const_cast<ObjectPtr<U>&>(other).ptr()))
{
}
ObjectPtr(ObjectPtr&& other)
{
m_ptr = other.leak_ptr();
}
template<typename U>
ObjectPtr(const ObjectPtr<U>&& other)
{
m_ptr = static_cast<T*>(const_cast<ObjectPtr<U>&>(other).leak_ptr());
}
ObjectPtr& operator=(const ObjectPtr& other)
{
if (this != &other) {
clear();
m_ptr = other.m_ptr;
}
return *this;
}
ObjectPtr& operator=(ObjectPtr&& other)
{
if (this != &other) {
clear();
m_ptr = exchange(other.m_ptr, nullptr);
}
return *this;
}
T* operator->() { return m_ptr; }
const T* operator->() const { return m_ptr; }
operator T*() { return m_ptr; }
operator const T*() const { return m_ptr; }
T& operator*() { return *m_ptr; }
const T& operator*() const { return *m_ptr; }
T* ptr() const { return m_ptr; }
T* leak_ptr() { return exchange(m_ptr, nullptr); }
operator bool() const { return !!m_ptr; }
private:
T* m_ptr { nullptr };
};

View file

@ -18,7 +18,7 @@ GAboutDialog::GAboutDialog(const StringView& name, const GraphicsBitmap* icon, C
widget->set_fill_with_background_color(true); widget->set_fill_with_background_color(true);
widget->set_layout(make<GBoxLayout>(Orientation::Horizontal)); widget->set_layout(make<GBoxLayout>(Orientation::Horizontal));
auto left_container = GWidget::construct(widget); auto left_container = GWidget::construct(widget.ptr());
left_container->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); left_container->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
left_container->set_preferred_size(48, 0); left_container->set_preferred_size(48, 0);
left_container->set_layout(make<GBoxLayout>(Orientation::Vertical)); left_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
@ -28,7 +28,7 @@ GAboutDialog::GAboutDialog(const StringView& name, const GraphicsBitmap* icon, C
icon_label->set_preferred_size(40, 40); icon_label->set_preferred_size(40, 40);
left_container->layout()->add_spacer(); left_container->layout()->add_spacer();
auto right_container = GWidget::construct(widget); auto right_container = GWidget::construct(widget.ptr());
right_container->set_layout(make<GBoxLayout>(Orientation::Vertical)); right_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
right_container->layout()->set_margins({ 0, 4, 4, 4 }); right_container->layout()->set_margins({ 0, 4, 4, 4 });
@ -46,7 +46,7 @@ GAboutDialog::GAboutDialog(const StringView& name, const GraphicsBitmap* icon, C
right_container->layout()->add_spacer(); right_container->layout()->add_spacer();
auto button_container = GWidget::construct(right_container); auto button_container = GWidget::construct(right_container.ptr());
button_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); button_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
button_container->set_preferred_size(0, 20); button_container->set_preferred_size(0, 20);
button_container->set_layout(make<GBoxLayout>(Orientation::Horizontal)); button_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));

View file

@ -110,7 +110,6 @@ void GApplication::hide_tooltip()
{ {
if (m_tooltip_window) { if (m_tooltip_window) {
m_tooltip_window->hide(); m_tooltip_window->hide();
delete m_tooltip_window;
m_tooltip_window = nullptr; m_tooltip_window = nullptr;
} }
} }

View file

@ -57,11 +57,11 @@ GFilePicker::GFilePicker(Mode mode, const StringView& file_name, const StringVie
horizontal_container->set_fill_with_background_color(true); horizontal_container->set_fill_with_background_color(true);
horizontal_container->set_background_color(Color::WarmGray); horizontal_container->set_background_color(Color::WarmGray);
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->set_layout(make<GBoxLayout>(Orientation::Vertical));
vertical_container->layout()->set_spacing(4); vertical_container->layout()->set_spacing(4);
auto upper_container = GWidget::construct(vertical_container); auto upper_container = GWidget::construct(vertical_container.ptr());
upper_container->set_layout(make<GBoxLayout>(Orientation::Horizontal)); upper_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
upper_container->layout()->set_spacing(4); upper_container->layout()->set_spacing(4);
upper_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); upper_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
@ -118,13 +118,13 @@ GFilePicker::GFilePicker(Mode mode, const StringView& file_name, const StringVie
}); });
toolbar->add_action(*mkdir_action); toolbar->add_action(*mkdir_action);
auto lower_container = GWidget::construct(vertical_container); auto lower_container = GWidget::construct(vertical_container.ptr());
lower_container->set_layout(make<GBoxLayout>(Orientation::Vertical)); lower_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
lower_container->layout()->set_spacing(4); lower_container->layout()->set_spacing(4);
lower_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); lower_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
lower_container->set_preferred_size(0, 60); lower_container->set_preferred_size(0, 60);
auto filename_container = GWidget::construct(lower_container); auto filename_container = GWidget::construct(lower_container.ptr());
filename_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); filename_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
filename_container->set_preferred_size(0, 20); filename_container->set_preferred_size(0, 20);
filename_container->set_layout(make<GBoxLayout>(Orientation::Horizontal)); filename_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
@ -132,7 +132,7 @@ GFilePicker::GFilePicker(Mode mode, const StringView& file_name, const StringVie
filename_label->set_text_alignment(TextAlignment::CenterLeft); filename_label->set_text_alignment(TextAlignment::CenterLeft);
filename_label->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); filename_label->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
filename_label->set_preferred_size(60, 0); filename_label->set_preferred_size(60, 0);
m_filename_textbox = GTextBox::construct(filename_container); m_filename_textbox = GTextBox::construct(filename_container.ptr());
if (m_mode == Mode::Save) { if (m_mode == Mode::Save) {
m_filename_textbox->set_text(file_name); m_filename_textbox->set_text(file_name);
m_filename_textbox->set_focus(true); m_filename_textbox->set_focus(true);
@ -155,7 +155,7 @@ GFilePicker::GFilePicker(Mode mode, const StringView& file_name, const StringVie
set_preview(path); set_preview(path);
}; };
auto button_container = GWidget::construct(lower_container); auto button_container = GWidget::construct(lower_container.ptr());
button_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); button_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
button_container->set_preferred_size(0, 20); button_container->set_preferred_size(0, 20);
button_container->set_layout(make<GBoxLayout>(Orientation::Horizontal)); button_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));

View file

@ -42,12 +42,12 @@ void GInputBox::build()
m_text_editor->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); m_text_editor->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
m_text_editor->set_preferred_size(0, 19); m_text_editor->set_preferred_size(0, 19);
auto button_container_outer = GWidget::construct(widget); auto button_container_outer = GWidget::construct(widget.ptr());
button_container_outer->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); button_container_outer->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
button_container_outer->set_preferred_size(0, 20); button_container_outer->set_preferred_size(0, 20);
button_container_outer->set_layout(make<GBoxLayout>(Orientation::Vertical)); button_container_outer->set_layout(make<GBoxLayout>(Orientation::Vertical));
auto button_container_inner = GWidget::construct(button_container_outer); auto button_container_inner = GWidget::construct(button_container_outer.ptr());
button_container_inner->set_layout(make<GBoxLayout>(Orientation::Horizontal)); button_container_inner->set_layout(make<GBoxLayout>(Orientation::Horizontal));
button_container_inner->layout()->set_spacing(8); button_container_inner->layout()->set_spacing(8);

View file

@ -64,7 +64,7 @@ void GMessageBox::build()
ObjectPtr<GWidget> message_container = widget; ObjectPtr<GWidget> message_container = widget;
if (m_type != Type::None) { if (m_type != Type::None) {
message_container = GWidget::construct(widget); message_container = GWidget::construct(widget.ptr());
message_container->set_layout(make<GBoxLayout>(Orientation::Horizontal)); message_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
message_container->layout()->set_margins({ 8, 0, 8, 0 }); message_container->layout()->set_margins({ 8, 0, 8, 0 });
message_container->layout()->set_spacing(8); message_container->layout()->set_spacing(8);
@ -80,7 +80,7 @@ void GMessageBox::build()
label->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); label->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
label->set_preferred_size(text_width, 16); label->set_preferred_size(text_width, 16);
auto button_container = GWidget::construct(widget); auto button_container = GWidget::construct(widget.ptr());
button_container->set_layout(make<GBoxLayout>(Orientation::Horizontal)); button_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
button_container->layout()->set_spacing(5); button_container->layout()->set_spacing(5);
button_container->layout()->set_margins({ 15, 0, 15, 0 }); button_container->layout()->set_margins({ 15, 0, 15, 0 });

View file

@ -325,13 +325,13 @@ Rect GWidget::screen_relative_rect() const
GWidget* GWidget::child_at(const Point& point) const GWidget* GWidget::child_at(const Point& point) const
{ {
for (int i = children().size() - 1; i >= 0; --i) { for (int i = children().size() - 1; i >= 0; --i) {
if (!is<GWidget>(*children()[i])) if (!is<GWidget>(children()[i]))
continue; continue;
auto& child = to<GWidget>(*children()[i]); auto& child = to<GWidget>(children()[i]);
if (!child.is_visible()) if (!child.is_visible())
continue; continue;
if (child.relative_rect().contains(point)) if (child.relative_rect().contains(point))
return &child; return const_cast<GWidget*>(&child);
} }
return nullptr; return nullptr;
} }
@ -492,7 +492,7 @@ void GWidget::move_to_front()
parent->children().remove_first_matching([this](auto& entry) { parent->children().remove_first_matching([this](auto& entry) {
return entry == this; return entry == this;
}); });
parent->children().append(this); parent->children().append(*this);
parent->update(); parent->update();
} }
@ -506,7 +506,7 @@ void GWidget::move_to_back()
parent->children().remove_first_matching([this](auto& entry) { parent->children().remove_first_matching([this](auto& entry) {
return entry == this; return entry == this;
}); });
parent->children().prepend(this); parent->children().prepend(*this);
parent->update(); parent->update();
} }
@ -515,7 +515,7 @@ bool GWidget::is_frontmost() const
auto* parent = parent_widget(); auto* parent = parent_widget();
if (!parent) if (!parent)
return true; return true;
return parent->children().last() == this; return &parent->children().last() == this;
} }
bool GWidget::is_backmost() const bool GWidget::is_backmost() const
@ -523,7 +523,7 @@ bool GWidget::is_backmost() const
auto* parent = parent_widget(); auto* parent = parent_widget();
if (!parent) if (!parent)
return true; return true;
return parent->children().first() == this; return &parent->children().first() == this;
} }
GAction* GWidget::action_for_key_event(const GKeyEvent& event) GAction* GWidget::action_for_key_event(const GKeyEvent& event)

View file

@ -28,7 +28,7 @@ static int background_thread_func()
static void init() static void init()
{ {
s_all_actions = new LibThread::Lockable<Queue<Function<void()>>>(); s_all_actions = new LibThread::Lockable<Queue<Function<void()>>>();
s_background_thread = new LibThread::Thread(background_thread_func); s_background_thread = &LibThread::Thread::construct(background_thread_func).leak_ref();
s_background_thread->set_name("Background thread"); s_background_thread->set_name("Background thread");
s_background_thread->start(); s_background_thread->start();
} }

View file

@ -4,7 +4,6 @@
#include <AK/NonnullRefPtr.h> #include <AK/NonnullRefPtr.h>
#include <AK/Optional.h> #include <AK/Optional.h>
#include <AK/Queue.h> #include <AK/Queue.h>
#include <AK/RefCounted.h>
#include <LibCore/CEventLoop.h> #include <LibCore/CEventLoop.h>
#include <LibCore/CObject.h> #include <LibCore/CObject.h>
#include <LibThread/Lock.h> #include <LibThread/Lock.h>
@ -28,11 +27,8 @@ private:
template<typename Result> template<typename Result>
class BackgroundAction final : public CObject class BackgroundAction final : public CObject
, public RefCounted<BackgroundAction<Result>>
, private BackgroundActionBase { , private BackgroundActionBase {
C_OBJECT(BackgroundAction); C_OBJECT(BackgroundAction);
public: public:
static NonnullRefPtr<BackgroundAction<Result>> create( static NonnullRefPtr<BackgroundAction<Result>> create(
Function<Result()> action, Function<Result()> action,
@ -47,7 +43,7 @@ public:
private: private:
BackgroundAction(Function<Result()> action, Function<void(Result)> on_complete) BackgroundAction(Function<Result()> action, Function<void(Result)> on_complete)
: CObject(background_thread()) : CObject(&background_thread())
, m_action(move(action)) , m_action(move(action))
, m_on_complete(move(on_complete)) , m_on_complete(move(on_complete))
{ {

View file

@ -12,16 +12,24 @@
#include <sys/uio.h> #include <sys/uio.h>
#include <unistd.h> #include <unistd.h>
static HashMap<int, RefPtr<ASClientConnection>> s_connections;
ASClientConnection::ASClientConnection(CLocalSocket& client_socket, int client_id, ASMixer& mixer) ASClientConnection::ASClientConnection(CLocalSocket& client_socket, int client_id, ASMixer& mixer)
: ConnectionNG(*this, client_socket, client_id) : ConnectionNG(*this, client_socket, client_id)
, m_mixer(mixer) , m_mixer(mixer)
{ {
s_connections.set(client_id, *this);
} }
ASClientConnection::~ASClientConnection() ASClientConnection::~ASClientConnection()
{ {
} }
void ASClientConnection::die()
{
s_connections.remove(client_id());
}
void ASClientConnection::did_finish_playing_buffer(Badge<ASMixer>, int buffer_id) void ASClientConnection::did_finish_playing_buffer(Badge<ASMixer>, int buffer_id)
{ {
(void)buffer_id; (void)buffer_id;

View file

@ -15,6 +15,8 @@ public:
~ASClientConnection() override; ~ASClientConnection() override;
void did_finish_playing_buffer(Badge<ASMixer>, int buffer_id); void did_finish_playing_buffer(Badge<ASMixer>, int buffer_id);
virtual void die() override;
private: private:
virtual OwnPtr<AudioServer::GreetResponse> handle(const AudioServer::Greet&) override; virtual OwnPtr<AudioServer::GreetResponse> handle(const AudioServer::Greet&) override;
virtual OwnPtr<AudioServer::GetMainMixVolumeResponse> handle(const AudioServer::GetMainMixVolume&) override; virtual OwnPtr<AudioServer::GetMainMixVolumeResponse> handle(const AudioServer::GetMainMixVolume&) override;

View file

@ -20,7 +20,7 @@
#include <sys/uio.h> #include <sys/uio.h>
#include <unistd.h> #include <unistd.h>
HashMap<int, WSClientConnection*>* s_connections; HashMap<int, NonnullRefPtr<WSClientConnection>>* s_connections;
void WSClientConnection::for_each_client(Function<void(WSClientConnection&)> callback) 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); auto it = s_connections->find(client_id);
if (it == s_connections->end()) if (it == s_connections->end())
return nullptr; return nullptr;
return (*it).value; return (*it).value.ptr();
} }
WSClientConnection::WSClientConnection(CLocalSocket& client_socket, int client_id) WSClientConnection::WSClientConnection(CLocalSocket& client_socket, int client_id)
: Connection(client_socket, client_id) : Connection(client_socket, client_id)
{ {
if (!s_connections) if (!s_connections)
s_connections = new HashMap<int, WSClientConnection*>; s_connections = new HashMap<int, NonnullRefPtr<WSClientConnection>>;
s_connections->set(client_id, this); s_connections->set(client_id, *this);
} }
WSClientConnection::~WSClientConnection() 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); auto windows = move(m_windows);
s_connections->remove(client_id());
} }
void WSClientConnection::send_greeting() void WSClientConnection::send_greeting()
@ -68,6 +64,11 @@ void WSClientConnection::send_greeting()
post_message(message); post_message(message);
} }
void WSClientConnection::die()
{
s_connections->remove(client_id());
}
void WSClientConnection::post_error(const String& error_message) void WSClientConnection::post_error(const String& error_message)
{ {
dbgprintf("WSClientConnection::post_error: client_id=%d: %s\n", client_id(), error_message.characters()); 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) void WSClientConnection::handle_request(const WSAPICreateMenuRequest& request)
{ {
int menu_id = m_next_menu_id++; 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)); m_menus.set(menu_id, move(menu));
WSAPI_ServerMessage response; WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidCreateMenu; response.type = WSAPI_ServerMessage::Type::DidCreateMenu;
@ -389,6 +390,7 @@ void WSClientConnection::handle_request(const WSAPIDestroyMenuRequest& request)
auto& menu = *(*it).value; auto& menu = *(*it).value;
WSWindowManager::the().close_menu(menu); WSWindowManager::the().close_menu(menu);
m_menus.remove(it); m_menus.remove(it);
remove_child(menu);
WSAPI_ServerMessage response; WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidDestroyMenu; response.type = WSAPI_ServerMessage::Type::DidDestroyMenu;
response.menu.menu_id = menu_id; response.menu.menu_id = menu_id;
@ -738,7 +740,7 @@ void WSClientConnection::handle_request(const WSAPIGetClipboardContentsRequest&)
void WSClientConnection::handle_request(const WSAPICreateWindowRequest& request) void WSClientConnection::handle_request(const WSAPICreateWindowRequest& request)
{ {
int window_id = m_next_window_id++; 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_background_color(request.background_color());
window->set_has_alpha_channel(request.has_alpha_channel()); window->set_has_alpha_channel(request.has_alpha_channel());
window->set_title(request.title()); window->set_title(request.title());
@ -766,11 +768,15 @@ void WSClientConnection::handle_request(const WSAPIDestroyWindowRequest& request
} }
auto& window = *(*it).value; auto& window = *(*it).value;
WSWindowManager::the().invalidate(window); WSWindowManager::the().invalidate(window);
m_windows.remove(it);
WSAPI_ServerMessage response; WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidDestroyWindow; response.type = WSAPI_ServerMessage::Type::DidDestroyWindow;
response.window_id = window.window_id(); response.window_id = window.window_id();
post_message(response); 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) 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> { class WSClientConnection final : public IPC::Server::Connection<WSAPI_ServerMessage, WSAPI_ClientMessage> {
C_OBJECT(WSClientConnection) C_OBJECT(WSClientConnection)
public: public:
explicit WSClientConnection(CLocalSocket&, int client_id);
~WSClientConnection() override; ~WSClientConnection() override;
void send_greeting() override; virtual void send_greeting() override;
virtual void die() override;
bool handle_message(const WSAPI_ClientMessage&, const ByteBuffer&& = {}) override; bool handle_message(const WSAPI_ClientMessage&, const ByteBuffer&& = {}) override;
static WSClientConnection* from_client_id(int client_id); static WSClientConnection* from_client_id(int client_id);
@ -40,11 +40,14 @@ public:
WSMenu* find_menu_by_id(int menu_id) 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. auto menu = m_menus.get(menu_id);
return const_cast<WSMenu*>(m_menus.get(menu_id).value_or(nullptr)); if (!menu.has_value())
return nullptr;
return const_cast<WSMenu*>(menu.value().ptr());
} }
private: private:
explicit WSClientConnection(CLocalSocket&, int client_id);
virtual void event(CEvent&) override; virtual void event(CEvent&) override;
void on_request(const WSAPIClientRequest&); void on_request(const WSAPIClientRequest&);
@ -88,9 +91,9 @@ private:
void post_error(const String&); 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<WSMenuBar>> m_menubars;
HashMap<int, NonnullOwnPtr<WSMenu>> m_menus; HashMap<int, NonnullRefPtr<WSMenu>> m_menus;
WeakPtr<WSMenuBar> m_app_menubar; WeakPtr<WSMenuBar> m_app_menubar;
int m_next_menubar_id { 10000 }; int m_next_menubar_id { 10000 };

View file

@ -116,7 +116,7 @@ WSWindow& WSMenu::ensure_menu_window()
next_item_location.move_by(0, height); 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()); window->set_rect(0, 0, width, height());
m_menu_window = move(window); m_menu_window = move(window);
draw(); draw();

View file

@ -88,5 +88,5 @@ private:
WSMenuBar* m_menubar { nullptr }; WSMenuBar* m_menubar { nullptr };
WSMenuItem* m_hovered_item { nullptr }; WSMenuItem* m_hovered_item { nullptr };
NonnullOwnPtrVector<WSMenuItem> m_items; 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() 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()); m_window->set_rect(WSWindowManager::the().menubar_rect());
} }

View file

@ -30,7 +30,7 @@ private:
void draw(); void draw();
void tick_clock(); void tick_clock();
OwnPtr<WSWindow> m_window; RefPtr<WSWindow> m_window;
WSCPUMonitor m_cpu_monitor; WSCPUMonitor m_cpu_monitor;
String m_username; String m_username;
ObjectPtr<CTimer> m_timer; 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) void WSWindow::popup_window_menu(const Point& position)
{ {
if (!m_window_menu) { 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, 1, "Minimize"));
m_window_menu->add_item(make<WSMenuItem>(*m_window_menu, 2, "Unminimize")); 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)); 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 }; unsigned m_wm_event_mask { 0 };
DisjointRectSet m_pending_paint_rects; DisjointRectSet m_pending_paint_rects;
Rect m_unmaximized_rect; 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 }; 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; int appIndex = 1;
for (const auto& app : apps) { for (const auto& app : apps) {

View file

@ -248,7 +248,7 @@ private:
u8 m_keyboard_modifiers { 0 }; u8 m_keyboard_modifiers { 0 };
OwnPtr<WSMenu> m_system_menu; RefPtr<WSMenu> m_system_menu;
Color m_menu_selection_color; Color m_menu_selection_color;
WeakPtr<WSMenuBar> m_current_menubar; WeakPtr<WSMenuBar> m_current_menubar;
WeakPtr<WSMenu> m_current_menu; 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.set_height(window_count * item_height() + padding() * 2);
m_rect.center_within(WSScreen::the().rect()); m_rect.center_within(WSScreen::the().rect());
if (!m_switcher_window) 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); m_switcher_window->set_rect(m_rect);
draw(); draw();
} }

View file

@ -41,7 +41,7 @@ public:
WSWindow* switcher_window() { return m_switcher_window.ptr(); } WSWindow* switcher_window() { return m_switcher_window.ptr(); }
private: private:
OwnPtr<WSWindow> m_switcher_window; RefPtr<WSWindow> m_switcher_window;
Rect m_rect; Rect m_rect;
bool m_visible { false }; bool m_visible { false };
Vector<WeakPtr<WSWindow>> m_windows; 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), WSScreen screen(wm_config->read_num_entry("Screen", "Width", 1024),
wm_config->read_num_entry("Screen", "Height", 768)); wm_config->read_num_entry("Screen", "Height", 768));
WSCompositor::the(); WSCompositor::the();
WSWindowManager window_manager; auto wm = WSWindowManager::construct();
dbgprintf("Entering WindowServer main loop.\n"); dbgprintf("Entering WindowServer main loop.\n");
loop.exec(); loop.exec();

View file

@ -2,7 +2,7 @@
#include <LibAudio/AClientConnection.h> #include <LibAudio/AClientConnection.h>
#include <LibAudio/AWavLoader.h> #include <LibAudio/AWavLoader.h>
#include <LibCore/CEventLoop.h> #include <LibCore/CEventLoop.h>
#include <cstdio> #include <stdio.h>
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
@ -12,8 +12,8 @@ int main(int argc, char** argv)
return 1; return 1;
} }
AClientConnection a_conn; auto audio_client = AClientConnection::construct();
a_conn.handshake(); audio_client->handshake();
AWavLoader loader(argv[1]); AWavLoader loader(argv[1]);
printf("\033[34;1m Playing\033[0m: %s\n", argv[1]); printf("\033[34;1m Playing\033[0m: %s\n", argv[1]);
@ -29,7 +29,7 @@ int main(int argc, char** argv)
printf("\033[u"); printf("\033[u");
printf("%d/%d", loader.loaded_samples(), loader.total_samples()); printf("%d/%d", loader.loaded_samples(), loader.total_samples());
fflush(stdout); fflush(stdout);
a_conn.enqueue(*samples); audio_client->enqueue(*samples);
} }
printf("\n"); printf("\n");
return 0; return 0;

View file

@ -5,15 +5,15 @@
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CEventLoop loop; CEventLoop loop;
AClientConnection a_conn; auto audio_client = AClientConnection::construct();
a_conn.handshake(); audio_client->handshake();
if (argc > 1) { if (argc > 1) {
int new_volume = atoi(argv[1]); int new_volume = atoi(argv[1]);
a_conn.set_main_mix_volume(new_volume); audio_client->set_main_mix_volume(new_volume);
} }
int volume = a_conn.get_main_mix_volume(); int volume = audio_client->get_main_mix_volume();
printf("Volume: %d\n", volume); printf("Volume: %d\n", volume);
return 0; return 0;
} }