apio
909d0ed289
This functionality previously had to be repeated across all server programs using the IPC API.
138 lines
3.9 KiB
C++
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;
|
|
}
|
|
}
|