wind+libui: Add protocol for window close requests
This commit is contained in:
parent
2328987d81
commit
062b09e20c
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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:
|
||||||
|
@ -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;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -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!");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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, {});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
40
wind/IPC.cpp
40
wind/IPC.cpp
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user