From cc3314280d767d39e8d47c95a1b54c432b53cdf2 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Thu, 6 Feb 2025 09:04:35 +0100 Subject: [PATCH 1/2] core: move to UP and make widgets use SPs --- CMakeLists.txt | 2 +- src/auth/Auth.cpp | 13 +++---- src/auth/Auth.hpp | 29 +++++++-------- src/config/ConfigManager.hpp | 3 +- src/core/AnimationManager.hpp | 3 +- src/core/Egl.hpp | 6 ++-- src/core/LockSurface.cpp | 21 +++++------ src/core/LockSurface.hpp | 7 ++-- src/core/Output.cpp | 27 ++++++++------ src/core/Output.hpp | 31 +++++++++------- src/core/Seat.cpp | 2 +- src/core/Seat.hpp | 23 ++++++------ src/core/hyprlock.cpp | 33 ++++++++--------- src/core/hyprlock.hpp | 7 ++-- src/defines.hpp | 4 ++- src/main.cpp | 6 ++-- src/renderer/AsyncResourceGatherer.cpp | 7 ++-- src/renderer/AsyncResourceGatherer.hpp | 2 +- src/renderer/Renderer.cpp | 21 ++++++----- src/renderer/Renderer.hpp | 50 +++++++++++++------------- src/renderer/Screencopy.cpp | 20 ++++++----- src/renderer/Screencopy.hpp | 10 +++--- src/renderer/widgets/Background.cpp | 14 +++++--- src/renderer/widgets/Background.hpp | 4 +-- src/renderer/widgets/Shadowable.hpp | 2 +- 25 files changed, 180 insertions(+), 167 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b393038..d1cec679 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,7 +89,7 @@ pkg_check_modules( pangocairo libdrm gbm - hyprutils>=0.3.3 + hyprutils>=0.5.0 sdbus-c++>=2.0.0 hyprgraphics) diff --git a/src/auth/Auth.cpp b/src/auth/Auth.cpp index f9eacce6..31695d39 100644 --- a/src/auth/Auth.cpp +++ b/src/auth/Auth.cpp @@ -11,10 +11,10 @@ CAuth::CAuth() { static const auto ENABLEPAM = g_pConfigManager->getValue("auth:pam:enabled"); if (*ENABLEPAM) - m_vImpls.push_back(std::make_shared()); + m_vImpls.emplace_back(makeShared()); static const auto ENABLEFINGERPRINT = g_pConfigManager->getValue("auth:fingerprint:enabled"); if (*ENABLEFINGERPRINT) - m_vImpls.push_back(std::make_shared()); + m_vImpls.emplace_back(makeShared()); RASSERT(!m_vImpls.empty(), "At least one authentication method must be enabled!"); } @@ -32,12 +32,7 @@ void CAuth::submitInput(const std::string& input) { } bool CAuth::checkWaiting() { - for (const auto& i : m_vImpls) { - if (i->checkWaiting()) - return true; - } - - return false; + return std::ranges::any_of(m_vImpls, [](const auto& i) { return i->checkWaiting(); }); } const std::string& CAuth::getCurrentFailText() { @@ -64,7 +59,7 @@ size_t CAuth::getFailedAttempts() { return m_sCurrentFail.failedAttempts; } -std::shared_ptr CAuth::getImpl(eAuthImplementations implType) { +SP CAuth::getImpl(eAuthImplementations implType) { for (const auto& i : m_vImpls) { if (i->getImplType() == implType) return i; diff --git a/src/auth/Auth.hpp b/src/auth/Auth.hpp index 8a0682f8..ef9236f7 100644 --- a/src/auth/Auth.hpp +++ b/src/auth/Auth.hpp @@ -1,9 +1,10 @@ #pragma once -#include #include #include +#include "../defines.hpp" + enum eAuthImplementations { AUTH_IMPL_PAM = 0, AUTH_IMPL_FINGERPRINT = 1, @@ -28,23 +29,23 @@ class CAuth { public: CAuth(); - void start(); + void start(); - void submitInput(const std::string& input); - bool checkWaiting(); + void submitInput(const std::string& input); + bool checkWaiting(); - const std::string& getCurrentFailText(); + const std::string& getCurrentFailText(); - std::optional getFailText(eAuthImplementations implType); - std::optional getPrompt(eAuthImplementations implType); - size_t getFailedAttempts(); + std::optional getFailText(eAuthImplementations implType); + std::optional getPrompt(eAuthImplementations implType); + size_t getFailedAttempts(); - std::shared_ptr getImpl(eAuthImplementations implType); + SP getImpl(eAuthImplementations implType); - void terminate(); + void terminate(); - void enqueueUnlock(); - void enqueueFail(const std::string& failText, eAuthImplementations implType); + void enqueueUnlock(); + void enqueueFail(const std::string& failText, eAuthImplementations implType); // Should only be set via the main thread bool m_bDisplayFailText = false; @@ -56,7 +57,7 @@ class CAuth { size_t failedAttempts = 0; } m_sCurrentFail; - std::vector> m_vImpls; + std::vector> m_vImpls; }; -inline std::unique_ptr g_pAuth; +inline UP g_pAuth; diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 11d960de..9183f2bf 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "../defines.hpp" @@ -41,4 +40,4 @@ class CConfigManager { Hyprlang::CConfig m_config; }; -inline std::unique_ptr g_pConfigManager; +inline UP g_pConfigManager; diff --git a/src/core/AnimationManager.hpp b/src/core/AnimationManager.hpp index 553e780b..e6d01e86 100644 --- a/src/core/AnimationManager.hpp +++ b/src/core/AnimationManager.hpp @@ -4,7 +4,6 @@ #include #include "../helpers/AnimatedVariable.hpp" -#include "../helpers/Math.hpp" #include "../defines.hpp" class CHyprlockAnimationManager : public Hyprutils::Animation::CAnimationManager { @@ -31,4 +30,4 @@ class CHyprlockAnimationManager : public Hyprutils::Animation::CAnimationManager bool m_bTickScheduled = false; }; -inline std::unique_ptr g_pAnimationManager; +inline UP g_pAnimationManager; diff --git a/src/core/Egl.hpp b/src/core/Egl.hpp index 5a697d07..5fea7623 100644 --- a/src/core/Egl.hpp +++ b/src/core/Egl.hpp @@ -1,10 +1,10 @@ #pragma once -#include - #include #include +#include "../defines.hpp" + class CEGL { public: CEGL(wl_display*); @@ -19,4 +19,4 @@ class CEGL { void makeCurrent(EGLSurface surf); }; -inline std::unique_ptr g_pEGL; \ No newline at end of file +inline UP g_pEGL; diff --git a/src/core/LockSurface.cpp b/src/core/LockSurface.cpp index 249f1330..22f1a468 100644 --- a/src/core/LockSurface.cpp +++ b/src/core/LockSurface.cpp @@ -11,13 +11,9 @@ CSessionLockSurface::~CSessionLockSurface() { wl_egl_window_destroy(eglWindow); } -CSessionLockSurface::CSessionLockSurface(COutput* output) : output(output) { +CSessionLockSurface::CSessionLockSurface(const SP& pOutput) : m_outputRef(pOutput) { surface = makeShared(g_pHyprlock->getCompositor()->sendCreateSurface()); - - if (!surface) { - Debug::log(CRIT, "Couldn't create wl_surface"); - exit(1); - } + RASSERT(surface, "Couldn't create wl_surface"); static const auto FRACTIONALSCALING = g_pConfigManager->getValue("general:fractional_scaling"); const auto ENABLE_FSV1 = *FRACTIONALSCALING == 1 || /* auto enable */ (*FRACTIONALSCALING == 2); @@ -45,7 +41,7 @@ CSessionLockSurface::CSessionLockSurface(COutput* output) : output(output) { if (!PVIEWPORTER) Debug::log(LOG, "No viewporter support! Oops, won't be able to scale!"); - lockSurface = makeShared(g_pHyprlock->getSessionLock()->sendGetLockSurface(surface->resource(), output->output->resource())); + lockSurface = makeShared(g_pHyprlock->getSessionLock()->sendGetLockSurface(surface->resource(), pOutput->m_wlOutput->resource())); if (!lockSurface) { Debug::log(CRIT, "Couldn't create ext_session_lock_surface_v1"); @@ -62,6 +58,8 @@ void CSessionLockSurface::configure(const Vector2D& size_, uint32_t serial_) { const bool SAMESIZE = logicalSize == size_; const bool SAMESCALE = appliedScale == fractionalScale; + const auto POUTPUT = m_outputRef.lock(); + serial = serial_; logicalSize = size_; appliedScale = fractionalScale; @@ -71,8 +69,8 @@ void CSessionLockSurface::configure(const Vector2D& size_, uint32_t serial_) { viewport->sendSetDestination(logicalSize.x, logicalSize.y); surface->sendSetBufferScale(1); } else { - size = size_ * output->scale; - surface->sendSetBufferScale(output->scale); + size = size_ * POUTPUT->scale; + surface->sendSetBufferScale(POUTPUT->scale); } if (!SAMESERIAL) @@ -129,7 +127,10 @@ void CSessionLockSurface::render() { if (g_pHyprlock->m_bTerminate) return; - Debug::log(TRACE, "[{}] frame {}, Current fps: {:.2f}", output->stringPort, m_frames, 1000.f / (frameTime - m_lastFrameTime)); + if (Debug::verbose) { + const auto POUTPUT = m_outputRef.lock(); + Debug::log(TRACE, "[{}] frame {}, Current fps: {:.2f}", POUTPUT->stringPort, m_frames, 1000.f / (frameTime - m_lastFrameTime)); + } m_lastFrameTime = frameTime; diff --git a/src/core/LockSurface.hpp b/src/core/LockSurface.hpp index f4f64e77..a6bb0ef9 100644 --- a/src/core/LockSurface.hpp +++ b/src/core/LockSurface.hpp @@ -14,7 +14,7 @@ class CRenderer; class CSessionLockSurface { public: - CSessionLockSurface(COutput* output); + CSessionLockSurface(const SP& pOutput); ~CSessionLockSurface(); void configure(const Vector2D& size, uint32_t serial); @@ -28,7 +28,8 @@ class CSessionLockSurface { void onScaleUpdate(); private: - COutput* output = nullptr; + WP m_outputRef; + SP surface = nullptr; SP lockSurface = nullptr; uint32_t serial = 0; @@ -49,4 +50,4 @@ class CSessionLockSurface { SP frameCallback = nullptr; friend class CRenderer; -}; \ No newline at end of file +}; diff --git a/src/core/Output.cpp b/src/core/Output.cpp index 82986bda..0e069da0 100644 --- a/src/core/Output.cpp +++ b/src/core/Output.cpp @@ -1,32 +1,35 @@ #include "Output.hpp" #include "../helpers/Log.hpp" #include "hyprlock.hpp" -#include "../renderer/Renderer.hpp" -COutput::COutput(SP output_, uint32_t name_) : name(name_), output(output_) { - output->setDescription([this](CCWlOutput* r, const char* description) { +void COutput::create(WP pSelf, SP pWlOutput, uint32_t _name) { + name = _name; + m_wlOutput = pWlOutput; + m_self = pSelf; + + m_wlOutput->setDescription([this](CCWlOutput* r, const char* description) { stringDesc = description ? std::string{description} : ""; Debug::log(LOG, "output {} description {}", name, stringDesc); }); - output->setName([this](CCWlOutput* r, const char* name) { + m_wlOutput->setName([this](CCWlOutput* r, const char* name) { stringName = std::string{name} + stringName; stringPort = std::string{name}; Debug::log(LOG, "output {} name {}", name, name); }); - output->setScale([this](CCWlOutput* r, int32_t sc) { scale = sc; }); + m_wlOutput->setScale([this](CCWlOutput* r, int32_t sc) { scale = sc; }); - output->setDone([this](CCWlOutput* r) { + m_wlOutput->setDone([this](CCWlOutput* r) { Debug::log(LOG, "output {} done", name); - if (g_pHyprlock->m_bLocked && !sessionLockSurface) { + if (g_pHyprlock->m_bLocked && !m_sessionLockSurface) { // if we are already locked, create a surface dynamically Debug::log(LOG, "Creating a surface dynamically for output as we are already locked"); - sessionLockSurface = std::make_unique(this); + createSessionLockSurface(); } }); - output->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { + m_wlOutput->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { // handle portrait mode and flipped cases if (transform % 2 == 1) size = {height, width}; @@ -34,10 +37,14 @@ COutput::COutput(SP output_, uint32_t name_) : name(name_), output(o size = {width, height}; }); - output->setGeometry( + m_wlOutput->setGeometry( [this](CCWlOutput* r, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char* make, const char* model, int32_t transform_) { transform = (wl_output_transform)transform_; Debug::log(LOG, "output {} make {} model {}", name, make ? make : "", model ? model : ""); }); } + +void COutput::createSessionLockSurface() { + m_sessionLockSurface = makeUnique(m_self.lock()); +} diff --git a/src/core/Output.hpp b/src/core/Output.hpp index d42c8008..3a610f81 100644 --- a/src/core/Output.hpp +++ b/src/core/Output.hpp @@ -2,26 +2,31 @@ #include "../defines.hpp" #include "wayland.hpp" -#include "../helpers/Math.hpp" #include "LockSurface.hpp" -#include class COutput { public: - COutput(SP output, uint32_t name); + COutput() = default; + ~COutput() = default; - uint32_t name = 0; - bool focused = false; - wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; - Vector2D size; - int scale = 1; - std::string stringName = ""; - std::string stringPort = ""; - std::string stringDesc = ""; + void create(WP pSelf, SP pWlOutput, uint32_t name); - std::unique_ptr sessionLockSurface; + uint32_t name = 0; + bool focused = false; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; + Vector2D size; + int scale = 1; + std::string stringName = ""; + std::string stringPort = ""; + std::string stringDesc = ""; - SP output = nullptr; + UP m_sessionLockSurface; + + SP m_wlOutput = nullptr; + + WP m_self; + + void createSessionLockSurface(); private: }; diff --git a/src/core/Seat.cpp b/src/core/Seat.cpp index 7e2ebcb3..56d96fd8 100644 --- a/src/core/Seat.cpp +++ b/src/core/Seat.cpp @@ -131,7 +131,7 @@ void CSeatManager::registerSeat(SP seat) { } void CSeatManager::registerCursorShape(SP shape) { - m_pCursorShape = std::make_unique(shape); + m_pCursorShape = makeUnique(shape); } bool CSeatManager::registered() { diff --git a/src/core/Seat.hpp b/src/core/Seat.hpp index 4a89738d..bf6a7a0d 100644 --- a/src/core/Seat.hpp +++ b/src/core/Seat.hpp @@ -5,29 +5,28 @@ #include "wayland.hpp" #include #include -#include class CSeatManager { public: CSeatManager() = default; ~CSeatManager(); - void registerSeat(SP seat); - void registerCursorShape(SP shape); - bool registered(); + void registerSeat(SP seat); + void registerCursorShape(SP shape); + bool registered(); - SP m_pKeeb; - SP m_pPointer; + SP m_pKeeb; + SP m_pPointer; - std::unique_ptr m_pCursorShape; + UP m_pCursorShape; - xkb_context* m_pXKBContext = nullptr; - xkb_keymap* m_pXKBKeymap = nullptr; - xkb_state* m_pXKBState = nullptr; - xkb_compose_state* m_pXKBComposeState = nullptr; + xkb_context* m_pXKBContext = nullptr; + xkb_keymap* m_pXKBKeymap = nullptr; + xkb_state* m_pXKBState = nullptr; + xkb_compose_state* m_pXKBComposeState = nullptr; private: SP m_pSeat; }; -inline std::unique_ptr g_pSeatManager = std::make_unique(); +inline UP g_pSeatManager = makeUnique(); diff --git a/src/core/hyprlock.cpp b/src/core/hyprlock.cpp index 144b288d..cfd3e75e 100644 --- a/src/core/hyprlock.cpp +++ b/src/core/hyprlock.cpp @@ -6,6 +6,7 @@ #include "../auth/Auth.hpp" #include "../auth/Fingerprint.hpp" #include "Egl.hpp" +#include #include #include #include @@ -43,7 +44,7 @@ CHyprlock::CHyprlock(const std::string& wlDisplay, const bool immediate, const b exit(1); } - g_pEGL = std::make_unique(m_sWaylandState.display); + g_pEGL = makeUnique(m_sWaylandState.display); if (!immediate) { static const auto GRACE = g_pConfigManager->getValue("general:grace"); @@ -283,10 +284,10 @@ void CHyprlock::run() { } else if (IFACE == ext_session_lock_manager_v1_interface.name) m_sWaylandState.sessionLock = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &ext_session_lock_manager_v1_interface, 1)); - else if (IFACE == wl_output_interface.name) - m_vOutputs.emplace_back( - std::make_unique(makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wl_output_interface, 4)), name)); - else if (IFACE == wp_cursor_shape_manager_v1_interface.name) + else if (IFACE == wl_output_interface.name) { + m_vOutputs.emplace_back(makeShared()); + m_vOutputs.back()->create(m_vOutputs.back(), makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wl_output_interface, 4)), name); + } else if (IFACE == wp_cursor_shape_manager_v1_interface.name) g_pSeatManager->registerCursorShape( makeShared((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wp_cursor_shape_manager_v1_interface, 1))); else if (IFACE == wl_compositor_interface.name) @@ -310,7 +311,7 @@ void CHyprlock::run() { Debug::log(LOG, " | removed iface {}", name); auto outputIt = std::ranges::find_if(m_vOutputs, [name](const auto& other) { return other->name == name; }); if (outputIt != m_vOutputs.end()) { - g_pRenderer->removeWidgetsFor(outputIt->get()->sessionLockSurface.get()); + g_pRenderer->removeWidgetsFor((*outputIt)->m_sessionLockSurface.get()); m_vOutputs.erase(outputIt); } }); @@ -325,8 +326,8 @@ void CHyprlock::run() { // gather info about monitors wl_display_roundtrip(m_sWaylandState.display); - g_pRenderer = std::make_unique(); - g_pAuth = std::make_unique(); + g_pRenderer = makeUnique(); + g_pAuth = makeUnique(); g_pAuth->start(); Debug::log(LOG, "Running on {}", m_sCurrentDesktop); @@ -433,7 +434,7 @@ void CHyprlock::run() { float least = 10000; for (auto& t : m_vTimers) { const auto TIME = std::clamp(t->leftMs(), 1.f, INFINITY); - least = std::min(TIME, least); + least = std::min(TIME, least); } m_sLoopState.timersMutex.unlock(); @@ -558,23 +559,23 @@ void CHyprlock::clearPasswordBuffer() { void CHyprlock::renderOutput(const std::string& stringPort) { const auto MON = std::ranges::find_if(m_vOutputs, [stringPort](const auto& other) { return other->stringPort == stringPort; }); - if (MON == m_vOutputs.end() || !MON->get()) + if (MON == m_vOutputs.end() || !*MON) return; - const auto PMONITOR = MON->get(); + const auto& PMONITOR = *MON; - if (!PMONITOR->sessionLockSurface) + if (!PMONITOR->m_sessionLockSurface) return; - PMONITOR->sessionLockSurface->render(); + PMONITOR->m_sessionLockSurface->render(); } void CHyprlock::renderAllOutputs() { for (auto& o : m_vOutputs) { - if (!o->sessionLockSurface) + if (!o->m_sessionLockSurface) continue; - o->sessionLockSurface->render(); + o->m_sessionLockSurface->render(); } } @@ -745,7 +746,7 @@ void CHyprlock::releaseSessionLock() { void CHyprlock::createSessionLockSurfaces() { for (auto& o : m_vOutputs) { - o->sessionLockSurface = std::make_unique(o.get()); + o->createSessionLockSurface(); } } diff --git a/src/core/hyprlock.hpp b/src/core/hyprlock.hpp index 862348e1..3fd4b588 100644 --- a/src/core/hyprlock.hpp +++ b/src/core/hyprlock.hpp @@ -37,9 +37,6 @@ class CHyprlock { void unlock(); bool isUnlocked(); - void onGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version); - void onGlobalRemoved(void* data, struct wl_registry* registry, uint32_t name); - std::shared_ptr addTimer(const std::chrono::system_clock::duration& timeout, std::function self, void* data)> cb_, void* data, bool force = false); @@ -104,7 +101,7 @@ class CHyprlock { std::shared_ptr m_pKeyRepeatTimer = nullptr; - std::vector> m_vOutputs; + std::vector> m_vOutputs; std::vector> getTimers(); struct { @@ -168,4 +165,4 @@ class CHyprlock { std::vector m_vPressedKeys; }; -inline std::unique_ptr g_pHyprlock; +inline UP g_pHyprlock; diff --git a/src/defines.hpp b/src/defines.hpp index 7ba623de..f7cd82ce 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -1,8 +1,10 @@ #pragma once #include +#include #include using namespace Hyprutils::Memory; using namespace Hyprgraphics; #define SP CSharedPointer -#define WP CWeakPointer \ No newline at end of file +#define WP CWeakPointer +#define UP CUniquePointer diff --git a/src/main.cpp b/src/main.cpp index ff2bcbcb..2d11b0cf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,10 +90,10 @@ int main(int argc, char** argv, char** envp) { } } - g_pAnimationManager = std::make_unique(); + g_pAnimationManager = makeUnique(); try { - g_pConfigManager = std::make_unique(configPath); + g_pConfigManager = makeUnique(configPath); g_pConfigManager->init(); } catch (const std::exception& ex) { Debug::log(CRIT, "ConfigManager threw: {}", ex.what()); @@ -107,7 +107,7 @@ int main(int argc, char** argv, char** envp) { g_pConfigManager->m_AnimationTree.setConfigForNode("fadeIn", false, 0.f, "default"); try { - g_pHyprlock = std::make_unique(wlDisplay, immediate, immediateRender); + g_pHyprlock = makeUnique(wlDisplay, immediate, immediateRender); g_pHyprlock->run(); } catch (const std::exception& ex) { Debug::log(CRIT, "Hyprlock threw: {}", ex.what()); diff --git a/src/renderer/AsyncResourceGatherer.cpp b/src/renderer/AsyncResourceGatherer.cpp index 7bfc401f..c1b1ec40 100644 --- a/src/renderer/AsyncResourceGatherer.cpp +++ b/src/renderer/AsyncResourceGatherer.cpp @@ -48,15 +48,12 @@ void CAsyncResourceGatherer::enqueueScreencopyFrames() { } for (auto& mon : mons) { - const auto MON = std::find_if(g_pHyprlock->m_vOutputs.begin(), g_pHyprlock->m_vOutputs.end(), - [mon](const auto& other) { return other->stringPort == mon || other->stringDesc.starts_with(mon); }); + const auto MON = std::ranges::find_if(g_pHyprlock->m_vOutputs, [mon](const auto& other) { return other->stringPort == mon || other->stringDesc.starts_with(mon); }); if (MON == g_pHyprlock->m_vOutputs.end()) continue; - const auto PMONITOR = MON->get(); - - scframes.emplace_back(std::make_unique(PMONITOR)); + scframes.emplace_back(makeUnique(*MON)); } } diff --git a/src/renderer/AsyncResourceGatherer.hpp b/src/renderer/AsyncResourceGatherer.hpp index d6aa13a3..bf177a51 100644 --- a/src/renderer/AsyncResourceGatherer.hpp +++ b/src/renderer/AsyncResourceGatherer.hpp @@ -75,7 +75,7 @@ class CAsyncResourceGatherer { Vector2D size; }; - std::vector> scframes; + std::vector> scframes; std::vector preloadTargets; std::mutex preloadTargetsMutex; diff --git a/src/renderer/Renderer.cpp b/src/renderer/Renderer.cpp index 6b75131e..04ae88cc 100644 --- a/src/renderer/Renderer.cpp +++ b/src/renderer/Renderer.cpp @@ -194,7 +194,7 @@ CRenderer::CRenderer() { borderShader.gradientLerp = glGetUniformLocation(prog, "gradientLerp"); borderShader.alpha = glGetUniformLocation(prog, "alpha"); - asyncResourceGatherer = std::make_unique(); + asyncResourceGatherer = makeUnique(); g_pAnimationManager->createAnimation(0.f, opacity, g_pConfigManager->m_AnimationTree.getConfig("fadeIn")); } @@ -397,9 +397,8 @@ void CRenderer::renderTextureMix(const CBox& box, const CTexture& tex, const CTe glBindTexture(tex.m_iTarget, 0); } -std::vector>* CRenderer::getOrCreateWidgetsFor(const CSessionLockSurface* surf) { +std::vector>* CRenderer::getOrCreateWidgetsFor(const CSessionLockSurface* surf) { if (!widgets.contains(surf)) { - auto CWIDGETS = g_pConfigManager->getWidgetConfigs(); std::ranges::sort(CWIDGETS, [](CConfigManager::SWidgetConfig& a, CConfigManager::SWidgetConfig& b) { @@ -407,8 +406,8 @@ std::vector>* CRenderer::getOrCreateWidgetsFor(const CS }); for (auto& c : CWIDGETS) { - if (!c.monitor.empty() && c.monitor != surf->output->stringPort && !surf->output->stringDesc.starts_with(c.monitor) && - !surf->output->stringDesc.starts_with("desc:" + c.monitor)) + const auto POUTPUT = surf->m_outputRef.lock(); + if (!c.monitor.empty() && c.monitor != POUTPUT->stringPort && !POUTPUT->stringDesc.starts_with(c.monitor) && !POUTPUT->stringDesc.starts_with("desc:" + c.monitor)) continue; // by type @@ -417,7 +416,7 @@ std::vector>* CRenderer::getOrCreateWidgetsFor(const CS std::string resourceID = ""; if (PATH == "screenshot") { - resourceID = CScreencopyFrame::getResourceId(surf->output); + resourceID = CScreencopyFrame::getResourceId(POUTPUT); // When the initial gather of the asyncResourceGatherer is completed (ready), all DMAFrames are available. // Dynamic ones are tricky, because a screencopy would copy hyprlock itself. if (asyncResourceGatherer->gathered) { @@ -433,13 +432,13 @@ std::vector>* CRenderer::getOrCreateWidgetsFor(const CS } else if (!PATH.empty()) resourceID = "background:" + PATH; - widgets[surf].emplace_back(std::make_unique(surf->size, surf->output, resourceID, c.values, PATH == "screenshot")); + widgets[surf].emplace_back(makeShared(surf->size, POUTPUT.get(), resourceID, c.values, PATH == "screenshot")); } else if (c.type == "input-field") { - widgets[surf].emplace_back(std::make_unique(surf->size, c.values, surf->output->stringPort)); + widgets[surf].emplace_back(makeShared(surf->size, c.values, POUTPUT->stringPort)); } else if (c.type == "label") { - widgets[surf].emplace_back(std::make_unique(surf->size, c.values, surf->output->stringPort)); + widgets[surf].emplace_back(makeShared(surf->size, c.values, POUTPUT->stringPort)); } else if (c.type == "shape") { - widgets[surf].emplace_back(std::make_unique(surf->size, c.values)); + widgets[surf].emplace_back(makeShared(surf->size, c.values)); } else if (c.type == "image") { const std::string PATH = std::any_cast(c.values.at("path")); @@ -447,7 +446,7 @@ std::vector>* CRenderer::getOrCreateWidgetsFor(const CS if (!PATH.empty()) resourceID = "image:" + PATH; - widgets[surf].emplace_back(std::make_unique(surf->size, surf->output, resourceID, c.values)); + widgets[surf].emplace_back(makeShared(surf->size, POUTPUT.get(), resourceID, c.values)); } } } diff --git a/src/renderer/Renderer.hpp b/src/renderer/Renderer.hpp index 344dadeb..128ce076 100644 --- a/src/renderer/Renderer.hpp +++ b/src/renderer/Renderer.hpp @@ -1,9 +1,9 @@ #pragma once -#include #include #include #include "Shader.hpp" +#include "../defines.hpp" #include "../core/LockSurface.hpp" #include "../helpers/AnimatedVariable.hpp" #include "../helpers/Color.hpp" @@ -12,7 +12,7 @@ #include "widgets/IWidget.hpp" #include "Framebuffer.hpp" -typedef std::unordered_map>> widgetMap_t; +typedef std::unordered_map>> widgetMap_t; class CRenderer { public: @@ -29,7 +29,7 @@ class CRenderer { float boostA = 1.0; }; - SRenderFeedback renderLock(const CSessionLockSurface& surface); + SRenderFeedback renderLock(const CSessionLockSurface& surf); void renderRect(const CBox& box, const CHyprColor& col, int rounding = 0); void renderBorder(const CBox& box, const CGradientValueData& gradient, int thickness, int rounding = 0, float alpha = 1.0); @@ -37,37 +37,37 @@ class CRenderer { void renderTextureMix(const CBox& box, const CTexture& tex, const CTexture& tex2, float a = 1.0, float mixFactor = 0.0, int rounding = 0, std::optional tr = {}); void blurFB(const CFramebuffer& outfb, SBlurParams params); - std::unique_ptr asyncResourceGatherer; - std::chrono::system_clock::time_point firstFullFrameTime; + UP asyncResourceGatherer; + std::chrono::system_clock::time_point firstFullFrameTime; - void pushFb(GLint fb); - void popFb(); + void pushFb(GLint fb); + void popFb(); - void removeWidgetsFor(const CSessionLockSurface* surf); + void removeWidgetsFor(const CSessionLockSurface* surf); - void startFadeIn(); - void startFadeOut(bool unlock = false, bool immediate = true); + void startFadeIn(); + void startFadeOut(bool unlock = false, bool immediate = true); private: - widgetMap_t widgets; + widgetMap_t widgets; - std::vector>* getOrCreateWidgetsFor(const CSessionLockSurface* surf); + std::vector>* getOrCreateWidgetsFor(const CSessionLockSurface* surf); - CShader rectShader; - CShader texShader; - CShader texMixShader; - CShader blurShader1; - CShader blurShader2; - CShader blurPrepareShader; - CShader blurFinishShader; - CShader borderShader; + CShader rectShader; + CShader texShader; + CShader texMixShader; + CShader blurShader1; + CShader blurShader2; + CShader blurPrepareShader; + CShader blurFinishShader; + CShader borderShader; - Mat3x3 projMatrix = Mat3x3::identity(); - Mat3x3 projection; + Mat3x3 projMatrix = Mat3x3::identity(); + Mat3x3 projection; - PHLANIMVAR opacity; + PHLANIMVAR opacity; - std::vector boundFBs; + std::vector boundFBs; }; -inline std::unique_ptr g_pRenderer; +inline UP g_pRenderer; diff --git a/src/renderer/Screencopy.cpp b/src/renderer/Screencopy.cpp index 16e6cd3b..ef84c04b 100644 --- a/src/renderer/Screencopy.cpp +++ b/src/renderer/Screencopy.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -22,24 +23,27 @@ static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullpt static PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr; // -std::string CScreencopyFrame::getResourceId(COutput* output) { - return std::format("screencopy:{}-{}x{}", output->stringPort, output->size.x, output->size.y); +std::string CScreencopyFrame::getResourceId(SP pOutput) { + return std::format("screencopy:{}-{}x{}", pOutput->stringPort, pOutput->size.x, pOutput->size.y); } -CScreencopyFrame::CScreencopyFrame(COutput* output) : m_output(output) { - m_resourceID = getResourceId(m_output); - +CScreencopyFrame::CScreencopyFrame(SP pOutput) : m_outputRef(pOutput) { captureOutput(); static const auto SCMODE = g_pConfigManager->getValue("general:screencopy_mode"); if (*SCMODE == 1) - m_frame = std::make_unique(m_sc); + m_frame = makeUnique(m_sc); else - m_frame = std::make_unique(m_sc); + m_frame = makeUnique(m_sc); } void CScreencopyFrame::captureOutput() { - m_sc = makeShared(g_pHyprlock->getScreencopy()->sendCaptureOutput(false, m_output->output->resource())); + const auto POUTPUT = m_outputRef.lock(); + RASSERT(POUTPUT, "Screencopy, but no valid output"); + + m_resourceID = getResourceId(POUTPUT); + + m_sc = makeShared(g_pHyprlock->getScreencopy()->sendCaptureOutput(false, POUTPUT->m_wlOutput->resource())); m_sc->setBufferDone([this](CCZwlrScreencopyFrameV1* r) { Debug::log(TRACE, "[sc] wlrOnBufferDone for {}", (void*)this); diff --git a/src/renderer/Screencopy.hpp b/src/renderer/Screencopy.hpp index 8a707a2c..7c0987bc 100644 --- a/src/renderer/Screencopy.hpp +++ b/src/renderer/Screencopy.hpp @@ -22,9 +22,9 @@ class ISCFrame { class CScreencopyFrame { public: - static std::string getResourceId(COutput* output); + static std::string getResourceId(SP pOutput); - CScreencopyFrame(COutput* mon); + CScreencopyFrame(SP pOutput); ~CScreencopyFrame() = default; void captureOutput(); @@ -35,10 +35,10 @@ class CScreencopyFrame { SPreloadedAsset m_asset; private: - COutput* m_output = nullptr; - std::unique_ptr m_frame = nullptr; + WP m_outputRef; + UP m_frame = nullptr; - bool m_dmaFailed = false; + bool m_dmaFailed = false; }; // Uses a gpu buffer created via gbm_bo diff --git a/src/renderer/widgets/Background.cpp b/src/renderer/widgets/Background.cpp index 42ec74f7..4b1fce81 100644 --- a/src/renderer/widgets/Background.cpp +++ b/src/renderer/widgets/Background.cpp @@ -150,8 +150,14 @@ bool CBackground::draw(const SRenderData& data) { HYPRUTILS_TRANSFORM_NORMAL); // this could be omitted but whatever it's only once and makes code cleaner plus less blurring on large texs if (blurPasses > 0) - g_pRenderer->blurFB(blurredFB, CRenderer::SBlurParams{ - .size = blurSize, .passes = blurPasses, .noise = noise, .contrast = contrast, .brightness = brightness, .vibrancy = vibrancy, .vibrancy_darkness = vibrancy_darkness}); + g_pRenderer->blurFB(blurredFB, + CRenderer::SBlurParams{.size = blurSize, + .passes = blurPasses, + .noise = noise, + .contrast = contrast, + .brightness = brightness, + .vibrancy = vibrancy, + .vibrancy_darkness = vibrancy_darkness}); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } @@ -190,7 +196,7 @@ void CBackground::onCrossFadeTimerUpdate() { if (fade) { fade->crossFadeTimer.reset(); - fade.reset(nullptr); + fade.reset(); } if (blurPasses <= 0 && !isScreenshot) @@ -262,7 +268,7 @@ void CBackground::startCrossFadeOrUpdateRender() { if (crossFadeTime > 0) { // Start a fade if (!fade) - fade = std::make_unique(std::chrono::system_clock::now(), 0, nullptr); + fade = makeUnique(std::chrono::system_clock::now(), 0, nullptr); else { // Maybe we where already fading so reset it just in case, but should'nt be happening. if (fade->crossFadeTimer) { diff --git a/src/renderer/widgets/Background.hpp b/src/renderer/widgets/Background.hpp index 65623f55..b8423027 100644 --- a/src/renderer/widgets/Background.hpp +++ b/src/renderer/widgets/Background.hpp @@ -60,11 +60,11 @@ class CBackground : public IWidget { SPreloadedAsset* pendingAsset = nullptr; bool firstRender = true; - std::unique_ptr fade; + UP fade; int reloadTime = -1; std::string reloadCommand; CAsyncResourceGatherer::SPreloadRequest request; std::shared_ptr reloadTimer; std::filesystem::file_time_type modificationTime; -}; \ No newline at end of file +}; diff --git a/src/renderer/widgets/Shadowable.hpp b/src/renderer/widgets/Shadowable.hpp index 5a18a158..daf7cddd 100644 --- a/src/renderer/widgets/Shadowable.hpp +++ b/src/renderer/widgets/Shadowable.hpp @@ -29,4 +29,4 @@ class CShadowable { bool ignoreDraw = false; CFramebuffer shadowFB; -}; \ No newline at end of file +}; From 51381df4f6cd88ec07ad5fa38aa76724ff73b952 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Sat, 8 Feb 2025 11:13:39 +0100 Subject: [PATCH 2/2] widgets: make widgets have a self ref to avoid UB --- src/config/ConfigDataValues.hpp | 2 +- src/core/LockSurface.cpp | 4 +- src/core/LockSurface.hpp | 1 + src/core/Output.cpp | 4 + src/core/Output.hpp | 2 + src/renderer/AsyncResourceGatherer.cpp | 13 +- src/renderer/AsyncResourceGatherer.hpp | 3 +- src/renderer/Renderer.cpp | 56 ++++----- src/renderer/Renderer.hpp | 1 + src/renderer/widgets/Background.cpp | 124 +++++++++++++------- src/renderer/widgets/Background.hpp | 15 ++- src/renderer/widgets/IWidget.cpp | 2 +- src/renderer/widgets/IWidget.hpp | 9 +- src/renderer/widgets/Image.cpp | 67 +++++++---- src/renderer/widgets/Image.hpp | 9 +- src/renderer/widgets/Label.cpp | 75 +++++++----- src/renderer/widgets/Label.hpp | 9 +- src/renderer/widgets/PasswordInputField.cpp | 65 +++++++--- src/renderer/widgets/PasswordInputField.hpp | 61 ++++++---- src/renderer/widgets/Shadowable.cpp | 11 +- src/renderer/widgets/Shadowable.hpp | 4 +- src/renderer/widgets/Shape.cpp | 15 ++- src/renderer/widgets/Shape.hpp | 8 +- 23 files changed, 359 insertions(+), 201 deletions(-) diff --git a/src/config/ConfigDataValues.hpp b/src/config/ConfigDataValues.hpp index 90b9fb76..7d10017e 100644 --- a/src/config/ConfigDataValues.hpp +++ b/src/config/ConfigDataValues.hpp @@ -27,7 +27,7 @@ class ICustomConfigValueData { class CLayoutValueData : public ICustomConfigValueData { public: - CLayoutValueData() {}; + CLayoutValueData() = default; virtual ~CLayoutValueData() {}; virtual eConfigValueDataTypes getDataType() { diff --git a/src/core/LockSurface.cpp b/src/core/LockSurface.cpp index 22f1a468..108b243e 100644 --- a/src/core/LockSurface.cpp +++ b/src/core/LockSurface.cpp @@ -101,8 +101,8 @@ void CSessionLockSurface::configure(const Vector2D& size_, uint32_t serial_) { } if (readyForFrame && !(SAMESIZE && SAMESCALE)) { - g_pRenderer->removeWidgetsFor(this); - Debug::log(LOG, "Reloading widgets"); + Debug::log(LOG, "output {} changed, reloading widgets!", POUTPUT->stringPort); + g_pRenderer->reconfigureWidgetsFor(this); } readyForFrame = true; diff --git a/src/core/LockSurface.hpp b/src/core/LockSurface.hpp index a6bb0ef9..c87c1c21 100644 --- a/src/core/LockSurface.hpp +++ b/src/core/LockSurface.hpp @@ -50,4 +50,5 @@ class CSessionLockSurface { SP frameCallback = nullptr; friend class CRenderer; + friend class COutput; }; diff --git a/src/core/Output.cpp b/src/core/Output.cpp index 0e069da0..f2f0519f 100644 --- a/src/core/Output.cpp +++ b/src/core/Output.cpp @@ -48,3 +48,7 @@ void COutput::create(WP pSelf, SP pWlOutput, uint32_t _name void COutput::createSessionLockSurface() { m_sessionLockSurface = makeUnique(m_self.lock()); } + +Vector2D COutput::getViewport() const { + return (m_sessionLockSurface) ? m_sessionLockSurface->size : size; +} diff --git a/src/core/Output.hpp b/src/core/Output.hpp index 3a610f81..5a189038 100644 --- a/src/core/Output.hpp +++ b/src/core/Output.hpp @@ -28,5 +28,7 @@ class COutput { void createSessionLockSurface(); + Vector2D getViewport() const; + private: }; diff --git a/src/renderer/AsyncResourceGatherer.cpp b/src/renderer/AsyncResourceGatherer.cpp index c1b1ec40..45219c5a 100644 --- a/src/renderer/AsyncResourceGatherer.cpp +++ b/src/renderer/AsyncResourceGatherer.cpp @@ -301,17 +301,6 @@ void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) { preloadTargets.push_back(target); } -struct STimerCallbackData { - void (*cb)(void*) = nullptr; - void* data = nullptr; -}; - -static void timerCallback(std::shared_ptr self, void* data_) { - auto data = (STimerCallbackData*)data_; - data->cb(data->data); - delete data; -} - void CAsyncResourceGatherer::asyncAssetSpinLock() { while (!g_pHyprlock->m_bTerminate) { @@ -346,7 +335,7 @@ void CAsyncResourceGatherer::asyncAssetSpinLock() { // plant timer for callback if (r.callback) - g_pHyprlock->addTimer(std::chrono::milliseconds(0), timerCallback, new STimerCallbackData{.cb = r.callback, .data = r.callbackData}); + g_pHyprlock->addTimer(std::chrono::milliseconds(0), [cb = r.callback](auto, auto) { cb(); }, nullptr); } } } diff --git a/src/renderer/AsyncResourceGatherer.hpp b/src/renderer/AsyncResourceGatherer.hpp index bf177a51..24aedd66 100644 --- a/src/renderer/AsyncResourceGatherer.hpp +++ b/src/renderer/AsyncResourceGatherer.hpp @@ -37,8 +37,7 @@ class CAsyncResourceGatherer { // optional. Callbacks will be dispatched from the main thread, // so wayland/gl calls are OK. // will fire once the resource is fully loaded and ready. - void (*callback)(void*) = nullptr; - void* callbackData = nullptr; + std::function callback = nullptr; }; void requestAsyncAssetPreload(const SPreloadRequest& request); diff --git a/src/renderer/Renderer.cpp b/src/renderer/Renderer.cpp index 04ae88cc..9bea0fea 100644 --- a/src/renderer/Renderer.cpp +++ b/src/renderer/Renderer.cpp @@ -397,6 +397,13 @@ void CRenderer::renderTextureMix(const CBox& box, const CTexture& tex, const CTe glBindTexture(tex.m_iTarget, 0); } +template +static void createWidget(std::vector>& widgets) { + const auto W = makeShared(); + W->registerSelf(W); + widgets.emplace_back(W); +} + std::vector>* CRenderer::getOrCreateWidgetsFor(const CSessionLockSurface* surf) { if (!widgets.contains(surf)) { auto CWIDGETS = g_pConfigManager->getWidgetConfigs(); @@ -412,42 +419,21 @@ std::vector>* CRenderer::getOrCreateWidgetsFor(const CSessionLockSur // by type if (c.type == "background") { - const std::string PATH = std::any_cast(c.values.at("path")); - - std::string resourceID = ""; - if (PATH == "screenshot") { - resourceID = CScreencopyFrame::getResourceId(POUTPUT); - // When the initial gather of the asyncResourceGatherer is completed (ready), all DMAFrames are available. - // Dynamic ones are tricky, because a screencopy would copy hyprlock itself. - if (asyncResourceGatherer->gathered) { - if (!asyncResourceGatherer->getAssetByID(resourceID)) - resourceID = ""; // Fallback to solid color (background:color) - } - - if (!g_pHyprlock->getScreencopy()) { - Debug::log(ERR, "No screencopy support! path=screenshot won't work. Falling back to background color."); - resourceID = ""; - } - - } else if (!PATH.empty()) - resourceID = "background:" + PATH; - - widgets[surf].emplace_back(makeShared(surf->size, POUTPUT.get(), resourceID, c.values, PATH == "screenshot")); + createWidget(widgets[surf]); } else if (c.type == "input-field") { - widgets[surf].emplace_back(makeShared(surf->size, c.values, POUTPUT->stringPort)); + createWidget(widgets[surf]); } else if (c.type == "label") { - widgets[surf].emplace_back(makeShared(surf->size, c.values, POUTPUT->stringPort)); + createWidget(widgets[surf]); } else if (c.type == "shape") { - widgets[surf].emplace_back(makeShared(surf->size, c.values)); + createWidget(widgets[surf]); } else if (c.type == "image") { - const std::string PATH = std::any_cast(c.values.at("path")); - - std::string resourceID = ""; - if (!PATH.empty()) - resourceID = "image:" + PATH; - - widgets[surf].emplace_back(makeShared(surf->size, POUTPUT.get(), resourceID, c.values)); + createWidget(widgets[surf]); + } else { + Debug::log(ERR, "Unknown widget type: {}", c.type); + continue; } + + widgets[surf].back()->configure(c.values, POUTPUT); } } @@ -621,6 +607,14 @@ void CRenderer::removeWidgetsFor(const CSessionLockSurface* surf) { widgets.erase(surf); } +void CRenderer::reconfigureWidgetsFor(const CSessionLockSurface* surf) { + // TODO: reconfigure widgets by just calling configure again. + // Requires a way to get a widgets config properties. + // I think the best way would be to store the anonymos key of the widget config. + removeWidgetsFor(surf); + getOrCreateWidgetsFor(surf); +} + void CRenderer::startFadeIn() { Debug::log(LOG, "Starting fade in"); *opacity = 1.f; diff --git a/src/renderer/Renderer.hpp b/src/renderer/Renderer.hpp index 128ce076..1cf40db4 100644 --- a/src/renderer/Renderer.hpp +++ b/src/renderer/Renderer.hpp @@ -44,6 +44,7 @@ class CRenderer { void popFb(); void removeWidgetsFor(const CSessionLockSurface* surf); + void reconfigureWidgetsFor(const CSessionLockSurface* surf); void startFadeIn(); void startFadeOut(bool unlock = false, bool immediate = true); diff --git a/src/renderer/widgets/Background.cpp b/src/renderer/widgets/Background.cpp index 4b1fce81..0bac3b7a 100644 --- a/src/renderer/widgets/Background.cpp +++ b/src/renderer/widgets/Background.cpp @@ -10,23 +10,15 @@ #include CBackground::~CBackground() { + reset(); +} - if (reloadTimer) { - reloadTimer->cancel(); - reloadTimer.reset(); - } - - if (fade) { - if (fade->crossFadeTimer) { - fade->crossFadeTimer->cancel(); - fade->crossFadeTimer.reset(); - } - fade.reset(); - } +void CBackground::registerSelf(const SP& self) { + m_self = self; } -CBackground::CBackground(const Vector2D& viewport_, COutput* output_, const std::string& resourceID_, const std::unordered_map& props, bool ss) : - viewport(viewport_), resourceID(resourceID_), output(output_), isScreenshot(ss) { +void CBackground::configure(const std::unordered_map& props, const SP& pOutput) { + reset(); try { color = std::any_cast(props.at("color")); @@ -48,6 +40,29 @@ CBackground::CBackground(const Vector2D& viewport_, COutput* output_, const std: RASSERT(false, "Missing propperty for CBackground: {}", e.what()); // } + isScreenshot = path == "screenshot"; + + viewport = pOutput->getViewport(); + outputPort = pOutput->stringPort; + transform = isScreenshot ? wlTransformToHyprutils(invertTransform(pOutput->transform)) : HYPRUTILS_TRANSFORM_NORMAL; + + if (isScreenshot) { + resourceID = CScreencopyFrame::getResourceId(pOutput); + // When the initial gather of the asyncResourceGatherer is completed (ready), all DMAFrames are available. + // Dynamic ones are tricky, because a screencopy would copy hyprlock itself. + if (g_pRenderer->asyncResourceGatherer->gathered) { + if (!g_pRenderer->asyncResourceGatherer->getAssetByID(resourceID)) + resourceID = ""; // Fallback to solid color (background:color) + } + + if (!g_pHyprlock->getScreencopy()) { + Debug::log(ERR, "No screencopy support! path=screenshot won't work. Falling back to background color."); + resourceID = ""; + } + + } else if (!path.empty()) + resourceID = "background:" + path; + if (!isScreenshot && reloadTime > -1) { try { modificationTime = std::filesystem::last_write_time(absolutePath(path, "")); @@ -57,30 +72,57 @@ CBackground::CBackground(const Vector2D& viewport_, COutput* output_, const std: } } +void CBackground::reset() { + if (reloadTimer) { + reloadTimer->cancel(); + reloadTimer.reset(); + } + + if (fade) { + if (fade->crossFadeTimer) { + fade->crossFadeTimer->cancel(); + fade->crossFadeTimer.reset(); + } + fade.reset(); + } + + if (g_pHyprlock->m_bTerminate) + return; // Who cares about unloading assets when we're about to exit?? + + // Unload existing assets + if (pendingAsset) + g_pRenderer->asyncResourceGatherer->unloadAsset(pendingAsset); + + pendingAsset = nullptr; + pendingResourceID = ""; + + if (asset) + g_pRenderer->asyncResourceGatherer->unloadAsset(asset); + + asset = nullptr; + resourceID = ""; +} + void CBackground::renderRect(CHyprColor color) { CBox monbox = {0, 0, viewport.x, viewport.y}; g_pRenderer->renderRect(monbox, color, 0); } -static void onReloadTimer(std::shared_ptr self, void* data) { - const auto PBG = (CBackground*)data; - - PBG->onReloadTimerUpdate(); - PBG->plantReloadTimer(); -} - -static void onCrossFadeTimer(std::shared_ptr self, void* data) { - const auto PBG = (CBackground*)data; - PBG->onCrossFadeTimerUpdate(); +static void onReloadTimer(WP ref) { + if (auto PBG = ref.lock(); PBG) { + PBG->onReloadTimerUpdate(); + PBG->plantReloadTimer(); + } } -static void onAssetCallback(void* data) { - const auto PBG = (CBackground*)data; - PBG->startCrossFadeOrUpdateRender(); +static void onCrossFadeTimer(WP ref) { + if (auto PBG = ref.lock(); PBG) + PBG->onCrossFadeTimerUpdate(); } -static void onAssetCallbackTimer(std::shared_ptr self, void* data) { - onAssetCallback(data); +static void onAssetCallback(WP ref) { + if (auto PBG = ref.lock(); PBG) + PBG->startCrossFadeOrUpdateRender(); } bool CBackground::draw(const SRenderData& data) { @@ -115,7 +157,7 @@ bool CBackground::draw(const SRenderData& data) { // make it brah Vector2D size = asset->texture.m_vSize; - if (output->transform % 2 == 1 && isScreenshot) { + if (transform % 2 == 1 && isScreenshot) { size.x = asset->texture.m_vSize.y; size.y = asset->texture.m_vSize.x; } @@ -142,12 +184,9 @@ bool CBackground::draw(const SRenderData& data) { if (fade) g_pRenderer->renderTextureMix(texbox, asset->texture, pendingAsset->texture, 1.0, std::chrono::duration_cast(std::chrono::system_clock::now() - fade->start).count() / (1000 * crossFadeTime), 0, - HYPRUTILS_TRANSFORM_NORMAL); + transform); else - g_pRenderer->renderTexture(texbox, asset->texture, 1.0, 0, - isScreenshot ? - wlTransformToHyprutils(invertTransform(output->transform)) : - HYPRUTILS_TRANSFORM_NORMAL); // this could be omitted but whatever it's only once and makes code cleaner plus less blurring on large texs + g_pRenderer->renderTexture(texbox, asset->texture, 1.0, 0, transform); if (blurPasses > 0) g_pRenderer->blurFB(blurredFB, @@ -185,9 +224,9 @@ bool CBackground::draw(const SRenderData& data) { void CBackground::plantReloadTimer() { if (reloadTime == 0) - reloadTimer = g_pHyprlock->addTimer(std::chrono::hours(1), onReloadTimer, this, true); + reloadTimer = g_pHyprlock->addTimer(std::chrono::hours(1), [REF = m_self](auto, auto) { onReloadTimer(REF); }, nullptr, true); else if (reloadTime > 0) - reloadTimer = g_pHyprlock->addTimer(std::chrono::seconds(reloadTime), onReloadTimer, this, false); + reloadTimer = g_pHyprlock->addTimer(std::chrono::seconds(reloadTime), [REF = m_self](auto, auto) { onReloadTimer(REF); }, nullptr, true); } void CBackground::onCrossFadeTimerUpdate() { @@ -208,7 +247,7 @@ void CBackground::onCrossFadeTimerUpdate() { pendingAsset = nullptr; firstRender = true; - g_pHyprlock->renderOutput(output->stringPort); + g_pHyprlock->renderOutput(outputPort); } void CBackground::onReloadTimerUpdate() { @@ -251,8 +290,7 @@ void CBackground::onReloadTimerUpdate() { request.asset = path; request.type = CAsyncResourceGatherer::eTargetType::TARGET_IMAGE; - request.callback = onAssetCallback; - request.callbackData = this; + request.callback = [REF = m_self]() { onAssetCallback(REF); }; g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request); } @@ -278,15 +316,15 @@ void CBackground::startCrossFadeOrUpdateRender() { } fade->start = std::chrono::system_clock::now(); fade->a = 0; - fade->crossFadeTimer = g_pHyprlock->addTimer(std::chrono::milliseconds((int)(1000.0 * crossFadeTime)), onCrossFadeTimer, this); + fade->crossFadeTimer = g_pHyprlock->addTimer(std::chrono::milliseconds((int)(1000.0 * crossFadeTime)), [REF = m_self](auto, auto) { onCrossFadeTimer(REF); }, this); } else { onCrossFadeTimerUpdate(); } } } else if (!pendingResourceID.empty()) { Debug::log(WARN, "Asset {} not available after the asyncResourceGatherer's callback!", pendingResourceID); - g_pHyprlock->addTimer(std::chrono::milliseconds(100), onAssetCallbackTimer, this); + g_pHyprlock->addTimer(std::chrono::milliseconds(100), [REF = m_self](auto, auto) { onAssetCallback(REF); }, this); } - g_pHyprlock->renderOutput(output->stringPort); + g_pHyprlock->renderOutput(outputPort); } diff --git a/src/renderer/widgets/Background.hpp b/src/renderer/widgets/Background.hpp index b8423027..55630020 100644 --- a/src/renderer/widgets/Background.hpp +++ b/src/renderer/widgets/Background.hpp @@ -6,6 +6,7 @@ #include "../../core/Timer.hpp" #include "../Framebuffer.hpp" #include "../AsyncResourceGatherer.hpp" +#include #include #include #include @@ -23,10 +24,16 @@ struct SFade { class CBackground : public IWidget { public: - CBackground(const Vector2D& viewport, COutput* output_, const std::string& resourceID, const std::unordered_map& props, bool ss_); + CBackground() = default; ~CBackground(); + void registerSelf(const SP& self); + + virtual void configure(const std::unordered_map& props, const SP& pOutput); virtual bool draw(const SRenderData& data); + + void reset(); // Unload assets, remove timers, etc. + void renderRect(CHyprColor color); void onReloadTimerUpdate(); @@ -35,6 +42,8 @@ class CBackground : public IWidget { void startCrossFadeOrUpdateRender(); private: + WP m_self; + // if needed CFramebuffer blurredFB; @@ -48,6 +57,9 @@ class CBackground : public IWidget { Vector2D viewport; std::string path = ""; + std::string outputPort; + Hyprutils::Math::eTransform transform; + std::string resourceID; std::string pendingResourceID; @@ -55,7 +67,6 @@ class CBackground : public IWidget { CHyprColor color; SPreloadedAsset* asset = nullptr; - COutput* output = nullptr; bool isScreenshot = false; SPreloadedAsset* pendingAsset = nullptr; bool firstRender = true; diff --git a/src/renderer/widgets/IWidget.cpp b/src/renderer/widgets/IWidget.cpp index bfff2930..bf39f98e 100644 --- a/src/renderer/widgets/IWidget.cpp +++ b/src/renderer/widgets/IWidget.cpp @@ -22,7 +22,7 @@ namespace std { } #endif -Vector2D rotateVector(const Vector2D& vec, const double& ang) { +static Vector2D rotateVector(const Vector2D& vec, const double& ang) { const double COS = std::abs(std::cos(ang)); const double SIN = std::abs(std::sin(ang)); return Vector2D((vec.x * COS) + (vec.y * SIN), (vec.x * SIN) + (vec.y * COS)); diff --git a/src/renderer/widgets/IWidget.hpp b/src/renderer/widgets/IWidget.hpp index e8ac135c..f13f6c38 100644 --- a/src/renderer/widgets/IWidget.hpp +++ b/src/renderer/widgets/IWidget.hpp @@ -1,16 +1,23 @@ #pragma once #include "../../helpers/Math.hpp" +#include "../../defines.hpp" #include +#include +#include + +class COutput; class IWidget { public: struct SRenderData { float opacity = 1; }; + virtual ~IWidget() = default; - virtual bool draw(const SRenderData& data) = 0; + virtual void configure(const std::unordered_map& prop, const SP& pOutput) = 0; + virtual bool draw(const SRenderData& data) = 0; static Vector2D posFromHVAlign(const Vector2D& viewport, const Vector2D& size, const Vector2D& offset, const std::string& halign, const std::string& valign, const double& ang = 0); diff --git a/src/renderer/widgets/Image.cpp b/src/renderer/widgets/Image.cpp index bae396c2..e376966c 100644 --- a/src/renderer/widgets/Image.cpp +++ b/src/renderer/widgets/Image.cpp @@ -8,28 +8,30 @@ #include CImage::~CImage() { - if (imageTimer) { - imageTimer->cancel(); - imageTimer.reset(); - } + reset(); } -static void onTimer(std::shared_ptr self, void* data) { - const auto PIMAGE = (CImage*)data; +void CImage::registerSelf(const SP& self) { + m_self = self; +} + +static void onTimer(WP ref) { + if (auto PIMAGE = ref.lock(); PIMAGE) { + PIMAGE->onTimerUpdate(); + PIMAGE->plantTimer(); + } +} - PIMAGE->onTimerUpdate(); - PIMAGE->plantTimer(); +static void onAssetCallback(WP ref) { + if (auto PIMAGE = ref.lock(); PIMAGE) + PIMAGE->renderUpdate(); } -static void onAssetCallback(void* data) { +static void onAssetCallbackTimer(std::shared_ptr m_self, void* data) { const auto PIMAGE = (CImage*)data; PIMAGE->renderUpdate(); } -static void onAssetCallbackTimer(std::shared_ptr self, void* data) { - onAssetCallback(data); -} - void CImage::onTimerUpdate() { const std::string OLDPATH = path; @@ -65,9 +67,7 @@ void CImage::onTimerUpdate() { pendingResourceID = request.id; request.asset = path; request.type = CAsyncResourceGatherer::eTargetType::TARGET_IMAGE; - - request.callback = onAssetCallback; - request.callbackData = this; + request.callback = [REF = m_self]() { onAssetCallback(REF); }; g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request); } @@ -75,20 +75,23 @@ void CImage::onTimerUpdate() { void CImage::plantTimer() { if (reloadTime == 0) { - imageTimer = g_pHyprlock->addTimer(std::chrono::hours(1), onTimer, this, true); + imageTimer = g_pHyprlock->addTimer(std::chrono::hours(1), [REF = m_self](auto, auto) { onTimer(REF); }, this, true); } else if (reloadTime > 0) - imageTimer = g_pHyprlock->addTimer(std::chrono::seconds(reloadTime), onTimer, this, false); + imageTimer = g_pHyprlock->addTimer(std::chrono::seconds(reloadTime), [REF = m_self](auto, auto) { onTimer(REF); }, this, false); } -CImage::CImage(const Vector2D& viewport_, COutput* output_, const std::string& resourceID_, const std::unordered_map& props) : - viewport(viewport_), resourceID(resourceID_), output(output_), shadow(this, props, viewport_) { +void CImage::configure(const std::unordered_map& props, const SP& pOutput) { + reset(); + + shadow.configure(this, props, viewport); + viewport = pOutput->getViewport(); try { size = std::any_cast(props.at("size")); rounding = std::any_cast(props.at("rounding")); border = std::any_cast(props.at("border_size")); color = *CGradientValueData::fromAnyPv(props.at("border_color")); - pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_); + pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport); halign = std::any_cast(props.at("halign")); valign = std::any_cast(props.at("valign")); angle = std::any_cast(props.at("rotate")); @@ -113,6 +116,25 @@ CImage::CImage(const Vector2D& viewport_, COutput* output_, const std::string& r } } +void CImage::reset() { + if (imageTimer) { + imageTimer->cancel(); + imageTimer.reset(); + } + + if (g_pHyprlock->m_bTerminate) + return; + + imageFB.release(); + + if (asset) + g_pRenderer->asyncResourceGatherer->unloadAsset(asset); + + asset = nullptr; + pendingResourceID = ""; + resourceID = ""; +} + bool CImage::draw(const SRenderData& data) { if (resourceID.empty()) @@ -204,6 +226,9 @@ void CImage::renderUpdate() { pendingResourceID = ""; } else if (!pendingResourceID.empty()) { Debug::log(WARN, "Asset {} not available after the asyncResourceGatherer's callback!", pendingResourceID); + pendingResourceID = ""; + } else if (!pendingResourceID.empty()) { + Debug::log(WARN, "Asset {} not available after the asyncResourceGatherer's callback!", pendingResourceID); g_pHyprlock->addTimer(std::chrono::milliseconds(100), onAssetCallbackTimer, this); } diff --git a/src/renderer/widgets/Image.hpp b/src/renderer/widgets/Image.hpp index 1831efbf..24e8a9f5 100644 --- a/src/renderer/widgets/Image.hpp +++ b/src/renderer/widgets/Image.hpp @@ -17,16 +17,23 @@ class COutput; class CImage : public IWidget { public: - CImage(const Vector2D& viewport, COutput* output_, const std::string& resourceID, const std::unordered_map& props); + CImage() = default; ~CImage(); + void registerSelf(const SP& self); + + virtual void configure(const std::unordered_map& props, const SP& pOutput); virtual bool draw(const SRenderData& data); + void reset(); + void renderUpdate(); void onTimerUpdate(); void plantTimer(); private: + WP m_self; + CFramebuffer imageFB; int size; diff --git a/src/renderer/widgets/Label.cpp b/src/renderer/widgets/Label.cpp index dbd533a3..cbd72bda 100644 --- a/src/renderer/widgets/Label.cpp +++ b/src/renderer/widgets/Label.cpp @@ -8,31 +8,25 @@ #include CLabel::~CLabel() { - if (labelTimer) { - labelTimer->cancel(); - labelTimer.reset(); - } + reset(); } -static void onTimer(std::shared_ptr self, void* data) { - if (data == nullptr) - return; - const auto PLABEL = (CLabel*)data; - - // update label - PLABEL->onTimerUpdate(); - - // plant new timer - PLABEL->plantTimer(); +void CLabel::registerSelf(const SP& self) { + m_self = self; } -static void onAssetCallback(void* data) { - const auto PLABEL = (CLabel*)data; - PLABEL->renderUpdate(); +static void onTimer(WP ref) { + if (auto PLABEL = ref.lock(); PLABEL) { + // update label + PLABEL->onTimerUpdate(); + // plant new timer + PLABEL->plantTimer(); + } } -static void onAssetCallbackTimer(std::shared_ptr self, void* data) { - onAssetCallback(data); +static void onAssetCallback(WP ref) { + if (auto PLABEL = ref.lock(); PLABEL) + PLABEL->renderUpdate(); } std::string CLabel::getUniqueResourceId() { @@ -57,23 +51,28 @@ void CLabel::onTimerUpdate() { pendingResourceID = request.id; request.asset = label.formatted; - request.callback = onAssetCallback; - request.callbackData = this; + request.callback = [REF = m_self]() { onAssetCallback(REF); }; g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request); } void CLabel::plantTimer() { + if (label.updateEveryMs != 0) - labelTimer = g_pHyprlock->addTimer(std::chrono::milliseconds((int)label.updateEveryMs), onTimer, this, label.allowForceUpdate); + labelTimer = g_pHyprlock->addTimer(std::chrono::milliseconds((int)label.updateEveryMs), [REF = m_self](auto, auto) { onTimer(REF); }, this, label.allowForceUpdate); else if (label.updateEveryMs == 0 && label.allowForceUpdate) - labelTimer = g_pHyprlock->addTimer(std::chrono::hours(1), onTimer, this, true); + labelTimer = g_pHyprlock->addTimer(std::chrono::hours(1), [REF = m_self](auto, auto) { onTimer(REF); }, this, true); } -CLabel::CLabel(const Vector2D& viewport_, const std::unordered_map& props, const std::string& output) : - outputStringPort(output), shadow(this, props, viewport_) { +void CLabel::configure(const std::unordered_map& props, const SP& pOutput) { + reset(); + shadow.configure(this, props, viewport); + + outputStringPort = pOutput->stringPort; + viewport = pOutput->getViewport(); + try { - pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_); + configPos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport); labelPreFormat = std::any_cast(props.at("text")); halign = std::any_cast(props.at("halign")); valign = std::any_cast(props.at("valign")); @@ -82,7 +81,7 @@ CLabel::CLabel(const Vector2D& viewport_, const std::unordered_map(props.at("text_align")); std::string fontFamily = std::any_cast(props.at("font_family")); - CHyprColor labelColor = std::any_cast(props.at("color")); + CHyprColor labelColor = std::any_cast(props.at("color")); int fontSize = std::any_cast(props.at("font_size")); label = formatString(labelPreFormat); @@ -105,14 +104,30 @@ CLabel::CLabel(const Vector2D& viewport_, const std::unordered_mapasyncResourceGatherer->requestAsyncAssetPreload(request); plantTimer(); } +void CLabel::reset() { + if (labelTimer) { + labelTimer->cancel(); + labelTimer.reset(); + } + + if (g_pHyprlock->m_bTerminate) + return; + + if (asset) + g_pRenderer->asyncResourceGatherer->unloadAsset(asset); + + asset = nullptr; + pendingResourceID.clear(); + resourceID.clear(); +} + bool CLabel::draw(const SRenderData& data) { if (!asset) { asset = g_pRenderer->asyncResourceGatherer->getAssetByID(resourceID); @@ -150,7 +165,7 @@ void CLabel::renderUpdate() { } else { Debug::log(WARN, "Asset {} not available after the asyncResourceGatherer's callback!", pendingResourceID); - g_pHyprlock->addTimer(std::chrono::milliseconds(100), onAssetCallbackTimer, this); + g_pHyprlock->addTimer(std::chrono::milliseconds(100), [REF = m_self](auto, auto) { onAssetCallback(REF); }, this); return; } diff --git a/src/renderer/widgets/Label.hpp b/src/renderer/widgets/Label.hpp index 9a41cb59..b9d489a8 100644 --- a/src/renderer/widgets/Label.hpp +++ b/src/renderer/widgets/Label.hpp @@ -14,16 +14,23 @@ class CSessionLockSurface; class CLabel : public IWidget { public: - CLabel(const Vector2D& viewport, const std::unordered_map& props, const std::string& output); + CLabel() = default; ~CLabel(); + void registerSelf(const SP& self); + + virtual void configure(const std::unordered_map& prop, const SP& pOutput); virtual bool draw(const SRenderData& data); + void reset(); + void renderUpdate(); void onTimerUpdate(); void plantTimer(); private: + WP m_self; + std::string getUniqueResourceId(); std::string labelPreFormat; diff --git a/src/renderer/widgets/PasswordInputField.cpp b/src/renderer/widgets/PasswordInputField.cpp index fb630956..29fdf763 100644 --- a/src/renderer/widgets/PasswordInputField.cpp +++ b/src/renderer/widgets/PasswordInputField.cpp @@ -15,11 +15,24 @@ using namespace Hyprutils::String; -CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::unordered_map& props, const std::string& output) : - viewport(viewport_), outputStringPort(output), shadow(this, props, viewport_) { +CPasswordInputField::~CPasswordInputField() { + reset(); +} + +void CPasswordInputField::registerSelf(const SP& self) { + m_self = self; +} + +void CPasswordInputField::configure(const std::unordered_map& props, const SP& pOutput) { + reset(); + shadow.configure(this, props, viewport); + + outputStringPort = pOutput->stringPort; + viewport = pOutput->getViewport(); + try { - pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_); - configSize = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport_); + pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport); + configSize = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport); halign = std::any_cast(props.at("halign")); valign = std::any_cast(props.at("valign")); outThick = std::any_cast(props.at("outline_thickness")); @@ -61,6 +74,16 @@ CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::u colorConfig.caps = colorConfig.caps->m_bIsFallback ? colorConfig.fail : colorConfig.caps; + g_pAnimationManager->createAnimation(0.f, fade.a, g_pConfigManager->m_AnimationTree.getConfig("inputFieldFade")); + g_pAnimationManager->createAnimation(0.f, dots.currentAmount, g_pConfigManager->m_AnimationTree.getConfig("inputFieldDots")); + g_pAnimationManager->createAnimation(configSize, size, g_pConfigManager->m_AnimationTree.getConfig("inputFieldWidth")); + g_pAnimationManager->createAnimation(colorConfig.inner, colorState.inner, g_pConfigManager->m_AnimationTree.getConfig("inputFieldColors")); + g_pAnimationManager->createAnimation(*colorConfig.outer, colorState.outer, g_pConfigManager->m_AnimationTree.getConfig("inputFieldColors")); + + srand(std::chrono::system_clock::now().time_since_epoch().count()); + + pos = posFromHVAlign(viewport, size->goal(), configPos, halign, valign); + if (!dots.textFormat.empty()) { dots.textResourceID = std::format("input:{}-{}", (uintptr_t)this, dots.textFormat); CAsyncResourceGatherer::SPreloadRequest request; @@ -74,23 +97,30 @@ CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::u g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request); } - g_pAnimationManager->createAnimation(0.f, fade.a, g_pConfigManager->m_AnimationTree.getConfig("inputFieldFade")); - g_pAnimationManager->createAnimation(0.f, dots.currentAmount, g_pConfigManager->m_AnimationTree.getConfig("inputFieldDots")); - g_pAnimationManager->createAnimation(configSize, size, g_pConfigManager->m_AnimationTree.getConfig("inputFieldWidth")); - - g_pAnimationManager->createAnimation(colorConfig.inner, colorState.inner, g_pConfigManager->m_AnimationTree.getConfig("inputFieldColors")); - g_pAnimationManager->createAnimation(*colorConfig.outer, colorState.outer, g_pConfigManager->m_AnimationTree.getConfig("inputFieldColors")); - - srand(std::chrono::system_clock::now().time_since_epoch().count()); - // request the inital placeholder asset updatePlaceholder(); } -static void fadeOutCallback(std::shared_ptr self, void* data) { - CPasswordInputField* p = (CPasswordInputField*)data; +void CPasswordInputField::reset() { + if (fade.fadeOutTimer.get()) { + fade.fadeOutTimer->cancel(); + fade.fadeOutTimer.reset(); + } + + if (g_pHyprlock->m_bTerminate) + return; + + if (placeholder.asset) + g_pRenderer->asyncResourceGatherer->unloadAsset(placeholder.asset); + + placeholder.asset = nullptr; + placeholder.resourceID.clear(); + placeholder.currentText.clear(); +} - p->onFadeOutTimer(); +static void fadeOutCallback(WP ref) { + if (const auto PP = ref.lock(); PP) + PP->onFadeOutTimer(); } void CPasswordInputField::onFadeOutTimer() { @@ -121,7 +151,8 @@ void CPasswordInputField::updateFade() { *fade.a = 0.0; fade.allowFadeOut = false; } else if (!fade.fadeOutTimer.get()) - fade.fadeOutTimer = g_pHyprlock->addTimer(std::chrono::milliseconds(fadeTimeoutMs), fadeOutCallback, this); + fade.fadeOutTimer = g_pHyprlock->addTimer(std::chrono::milliseconds(fadeTimeoutMs), [REF = m_self](auto, auto) { fadeOutCallback(REF); }, nullptr); + } else if (INPUTUSED && fade.a->goal() != 1.0) *fade.a = 1.0; diff --git a/src/renderer/widgets/PasswordInputField.hpp b/src/renderer/widgets/PasswordInputField.hpp index b9d709f7..83d4fea3 100644 --- a/src/renderer/widgets/PasswordInputField.hpp +++ b/src/renderer/widgets/PasswordInputField.hpp @@ -8,6 +8,7 @@ #include "../../config/ConfigDataValues.hpp" #include "../../helpers/AnimatedVariable.hpp" #include +#include #include #include #include @@ -16,37 +17,45 @@ struct SPreloadedAsset; class CPasswordInputField : public IWidget { public: - CPasswordInputField(const Vector2D& viewport, const std::unordered_map& props, const std::string& output); + CPasswordInputField() = default; + virtual ~CPasswordInputField(); + void registerSelf(const SP& self); + + virtual void configure(const std::unordered_map& prop, const SP& pOutput); virtual bool draw(const SRenderData& data); + + void reset(); void onFadeOutTimer(); private: - void updateDots(); - void updateFade(); - void updatePlaceholder(); - void updateWidth(); - void updateHiddenInputState(); - void updateInputState(); - void updateColors(); - - bool firstRender = true; - bool redrawShadow = false; - bool checkWaiting = false; - bool displayFail = false; - - size_t passwordLength = 0; - - PHLANIMVAR size; - Vector2D pos; - Vector2D viewport; - Vector2D configPos; - Vector2D configSize; - - std::string halign, valign, configFailText, outputStringPort, configPlaceholderText, fontFamily; - uint64_t configFailTimeoutMs = 2000; - - int outThick, rounding; + WP m_self; + + void updateDots(); + void updateFade(); + void updatePlaceholder(); + void updateWidth(); + void updateHiddenInputState(); + void updateInputState(); + void updateColors(); + + bool firstRender = true; + bool redrawShadow = false; + bool checkWaiting = false; + bool displayFail = false; + + size_t passwordLength = 0; + + PHLANIMVAR size; + Vector2D pos; + Vector2D viewport; + Vector2D configPos; + Vector2D configSize; + + std::string halign, valign, configFailText, outputStringPort, configPlaceholderText, fontFamily; + uint64_t configFailTimeoutMs = 2000; + + int outThick, rounding; struct { PHLANIMVAR currentAmount; diff --git a/src/renderer/widgets/Shadowable.cpp b/src/renderer/widgets/Shadowable.cpp index 0eabedcb..151ebf52 100644 --- a/src/renderer/widgets/Shadowable.cpp +++ b/src/renderer/widgets/Shadowable.cpp @@ -2,7 +2,10 @@ #include "../Renderer.hpp" #include -CShadowable::CShadowable(IWidget* widget_, const std::unordered_map& props, const Vector2D& viewport_) : widget(widget_), viewport(viewport_) { +void CShadowable::configure(IWidget* widget_, const std::unordered_map& props, const Vector2D& viewport_) { + widget = widget_; + viewport = viewport_; + size = std::any_cast(props.at("shadow_size")); passes = std::any_cast(props.at("shadow_passes")); color = std::any_cast(props.at("shadow_color")); @@ -10,6 +13,8 @@ CShadowable::CShadowable(IWidget* widget_, const std::unordered_maprenderTexture(box, shadowFB.m_cTex, data.opacity, 0, HYPRUTILS_TRANSFORM_NORMAL); return true; -} \ No newline at end of file +} diff --git a/src/renderer/widgets/Shadowable.hpp b/src/renderer/widgets/Shadowable.hpp index daf7cddd..cb07b1e9 100644 --- a/src/renderer/widgets/Shadowable.hpp +++ b/src/renderer/widgets/Shadowable.hpp @@ -11,7 +11,9 @@ class CShadowable { public: - CShadowable(IWidget* widget_, const std::unordered_map& props, const Vector2D& viewport_ /* TODO: make this not the entire viewport */); + virtual ~CShadowable() = default; + CShadowable() = default; + void configure(IWidget* widget_, const std::unordered_map& props, const Vector2D& viewport_ /* TODO: make this not the entire viewport */); // instantly re-renders the shadow using the widget's draw() method void markShadowDirty(); diff --git a/src/renderer/widgets/Shape.cpp b/src/renderer/widgets/Shape.cpp index 144fe144..bb82ba5a 100644 --- a/src/renderer/widgets/Shape.cpp +++ b/src/renderer/widgets/Shape.cpp @@ -4,15 +4,21 @@ #include #include -CShape::CShape(const Vector2D& viewport_, const std::unordered_map& props) : shadow(this, props, viewport_) { +void CShape::registerSelf(const SP& self) { + m_self = self; +} + +void CShape::configure(const std::unordered_map& props, const SP& pOutput) { + shadow.configure(this, props, viewport); + viewport = pOutput->getViewport(); try { - size = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport_); + size = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport); rounding = std::any_cast(props.at("rounding")); border = std::any_cast(props.at("border_size")); color = std::any_cast(props.at("color")); borderGrad = *CGradientValueData::fromAnyPv(props.at("border_color")); - pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_); + pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport); halign = std::any_cast(props.at("halign")); valign = std::any_cast(props.at("valign")); angle = std::any_cast(props.at("rotate")); @@ -23,8 +29,7 @@ CShape::CShape(const Vector2D& viewport_, const std::unordered_map& props); + CShape() = default; + virtual ~CShape() = default; + void registerSelf(const SP& self); + + virtual void configure(const std::unordered_map& prop, const SP& pOutput); virtual bool draw(const SRenderData& data); private: + WP m_self; + CFramebuffer shapeFB; int rounding;