Add a display server and graphical user interface #38
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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, {});
|
||||
}
|
||||
}
|
||||
|
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)
|
||||
|
||||
#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,17 +136,28 @@ 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!");
|
||||
return {};
|
||||
}
|
||||
CHECK_WINDOW_ID(request);
|
||||
|
||||
client.windows[request.window]->dirty = true;
|
||||
|
||||
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
|
||||
{
|
||||
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::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);
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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();
|
||||
|
||||
|
@ -128,8 +128,11 @@ Result<int> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user