2024-04-07 03:31:51 +01:00
|
|
|
#include "EventLoopManager.hpp"
|
|
|
|
|
#include "../../debug/Log.hpp"
|
2024-07-21 13:09:54 +02:00
|
|
|
#include "../../Compositor.hpp"
|
2025-01-19 15:39:19 +01:00
|
|
|
#include "../../config/ConfigWatcher.hpp"
|
2024-04-07 03:31:51 +01:00
|
|
|
|
|
|
|
|
#include <algorithm>
|
2024-04-07 21:55:14 +01:00
|
|
|
#include <limits>
|
2025-01-23 13:08:19 +02:00
|
|
|
#include <ranges>
|
2024-04-07 03:31:51 +01:00
|
|
|
|
2024-04-07 21:55:14 +01:00
|
|
|
#include <sys/timerfd.h>
|
2024-12-07 18:51:18 +01:00
|
|
|
#include <ctime>
|
2024-04-07 21:55:14 +01:00
|
|
|
|
2024-07-21 13:09:54 +02:00
|
|
|
#include <aquamarine/backend/Backend.hpp>
|
|
|
|
|
|
2024-04-07 21:55:14 +01:00
|
|
|
#define TIMESPEC_NSEC_PER_SEC 1000000000L
|
|
|
|
|
|
2024-07-05 23:05:03 +02:00
|
|
|
CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) {
|
|
|
|
|
m_sTimers.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
|
|
|
|
|
m_sWayland.loop = wlEventLoop;
|
|
|
|
|
m_sWayland.display = display;
|
2024-04-07 21:55:14 +01:00
|
|
|
}
|
|
|
|
|
|
2024-06-02 18:42:54 +02:00
|
|
|
CEventLoopManager::~CEventLoopManager() {
|
2025-01-23 13:08:19 +02:00
|
|
|
for (auto const& [_, eventSourceData] : aqEventSources) {
|
|
|
|
|
wl_event_source_remove(eventSourceData.eventSource);
|
2024-07-24 12:07:36 -05:00
|
|
|
}
|
|
|
|
|
|
2024-06-02 18:42:54 +02:00
|
|
|
if (m_sWayland.eventSource)
|
|
|
|
|
wl_event_source_remove(m_sWayland.eventSource);
|
2024-07-24 12:07:36 -05:00
|
|
|
if (m_sIdle.eventSource)
|
|
|
|
|
wl_event_source_remove(m_sIdle.eventSource);
|
2025-01-19 15:39:19 +01:00
|
|
|
if (m_configWatcherInotifySource)
|
|
|
|
|
wl_event_source_remove(m_configWatcherInotifySource);
|
2024-07-31 21:00:14 +02:00
|
|
|
if (m_sTimers.timerfd >= 0)
|
|
|
|
|
close(m_sTimers.timerfd);
|
2024-06-02 18:42:54 +02:00
|
|
|
}
|
|
|
|
|
|
2024-04-07 21:55:14 +01:00
|
|
|
static int timerWrite(int fd, uint32_t mask, void* data) {
|
|
|
|
|
g_pEventLoopManager->onTimerFire();
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2024-04-07 03:31:51 +01:00
|
|
|
|
2024-07-21 13:09:54 +02:00
|
|
|
static int aquamarineFDWrite(int fd, uint32_t mask, void* data) {
|
|
|
|
|
auto POLLFD = (Aquamarine::SPollFD*)data;
|
|
|
|
|
POLLFD->onSignal();
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-19 15:39:19 +01:00
|
|
|
static int configWatcherWrite(int fd, uint32_t mask, void* data) {
|
|
|
|
|
g_pConfigWatcher->onInotifyEvent();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-05 23:05:03 +02:00
|
|
|
void CEventLoopManager::enterLoop() {
|
|
|
|
|
m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr);
|
2024-04-07 21:55:14 +01:00
|
|
|
|
2025-01-19 15:39:19 +01:00
|
|
|
if (const auto FD = g_pConfigWatcher->getInotifyFD(); FD >= 0)
|
|
|
|
|
m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD, WL_EVENT_READABLE, configWatcherWrite, nullptr);
|
|
|
|
|
|
2025-01-23 13:08:19 +02:00
|
|
|
syncPollFDs();
|
|
|
|
|
m_sListeners.pollFDsChanged = g_pCompositor->m_pAqBackend->events.pollFDsChanged.registerListener([this](std::any d) { syncPollFDs(); });
|
2024-07-21 13:09:54 +02:00
|
|
|
|
2024-09-24 00:49:29 +01:00
|
|
|
// if we have a session, dispatch it to get the pending input devices
|
|
|
|
|
if (g_pCompositor->m_pAqBackend->hasSession())
|
|
|
|
|
g_pCompositor->m_pAqBackend->session->dispatchPendingEventsAsync();
|
|
|
|
|
|
2024-07-05 23:05:03 +02:00
|
|
|
wl_display_run(m_sWayland.display);
|
2024-04-07 03:31:51 +01:00
|
|
|
|
|
|
|
|
Debug::log(LOG, "Kicked off the event loop! :(");
|
2024-04-07 21:55:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CEventLoopManager::onTimerFire() {
|
2024-08-26 20:24:30 +02:00
|
|
|
for (auto const& t : m_sTimers.timers) {
|
2024-05-07 13:30:31 +01:00
|
|
|
if (t.strongRef() > 1 /* if it's 1, it was lost. Don't call it. */ && t->passed() && !t->cancelled())
|
2024-04-07 21:55:14 +01:00
|
|
|
t->call(t);
|
|
|
|
|
}
|
2024-04-07 03:31:51 +01:00
|
|
|
|
2024-04-07 21:55:14 +01:00
|
|
|
nudgeTimers();
|
2024-04-07 03:31:51 +01:00
|
|
|
}
|
|
|
|
|
|
2024-05-05 17:16:00 +01:00
|
|
|
void CEventLoopManager::addTimer(SP<CEventLoopTimer> timer) {
|
2024-04-07 03:31:51 +01:00
|
|
|
m_sTimers.timers.push_back(timer);
|
|
|
|
|
nudgeTimers();
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-05 17:16:00 +01:00
|
|
|
void CEventLoopManager::removeTimer(SP<CEventLoopTimer> timer) {
|
2024-04-07 03:31:51 +01:00
|
|
|
std::erase_if(m_sTimers.timers, [timer](const auto& t) { return timer == t; });
|
2024-04-07 21:55:14 +01:00
|
|
|
nudgeTimers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void timespecAddNs(timespec* pTimespec, int64_t delta) {
|
2024-08-08 21:01:50 +02:00
|
|
|
auto delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC;
|
|
|
|
|
auto delta_s_high = delta / TIMESPEC_NSEC_PER_SEC;
|
2024-04-07 21:55:14 +01:00
|
|
|
|
|
|
|
|
pTimespec->tv_sec += delta_s_high;
|
|
|
|
|
|
|
|
|
|
pTimespec->tv_nsec += (long)delta_ns_low;
|
|
|
|
|
if (pTimespec->tv_nsec >= TIMESPEC_NSEC_PER_SEC) {
|
|
|
|
|
pTimespec->tv_nsec -= TIMESPEC_NSEC_PER_SEC;
|
|
|
|
|
++pTimespec->tv_sec;
|
|
|
|
|
}
|
2024-04-07 03:31:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CEventLoopManager::nudgeTimers() {
|
2024-05-07 13:30:31 +01:00
|
|
|
// remove timers that have gone missing
|
|
|
|
|
std::erase_if(m_sTimers.timers, [](const auto& t) { return t.strongRef() <= 1; });
|
2024-04-07 21:55:14 +01:00
|
|
|
|
2024-12-07 18:51:18 +01:00
|
|
|
long nextTimerUs = 10L * 1000 * 1000; // 10s
|
2024-04-07 21:55:14 +01:00
|
|
|
|
2024-08-26 20:24:30 +02:00
|
|
|
for (auto const& t : m_sTimers.timers) {
|
2024-10-31 00:20:32 +01:00
|
|
|
if (auto const& µs = t->leftUs(); µs < nextTimerUs)
|
2024-04-07 21:55:14 +01:00
|
|
|
nextTimerUs = µs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nextTimerUs = std::clamp(nextTimerUs + 1, 1L, std::numeric_limits<long>::max());
|
|
|
|
|
|
|
|
|
|
timespec now;
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
|
|
|
timespecAddNs(&now, nextTimerUs * 1000L);
|
|
|
|
|
|
|
|
|
|
itimerspec ts = {.it_value = now};
|
|
|
|
|
|
|
|
|
|
timerfd_settime(m_sTimers.timerfd, TFD_TIMER_ABSTIME, &ts, nullptr);
|
2024-07-05 23:05:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CEventLoopManager::doLater(const std::function<void()>& fn) {
|
|
|
|
|
m_sIdle.fns.emplace_back(fn);
|
|
|
|
|
|
|
|
|
|
if (m_sIdle.eventSource)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_sIdle.eventSource = wl_event_loop_add_idle(
|
|
|
|
|
m_sWayland.loop,
|
|
|
|
|
[](void* data) {
|
|
|
|
|
auto IDLE = (CEventLoopManager::SIdleData*)data;
|
|
|
|
|
auto cpy = IDLE->fns;
|
|
|
|
|
IDLE->fns.clear();
|
|
|
|
|
IDLE->eventSource = nullptr;
|
2024-08-26 20:24:30 +02:00
|
|
|
for (auto const& c : cpy) {
|
2024-07-05 23:05:03 +02:00
|
|
|
if (c)
|
|
|
|
|
c();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
&m_sIdle);
|
|
|
|
|
}
|
2025-01-23 13:08:19 +02:00
|
|
|
|
|
|
|
|
void CEventLoopManager::syncPollFDs() {
|
|
|
|
|
auto aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs();
|
|
|
|
|
|
|
|
|
|
std::erase_if(aqEventSources, [&](const auto& item) {
|
|
|
|
|
auto const& [fd, eventSourceData] = item;
|
|
|
|
|
|
|
|
|
|
// If no pollFD has the same fd, remove this event source
|
|
|
|
|
const bool shouldRemove = std::ranges::none_of(aqPollFDs, [&](const auto& pollFD) { return pollFD->fd == fd; });
|
|
|
|
|
|
|
|
|
|
if (shouldRemove)
|
|
|
|
|
wl_event_source_remove(eventSourceData.eventSource);
|
|
|
|
|
|
|
|
|
|
return shouldRemove;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for (auto& fd : aqPollFDs | std::views::filter([&](SP<Aquamarine::SPollFD> fd) { return !aqEventSources.contains(fd->fd); })) {
|
|
|
|
|
auto eventSource = wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get());
|
|
|
|
|
aqEventSources[fd->fd] = {.pollFD = fd, .eventSource = eventSource};
|
|
|
|
|
}
|
|
|
|
|
}
|