From 02c72e15d5fbfef41d7413f664169b5b39f24067 Mon Sep 17 00:00:00 2001 From: apio Date: Tue, 15 Aug 2023 11:20:17 +0200 Subject: [PATCH] wind+libui: Add protocol for window close requests --- apps/gclient.cpp | 19 +++++++-------- libui/include/ui/App.h | 22 ++++++++++++++++++ libui/include/ui/Window.h | 9 ++++++- libui/include/ui/ipc/Client.h | 8 +++++++ libui/include/ui/ipc/Server.h | 8 +++++++ libui/src/App.cpp | 44 +++++++++++++++++++++++++++++++++++ libui/src/Window.cpp | 21 +++++++++++++++-- wind/IPC.cpp | 40 +++++++++++++++++++++++-------- wind/Mouse.cpp | 10 +++++--- wind/Window.h | 4 ++++ wind/main.cpp | 7 ++++-- 11 files changed, 163 insertions(+), 29 deletions(-) diff --git a/apps/gclient.cpp b/apps/gclient.cpp index 3d9558a8..52f224ce 100644 --- a/apps/gclient.cpp +++ b/apps/gclient.cpp @@ -1,24 +1,21 @@ -#include #include -#include -#include - -Result handle_ipc_client_event(os::LocalClient&, u8) -{ - todo(); -} Result luna_main(int argc, char** argv) { ui::App app; TRY(app.init(argc, argv)); - auto window = TRY(ui::Window::create(ui::Rect { 200, 200, 400, 300 })); - os::println("gclient: Created new window!"); + auto* window = TRY(ui::Window::create(ui::Rect { 200, 200, 400, 300 })); + app.set_main_window(window); - window->set_title("Example Window"); + window->set_title("Main Window"); window->canvas().fill(ui::CYAN); window->update(); + auto* dialog = TRY(ui::Window::create(ui::Rect { 400, 400, 200, 150 })); + dialog->set_title("Error: Unknown Error"); + dialog->canvas().fill(ui::RED); + dialog->update(); + return app.run(); } diff --git a/libui/include/ui/App.h b/libui/include/ui/App.h index 1f3b899f..0e1e1262 100644 --- a/libui/include/ui/App.h +++ b/libui/include/ui/App.h @@ -8,7 +8,9 @@ */ #pragma once +#include #include +#include namespace ui { @@ -31,11 +33,31 @@ namespace ui m_should_close = b; } + void set_main_window(Window* window) + { + check(!m_main_window); + m_main_window = window; + } + + Window* main_window() + { + return m_main_window; + } + + Result register_window(OwnedPtr&& window, Badge); + void unregister_window(Window* window, Badge); + + Result handle_ipc_event(u8 id); + static App& the(); private: static App* s_app; OwnedPtr m_client; + Window* m_main_window { nullptr }; + HashMap> m_windows; bool m_should_close { false }; + + Window* find_window(int id); }; } diff --git a/libui/include/ui/Window.h b/libui/include/ui/Window.h index 0c0dae1c..bf13d32b 100644 --- a/libui/include/ui/Window.h +++ b/libui/include/ui/Window.h @@ -18,7 +18,7 @@ namespace ui class Window { public: - static Result> create(Rect rect); + static Result create(Rect rect); void set_title(StringView title); @@ -29,6 +29,13 @@ namespace ui void update(); + void close(); + + int id() const + { + return m_id; + } + ~Window(); private: diff --git a/libui/include/ui/ipc/Client.h b/libui/include/ui/ipc/Client.h index 3320c796..35fbbef9 100644 --- a/libui/include/ui/ipc/Client.h +++ b/libui/include/ui/ipc/Client.h @@ -16,6 +16,7 @@ namespace ui { IPC_ENUM_CLIENT(ui), CREATE_WINDOW_RESPONSE_ID, + WINDOW_CLOSE_REQUEST_ID, }; struct CreateWindowResponse @@ -25,4 +26,11 @@ namespace ui int window; IPC_STRING(shm_path); }; + + struct WindowCloseRequest + { + static constexpr u8 ID = WINDOW_CLOSE_REQUEST_ID; + + int window; + }; } diff --git a/libui/include/ui/ipc/Server.h b/libui/include/ui/ipc/Server.h index 5cde93e9..cd18e336 100644 --- a/libui/include/ui/ipc/Server.h +++ b/libui/include/ui/ipc/Server.h @@ -21,6 +21,7 @@ namespace ui CREATE_WINDOW_ID, SET_WINDOW_TITLE_ID, INVALIDATE_ID, + CLOSE_WINDOW_ID, }; struct CreateWindowRequest @@ -45,4 +46,11 @@ namespace ui int window; }; + + struct CloseWindowRequest + { + static constexpr u8 ID = CLOSE_WINDOW_ID; + + int window; + }; } diff --git a/libui/src/App.cpp b/libui/src/App.cpp index d7686c98..79c00d23 100644 --- a/libui/src/App.cpp +++ b/libui/src/App.cpp @@ -8,8 +8,15 @@ */ #include +#include #include #include +#include + +Result handle_ipc_client_event(os::LocalClient&, u8 id) +{ + return ui::App::the().handle_ipc_event(id); +} namespace ui { @@ -42,6 +49,7 @@ namespace ui Result App::run() { + check(m_main_window); while (!m_should_close) { TRY(os::IPC::check_for_messages(*m_client)); } return 0; } @@ -51,4 +59,40 @@ namespace ui check(s_app); return *s_app; } + + Result App::register_window(OwnedPtr&& window, Badge) + { + int id = window->id(); + check(TRY(m_windows.try_set(id, move(window)))); + return {}; + } + + void App::unregister_window(Window* window, Badge) + { + int id = window->id(); + check(m_windows.try_remove(id)); + } + + Window* App::find_window(int id) + { + auto* window = m_windows.try_get_ref(id); + check(window); + return window->ptr(); + } + + Result App::handle_ipc_event(u8 id) + { + switch (id) + { + case WINDOW_CLOSE_REQUEST_ID: { + WindowCloseRequest request; + TRY(m_client->recv_typed(request)); + os::eprintln("ui: Window close request from server! Shall comply."); + auto* window = find_window(request.window); + window->close(); + return {}; + } + default: fail("Unexpected IPC request from server!"); + } + } } diff --git a/libui/src/Window.cpp b/libui/src/Window.cpp index d56c1941..f1c97b78 100644 --- a/libui/src/Window.cpp +++ b/libui/src/Window.cpp @@ -39,7 +39,7 @@ static Result create_shm_region(const char* path, int* outfd, ui::Rect rec namespace ui { - Result> Window::create(Rect rect) + Result Window::create(Rect rect) { auto window = TRY(make_owned()); @@ -52,7 +52,11 @@ namespace ui window->m_canvas = ui::Canvas { rect.width, rect.height, rect.width, (u8*)pixels }; window->m_id = response.window; - return window; + Window* p = window.ptr(); + + App::the().register_window(move(window), {}); + + return p; } Window::~Window() @@ -74,4 +78,17 @@ namespace ui request.window = m_id; os::IPC::send_async(App::the().client(), request); } + + void Window::close() + { + App& app = App::the(); + + ui::CloseWindowRequest request; + request.window = m_id; + os::IPC::send_async(app.client(), request); + + if (this == app.main_window()) app.set_should_close(true); + + app.unregister_window(this, {}); + } } diff --git a/wind/IPC.cpp b/wind/IPC.cpp index 77392736..3abeedf4 100644 --- a/wind/IPC.cpp +++ b/wind/IPC.cpp @@ -72,6 +72,15 @@ static Result create_shm_region(const char* path, int* outfd, ui::Rect rec } \ } while (0) +#define CHECK_WINDOW_ID(request) \ + do { \ + if ((usize)request.window >= client.windows.size() || !client.windows[request.window]) \ + { \ + os::eprintln("wind: Window id is invalid!"); \ + return {}; \ + } \ + } while (0) + static Result handle_create_window_message(Client& client) { ui::CreateWindowRequest request; @@ -96,6 +105,9 @@ static Result handle_create_window_message(Client& client) TRY_OR_IPC_ERROR(client.windows.try_append(window)); int id = static_cast(client.windows.size() - 1); + window->client = &client; + window->id = id; + ui::CreateWindowResponse response; response.window = id; SET_IPC_STRING(response.shm_path, shm_path.chars()); @@ -112,11 +124,7 @@ static Result handle_set_window_title_message(Client& client) os::println("wind: SetWindowTitle(\"%s\") for window %d", name.chars(), request.window); - if ((usize)request.window >= client.windows.size()) - { - os::eprintln("wind: Window id out of range!"); - return {}; - } + CHECK_WINDOW_ID(request); client.windows[request.window]->name = move(name); @@ -128,17 +136,28 @@ static Result handle_invalidate_message(Client& client) ui::InvalidateRequest request; READ_MESSAGE(request); - if ((usize)request.window >= client.windows.size()) - { - os::eprintln("wind: Window id out of range!"); - return {}; - } + CHECK_WINDOW_ID(request); client.windows[request.window]->dirty = true; return {}; } +static Result handle_close_window_message(Client& client) +{ + ui::CloseWindowRequest request; + READ_MESSAGE(request); + + CHECK_WINDOW_ID(request); + + auto* window = client.windows[request.window]; + client.windows[request.window] = nullptr; + g_windows.remove(window); + delete window; + + return {}; +} + namespace wind { Result handle_ipc_message(Client& client, u8 id) @@ -149,6 +168,7 @@ namespace wind case ui::CREATE_WINDOW_ID: return handle_create_window_message(client); case ui::SET_WINDOW_TITLE_ID: return handle_set_window_title_message(client); case ui::INVALIDATE_ID: return handle_invalidate_message(client); + case ui::CLOSE_WINDOW_ID: return handle_close_window_message(client); default: os::eprintln("wind: Invalid IPC message from client!"); return err(EINVAL); } } diff --git a/wind/Mouse.cpp b/wind/Mouse.cpp index 2d1bb076..63ea0aad 100644 --- a/wind/Mouse.cpp +++ b/wind/Mouse.cpp @@ -1,6 +1,9 @@ #include "Mouse.h" +#include "Client.h" #include +#include #include +#include static SharedPtr g_mouse_cursor; @@ -51,9 +54,10 @@ void Mouse::update(const moon::MousePacket& packet) { if (window->surface.absolute(window->close_button).contains(m_position)) { - // Close button pressed - g_windows.remove(window); - delete window; + ui::WindowCloseRequest request; + request.window = window->id; + auto& client = *window->client; + os::IPC::send_async(client.conn, request); break; } else if (window->surface.absolute(window->titlebar).contains(m_position)) diff --git a/wind/Window.h b/wind/Window.h index e4458fa7..a5cddaaf 100644 --- a/wind/Window.h +++ b/wind/Window.h @@ -5,6 +5,8 @@ #include #include +struct Client; + struct Window : public LinkedListNode { ui::Rect surface; @@ -14,6 +16,8 @@ struct Window : public LinkedListNode u32* pixels; String name; bool dirty { false }; + Client* client; + int id; static int titlebar_height(); diff --git a/wind/main.cpp b/wind/main.cpp index a6f64cc3..9ebd3e6a 100644 --- a/wind/main.cpp +++ b/wind/main.cpp @@ -128,8 +128,11 @@ Result luna_main(int argc, char** argv) client.conn.disconnect(); for (auto& window : client.windows) { - g_windows.remove(window); - delete window; + if (window) + { + g_windows.remove(window); + delete window; + } } } }