mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-07 21:46:00 +01:00
parent
9f1604e4b0
commit
f2a848cbcc
7 changed files with 281 additions and 7 deletions
|
@ -2,6 +2,7 @@
|
||||||
#include "helpers/Splashes.hpp"
|
#include "helpers/Splashes.hpp"
|
||||||
#include "config/ConfigValue.hpp"
|
#include "config/ConfigValue.hpp"
|
||||||
#include "managers/CursorManager.hpp"
|
#include "managers/CursorManager.hpp"
|
||||||
|
#include "managers/eventLoop/EventLoopManager.hpp"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include "debug/HyprCtl.hpp"
|
#include "debug/HyprCtl.hpp"
|
||||||
|
@ -453,6 +454,9 @@ void CCompositor::cleanup() {
|
||||||
void CCompositor::initManagers(eManagersInitStage stage) {
|
void CCompositor::initManagers(eManagersInitStage stage) {
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
case STAGE_PRIORITY: {
|
case STAGE_PRIORITY: {
|
||||||
|
Debug::log(LOG, "Creating the EventLoopManager!");
|
||||||
|
g_pEventLoopManager = std::make_unique<CEventLoopManager>();
|
||||||
|
|
||||||
Debug::log(LOG, "Creating the HookSystem!");
|
Debug::log(LOG, "Creating the HookSystem!");
|
||||||
g_pHookSystem = std::make_unique<CHookSystemManager>();
|
g_pHookSystem = std::make_unique<CHookSystemManager>();
|
||||||
|
|
||||||
|
@ -628,7 +632,7 @@ void CCompositor::startCompositor() {
|
||||||
|
|
||||||
// This blocks until we are done.
|
// This blocks until we are done.
|
||||||
Debug::log(LOG, "Hyprland is ready, running the event loop!");
|
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) {
|
CMonitor* CCompositor::getMonitorFromID(const int& id) {
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
#include "macros.hpp"
|
#include "macros.hpp"
|
||||||
#include "../config/ConfigValue.hpp"
|
#include "../config/ConfigValue.hpp"
|
||||||
#include "../desktop/Window.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)
|
if (g_pAnimationManager)
|
||||||
g_pAnimationManager->onTicked();
|
g_pAnimationManager->onTicked();
|
||||||
|
|
||||||
|
@ -25,8 +26,8 @@ CAnimationManager::CAnimationManager() {
|
||||||
std::vector<Vector2D> points = {Vector2D(0, 0.75f), Vector2D(0.15f, 1.f)};
|
std::vector<Vector2D> points = {Vector2D(0, 0.75f), Vector2D(0.15f, 1.f)};
|
||||||
m_mBezierCurves["default"].setup(&points);
|
m_mBezierCurves["default"].setup(&points);
|
||||||
|
|
||||||
m_pAnimationTick = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, &wlTick, nullptr);
|
m_pAnimationTimer = std::make_unique<CEventLoopTimer>(std::chrono::microseconds(500), wlTick, nullptr);
|
||||||
wl_event_source_timer_update(m_pAnimationTick, 1);
|
g_pEventLoopManager->addTimer(m_pAnimationTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAnimationManager::removeAllBeziers() {
|
void CAnimationManager::removeAllBeziers() {
|
||||||
|
@ -545,7 +546,7 @@ void CAnimationManager::scheduleTick() {
|
||||||
const auto PMOSTHZ = g_pHyprRenderer->m_pMostHzMonitor;
|
const auto PMOSTHZ = g_pHyprRenderer->m_pMostHzMonitor;
|
||||||
|
|
||||||
if (!PMOSTHZ) {
|
if (!PMOSTHZ) {
|
||||||
wl_event_source_timer_update(m_pAnimationTick, 16);
|
m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(16));
|
||||||
return;
|
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
|
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)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "../helpers/AnimatedVariable.hpp"
|
#include "../helpers/AnimatedVariable.hpp"
|
||||||
#include "../helpers/BezierCurve.hpp"
|
#include "../helpers/BezierCurve.hpp"
|
||||||
#include "../helpers/Timer.hpp"
|
#include "../helpers/Timer.hpp"
|
||||||
|
#include "eventLoop/EventLoopTimer.hpp"
|
||||||
|
|
||||||
class CWindow;
|
class CWindow;
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ class CAnimationManager {
|
||||||
std::vector<CBaseAnimatedVariable*> m_vAnimatedVariables;
|
std::vector<CBaseAnimatedVariable*> m_vAnimatedVariables;
|
||||||
std::vector<CBaseAnimatedVariable*> m_vActiveAnimatedVariables;
|
std::vector<CBaseAnimatedVariable*> m_vActiveAnimatedVariables;
|
||||||
|
|
||||||
wl_event_source* m_pAnimationTick;
|
std::shared_ptr<CEventLoopTimer> m_pAnimationTimer;
|
||||||
|
|
||||||
float m_fLastTickTime; // in ms
|
float m_fLastTickTime; // in ms
|
||||||
|
|
||||||
|
|
140
src/managers/eventLoop/EventLoopManager.cpp
Normal file
140
src/managers/eventLoop/EventLoopManager.cpp
Normal file
|
@ -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();
|
||||||
|
}
|
46
src/managers/eventLoop/EventLoopManager.hpp
Normal file
46
src/managers/eventLoop/EventLoopManager.hpp
Normal file
|
@ -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;
|
53
src/managers/eventLoop/EventLoopTimer.cpp
Normal file
53
src/managers/eventLoop/EventLoopTimer.cpp
Normal file
|
@ -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();
|
||||||
|
}
|
29
src/managers/eventLoop/EventLoopTimer.hpp
Normal file
29
src/managers/eventLoop/EventLoopTimer.hpp
Normal file
|
@ -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;
|
||||||
|
};
|
Loading…
Reference in a new issue