/** * @file App.cpp * @author apio (cloudapio.eu) * @brief UI application event loop. * * @copyright Copyright (c) 2023, the Luna authors. * */ #include #include #include #include #include #include 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 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 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(request).release_value(); return response.rect; } Result App::register_window(OwnedPtr&& window, Badge) { int id = window->id(); check(TRY(m_windows.try_set(id, move(window)))); return {}; } void App::unregister_window(Window* window, Badge) { 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 App::handle_ipc_event(os::IPC::Client&, u8 id, void*) { switch (id) { 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; } }