Luna/libui/src/App.cpp
apio 909d0ed289
libos+wind+apps: Make IPC code object-oriented and add functionality for properly receiving messages
This functionality previously had to be repeated across all server programs using the IPC API.
2024-02-03 19:16:39 +01:00

138 lines
3.9 KiB
C++

/**
* @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>
namespace ui
{
void handle_socket_event(int, int status)
{
if (status & POLLHUP) ui::App::the().set_should_close(true);
if (status & POLLIN) { ui::App::the().process_events(); }
}
App* App::s_app { nullptr };
App::App()
{
s_app = this;
}
App::~App()
{
s_app = nullptr;
}
Result<void> App::init(StringView socket_path)
{
m_client = TRY(os::IPC::Client::connect(socket_path, false));
m_client->set_message_handler(
[this](os::IPC::Client& client, u8 id, void* arg) { this->handle_ipc_event(client, id, arg); }, nullptr);
TRY(m_loop.register_fd_listener(m_client->fd(), handle_socket_event));
return {};
}
Result<int> App::run()
{
TRY(m_main_window->draw());
return m_loop.run();
}
App& App::the()
{
check(s_app);
return *s_app;
}
Rect App::screen_rect()
{
ui::GetScreenRectRequest request {};
auto response = m_client->send_sync<ui::GetScreenRectResponse>(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();
}
Result<void> App::handle_ipc_event(os::IPC::Client&, u8 id, void*)
{
switch (id)
{
case WINDOW_CLOSE_REQUEST_ID: {
WindowCloseRequest request;
if (!TRY(m_client->read_message(request))) return {};
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;
if (!TRY(m_client->read_message(request))) return {};
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;
if (!TRY(m_client->read_message(request))) return {};
auto* window = find_window(request.window);
if (window->handle_mouse_leave().value_or(ui::EventResult::DidNotHandle) == ui::EventResult::DidHandle)
window->draw();
return {};
}
case KEY_EVENT_REQUEST_ID: {
KeyEventRequest request;
if (!TRY(m_client->read_message(request))) return {};
auto* window = find_window(request.window);
if (window->handle_key_event(request).value_or(ui::EventResult::DidNotHandle) == ui::EventResult::DidHandle)
window->draw();
return {};
}
default: fail("Unexpected IPC request from server!");
}
}
bool App::process_events()
{
check(m_main_window);
m_client->check_for_messages().release_value();
return !m_should_close;
}
}