aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorUjinT34 <[email protected]>2024-10-12 03:29:51 +0300
committerGitHub <[email protected]>2024-10-12 01:29:51 +0100
commitee8116ac5dc412dce924a0163074ce7988dd0cfc (patch)
treed7c4785660a0d9112e57f20780d60e7542934117 /src
parentf5db4839730643169b7e8b7fb6ae2fbb8743ebe9 (diff)
downloadHyprland-ee8116ac5dc412dce924a0163074ce7988dd0cfc.tar.gz
Hyprland-ee8116ac5dc412dce924a0163074ce7988dd0cfc.zip
input: Fix VRR for constrained cursors (#6877)
Diffstat (limited to 'src')
-rw-r--r--src/Compositor.cpp4
-rw-r--r--src/events/Windows.cpp19
-rw-r--r--src/helpers/Monitor.cpp8
-rw-r--r--src/helpers/Monitor.hpp2
-rw-r--r--src/helpers/Timer.cpp5
-rw-r--r--src/helpers/Timer.hpp2
-rw-r--r--src/managers/AnimationManager.cpp2
-rw-r--r--src/managers/PointerManager.cpp43
-rw-r--r--src/managers/PointerManager.hpp7
-rw-r--r--src/managers/SeatManager.hpp3
-rw-r--r--src/managers/input/InputManager.cpp21
-rw-r--r--src/managers/input/InputManager.hpp1
12 files changed, 100 insertions, 17 deletions
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index 459aca11..dcc6422d 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -1,4 +1,5 @@
#include "Compositor.hpp"
+#include "debug/Log.hpp"
#include "helpers/Splashes.hpp"
#include "config/ConfigValue.hpp"
#include "managers/CursorManager.hpp"
@@ -1380,6 +1381,9 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
if (!validMapped(pWindow))
return;
+ if (pWindow == (top ? m_vWindows.back() : m_vWindows.front()))
+ return;
+
auto moveToZ = [&](PHLWINDOW pw, bool top) -> void {
if (top) {
for (auto it = m_vWindows.begin(); it != m_vWindows.end(); ++it) {
diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp
index 37f29130..e549907e 100644
--- a/src/events/Windows.cpp
+++ b/src/events/Windows.cpp
@@ -12,6 +12,7 @@
#include "../protocols/core/Compositor.hpp"
#include "../protocols/ToplevelExport.hpp"
#include "../xwayland/XSurface.hpp"
+#include "managers/PointerManager.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
@@ -758,8 +759,21 @@ void Events::listener_commitWindow(void* owner, void* data) {
if (!PWINDOW->m_pWorkspace->m_bVisible)
return;
- g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
- PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
+ const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
+
+ PMONITOR->debugLastPresentation(g_pSeatManager->isPointerFrameCommit ? "listener_commitWindow skip" : "listener_commitWindow");
+ if (g_pSeatManager->isPointerFrameCommit) {
+ g_pSeatManager->isPointerFrameSkipped = false;
+ g_pSeatManager->isPointerFrameCommit = false;
+ } else
+ g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
+ PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
+
+ if (g_pSeatManager->isPointerFrameSkipped) {
+ g_pPointerManager->sendStoredMovement();
+ g_pSeatManager->sendPointerFrame();
+ g_pSeatManager->isPointerFrameCommit = true;
+ }
if (!PWINDOW->m_bIsX11) {
PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces();
@@ -767,7 +781,6 @@ void Events::listener_commitWindow(void* owner, void* data) {
}
// tearing: if solitary, redraw it. This still might be a single surface window
- const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) {
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index f3e7de4e..091745df 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -16,6 +16,7 @@
#include "../protocols/core/Compositor.hpp"
#include "sync/SyncTimeline.hpp"
#include <aquamarine/output/Output.hpp>
+#include "debug/Log.hpp"
#include <hyprutils/string/String.hpp>
#include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::String;
@@ -384,7 +385,7 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
*PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
// keep requested minimum refresh rate
- if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) {
+ if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) {
// damage whole screen because some previous cursor box damages were skipped
damage.damageEntire();
return false;
@@ -933,6 +934,11 @@ bool CMonitor::attemptDirectScanout() {
return true;
}
+void CMonitor::debugLastPresentation(const std::string& message) {
+ Debug::log(TRACE, "{} (last presentation {} - {} fps)", message, lastPresentationTimer.getMillis(),
+ lastPresentationTimer.getMillis() > 0 ? 1000.0f / lastPresentationTimer.getMillis() : 0.0f);
+}
+
CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner;
}
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
index f5068dba..ad8a823b 100644
--- a/src/helpers/Monitor.hpp
+++ b/src/helpers/Monitor.hpp
@@ -185,6 +185,8 @@ class CMonitor {
bool attemptDirectScanout();
void setCTM(const Mat3x3& ctm);
+ void debugLastPresentation(const std::string& message);
+
bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;
diff --git a/src/helpers/Timer.cpp b/src/helpers/Timer.cpp
index 7b1726df..e00c5918 100644
--- a/src/helpers/Timer.cpp
+++ b/src/helpers/Timer.cpp
@@ -1,4 +1,5 @@
#include "Timer.hpp"
+#include <chrono>
void CTimer::reset() {
m_tpLastReset = std::chrono::steady_clock::now();
@@ -8,8 +9,8 @@ std::chrono::steady_clock::duration CTimer::getDuration() {
return std::chrono::steady_clock::now() - m_tpLastReset;
}
-long CTimer::getMillis() {
- return std::chrono::duration_cast<std::chrono::milliseconds>(getDuration()).count();
+float CTimer::getMillis() {
+ return std::chrono::duration_cast<std::chrono::microseconds>(getDuration()).count() / 1000.f;
}
float CTimer::getSeconds() {
diff --git a/src/helpers/Timer.hpp b/src/helpers/Timer.hpp
index 827e7625..a58225d0 100644
--- a/src/helpers/Timer.hpp
+++ b/src/helpers/Timer.hpp
@@ -6,7 +6,7 @@ class CTimer {
public:
void reset();
float getSeconds();
- long getMillis();
+ float getMillis();
const std::chrono::steady_clock::time_point& chrono() const;
private:
diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp
index 092d9721..0ff94f1f 100644
--- a/src/managers/AnimationManager.cpp
+++ b/src/managers/AnimationManager.cpp
@@ -259,7 +259,7 @@ void CAnimationManager::tick() {
// manually schedule a frame
if (PMONITOR)
- g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
+ g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_ANIMATION);
}
// do it here, because if this alters the animation vars deque we would be in trouble above.
diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp
index cc9deec7..8c2a1bad 100644
--- a/src/managers/PointerManager.cpp
+++ b/src/managers/PointerManager.cpp
@@ -2,6 +2,7 @@
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../protocols/PointerGestures.hpp"
+#include "../protocols/RelativePointer.hpp"
#include "../protocols/FractionalScale.hpp"
#include "../protocols/IdleNotify.hpp"
#include "../protocols/core/Compositor.hpp"
@@ -328,7 +329,7 @@ void CPointerManager::onCursorMoved() {
continue;
const auto CURSORPOS = getCursorPosForMonitor(m);
- m->output->moveCursor(CURSORPOS);
+ m->output->moveCursor(CURSORPOS, m->shouldSkipScheduleFrameOnMouseEvent());
}
if (recalc)
@@ -342,7 +343,7 @@ bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerS
return false;
const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock());
- state->monitor->output->moveCursor(CURSORPOS);
+ state->monitor->output->moveCursor(CURSORPOS, state->monitor->shouldSkipScheduleFrameOnMouseEvent());
auto texture = getCurrentCursorTexture();
@@ -385,7 +386,8 @@ bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquam
state->cursorFrontBuffer = buf;
- g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
+ if (!state->monitor->shouldSkipScheduleFrameOnMouseEvent())
+ g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
return true;
}
@@ -676,8 +678,11 @@ void CPointerManager::warpTo(const Vector2D& logical) {
damageIfSoftware();
pointerPos = closestValid(logical);
- recheckEnteredOutputs();
- onCursorMoved();
+
+ if (!g_pInputManager->isLocked()) {
+ recheckEnteredOutputs();
+ onCursorMoved();
+ }
damageIfSoftware();
}
@@ -859,7 +864,14 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
});
listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) {
- g_pSeatManager->sendPointerFrame();
+ bool shouldSkip = false;
+ if (!g_pSeatManager->mouse.expired() && g_pInputManager->isLocked()) {
+ auto PMONITOR = g_pCompositor->m_pLastMonitor.get();
+ shouldSkip = PMONITOR && PMONITOR->shouldSkipScheduleFrameOnMouseEvent();
+ }
+ g_pSeatManager->isPointerFrameSkipped = shouldSkip;
+ if (!g_pSeatManager->isPointerFrameSkipped)
+ g_pSeatManager->sendPointerFrame();
});
listener->swipeBegin = pointer->pointerEvents.swipeBegin.registerListener([this] (std::any e) {
@@ -1080,3 +1092,22 @@ void CPointerManager::damageCursor(SP<CMonitor> pMonitor) {
Vector2D CPointerManager::cursorSizeLogical() {
return currentCursorImage.size / currentCursorImage.scale;
}
+
+void CPointerManager::storeMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel) {
+ storedTime = time;
+ storedDelta += delta;
+ storedUnaccel += deltaUnaccel;
+}
+
+void CPointerManager::setStoredMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel) {
+ storedTime = time;
+ storedDelta = delta;
+ storedUnaccel = deltaUnaccel;
+}
+
+void CPointerManager::sendStoredMovement() {
+ PROTO::relativePointer->sendRelativeMotion((uint64_t)storedTime * 1000, storedDelta, storedUnaccel);
+ storedTime = 0;
+ storedDelta = Vector2D{};
+ storedUnaccel = Vector2D{};
+}
diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp
index 4a4c4f61..6b89eb16 100644
--- a/src/managers/PointerManager.hpp
+++ b/src/managers/PointerManager.hpp
@@ -61,6 +61,9 @@ class CPointerManager {
//
Vector2D position();
Vector2D cursorSizeLogical();
+ void storeMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel);
+ void setStoredMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel);
+ void sendStoredMovement();
void recheckEnteredOutputs();
@@ -154,6 +157,10 @@ class CPointerManager {
Vector2D pointerPos = {0, 0};
+ uint64_t storedTime = 0;
+ Vector2D storedDelta = {0, 0};
+ Vector2D storedUnaccel = {0, 0};
+
struct SMonitorPointerState {
SMonitorPointerState(SP<CMonitor> m) : monitor(m) {}
~SMonitorPointerState() {}
diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp
index 5cc7eee0..e50f123f 100644
--- a/src/managers/SeatManager.hpp
+++ b/src/managers/SeatManager.hpp
@@ -128,6 +128,9 @@ class CSeatManager {
void setGrab(SP<CSeatGrab> grab); // nullptr removes
SP<CSeatGrab> seatGrab;
+ bool isPointerFrameSkipped = false;
+ bool isPointerFrameCommit = false;
+
private:
struct SSeatResourceContainer {
SSeatResourceContainer(SP<CWLSeatResource>);
diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp
index 03c72919..eef5e040 100644
--- a/src/managers/input/InputManager.cpp
+++ b/src/managers/input/InputManager.cpp
@@ -87,6 +87,11 @@ void CInputManager::onMouseMoved(IPointer::SMotionEvent e) {
const auto DELTA = *PNOACCEL == 1 ? e.unaccel : e.delta;
+ if (g_pSeatManager->isPointerFrameSkipped)
+ g_pPointerManager->storeMovement((uint64_t)e.timeMs, DELTA, e.unaccel);
+ else
+ g_pPointerManager->setStoredMovement((uint64_t)e.timeMs, DELTA, e.unaccel);
+
PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel);
g_pPointerManager->move(DELTA);
@@ -167,7 +172,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
m_vLastCursorPosFloored = MOUSECOORDSFLOORED;
- const auto PMONITOR = g_pCompositor->getMonitorFromCursor();
+ const auto PMONITOR = isLocked() && g_pCompositor->m_pLastMonitor ? g_pCompositor->m_pLastMonitor.get() : g_pCompositor->getMonitorFromCursor();
// this can happen if there are no displays hooked up to Hyprland
if (PMONITOR == nullptr)
@@ -184,9 +189,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// constraints
if (!g_pSeatManager->mouse.expired() && isConstrained()) {
const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock());
- const auto CONSTRAINT = SURF->constraint();
+ const auto CONSTRAINT = SURF ? SURF->constraint() : nullptr;
- if (SURF && CONSTRAINT) {
+ if (CONSTRAINT) {
if (CONSTRAINT->isLocked()) {
const auto HINT = CONSTRAINT->logicPositionHint();
g_pCompositor->warpCursorTo(HINT, true);
@@ -1428,6 +1433,16 @@ bool CInputManager::isConstrained() {
return false;
}
+bool CInputManager::isLocked() {
+ if (!isConstrained())
+ return false;
+
+ const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock());
+ const auto CONSTRAINT = SURF ? SURF->constraint() : nullptr;
+
+ return CONSTRAINT && CONSTRAINT->isLocked();
+}
+
void CInputManager::updateCapabilities() {
uint32_t caps = 0;
diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp
index ebf00b2d..d5634796 100644
--- a/src/managers/input/InputManager.hpp
+++ b/src/managers/input/InputManager.hpp
@@ -108,6 +108,7 @@ class CInputManager {
void unconstrainMouse();
bool isConstrained();
+ bool isLocked();
Vector2D getMouseCoordsInternal();
void refocus();