Luna/libui/src/App.cpp

139 lines
4.7 KiB
C++
Raw Normal View History

/**
* @file App.cpp
* @author apio (cloudapio.eu)
* @brief UI application event loop.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#include <os/ArgumentParser.h>
#include <os/File.h>
#include <os/IPC.h>
#include <ui/App.h>
#include <ui/ipc/Client.h>
#include <ui/ipc/Server.h>
Result<void> handle_ipc_client_event(os::LocalClient&, u8 id)
{
return ui::App::the().handle_ipc_event(id);
}
namespace ui
{
App* App::s_app { nullptr };
App::App()
{
s_app = this;
}
App::~App()
{
s_app = nullptr;
}
Result<void> App::init(int argc, char** argv)
{
StringView socket_path = "/tmp/wind.sock";
os::ArgumentParser parser;
parser.add_description("A UI application."_sv);
parser.add_system_program_info(argv[0]);
parser.add_value_argument(socket_path, 's', "socket"_sv, "the path for the local IPC socket"_sv);
parser.parse(argc, argv);
m_client = TRY(os::LocalClient::connect(socket_path, true));
return {};
}
Result<int> App::run()
{
check(m_main_window);
while (!m_should_close) { TRY(os::IPC::check_for_messages(*m_client)); }
return 0;
}
App& App::the()
{
check(s_app);
return *s_app;
}
Rect App::screen_rect()
{
ui::GetScreenRectRequest request {};
auto response = os::IPC::send_sync<ui::GetScreenRectResponse>(*m_client, request).release_value();
return response.rect;
}
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();
}
#define READ_MESSAGE(request) \
do { \
auto rc = m_client->recv_typed(request); \
if (rc.has_error()) \
{ \
if (rc.error() == EAGAIN) { continue; } \
if (rc.error() == EINTR) { continue; } \
else \
return rc.release_error(); \
} \
break; \
} while (true)
Result<void> App::handle_ipc_event(u8 id)
{
switch (id)
{
case WINDOW_CLOSE_REQUEST_ID: {
WindowCloseRequest request;
READ_MESSAGE(request);
os::eprintln("ui: Window close request from server! Shall comply.");
auto* window = find_window(request.window);
window->close();
return {};
}
case MOUSE_EVENT_REQUEST_ID: {
MouseEventRequest request;
READ_MESSAGE(request);
auto* window = find_window(request.window);
auto move_result = window->handle_mouse_move(request.position).value_or(ui::EventResult::DidNotHandle);
auto button_result =
window->handle_mouse_buttons(request.position, request.buttons).value_or(ui::EventResult::DidNotHandle);
if (move_result == ui::EventResult::DidHandle || button_result == ui::EventResult::DidHandle)
window->draw();
return {};
}
case MOUSE_LEAVE_REQUEST_ID: {
MouseLeaveRequest request;
READ_MESSAGE(request);
auto* window = find_window(request.window);
if (window->handle_mouse_leave().value_or(ui::EventResult::DidNotHandle) == ui::EventResult::DidHandle)
window->draw();
return {};
}
default: fail("Unexpected IPC request from server!");
}
}
}