wind+libui: Add protocol for window close requests

This commit is contained in:
apio 2023-08-15 11:20:17 +02:00
parent 2328987d81
commit 062b09e20c
Signed by: apio
GPG Key ID: B8A7D06E42258954
11 changed files with 163 additions and 29 deletions

View File

@ -1,24 +1,21 @@
#include <os/File.h>
#include <ui/App.h> #include <ui/App.h>
#include <ui/Color.h>
#include <ui/Window.h>
Result<void> handle_ipc_client_event(os::LocalClient&, u8)
{
todo();
}
Result<int> luna_main(int argc, char** argv) Result<int> luna_main(int argc, char** argv)
{ {
ui::App app; ui::App app;
TRY(app.init(argc, argv)); TRY(app.init(argc, argv));
auto window = TRY(ui::Window::create(ui::Rect { 200, 200, 400, 300 })); auto* window = TRY(ui::Window::create(ui::Rect { 200, 200, 400, 300 }));
os::println("gclient: Created new window!"); app.set_main_window(window);
window->set_title("Example Window"); window->set_title("Main Window");
window->canvas().fill(ui::CYAN); window->canvas().fill(ui::CYAN);
window->update(); 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(); return app.run();
} }

View File

@ -8,7 +8,9 @@
*/ */
#pragma once #pragma once
#include <luna/HashMap.h>
#include <os/LocalClient.h> #include <os/LocalClient.h>
#include <ui/Window.h>
namespace ui namespace ui
{ {
@ -31,11 +33,31 @@ namespace ui
m_should_close = b; 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<void> register_window(OwnedPtr<Window>&& window, Badge<Window>);
void unregister_window(Window* window, Badge<Window>);
Result<void> handle_ipc_event(u8 id);
static App& the(); static App& the();
private: private:
static App* s_app; static App* s_app;
OwnedPtr<os::LocalClient> m_client; OwnedPtr<os::LocalClient> m_client;
Window* m_main_window { nullptr };
HashMap<int, OwnedPtr<Window>> m_windows;
bool m_should_close { false }; bool m_should_close { false };
Window* find_window(int id);
}; };
} }

View File

@ -18,7 +18,7 @@ namespace ui
class Window class Window
{ {
public: public:
static Result<OwnedPtr<Window>> create(Rect rect); static Result<Window*> create(Rect rect);
void set_title(StringView title); void set_title(StringView title);
@ -29,6 +29,13 @@ namespace ui
void update(); void update();
void close();
int id() const
{
return m_id;
}
~Window(); ~Window();
private: private:

View File

@ -16,6 +16,7 @@ namespace ui
{ {
IPC_ENUM_CLIENT(ui), IPC_ENUM_CLIENT(ui),
CREATE_WINDOW_RESPONSE_ID, CREATE_WINDOW_RESPONSE_ID,
WINDOW_CLOSE_REQUEST_ID,
}; };
struct CreateWindowResponse struct CreateWindowResponse
@ -25,4 +26,11 @@ namespace ui
int window; int window;
IPC_STRING(shm_path); IPC_STRING(shm_path);
}; };
struct WindowCloseRequest
{
static constexpr u8 ID = WINDOW_CLOSE_REQUEST_ID;
int window;
};
} }

View File

@ -21,6 +21,7 @@ namespace ui
CREATE_WINDOW_ID, CREATE_WINDOW_ID,
SET_WINDOW_TITLE_ID, SET_WINDOW_TITLE_ID,
INVALIDATE_ID, INVALIDATE_ID,
CLOSE_WINDOW_ID,
}; };
struct CreateWindowRequest struct CreateWindowRequest
@ -45,4 +46,11 @@ namespace ui
int window; int window;
}; };
struct CloseWindowRequest
{
static constexpr u8 ID = CLOSE_WINDOW_ID;
int window;
};
} }

View File

@ -8,8 +8,15 @@
*/ */
#include <os/ArgumentParser.h> #include <os/ArgumentParser.h>
#include <os/File.h>
#include <os/IPC.h> #include <os/IPC.h>
#include <ui/App.h> #include <ui/App.h>
#include <ui/ipc/Client.h>
Result<void> handle_ipc_client_event(os::LocalClient&, u8 id)
{
return ui::App::the().handle_ipc_event(id);
}
namespace ui namespace ui
{ {
@ -42,6 +49,7 @@ namespace ui
Result<int> App::run() Result<int> App::run()
{ {
check(m_main_window);
while (!m_should_close) { TRY(os::IPC::check_for_messages(*m_client)); } while (!m_should_close) { TRY(os::IPC::check_for_messages(*m_client)); }
return 0; return 0;
} }
@ -51,4 +59,40 @@ namespace ui
check(s_app); check(s_app);
return *s_app; return *s_app;
} }
Result<void> App::register_window(OwnedPtr<Window>&& window, Badge<Window>)
{
int id = window->id();
check(TRY(m_windows.try_set(id, move(window))));
return {};
}
void App::unregister_window(Window* window, Badge<Window>)
{
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<void> 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!");
}
}
} }

View File

@ -39,7 +39,7 @@ static Result<u32*> create_shm_region(const char* path, int* outfd, ui::Rect rec
namespace ui namespace ui
{ {
Result<OwnedPtr<Window>> Window::create(Rect rect) Result<Window*> Window::create(Rect rect)
{ {
auto window = TRY(make_owned<Window>()); auto window = TRY(make_owned<Window>());
@ -52,7 +52,11 @@ namespace ui
window->m_canvas = ui::Canvas { rect.width, rect.height, rect.width, (u8*)pixels }; window->m_canvas = ui::Canvas { rect.width, rect.height, rect.width, (u8*)pixels };
window->m_id = response.window; window->m_id = response.window;
return window; Window* p = window.ptr();
App::the().register_window(move(window), {});
return p;
} }
Window::~Window() Window::~Window()
@ -74,4 +78,17 @@ namespace ui
request.window = m_id; request.window = m_id;
os::IPC::send_async(App::the().client(), request); 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, {});
}
} }

View File

@ -72,6 +72,15 @@ static Result<u32*> create_shm_region(const char* path, int* outfd, ui::Rect rec
} \ } \
} while (0) } 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<void> handle_create_window_message(Client& client) static Result<void> handle_create_window_message(Client& client)
{ {
ui::CreateWindowRequest request; ui::CreateWindowRequest request;
@ -96,6 +105,9 @@ static Result<void> handle_create_window_message(Client& client)
TRY_OR_IPC_ERROR(client.windows.try_append(window)); TRY_OR_IPC_ERROR(client.windows.try_append(window));
int id = static_cast<int>(client.windows.size() - 1); int id = static_cast<int>(client.windows.size() - 1);
window->client = &client;
window->id = id;
ui::CreateWindowResponse response; ui::CreateWindowResponse response;
response.window = id; response.window = id;
SET_IPC_STRING(response.shm_path, shm_path.chars()); SET_IPC_STRING(response.shm_path, shm_path.chars());
@ -112,11 +124,7 @@ static Result<void> handle_set_window_title_message(Client& client)
os::println("wind: SetWindowTitle(\"%s\") for window %d", name.chars(), request.window); os::println("wind: SetWindowTitle(\"%s\") for window %d", name.chars(), request.window);
if ((usize)request.window >= client.windows.size()) CHECK_WINDOW_ID(request);
{
os::eprintln("wind: Window id out of range!");
return {};
}
client.windows[request.window]->name = move(name); client.windows[request.window]->name = move(name);
@ -128,17 +136,28 @@ static Result<void> handle_invalidate_message(Client& client)
ui::InvalidateRequest request; ui::InvalidateRequest request;
READ_MESSAGE(request); READ_MESSAGE(request);
if ((usize)request.window >= client.windows.size()) CHECK_WINDOW_ID(request);
{
os::eprintln("wind: Window id out of range!");
return {};
}
client.windows[request.window]->dirty = true; client.windows[request.window]->dirty = true;
return {}; return {};
} }
static Result<void> 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 namespace wind
{ {
Result<void> handle_ipc_message(Client& client, u8 id) Result<void> 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::CREATE_WINDOW_ID: return handle_create_window_message(client);
case ui::SET_WINDOW_TITLE_ID: return handle_set_window_title_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::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); default: os::eprintln("wind: Invalid IPC message from client!"); return err(EINVAL);
} }
} }

View File

@ -1,6 +1,9 @@
#include "Mouse.h" #include "Mouse.h"
#include "Client.h"
#include <os/File.h> #include <os/File.h>
#include <os/IPC.h>
#include <ui/Image.h> #include <ui/Image.h>
#include <ui/ipc/Client.h>
static SharedPtr<ui::Image> g_mouse_cursor; static SharedPtr<ui::Image> g_mouse_cursor;
@ -51,9 +54,10 @@ void Mouse::update(const moon::MousePacket& packet)
{ {
if (window->surface.absolute(window->close_button).contains(m_position)) if (window->surface.absolute(window->close_button).contains(m_position))
{ {
// Close button pressed ui::WindowCloseRequest request;
g_windows.remove(window); request.window = window->id;
delete window; auto& client = *window->client;
os::IPC::send_async(client.conn, request);
break; break;
} }
else if (window->surface.absolute(window->titlebar).contains(m_position)) else if (window->surface.absolute(window->titlebar).contains(m_position))

View File

@ -5,6 +5,8 @@
#include <ui/Color.h> #include <ui/Color.h>
#include <ui/Rect.h> #include <ui/Rect.h>
struct Client;
struct Window : public LinkedListNode<Window> struct Window : public LinkedListNode<Window>
{ {
ui::Rect surface; ui::Rect surface;
@ -14,6 +16,8 @@ struct Window : public LinkedListNode<Window>
u32* pixels; u32* pixels;
String name; String name;
bool dirty { false }; bool dirty { false };
Client* client;
int id;
static int titlebar_height(); static int titlebar_height();

View File

@ -128,8 +128,11 @@ Result<int> luna_main(int argc, char** argv)
client.conn.disconnect(); client.conn.disconnect();
for (auto& window : client.windows) for (auto& window : client.windows)
{ {
g_windows.remove(window); if (window)
delete window; {
g_windows.remove(window);
delete window;
}
} }
} }
} }