summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2024-04-07 03:31:51 +0100
committerGitHub <noreply@github.com>2024-04-07 03:31:51 +0100
commitf2a848cbcc41f29fb62ee67aef95136ae1a650da (patch)
tree6af50d58aa94fbb48880694a76f6edb79fa370ed /src
parent9f1604e4b0afec40cfa9bc095d6613a7f749b2c1 (diff)
core: Event loop rework (#5466)
* Event loop rework * revert missed
Diffstat (limited to 'src')
-rw-r--r--src/Compositor.cpp6
-rw-r--r--src/managers/AnimationManager.cpp11
-rw-r--r--src/managers/AnimationManager.hpp3
-rw-r--r--src/managers/eventLoop/EventLoopManager.cpp140
-rw-r--r--src/managers/eventLoop/EventLoopManager.hpp46
-rw-r--r--src/managers/eventLoop/EventLoopTimer.cpp53
-rw-r--r--src/managers/eventLoop/EventLoopTimer.hpp29
7 files changed, 281 insertions, 7 deletions
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index 6c0025ea..746011ef 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -2,6 +2,7 @@
#include "helpers/Splashes.hpp"
#include "config/ConfigValue.hpp"
#include "managers/CursorManager.hpp"
+#include "managers/eventLoop/EventLoopManager.hpp"
#include <random>
#include <unordered_set>
#include "debug/HyprCtl.hpp"
@@ -453,6 +454,9 @@ void CCompositor::cleanup() {
void CCompositor::initManagers(eManagersInitStage stage) {
switch (stage) {
case STAGE_PRIORITY: {
+ Debug::log(LOG, "Creating the EventLoopManager!");
+ g_pEventLoopManager = std::make_unique<CEventLoopManager>();
+
Debug::log(LOG, "Creating the HookSystem!");
g_pHookSystem = std::make_unique<CHookSystemManager>();
@@ -628,7 +632,7 @@ void CCompositor::startCompositor() {
// This blocks until we are done.
Debug::log(LOG, "Hyprland is ready, running the event loop!");
- wl_display_run(m_sWLDisplay);
+ g_pEventLoopManager->enterLoop(m_sWLDisplay, m_sWLEventLoop);
}
CMonitor* CCompositor::getMonitorFromID(const int& id) {
diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp
index ac849b58..f017a9e8 100644
--- a/src/managers/AnimationManager.cpp
+++ b/src/managers/AnimationManager.cpp
@@ -4,8 +4,9 @@
#include "macros.hpp"
#include "../config/ConfigValue.hpp"
#include "../desktop/Window.hpp"
+#include "eventLoop/EventLoopManager.hpp"
-int wlTick(void* data) {
+int wlTick(std::shared_ptr<CEventLoopTimer> self, void* data) {
if (g_pAnimationManager)
g_pAnimationManager->onTicked();
@@ -25,8 +26,8 @@ CAnimationManager::CAnimationManager() {
std::vector<Vector2D> points = {Vector2D(0, 0.75f), Vector2D(0.15f, 1.f)};
m_mBezierCurves["default"].setup(&points);
- m_pAnimationTick = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, &wlTick, nullptr);
- wl_event_source_timer_update(m_pAnimationTick, 1);
+ m_pAnimationTimer = std::make_unique<CEventLoopTimer>(std::chrono::microseconds(500), wlTick, nullptr);
+ g_pEventLoopManager->addTimer(m_pAnimationTimer);
}
void CAnimationManager::removeAllBeziers() {
@@ -545,7 +546,7 @@ void CAnimationManager::scheduleTick() {
const auto PMOSTHZ = g_pHyprRenderer->m_pMostHzMonitor;
if (!PMOSTHZ) {
- wl_event_source_timer_update(m_pAnimationTick, 16);
+ m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(16));
return;
}
@@ -555,5 +556,5 @@ void CAnimationManager::scheduleTick() {
const auto TOPRES = std::clamp(refreshDelayMs - SINCEPRES, 1.1f, 1000.f); // we can't send 0, that will disarm it
- wl_event_source_timer_update(m_pAnimationTick, std::floor(TOPRES));
+ m_pAnimationTimer->updateTimeout(std::chrono::milliseconds((int)std::floor(TOPRES)));
}
diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp
index 483c9813..23729502 100644
--- a/src/managers/AnimationManager.hpp
+++ b/src/managers/AnimationManager.hpp
@@ -6,6 +6,7 @@
#include "../helpers/AnimatedVariable.hpp"
#include "../helpers/BezierCurve.hpp"
#include "../helpers/Timer.hpp"
+#include "eventLoop/EventLoopTimer.hpp"
class CWindow;
@@ -32,7 +33,7 @@ class CAnimationManager {
std::vector<CBaseAnimatedVariable*> m_vAnimatedVariables;
std::vector<CBaseAnimatedVariable*> m_vActiveAnimatedVariables;
- wl_event_source* m_pAnimationTick;
+ std::shared_ptr<CEventLoopTimer> m_pAnimationTimer;
float m_fLastTickTime; // in ms
diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp
new file mode 100644
index 00000000..0dabdcfb
--- /dev/null
+++ b/src/managers/eventLoop/EventLoopManager.cpp
@@ -0,0 +1,140 @@
+#include "EventLoopManager.hpp"
+#include "../../debug/Log.hpp"
+
+#include <algorithm>
+
+#include <sys/poll.h>
+
+void CEventLoopManager::enterLoop(wl_display* display, wl_event_loop* wlEventLoop) {
+ m_sWayland.loop = wlEventLoop;
+ m_sWayland.display = display;
+
+ pollfd pollfds[] = {
+ {
+ .fd = wl_event_loop_get_fd(wlEventLoop),
+ .events = POLLIN,
+ },
+ };
+
+ std::thread pollThr([this, &pollfds]() {
+ while (!m_bTerminate) {
+ int ret = poll(pollfds, 1, 5000 /* 5 seconds, reasonable. Just in case we need to terminate and the signal fails */);
+
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+
+ Debug::log(CRIT, "Polling fds failed with {}", errno);
+ m_bTerminate = true;
+ return;
+ }
+
+ for (size_t i = 0; i < 1; ++i) {
+ if (pollfds[i].revents & POLLHUP) {
+ Debug::log(CRIT, "Disconnected from pollfd id {}", i);
+ m_bTerminate = true;
+ return;
+ }
+ }
+
+ if (ret != 0) {
+ {
+ std::lock_guard<std::mutex> lg2(m_sLoopState.eventRequestMutex);
+ std::lock_guard<std::mutex> lg(m_sLoopState.loopMutex);
+ m_sLoopState.event = true;
+ }
+ m_sLoopState.cv.notify_all();
+ }
+ }
+ });
+
+ std::thread timersThr([this]() {
+ while (!m_bTerminate) {
+ // calc nearest thing
+
+ m_sTimers.timersMutex.lock();
+ float least = 1000 * 1000 * 10; // 10s in µs
+ for (auto& t : m_sTimers.timers) {
+ const auto TIME = std::clamp(t->leftUs(), 0.f, INFINITY);
+ if (TIME < least)
+ least = TIME;
+ }
+ m_sTimers.timersMutex.unlock();
+
+ if (least > 0) {
+ std::unique_lock lk(m_sTimers.timersRqMutex);
+ m_sTimers.cv.wait_for(lk, std::chrono::microseconds((int)least + 1), [this] { return m_sTimers.event; });
+ m_sTimers.event = false;
+ }
+
+ // notify main
+ {
+ std::lock_guard<std::mutex> lg2(m_sLoopState.eventRequestMutex);
+ std::lock_guard<std::mutex> lg(m_sLoopState.loopMutex);
+ m_sLoopState.event = true;
+ }
+
+ m_sLoopState.cv.notify_all();
+ }
+ });
+
+ m_sLoopState.event = true; // let it process once
+
+ while (1) {
+ std::unique_lock lk(m_sLoopState.eventRequestMutex);
+ m_sLoopState.cv.wait_for(lk, std::chrono::milliseconds(5000), [this] { return m_sLoopState.event; });
+
+ if (m_bTerminate)
+ break;
+
+ std::lock_guard<std::mutex> lg(m_sLoopState.loopMutex);
+
+ m_sLoopState.event = false;
+
+ if (pollfds[0].revents & POLLIN /* wl event loop */) {
+ wl_display_flush_clients(m_sWayland.display);
+ if (wl_event_loop_dispatch(m_sWayland.loop, -1) < 0) {
+ m_bTerminate = true;
+ break;
+ }
+ }
+
+ // TODO: don't check timers without the timer thread requesting it
+ // I tried but it didnt work :/
+
+ m_sTimers.timersMutex.lock();
+ auto timerscpy = m_sTimers.timers;
+ m_sTimers.timersMutex.unlock();
+
+ for (auto& t : timerscpy) {
+ if (t->passed() && !t->cancelled())
+ t->call(t);
+ }
+
+ if (m_bTerminate)
+ break;
+ }
+
+ Debug::log(LOG, "Kicked off the event loop! :(");
+
+ m_sTimers.event = true;
+ m_sTimers.cv.notify_all();
+}
+
+void CEventLoopManager::addTimer(std::shared_ptr<CEventLoopTimer> timer) {
+ m_sTimers.timersMutex.lock();
+ m_sTimers.timers.push_back(timer);
+ m_sTimers.timersMutex.unlock();
+ nudgeTimers();
+}
+
+void CEventLoopManager::removeTimer(std::shared_ptr<CEventLoopTimer> timer) {
+ m_sTimers.timersMutex.lock();
+ std::erase_if(m_sTimers.timers, [timer](const auto& t) { return timer == t; });
+ m_sTimers.timersMutex.unlock();
+}
+
+void CEventLoopManager::nudgeTimers() {
+ m_sTimers.event = true;
+ m_sTimers.cv.notify_all();
+} \ No newline at end of file
diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp
new file mode 100644
index 00000000..d55b54a9
--- /dev/null
+++ b/src/managers/eventLoop/EventLoopManager.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <condition_variable>
+#include <mutex>
+#include <memory>
+#include <thread>
+#include <wayland-server.h>
+
+#include "EventLoopTimer.hpp"
+
+class CEventLoopManager {
+ public:
+ void enterLoop(wl_display* display, wl_event_loop* wlEventLoop);
+ void addTimer(std::shared_ptr<CEventLoopTimer> timer);
+ void removeTimer(std::shared_ptr<CEventLoopTimer> timer);
+
+ // recalculates timers
+ void nudgeTimers();
+
+ private:
+ struct {
+ wl_event_loop* loop = nullptr;
+ wl_display* display = nullptr;
+ std::thread pollThread;
+ } m_sWayland;
+
+ struct {
+ std::mutex timersMutex;
+ std::mutex timersRqMutex;
+ std::vector<std::shared_ptr<CEventLoopTimer>> timers;
+ std::thread timerThread;
+ bool event = false;
+ std::condition_variable cv;
+ } m_sTimers;
+
+ struct {
+ std::mutex loopMutex;
+ std::mutex eventRequestMutex;
+ bool event = false;
+ std::condition_variable cv;
+ } m_sLoopState;
+
+ bool m_bTerminate = false;
+};
+
+inline std::unique_ptr<CEventLoopManager> g_pEventLoopManager; \ No newline at end of file
diff --git a/src/managers/eventLoop/EventLoopTimer.cpp b/src/managers/eventLoop/EventLoopTimer.cpp
new file mode 100644
index 00000000..ebfb696c
--- /dev/null
+++ b/src/managers/eventLoop/EventLoopTimer.cpp
@@ -0,0 +1,53 @@
+#include "EventLoopTimer.hpp"
+#include <numeric>
+#include "EventLoopManager.hpp"
+
+CEventLoopTimer::CEventLoopTimer(std::optional<std::chrono::system_clock::duration> timeout, std::function<void(std::shared_ptr<CEventLoopTimer> self, void* data)> cb_,
+ void* data_) :
+ cb(cb_),
+ data(data_) {
+
+ if (!timeout.has_value())
+ expires.reset();
+ else
+ expires = std::chrono::system_clock::now() + *timeout;
+}
+
+void CEventLoopTimer::updateTimeout(std::optional<std::chrono::system_clock::duration> timeout) {
+ if (!timeout.has_value()) {
+ expires.reset();
+ g_pEventLoopManager->nudgeTimers();
+ return;
+ }
+
+ expires = std::chrono::system_clock::now() + *timeout;
+
+ g_pEventLoopManager->nudgeTimers();
+}
+
+bool CEventLoopTimer::passed() {
+ if (!expires.has_value())
+ return false;
+ return std::chrono::system_clock::now() > *expires;
+}
+
+void CEventLoopTimer::cancel() {
+ wasCancelled = true;
+ expires.reset();
+}
+
+bool CEventLoopTimer::cancelled() {
+ return wasCancelled;
+}
+
+void CEventLoopTimer::call(std::shared_ptr<CEventLoopTimer> self) {
+ expires.reset();
+ cb(self, data);
+}
+
+float CEventLoopTimer::leftUs() {
+ if (!expires.has_value())
+ return std::numeric_limits<float>::max();
+
+ return std::chrono::duration_cast<std::chrono::microseconds>(*expires - std::chrono::system_clock::now()).count();
+}
diff --git a/src/managers/eventLoop/EventLoopTimer.hpp b/src/managers/eventLoop/EventLoopTimer.hpp
new file mode 100644
index 00000000..8865d29f
--- /dev/null
+++ b/src/managers/eventLoop/EventLoopTimer.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <chrono>
+#include <functional>
+#include <optional>
+
+class CEventLoopTimer {
+ public:
+ CEventLoopTimer(std::optional<std::chrono::system_clock::duration> timeout, std::function<void(std::shared_ptr<CEventLoopTimer> self, void* data)> cb_, void* data_);
+
+ // if not specified, disarms.
+ // if specified, arms.
+ void updateTimeout(std::optional<std::chrono::system_clock::duration> timeout);
+
+ void cancel();
+ bool passed();
+
+ float leftUs();
+
+ bool cancelled();
+ // resets expires
+ void call(std::shared_ptr<CEventLoopTimer> self);
+
+ private:
+ std::function<void(std::shared_ptr<CEventLoopTimer> self, void* data)> cb;
+ void* data = nullptr;
+ std::optional<std::chrono::system_clock::time_point> expires;
+ bool wasCancelled = false;
+};