From fb87e332c59ce386a095b3e81bb1abbcc9cc3e5c Mon Sep 17 00:00:00 2001 From: bvr-yr <130279855+bvr-yr@users.noreply.github.com> Date: Wed, 6 Mar 2024 03:15:44 +0300 Subject: [PATCH] input: fix window move stutter by introducing additional checks for low-hz monitors (#4553) * resize-limiter: add additional check for low-hz monitors * simplify checker * add comment * rename variable --- src/layout/IHyprLayout.cpp | 30 +++++++++++++++++++++++++----- src/layout/IHyprLayout.hpp | 1 + 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 2a84b024..26a30ecf 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -173,7 +173,8 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) { void IHyprLayout::onBeginDragWindow() { const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; - m_vBeginDragSizeXY = Vector2D(); + m_iMouseMoveEventCount = 1; + m_vBeginDragSizeXY = Vector2D(); // Window will be floating. Let's check if it's valid. It should be, but I don't like crashing. if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW)) { @@ -248,6 +249,8 @@ void IHyprLayout::onBeginDragWindow() { void IHyprLayout::onEndDragWindow() { const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; + m_iMouseMoveEventCount = 1; + if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW)) { if (DRAGGINGWINDOW) { g_pInputManager->unsetCursorImage(); @@ -303,7 +306,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { return; } - static auto TIMER = std::chrono::high_resolution_clock::now(); + static auto TIMER = std::chrono::high_resolution_clock::now(), MSTIMER = TIMER; const auto SPECIAL = g_pCompositor->isWorkspaceSpecial(DRAGGINGWINDOW->m_iWorkspaceID); @@ -313,9 +316,26 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { static auto PANIMATEMOUSE = CConfigValue("misc:animate_mouse_windowdragging"); static auto PANIMATE = CConfigValue("misc:animate_manual_resizes"); - if ((abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) || - (std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - TIMER).count() < - 1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate)) + const auto TIMERDELTA = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - TIMER).count(); + const auto MSDELTA = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - MSTIMER).count(); + const auto MSMONITOR = 1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate; + static int totalMs = 0; + bool canSkipUpdate = true; + + MSTIMER = std::chrono::high_resolution_clock::now(); + + if (m_iMouseMoveEventCount == 1) + totalMs = 0; + + if (MSMONITOR > 16.0) { + totalMs += MSDELTA < MSMONITOR ? MSDELTA : std::round(totalMs * 1.0 / m_iMouseMoveEventCount); + m_iMouseMoveEventCount += 1; + + // check if time-window is enough to skip update on 60hz monitor + canSkipUpdate = std::clamp(MSMONITOR - TIMERDELTA, 0.0, MSMONITOR) > totalMs * 1.0 / m_iMouseMoveEventCount; + } + + if ((abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) || (TIMERDELTA < MSMONITOR && canSkipUpdate)) return; TIMER = std::chrono::high_resolution_clock::now(); diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index ffe004bc..d3f8dfa6 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -188,6 +188,7 @@ class IHyprLayout { virtual Vector2D predictSizeForNewWindow(); private: + int m_iMouseMoveEventCount; Vector2D m_vBeginDragXY; Vector2D m_vLastDragXY; Vector2D m_vBeginDragPositionXY;