diff --git a/Applications/About/main.cpp b/Applications/About/main.cpp index b98b4ca496..045b02681d 100644 --- a/Applications/About/main.cpp +++ b/Applications/About/main.cpp @@ -14,7 +14,7 @@ int main(int argc, char** argv) Rect window_rect { 0, 0, 240, 120 }; window_rect.center_within({ 0, 0, 1024, 768 }); window->set_rect(window_rect); - window->set_should_exit_app_on_close(true); + window->set_should_exit_event_loop_on_close(true); auto* widget = new GWidget; window->set_main_widget(widget); diff --git a/Applications/FileManager/main.cpp b/Applications/FileManager/main.cpp index a3a9eafed3..d7b4ab5c9d 100644 --- a/Applications/FileManager/main.cpp +++ b/Applications/FileManager/main.cpp @@ -29,7 +29,7 @@ int main(int argc, char** argv) auto* window = new GWindow; window->set_title("FileManager"); window->set_rect(20, 200, 640, 480); - window->set_should_exit_app_on_close(true); + window->set_should_exit_event_loop_on_close(true); auto* widget = new GWidget; widget->set_layout(make(Orientation::Vertical)); diff --git a/Applications/FontEditor/main.cpp b/Applications/FontEditor/main.cpp index bf0511e6da..36f5e1d402 100644 --- a/Applications/FontEditor/main.cpp +++ b/Applications/FontEditor/main.cpp @@ -29,7 +29,7 @@ int main(int argc, char** argv) window->set_rect({ 50, 50, 420, 300 }); auto* font_editor = new FontEditorWidget(path, move(edited_font)); window->set_main_widget(font_editor); - window->set_should_exit_app_on_close(true); + window->set_should_exit_event_loop_on_close(true); window->show(); return app.exec(); } diff --git a/Applications/IRCClient/IRCAppWindow.cpp b/Applications/IRCClient/IRCAppWindow.cpp index d61e56fcf3..1b431ecbd6 100644 --- a/Applications/IRCClient/IRCAppWindow.cpp +++ b/Applications/IRCClient/IRCAppWindow.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include IRCAppWindow::IRCAppWindow() @@ -40,6 +41,9 @@ void IRCAppWindow::setup_client() }; m_client.on_connect = [this] { + GMessageBox box("We are connected!", "Message"); + int code = box.exec(); + dbgprintf("GMessageBox::exec() returned %d\n", code); m_client.join_channel("#test"); }; diff --git a/Applications/Launcher/main.cpp b/Applications/Launcher/main.cpp index 44aca4d460..616df66b0b 100644 --- a/Applications/Launcher/main.cpp +++ b/Applications/Launcher/main.cpp @@ -27,7 +27,7 @@ int main(int argc, char** argv) signal(SIGCHLD, handle_sigchld); auto* launcher_window = make_launcher_window(); - launcher_window->set_should_exit_app_on_close(true); + launcher_window->set_should_exit_event_loop_on_close(true); launcher_window->show(); return app.exec(); diff --git a/Applications/ProcessManager/main.cpp b/Applications/ProcessManager/main.cpp index 14008e63b7..38bfdde050 100644 --- a/Applications/ProcessManager/main.cpp +++ b/Applications/ProcessManager/main.cpp @@ -71,7 +71,7 @@ int main(int argc, char** argv) window->set_title("ProcessManager"); window->set_rect(20, 200, 640, 400); window->set_main_widget(widget); - window->set_should_exit_app_on_close(true); + window->set_should_exit_event_loop_on_close(true); window->show(); return app.exec(); diff --git a/Applications/Terminal/main.cpp b/Applications/Terminal/main.cpp index 808b14e9b3..a3cba5d296 100644 --- a/Applications/Terminal/main.cpp +++ b/Applications/Terminal/main.cpp @@ -89,7 +89,7 @@ int main(int argc, char** argv) auto* window = new GWindow; window->set_double_buffering_enabled(false); - window->set_should_exit_app_on_close(true); + window->set_should_exit_event_loop_on_close(true); Terminal terminal(ptm_fd); window->set_has_alpha_channel(true); diff --git a/Applications/TextEditor/main.cpp b/Applications/TextEditor/main.cpp index 4df7073241..16023de124 100644 --- a/Applications/TextEditor/main.cpp +++ b/Applications/TextEditor/main.cpp @@ -136,7 +136,7 @@ int main(int argc, char** argv) window->set_title(String::format("TextEditor: %s", path.characters())); window->set_rect(20, 200, 640, 400); window->set_main_widget(widget); - window->set_should_exit_app_on_close(true); + window->set_should_exit_event_loop_on_close(true); text_editor->set_focus(true); window->show(); diff --git a/Kernel/makeall.sh b/Kernel/makeall.sh index 2929983813..d246871f3f 100755 --- a/Kernel/makeall.sh +++ b/Kernel/makeall.sh @@ -12,12 +12,12 @@ $make_cmd -C ../LibM && \ (cd ../LibM && ./install.sh) && \ $make_cmd -C ../LibM clean && \ $make_cmd -C ../LibM clean && \ +$make_cmd -C ../WindowServer clean && \ +$make_cmd -C ../WindowServer && \ $make_cmd -C ../LibGUI clean && \ $make_cmd -C ../LibGUI && \ $make_cmd -C ../Userland clean && \ $make_cmd -C ../Userland && \ -$make_cmd -C ../WindowServer clean && \ -$make_cmd -C ../WindowServer && \ $make_cmd -C ../Applications/Terminal clean && \ $make_cmd -C ../Applications/Terminal && \ $make_cmd -C ../Applications/FontEditor clean && \ diff --git a/LibGUI/GBoxLayout.cpp b/LibGUI/GBoxLayout.cpp index 9abea5ed62..8e5ecad875 100644 --- a/LibGUI/GBoxLayout.cpp +++ b/LibGUI/GBoxLayout.cpp @@ -37,7 +37,8 @@ void GBoxLayout::run(GWidget& widget) should_log = true; #endif if (should_log) - printf("GBoxLayout: running layout on %s{%p}\n", widget.class_name(), &widget); + printf("GBoxLayout: running layout on %s{%p}, entry count: %d\n", widget.class_name(), &widget, m_entries.size()); + if (m_entries.is_empty()) return; diff --git a/LibGUI/GButton.cpp b/LibGUI/GButton.cpp index 4b1a35b988..9023aaac19 100644 --- a/LibGUI/GButton.cpp +++ b/LibGUI/GButton.cpp @@ -13,11 +13,11 @@ GButton::~GButton() { } -void GButton::set_caption(String&& caption) +void GButton::set_caption(const String& caption) { if (caption == m_caption) return; - m_caption = move(caption); + m_caption = caption; update(); } diff --git a/LibGUI/GButton.h b/LibGUI/GButton.h index d5897a5d7a..3e76476d15 100644 --- a/LibGUI/GButton.h +++ b/LibGUI/GButton.h @@ -12,7 +12,7 @@ public: virtual ~GButton() override; String caption() const { return m_caption; } - void set_caption(String&&); + void set_caption(const String&); void set_icon(RetainPtr&& icon) { m_icon = move(icon); } const GraphicsBitmap* icon() const { return m_icon.ptr(); } diff --git a/LibGUI/GClipboard.cpp b/LibGUI/GClipboard.cpp index d6fe9efba3..9a349a157d 100644 --- a/LibGUI/GClipboard.cpp +++ b/LibGUI/GClipboard.cpp @@ -19,7 +19,7 @@ String GClipboard::data() const { WSAPI_ClientMessage request; request.type = WSAPI_ClientMessage::Type::GetClipboardContents; - auto response = GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidGetClipboardContents); + auto response = GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidGetClipboardContents); if (response.clipboard.shared_buffer_id < 0) return { }; auto shared_buffer = SharedBuffer::create_from_shared_buffer_id(response.clipboard.shared_buffer_id); @@ -38,7 +38,7 @@ void GClipboard::set_data(const String& data) { WSAPI_ClientMessage request; request.type = WSAPI_ClientMessage::Type::SetClipboardContents; - auto shared_buffer = SharedBuffer::create(GEventLoop::main().server_pid(), data.length() + 1); + auto shared_buffer = SharedBuffer::create(GEventLoop::current().server_pid(), data.length() + 1); if (!shared_buffer) { dbgprintf("GClipboard::set_data() failed to create a shared buffer\n"); return; @@ -50,6 +50,6 @@ void GClipboard::set_data(const String& data) shared_buffer->seal(); request.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id(); request.clipboard.contents_size = data.length(); - auto response = GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidSetClipboardContents); + auto response = GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidSetClipboardContents); ASSERT(response.clipboard.shared_buffer_id == shared_buffer->shared_buffer_id()); } diff --git a/LibGUI/GDialog.cpp b/LibGUI/GDialog.cpp new file mode 100644 index 0000000000..97f0c103c6 --- /dev/null +++ b/LibGUI/GDialog.cpp @@ -0,0 +1,26 @@ +#include +#include + +GDialog::GDialog(GObject* parent) + : GWindow(parent) +{ + set_modal(true); + set_should_exit_event_loop_on_close(true); +} + +GDialog::~GDialog() +{ +} + +int GDialog::exec() +{ + GEventLoop loop; + show(); + return loop.exec(); +} + +void GDialog::done(int result) +{ + m_result = result; + GEventLoop::current().quit(result); +} diff --git a/LibGUI/GDialog.h b/LibGUI/GDialog.h new file mode 100644 index 0000000000..9dcf88a772 --- /dev/null +++ b/LibGUI/GDialog.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +class GDialog : public GWindow { +public: + virtual ~GDialog() override; + + int exec(); + + int result() const { return m_result; } + void done(int result); + +protected: + explicit GDialog(GObject* parent); + +private: + int m_result { 0 }; +}; diff --git a/LibGUI/GEventLoop.cpp b/LibGUI/GEventLoop.cpp index 2015a65ae7..ed9aba0726 100644 --- a/LibGUI/GEventLoop.cpp +++ b/LibGUI/GEventLoop.cpp @@ -21,11 +21,16 @@ static HashMap* g_actions; static GEventLoop* s_main_event_loop; +static Vector* s_event_loop_stack; int GEventLoop::s_event_fd = -1; pid_t GEventLoop::s_server_pid = -1; +HashMap>* GEventLoop::s_timers; +HashTable* GEventLoop::s_notifiers; +int GEventLoop::s_next_timer_id = 1; void GEventLoop::connect_to_server() { + ASSERT(s_event_fd == -1); s_event_fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); if (s_event_fd < 0) { perror("socket"); @@ -51,12 +56,25 @@ void GEventLoop::connect_to_server() if (rc < 0) { ASSERT_NOT_REACHED(); } + + WSAPI_ClientMessage request; + request.type = WSAPI_ClientMessage::Type::Greeting; + request.greeting.client_pid = getpid(); + auto response = sync_request(request, WSAPI_ServerMessage::Type::Greeting); + s_server_pid = response.greeting.server_pid; } GEventLoop::GEventLoop() { + if (!s_event_loop_stack) { + s_event_loop_stack = new Vector; + s_timers = new HashMap>; + s_notifiers = new HashTable; + } + if (!s_main_event_loop) { s_main_event_loop = this; + s_event_loop_stack->append(this); connect_to_server(); } @@ -78,14 +96,41 @@ GEventLoop& GEventLoop::main() return *s_main_event_loop; } +GEventLoop& GEventLoop::current() +{ + return *s_event_loop_stack->last(); +} + void GEventLoop::quit(int code) { m_exit_requested = true; m_exit_code = code; } +struct GEventLoopPusher { +public: + GEventLoopPusher(GEventLoop& event_loop) : m_event_loop(event_loop) + { + if (&m_event_loop != s_main_event_loop) { + m_event_loop.take_pending_events_from(GEventLoop::current()); + s_event_loop_stack->append(&event_loop); + } + } + ~GEventLoopPusher() + { + if (&m_event_loop != s_main_event_loop) { + s_event_loop_stack->take_last(); + GEventLoop::current().take_pending_events_from(m_event_loop); + } + } +private: + GEventLoop& m_event_loop; +}; + int GEventLoop::exec() { + GEventLoopPusher pusher(*this); + m_running = true; for (;;) { if (m_exit_requested) @@ -228,7 +273,7 @@ void GEventLoop::wait_for_event() }; add_fd_to_set(s_event_fd, rfds); - for (auto& notifier : m_notifiers) { + for (auto& notifier : *s_notifiers) { if (notifier->event_mask() & GNotifier::Read) add_fd_to_set(notifier->fd(), rfds); if (notifier->event_mask() & GNotifier::Write) @@ -238,15 +283,15 @@ void GEventLoop::wait_for_event() } struct timeval timeout = { 0, 0 }; - if (!m_timers.is_empty() && m_queued_events.is_empty()) + if (!s_timers->is_empty() && m_queued_events.is_empty()) get_next_timer_expiration(timeout); ASSERT(m_unprocessed_messages.is_empty()); - int rc = select(max_fd + 1, &rfds, &wfds, nullptr, (m_queued_events.is_empty() && m_timers.is_empty()) ? nullptr : &timeout); + int rc = select(max_fd + 1, &rfds, &wfds, nullptr, (m_queued_events.is_empty() && s_timers->is_empty()) ? nullptr : &timeout); if (rc < 0) { ASSERT_NOT_REACHED(); } - for (auto& it : m_timers) { + for (auto& it : *s_timers) { auto& timer = *it.value; if (!timer.has_expired()) continue; @@ -262,7 +307,7 @@ void GEventLoop::wait_for_event() } } - for (auto& notifier : m_notifiers) { + for (auto& notifier : *s_notifiers) { if (FD_ISSET(notifier->fd(), &rfds)) { if (notifier->on_ready_to_read) notifier->on_ready_to_read(*notifier); @@ -378,9 +423,9 @@ void GEventLoop::EventLoopTimer::reload() void GEventLoop::get_next_timer_expiration(timeval& soonest) { - ASSERT(!m_timers.is_empty()); + ASSERT(!s_timers->is_empty()); bool has_checked_any = false; - for (auto& it : m_timers) { + for (auto& it : *s_timers) { auto& fire_time = it.value->fire_time; if (!has_checked_any || fire_time.tv_sec < soonest.tv_sec || (fire_time.tv_sec == soonest.tv_sec && fire_time.tv_usec < soonest.tv_usec)) soonest = fire_time; @@ -396,30 +441,30 @@ int GEventLoop::register_timer(GObject& object, int milliseconds, bool should_re timer->interval = milliseconds; timer->reload(); timer->should_reload = should_reload; - int timer_id = ++m_next_timer_id; // FIXME: This will eventually wrap around. + int timer_id = ++s_next_timer_id; // FIXME: This will eventually wrap around. ASSERT(timer_id); // FIXME: Aforementioned wraparound. timer->timer_id = timer_id; - m_timers.set(timer->timer_id, move(timer)); + s_timers->set(timer->timer_id, move(timer)); return timer_id; } bool GEventLoop::unregister_timer(int timer_id) { - auto it = m_timers.find(timer_id); - if (it == m_timers.end()) + auto it = s_timers->find(timer_id); + if (it == s_timers->end()) return false; - m_timers.remove(it); + s_timers->remove(it); return true; } void GEventLoop::register_notifier(Badge, GNotifier& notifier) { - m_notifiers.set(¬ifier); + s_notifiers->set(¬ifier); } void GEventLoop::unregister_notifier(Badge, GNotifier& notifier) { - m_notifiers.remove(¬ifier); + s_notifiers->remove(¬ifier); } bool GEventLoop::post_message_to_server(const WSAPI_ClientMessage& message) @@ -456,7 +501,7 @@ WSAPI_ServerMessage GEventLoop::sync_request(const WSAPI_ClientMessage& request, ASSERT(success); WSAPI_ServerMessage response; - success = GEventLoop::main().wait_for_specific_event(response_type, response); + success = wait_for_specific_event(response_type, response); ASSERT(success); return response; } diff --git a/LibGUI/GEventLoop.h b/LibGUI/GEventLoop.h index 325115e70a..14ea43bd41 100644 --- a/LibGUI/GEventLoop.h +++ b/LibGUI/GEventLoop.h @@ -23,14 +23,15 @@ public: void post_event(GObject& receiver, OwnPtr&&); static GEventLoop& main(); + static GEventLoop& current(); bool running() const { return m_running; } - int register_timer(GObject&, int milliseconds, bool should_reload); - bool unregister_timer(int timer_id); + static int register_timer(GObject&, int milliseconds, bool should_reload); + static bool unregister_timer(int timer_id); - void register_notifier(Badge, GNotifier&); - void unregister_notifier(Badge, GNotifier&); + static void register_notifier(Badge, GNotifier&); + static void unregister_notifier(Badge, GNotifier&); void quit(int); @@ -41,6 +42,12 @@ public: static pid_t server_pid() { return s_server_pid; } + void take_pending_events_from(GEventLoop& other) + { + m_queued_events.append(move(other.m_queued_events)); + m_unprocessed_messages.append(move(other.m_unprocessed_messages)); + } + private: void wait_for_event(); bool drain_messages_from_server(); @@ -67,7 +74,6 @@ private: bool m_running { false }; bool m_exit_requested { false }; int m_exit_code { 0 }; - int m_next_timer_id { 1 }; static pid_t s_server_pid; static pid_t s_event_fd; @@ -83,6 +89,8 @@ private: bool has_expired() const; }; - HashMap> m_timers; - HashTable m_notifiers; + static HashMap>* s_timers; + static int s_next_timer_id; + + static HashTable* s_notifiers; }; diff --git a/LibGUI/GMenu.cpp b/LibGUI/GMenu.cpp index 69ecad518d..54712228ce 100644 --- a/LibGUI/GMenu.cpp +++ b/LibGUI/GMenu.cpp @@ -46,7 +46,7 @@ int GMenu::realize_menu() ASSERT(m_name.length() < (ssize_t)sizeof(request.text)); strcpy(request.text, m_name.characters()); request.text_length = m_name.length(); - auto response = GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidCreateMenu); + auto response = GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidCreateMenu); m_menu_id = response.menu.menu_id; ASSERT(m_menu_id > 0); @@ -56,7 +56,7 @@ int GMenu::realize_menu() WSAPI_ClientMessage request; request.type = WSAPI_ClientMessage::Type::AddMenuSeparator; request.menu.menu_id = m_menu_id; - GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidAddMenuSeparator); + GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidAddMenuSeparator); continue; } if (item.type() == GMenuItem::Action) { @@ -78,7 +78,7 @@ int GMenu::realize_menu() request.menu.shortcut_text_length = 0; } - GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidAddMenuItem); + GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidAddMenuItem); } } all_menus().set(m_menu_id, this); @@ -93,7 +93,7 @@ void GMenu::unrealize_menu() WSAPI_ClientMessage request; request.type = WSAPI_ClientMessage::Type::DestroyMenu; request.menu.menu_id = m_menu_id; - GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidDestroyMenu); + GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidDestroyMenu); m_menu_id = 0; } diff --git a/LibGUI/GMenuBar.cpp b/LibGUI/GMenuBar.cpp index 1cce445e69..8befe45944 100644 --- a/LibGUI/GMenuBar.cpp +++ b/LibGUI/GMenuBar.cpp @@ -19,7 +19,7 @@ int GMenuBar::realize_menubar() { WSAPI_ClientMessage request; request.type = WSAPI_ClientMessage::Type::CreateMenubar; - WSAPI_ServerMessage response = GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidCreateMenubar); + WSAPI_ServerMessage response = GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidCreateMenubar); return response.menu.menubar_id; } @@ -30,7 +30,7 @@ void GMenuBar::unrealize_menubar() WSAPI_ClientMessage request; request.type = WSAPI_ClientMessage::Type::DestroyMenubar; request.menu.menubar_id = m_menubar_id; - GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidDestroyMenubar); + GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidDestroyMenubar); m_menubar_id = 0; } @@ -47,12 +47,12 @@ void GMenuBar::notify_added_to_application(Badge) request.type = WSAPI_ClientMessage::Type::AddMenuToMenubar; request.menu.menubar_id = m_menubar_id; request.menu.menu_id = menu_id; - GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidAddMenuToMenubar); + GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidAddMenuToMenubar); } WSAPI_ClientMessage request; request.type = WSAPI_ClientMessage::Type::SetApplicationMenubar; request.menu.menubar_id = m_menubar_id; - GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidSetApplicationMenubar); + GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidSetApplicationMenubar); } void GMenuBar::notify_removed_from_application(Badge) diff --git a/LibGUI/GMessageBox.cpp b/LibGUI/GMessageBox.cpp new file mode 100644 index 0000000000..8f97cca5bd --- /dev/null +++ b/LibGUI/GMessageBox.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +GMessageBox::GMessageBox(const String& text, const String& title, GObject* parent) + : GDialog(parent) + , m_text(text) +{ + set_title(title); + build(); +} + +GMessageBox::~GMessageBox() +{ +} + +void GMessageBox::build() +{ + auto* widget = new GWidget; + set_main_widget(widget); + + int text_width = widget->font().width(m_text); + + set_rect(x(), y(), text_width + 80, 80); + + widget->set_layout(make(Orientation::Vertical)); + widget->set_fill_with_background_color(true); + + widget->layout()->set_margins({ 0, 15, 0, 15 }); + widget->layout()->set_spacing(15); + + auto* label = new GLabel(m_text, widget); + label->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed); + label->set_preferred_size({ text_width, 16 }); + + auto* button = new GButton(widget); + button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed); + button->set_preferred_size({ 100, 16 }); + button->set_caption("OK"); + button->on_click = [this] (auto&) { + dbgprintf("OK button clicked\n"); + done(0); + }; +} diff --git a/LibGUI/GMessageBox.h b/LibGUI/GMessageBox.h new file mode 100644 index 0000000000..fbbc371fba --- /dev/null +++ b/LibGUI/GMessageBox.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +class GMessageBox : public GDialog { +public: + explicit GMessageBox(const String& text, const String& title, GObject* parent = nullptr); + virtual ~GMessageBox() override; + + String text() const { return m_text; } + + void build(); + +private: + String m_text; +}; diff --git a/LibGUI/GNotifier.cpp b/LibGUI/GNotifier.cpp index 1d5ad6c816..649cc84bcc 100644 --- a/LibGUI/GNotifier.cpp +++ b/LibGUI/GNotifier.cpp @@ -5,11 +5,11 @@ GNotifier::GNotifier(int fd, unsigned event_mask) : m_fd(fd) , m_event_mask(event_mask) { - GEventLoop::main().register_notifier(Badge(), *this); + GEventLoop::register_notifier(Badge(), *this); } GNotifier::~GNotifier() { - GEventLoop::main().unregister_notifier(Badge(), *this); + GEventLoop::unregister_notifier(Badge(), *this); } diff --git a/LibGUI/GObject.cpp b/LibGUI/GObject.cpp index 1d2c59b427..4dbbe4bc0b 100644 --- a/LibGUI/GObject.cpp +++ b/LibGUI/GObject.cpp @@ -2,6 +2,7 @@ #include "GEvent.h" #include "GEventLoop.h" #include +#include GObject::GObject(GObject* parent) : m_parent(parent) @@ -42,7 +43,7 @@ void GObject::event(GEvent& event) void GObject::add_child(GObject& object) { m_children.append(&object); - GEventLoop::main().post_event(*this, make(GEvent::ChildAdded, object)); + GEventLoop::current().post_event(*this, make(GEvent::ChildAdded, object)); } void GObject::remove_child(GObject& object) @@ -50,7 +51,7 @@ void GObject::remove_child(GObject& object) for (ssize_t i = 0; i < m_children.size(); ++i) { if (m_children[i] == &object) { m_children.remove(i); - GEventLoop::main().post_event(*this, make(GEvent::ChildRemoved, object)); + GEventLoop::current().post_event(*this, make(GEvent::ChildRemoved, object)); return; } } @@ -71,20 +72,32 @@ void GObject::start_timer(int ms) ASSERT_NOT_REACHED(); } - m_timer_id = GEventLoop::main().register_timer(*this, ms, true); + m_timer_id = GEventLoop::register_timer(*this, ms, true); } void GObject::stop_timer() { if (!m_timer_id) return; - bool success = GEventLoop::main().unregister_timer(m_timer_id); + bool success = GEventLoop::unregister_timer(m_timer_id); ASSERT(success); m_timer_id = 0; } void GObject::delete_later() { - GEventLoop::main().post_event(*this, make(GEvent::DeferredDestroy)); + GEventLoop::current().post_event(*this, make(GEvent::DeferredDestroy)); } +void GObject::dump_tree(int indent) +{ + for (int i = 0; i < indent; ++i) { + printf(" "); + } + printf("%s{%p}\n", class_name(), this); + + for (auto* child : children()) { + child->dump_tree(indent + 2); + } + +} diff --git a/LibGUI/GObject.h b/LibGUI/GObject.h index b1f24462fe..694112dace 100644 --- a/LibGUI/GObject.h +++ b/LibGUI/GObject.h @@ -30,6 +30,8 @@ public: void delete_later(); + void dump_tree(int indent = 0); + virtual bool is_widget() const { return false; } protected: diff --git a/LibGUI/GWindow.cpp b/LibGUI/GWindow.cpp index 8486489f16..3dd4b9557a 100644 --- a/LibGUI/GWindow.cpp +++ b/LibGUI/GWindow.cpp @@ -44,10 +44,8 @@ GWindow::~GWindow() void GWindow::close() { - // FIXME: If we exit the event loop, we're never gonna deal with the delete_later request! - // This will become relevant once we support nested event loops. - if (should_exit_app_on_close()) - GEventLoop::main().quit(0); + if (should_exit_event_loop_on_close()) + GEventLoop::current().quit(0); delete_later(); } @@ -67,7 +65,7 @@ void GWindow::show() ASSERT(m_title_when_windowless.length() < (ssize_t)sizeof(request.text)); strcpy(request.text, m_title_when_windowless.characters()); request.text_length = m_title_when_windowless.length(); - auto response = GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidCreateWindow); + auto response = GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidCreateWindow); m_window_id = response.window_id; windows().set(m_window_id, this); @@ -82,12 +80,12 @@ void GWindow::hide() WSAPI_ClientMessage request; request.type = WSAPI_ClientMessage::Type::DestroyWindow; request.window_id = m_window_id; - GEventLoop::main().post_message_to_server(request); + GEventLoop::current().post_message_to_server(request); } -void GWindow::set_title(String&& title) +void GWindow::set_title(const String& title) { - m_title_when_windowless = move(title); + m_title_when_windowless = title; if (!m_window_id) return; @@ -97,7 +95,7 @@ void GWindow::set_title(String&& title) ASSERT(m_title_when_windowless.length() < (ssize_t)sizeof(request.text)); strcpy(request.text, m_title_when_windowless.characters()); request.text_length = m_title_when_windowless.length(); - GEventLoop::main().post_message_to_server(request); + GEventLoop::current().post_message_to_server(request); } String GWindow::title() const @@ -108,7 +106,7 @@ String GWindow::title() const WSAPI_ClientMessage request; request.type = WSAPI_ClientMessage::Type::GetWindowTitle; request.window_id = m_window_id; - auto response = GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidGetWindowTitle); + auto response = GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidGetWindowTitle); return String(response.text, response.text_length); } @@ -120,7 +118,7 @@ Rect GWindow::rect() const WSAPI_ClientMessage request; request.type = WSAPI_ClientMessage::Type::GetWindowRect; request.window_id = m_window_id; - auto response = GEventLoop::main().sync_request(request, WSAPI_ServerMessage::Type::DidGetWindowRect); + auto response = GEventLoop::current().sync_request(request, WSAPI_ServerMessage::Type::DidGetWindowRect); ASSERT(response.window_id == m_window_id); return response.window.rect; } @@ -128,13 +126,16 @@ Rect GWindow::rect() const void GWindow::set_rect(const Rect& a_rect) { m_rect_when_windowless = a_rect; - if (!m_window_id) + if (!m_window_id) { + if (m_main_widget) + m_main_widget->resize(m_rect_when_windowless.size()); return; + } WSAPI_ClientMessage request; request.type = WSAPI_ClientMessage::Type::SetWindowRect; request.window_id = m_window_id; request.window.rect = a_rect; - GEventLoop::main().post_message_to_server(request); + GEventLoop::current().post_message_to_server(request); } void GWindow::event(GEvent& event) @@ -185,7 +186,7 @@ void GWindow::event(GEvent& event) message.type = WSAPI_ClientMessage::Type::DidFinishPainting; message.window_id = m_window_id; message.window.rect = rect; - GEventLoop::main().post_message_to_server(message); + GEventLoop::current().post_message_to_server(message); } return; } @@ -255,7 +256,7 @@ void GWindow::update(const Rect& a_rect) request.type = WSAPI_ClientMessage::Type::InvalidateRect; request.window_id = m_window_id; request.window.rect = a_rect; - GEventLoop::main().post_message_to_server(request); + GEventLoop::current().post_message_to_server(request); } void GWindow::set_main_widget(GWidget* widget) @@ -283,12 +284,12 @@ void GWindow::set_focused_widget(GWidget* widget) if (m_focused_widget == widget) return; if (m_focused_widget) { - GEventLoop::main().post_event(*m_focused_widget, make(GEvent::FocusOut)); + GEventLoop::current().post_event(*m_focused_widget, make(GEvent::FocusOut)); m_focused_widget->update(); } m_focused_widget = widget; if (m_focused_widget) { - GEventLoop::main().post_event(*m_focused_widget, make(GEvent::FocusIn)); + GEventLoop::current().post_event(*m_focused_widget, make(GEvent::FocusIn)); m_focused_widget->update(); } } @@ -306,7 +307,7 @@ void GWindow::set_global_cursor_tracking_widget(GWidget* widget) request.value = widget != nullptr; // FIXME: What if the cursor moves out of our interest range before the server can handle this? // Maybe there could be a response that includes the current cursor location as of enabling. - GEventLoop::main().post_message_to_server(request); + GEventLoop::current().post_message_to_server(request); } void GWindow::set_has_alpha_channel(bool value) @@ -331,7 +332,7 @@ void GWindow::set_opacity(float opacity) request.window_id = m_window_id; request.window.opacity = opacity; m_opacity_when_windowless = opacity; - GEventLoop::main().post_message_to_server(request); + GEventLoop::current().post_message_to_server(request); } void GWindow::set_hovered_widget(GWidget* widget) @@ -340,12 +341,12 @@ void GWindow::set_hovered_widget(GWidget* widget) return; if (m_hovered_widget) - GEventLoop::main().post_event(*m_hovered_widget, make(GEvent::Leave)); + GEventLoop::current().post_event(*m_hovered_widget, make(GEvent::Leave)); m_hovered_widget = widget ? widget->make_weak_ptr() : nullptr; if (m_hovered_widget) - GEventLoop::main().post_event(*m_hovered_widget, make(GEvent::Enter)); + GEventLoop::current().post_event(*m_hovered_widget, make(GEvent::Enter)); } void GWindow::set_current_backing_bitmap(GraphicsBitmap& bitmap, bool flush_immediately) @@ -359,7 +360,7 @@ void GWindow::set_current_backing_bitmap(GraphicsBitmap& bitmap, bool flush_imme message.backing.has_alpha_channel = bitmap.has_alpha_channel(); message.backing.size = bitmap.size(); message.backing.flush_immediately = flush_immediately; - GEventLoop::main().sync_request(message, WSAPI_ServerMessage::Type::DidSetWindowBackingStore); + GEventLoop::current().sync_request(message, WSAPI_ServerMessage::Type::DidSetWindowBackingStore); } void GWindow::flip(const Rect& dirty_rect) @@ -389,3 +390,9 @@ Retained GWindow::create_backing_bitmap(const Size& size) auto format = m_has_alpha_channel ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32; return GraphicsBitmap::create_with_shared_buffer(format, *shared_buffer, size); } + +void GWindow::set_modal(bool modal) +{ + ASSERT(!m_window_id); + m_modal = modal; +} diff --git a/LibGUI/GWindow.h b/LibGUI/GWindow.h index 16abab6cbf..3874887c5f 100644 --- a/LibGUI/GWindow.h +++ b/LibGUI/GWindow.h @@ -15,6 +15,9 @@ public: static GWindow* from_window_id(int); + bool is_modal() const { return m_modal; } + void set_modal(bool); + void set_double_buffering_enabled(bool); void set_has_alpha_channel(bool); void set_opacity(float); @@ -22,7 +25,7 @@ public: int window_id() const { return m_window_id; } String title() const; - void set_title(String&&); + void set_title(const String&); int x() const { return rect().x(); } int y() const { return rect().y(); } @@ -62,8 +65,8 @@ public: GWidget* global_cursor_tracking_widget() { return m_global_cursor_tracking_widget.ptr(); } const GWidget* global_cursor_tracking_widget() const { return m_global_cursor_tracking_widget.ptr(); } - bool should_exit_app_on_close() const { return m_should_exit_app_on_close; } - void set_should_exit_app_on_close(bool b) { m_should_exit_app_on_close = b; } + bool should_exit_event_loop_on_close() const { return m_should_exit_app_on_close; } + void set_should_exit_event_loop_on_close(bool b) { m_should_exit_app_on_close = b; } GWidget* hovered_widget() { return m_hovered_widget.ptr(); } const GWidget* hovered_widget() const { return m_hovered_widget.ptr(); } @@ -101,5 +104,6 @@ private: bool m_should_exit_app_on_close { false }; bool m_has_alpha_channel { false }; bool m_double_buffering_enabled { true }; + bool m_modal { false }; }; diff --git a/LibGUI/Makefile b/LibGUI/Makefile index 098c3cf779..025391745a 100644 --- a/LibGUI/Makefile +++ b/LibGUI/Makefile @@ -42,6 +42,8 @@ LIBGUI_OBJS = \ GScrollableWidget.o \ GSocket.o \ GTCPSocket.o \ + GMessageBox.o \ + GDialog.o \ GWindow.o OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS) diff --git a/Userland/guitest2.cpp b/Userland/guitest2.cpp index f91cf451e7..4e8e593b67 100644 --- a/Userland/guitest2.cpp +++ b/Userland/guitest2.cpp @@ -35,7 +35,7 @@ int main(int argc, char** argv) signal(SIGCHLD, handle_sigchld); auto* launcher_window = make_launcher_window(); - launcher_window->set_should_exit_app_on_close(true); + launcher_window->set_should_exit_event_loop_on_close(true); launcher_window->show(); return app.exec(); diff --git a/WindowServer/WSAPITypes.h b/WindowServer/WSAPITypes.h index bcf075cca9..65dce5e0af 100644 --- a/WindowServer/WSAPITypes.h +++ b/WindowServer/WSAPITypes.h @@ -164,6 +164,7 @@ struct WSAPI_ClientMessage { SetWindowBackingStore, GetClipboardContents, SetClipboardContents, + Greeting, }; Type type { Invalid }; int window_id { -1 }; @@ -172,6 +173,9 @@ struct WSAPI_ClientMessage { int value { 0 }; union { + struct { + int client_pid; + } greeting; struct { int menubar_id; int menu_id;