wind+libui: Add protocol for window close requests

This commit is contained in:
apio 2023-08-15 11:20:17 +02:00
parent c99c2e4fe3
commit 02c72e15d5
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/Color.h>
#include <ui/Window.h>
Result<void> handle_ipc_client_event(os::LocalClient&, u8)
{
todo();
}
Result<int> 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();
}

View File

@ -8,7 +8,9 @@
*/
#pragma once
#include <luna/HashMap.h>
#include <os/LocalClient.h>
#include <ui/Window.h>
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<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();
private:
static App* s_app;
OwnedPtr<os::LocalClient> m_client;
Window* m_main_window { nullptr };
HashMap<int, OwnedPtr<Window>> m_windows;
bool m_should_close { false };
Window* find_window(int id);
};
}

View File

@ -18,7 +18,7 @@ namespace ui
class Window
{
public:
static Result<OwnedPtr<Window>> create(Rect rect);
static Result<Window*> 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:

View File

@ -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;
};
}

View File

@ -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;
};
}

View File

@ -8,8 +8,15 @@
*/
#include <os/ArgumentParser.h>
#include <os/File.h>
#include <os/IPC.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
{
@ -42,6 +49,7 @@ namespace ui
Result<int> 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<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
{
Result<OwnedPtr<Window>> Window::create(Rect rect)
Result<Window*> Window::create(Rect rect)
{
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_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, {});
}
}

View File

@ -72,6 +72,15 @@ static Result<u32*> 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<void> handle_create_window_message(Client& client)
{
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));
int id = static_cast<int>(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<void> 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,13 +136,24 @@ static Result<void> 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!");
CHECK_WINDOW_ID(request);
client.windows[request.window]->dirty = true;
return {};
}
client.windows[request.window]->dirty = true;
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 {};
}
@ -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);
}
}

View File

@ -1,6 +1,9 @@
#include "Mouse.h"
#include "Client.h"
#include <os/File.h>
#include <os/IPC.h>
#include <ui/Image.h>
#include <ui/ipc/Client.h>
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))
{
// 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))

View File

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

View File

@ -127,12 +127,15 @@ Result<int> luna_main(int argc, char** argv)
auto client = clients.remove_at(i);
client.conn.disconnect();
for (auto& window : client.windows)
{
if (window)
{
g_windows.remove(window);
delete window;
}
}
}
}
if (fds[2].revents & POLLIN)
{
auto client = TRY(server->accept());