mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-15 11:05:58 +01:00
input: Fix VRR for constrained cursors (#6877)
This commit is contained in:
parent
f5db483973
commit
ee8116ac5d
12 changed files with 100 additions and 17 deletions
|
@ -1,4 +1,5 @@
|
||||||
#include "Compositor.hpp"
|
#include "Compositor.hpp"
|
||||||
|
#include "debug/Log.hpp"
|
||||||
#include "helpers/Splashes.hpp"
|
#include "helpers/Splashes.hpp"
|
||||||
#include "config/ConfigValue.hpp"
|
#include "config/ConfigValue.hpp"
|
||||||
#include "managers/CursorManager.hpp"
|
#include "managers/CursorManager.hpp"
|
||||||
|
@ -1380,6 +1381,9 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
|
||||||
if (!validMapped(pWindow))
|
if (!validMapped(pWindow))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (pWindow == (top ? m_vWindows.back() : m_vWindows.front()))
|
||||||
|
return;
|
||||||
|
|
||||||
auto moveToZ = [&](PHLWINDOW pw, bool top) -> void {
|
auto moveToZ = [&](PHLWINDOW pw, bool top) -> void {
|
||||||
if (top) {
|
if (top) {
|
||||||
for (auto it = m_vWindows.begin(); it != m_vWindows.end(); ++it) {
|
for (auto it = m_vWindows.begin(); it != m_vWindows.end(); ++it) {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "../protocols/core/Compositor.hpp"
|
#include "../protocols/core/Compositor.hpp"
|
||||||
#include "../protocols/ToplevelExport.hpp"
|
#include "../protocols/ToplevelExport.hpp"
|
||||||
#include "../xwayland/XSurface.hpp"
|
#include "../xwayland/XSurface.hpp"
|
||||||
|
#include "managers/PointerManager.hpp"
|
||||||
|
|
||||||
#include <hyprutils/string/String.hpp>
|
#include <hyprutils/string/String.hpp>
|
||||||
using namespace Hyprutils::String;
|
using namespace Hyprutils::String;
|
||||||
|
@ -758,16 +759,28 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||||
if (!PWINDOW->m_pWorkspace->m_bVisible)
|
if (!PWINDOW->m_pWorkspace->m_bVisible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
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,
|
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);
|
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) {
|
if (!PWINDOW->m_bIsX11) {
|
||||||
PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces();
|
PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces();
|
||||||
PWINDOW->m_pPopupHead->recheckTree();
|
PWINDOW->m_pPopupHead->recheckTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
// tearing: if solitary, redraw it. This still might be a single surface window
|
// 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) {
|
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) {
|
||||||
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
|
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "../protocols/core/Compositor.hpp"
|
#include "../protocols/core/Compositor.hpp"
|
||||||
#include "sync/SyncTimeline.hpp"
|
#include "sync/SyncTimeline.hpp"
|
||||||
#include <aquamarine/output/Output.hpp>
|
#include <aquamarine/output/Output.hpp>
|
||||||
|
#include "debug/Log.hpp"
|
||||||
#include <hyprutils/string/String.hpp>
|
#include <hyprutils/string/String.hpp>
|
||||||
#include <hyprutils/utils/ScopeGuard.hpp>
|
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||||
using namespace Hyprutils::String;
|
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;
|
*PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
|
||||||
|
|
||||||
// keep requested minimum refresh rate
|
// 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 whole screen because some previous cursor box damages were skipped
|
||||||
damage.damageEntire();
|
damage.damageEntire();
|
||||||
return false;
|
return false;
|
||||||
|
@ -933,6 +934,11 @@ bool CMonitor::attemptDirectScanout() {
|
||||||
return true;
|
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) {
|
CMonitorState::CMonitorState(CMonitor* owner) {
|
||||||
m_pOwner = owner;
|
m_pOwner = owner;
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,6 +185,8 @@ class CMonitor {
|
||||||
bool attemptDirectScanout();
|
bool attemptDirectScanout();
|
||||||
void setCTM(const Mat3x3& ctm);
|
void setCTM(const Mat3x3& ctm);
|
||||||
|
|
||||||
|
void debugLastPresentation(const std::string& message);
|
||||||
|
|
||||||
bool m_bEnabled = false;
|
bool m_bEnabled = false;
|
||||||
bool m_bRenderingInitPassed = false;
|
bool m_bRenderingInitPassed = false;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "Timer.hpp"
|
#include "Timer.hpp"
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
void CTimer::reset() {
|
void CTimer::reset() {
|
||||||
m_tpLastReset = std::chrono::steady_clock::now();
|
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;
|
return std::chrono::steady_clock::now() - m_tpLastReset;
|
||||||
}
|
}
|
||||||
|
|
||||||
long CTimer::getMillis() {
|
float CTimer::getMillis() {
|
||||||
return std::chrono::duration_cast<std::chrono::milliseconds>(getDuration()).count();
|
return std::chrono::duration_cast<std::chrono::microseconds>(getDuration()).count() / 1000.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float CTimer::getSeconds() {
|
float CTimer::getSeconds() {
|
||||||
|
|
|
@ -6,7 +6,7 @@ class CTimer {
|
||||||
public:
|
public:
|
||||||
void reset();
|
void reset();
|
||||||
float getSeconds();
|
float getSeconds();
|
||||||
long getMillis();
|
float getMillis();
|
||||||
const std::chrono::steady_clock::time_point& chrono() const;
|
const std::chrono::steady_clock::time_point& chrono() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -259,7 +259,7 @@ void CAnimationManager::tick() {
|
||||||
|
|
||||||
// manually schedule a frame
|
// manually schedule a frame
|
||||||
if (PMONITOR)
|
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.
|
// do it here, because if this alters the animation vars deque we would be in trouble above.
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "../Compositor.hpp"
|
#include "../Compositor.hpp"
|
||||||
#include "../config/ConfigValue.hpp"
|
#include "../config/ConfigValue.hpp"
|
||||||
#include "../protocols/PointerGestures.hpp"
|
#include "../protocols/PointerGestures.hpp"
|
||||||
|
#include "../protocols/RelativePointer.hpp"
|
||||||
#include "../protocols/FractionalScale.hpp"
|
#include "../protocols/FractionalScale.hpp"
|
||||||
#include "../protocols/IdleNotify.hpp"
|
#include "../protocols/IdleNotify.hpp"
|
||||||
#include "../protocols/core/Compositor.hpp"
|
#include "../protocols/core/Compositor.hpp"
|
||||||
|
@ -328,7 +329,7 @@ void CPointerManager::onCursorMoved() {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const auto CURSORPOS = getCursorPosForMonitor(m);
|
const auto CURSORPOS = getCursorPosForMonitor(m);
|
||||||
m->output->moveCursor(CURSORPOS);
|
m->output->moveCursor(CURSORPOS, m->shouldSkipScheduleFrameOnMouseEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recalc)
|
if (recalc)
|
||||||
|
@ -342,7 +343,7 @@ bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerS
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock());
|
const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock());
|
||||||
state->monitor->output->moveCursor(CURSORPOS);
|
state->monitor->output->moveCursor(CURSORPOS, state->monitor->shouldSkipScheduleFrameOnMouseEvent());
|
||||||
|
|
||||||
auto texture = getCurrentCursorTexture();
|
auto texture = getCurrentCursorTexture();
|
||||||
|
|
||||||
|
@ -385,6 +386,7 @@ bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquam
|
||||||
|
|
||||||
state->cursorFrontBuffer = buf;
|
state->cursorFrontBuffer = buf;
|
||||||
|
|
||||||
|
if (!state->monitor->shouldSkipScheduleFrameOnMouseEvent())
|
||||||
g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
|
g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -676,8 +678,11 @@ void CPointerManager::warpTo(const Vector2D& logical) {
|
||||||
damageIfSoftware();
|
damageIfSoftware();
|
||||||
|
|
||||||
pointerPos = closestValid(logical);
|
pointerPos = closestValid(logical);
|
||||||
|
|
||||||
|
if (!g_pInputManager->isLocked()) {
|
||||||
recheckEnteredOutputs();
|
recheckEnteredOutputs();
|
||||||
onCursorMoved();
|
onCursorMoved();
|
||||||
|
}
|
||||||
|
|
||||||
damageIfSoftware();
|
damageIfSoftware();
|
||||||
}
|
}
|
||||||
|
@ -859,6 +864,13 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
|
||||||
});
|
});
|
||||||
|
|
||||||
listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) {
|
listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) {
|
||||||
|
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();
|
g_pSeatManager->sendPointerFrame();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1080,3 +1092,22 @@ void CPointerManager::damageCursor(SP<CMonitor> pMonitor) {
|
||||||
Vector2D CPointerManager::cursorSizeLogical() {
|
Vector2D CPointerManager::cursorSizeLogical() {
|
||||||
return currentCursorImage.size / currentCursorImage.scale;
|
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{};
|
||||||
|
}
|
||||||
|
|
|
@ -61,6 +61,9 @@ class CPointerManager {
|
||||||
//
|
//
|
||||||
Vector2D position();
|
Vector2D position();
|
||||||
Vector2D cursorSizeLogical();
|
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();
|
void recheckEnteredOutputs();
|
||||||
|
|
||||||
|
@ -154,6 +157,10 @@ class CPointerManager {
|
||||||
|
|
||||||
Vector2D pointerPos = {0, 0};
|
Vector2D pointerPos = {0, 0};
|
||||||
|
|
||||||
|
uint64_t storedTime = 0;
|
||||||
|
Vector2D storedDelta = {0, 0};
|
||||||
|
Vector2D storedUnaccel = {0, 0};
|
||||||
|
|
||||||
struct SMonitorPointerState {
|
struct SMonitorPointerState {
|
||||||
SMonitorPointerState(SP<CMonitor> m) : monitor(m) {}
|
SMonitorPointerState(SP<CMonitor> m) : monitor(m) {}
|
||||||
~SMonitorPointerState() {}
|
~SMonitorPointerState() {}
|
||||||
|
|
|
@ -128,6 +128,9 @@ class CSeatManager {
|
||||||
void setGrab(SP<CSeatGrab> grab); // nullptr removes
|
void setGrab(SP<CSeatGrab> grab); // nullptr removes
|
||||||
SP<CSeatGrab> seatGrab;
|
SP<CSeatGrab> seatGrab;
|
||||||
|
|
||||||
|
bool isPointerFrameSkipped = false;
|
||||||
|
bool isPointerFrameCommit = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SSeatResourceContainer {
|
struct SSeatResourceContainer {
|
||||||
SSeatResourceContainer(SP<CWLSeatResource>);
|
SSeatResourceContainer(SP<CWLSeatResource>);
|
||||||
|
|
|
@ -87,6 +87,11 @@ void CInputManager::onMouseMoved(IPointer::SMotionEvent e) {
|
||||||
|
|
||||||
const auto DELTA = *PNOACCEL == 1 ? e.unaccel : e.delta;
|
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);
|
PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel);
|
||||||
|
|
||||||
g_pPointerManager->move(DELTA);
|
g_pPointerManager->move(DELTA);
|
||||||
|
@ -167,7 +172,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||||
|
|
||||||
m_vLastCursorPosFloored = MOUSECOORDSFLOORED;
|
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
|
// this can happen if there are no displays hooked up to Hyprland
|
||||||
if (PMONITOR == nullptr)
|
if (PMONITOR == nullptr)
|
||||||
|
@ -184,9 +189,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||||
// constraints
|
// constraints
|
||||||
if (!g_pSeatManager->mouse.expired() && isConstrained()) {
|
if (!g_pSeatManager->mouse.expired() && isConstrained()) {
|
||||||
const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock());
|
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()) {
|
if (CONSTRAINT->isLocked()) {
|
||||||
const auto HINT = CONSTRAINT->logicPositionHint();
|
const auto HINT = CONSTRAINT->logicPositionHint();
|
||||||
g_pCompositor->warpCursorTo(HINT, true);
|
g_pCompositor->warpCursorTo(HINT, true);
|
||||||
|
@ -1428,6 +1433,16 @@ bool CInputManager::isConstrained() {
|
||||||
return false;
|
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() {
|
void CInputManager::updateCapabilities() {
|
||||||
uint32_t caps = 0;
|
uint32_t caps = 0;
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,7 @@ class CInputManager {
|
||||||
|
|
||||||
void unconstrainMouse();
|
void unconstrainMouse();
|
||||||
bool isConstrained();
|
bool isConstrained();
|
||||||
|
bool isLocked();
|
||||||
|
|
||||||
Vector2D getMouseCoordsInternal();
|
Vector2D getMouseCoordsInternal();
|
||||||
void refocus();
|
void refocus();
|
||||||
|
|
Loading…
Reference in a new issue