From 0dbd9970031940b50f9cce4c88989c2830d2a15f Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Wed, 20 Sep 2023 16:47:05 +0100 Subject: [PATCH] input: Various constraint handling fixes (#3381) Fixes #3204 --- src/Compositor.cpp | 7 ++- src/helpers/Monitor.hpp | 1 + src/helpers/Region.cpp | 12 +++-- src/helpers/Region.hpp | 9 ++-- src/helpers/WLClasses.cpp | 77 +++++++++++++++++++++++++++++ src/helpers/WLClasses.hpp | 8 ++- src/managers/input/InputManager.cpp | 21 ++++---- 7 files changed, 114 insertions(+), 21 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index e2b920c2..99e62a46 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -875,7 +875,7 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) { const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID); PWORKSPACE->m_pLastFocusedWindow = pWindow; PWORKSPACE->rememberPrevWorkspace(getWorkspaceByID(m_pLastMonitor->activeWorkspace)); - const auto PMONITOR = getMonitorFromID(PWORKSPACE->m_iMonitorID); + const auto PMONITOR = getMonitorFromID(PWORKSPACE->m_iMonitorID); PMONITOR->changeWorkspace(PWORKSPACE, false, true); // changeworkspace already calls focusWindow return; @@ -2530,5 +2530,10 @@ void CCompositor::arrangeMonitors() { Debug::log(LOG, "arrangeMonitors: {} xwayland [{}, {:.2f}]", m->szName, maxOffset, 0.f); m->vecXWaylandPosition = {maxOffset, 0}; maxOffset += (*PXWLFORCESCALEZERO ? m->vecTransformedSize.x : m->vecSize.x); + + if (*PXWLFORCESCALEZERO) + m->xwaylandScale = m->scale; + else + m->xwaylandScale = 1.f; } } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 2c4d4a89..93f345ba 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -59,6 +59,7 @@ class CMonitor { bool scheduledRecalc = false; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; bool gammaChanged = false; + float xwaylandScale = 1.f; bool dpmsStatus = true; bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. diff --git a/src/helpers/Region.cpp b/src/helpers/Region.cpp index 644bd5d4..e2db4664 100644 --- a/src/helpers/Region.cpp +++ b/src/helpers/Region.cpp @@ -1,5 +1,6 @@ #include "Region.hpp" #include +#include CRegion::CRegion() { pixman_region32_init(&m_rRegion); @@ -81,6 +82,11 @@ CRegion& CRegion::translate(const Vector2D& vec) { return *this; } +CRegion& CRegion::scale(float scale) { + wlr_region_scale(&m_rRegion, &m_rRegion, scale); + return *this; +} + std::vector CRegion::getRects() const { std::vector result; @@ -97,15 +103,15 @@ wlr_box CRegion::getExtents() { return {box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1}; } -bool CRegion::containsPoint(const Vector2D& vec) { +bool CRegion::containsPoint(const Vector2D& vec) const { return pixman_region32_contains_point(&m_rRegion, vec.x, vec.y, nullptr); } -bool CRegion::empty() { +bool CRegion::empty() const { return !pixman_region32_not_empty(&m_rRegion); } -Vector2D CRegion::closestPoint(const Vector2D& vec) { +Vector2D CRegion::closestPoint(const Vector2D& vec) const { double bestDist = __FLT_MAX__; Vector2D leader = vec; diff --git a/src/helpers/Region.hpp b/src/helpers/Region.hpp index e5a99da2..cc745f9e 100644 --- a/src/helpers/Region.hpp +++ b/src/helpers/Region.hpp @@ -42,15 +42,16 @@ class CRegion { CRegion& intersect(double x, double y, double w, double h); CRegion& translate(const Vector2D& vec); CRegion& invert(pixman_box32_t* box); + CRegion& scale(float scale); wlr_box getExtents(); - bool containsPoint(const Vector2D& vec); - bool empty(); - Vector2D closestPoint(const Vector2D& vec); + bool containsPoint(const Vector2D& vec) const; + bool empty() const; + Vector2D closestPoint(const Vector2D& vec) const; std::vector getRects() const; pixman_region32_t* pixman() { - return &m_rRegion; + return &m_rRegion; } private: diff --git a/src/helpers/WLClasses.cpp b/src/helpers/WLClasses.cpp index c257b6b8..1fa807fa 100644 --- a/src/helpers/WLClasses.cpp +++ b/src/helpers/WLClasses.cpp @@ -1,5 +1,6 @@ #include "WLClasses.hpp" #include "../config/ConfigManager.hpp" +#include "../Compositor.hpp" SLayerSurface::SLayerSurface() { alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_ENTIRE); @@ -37,4 +38,80 @@ void SLayerSurface::applyRules() { } catch (...) {} } } +} + +CRegion SConstraint::getLogicCoordsRegion() { + CRegion result; + + if (!constraint) + return result; + + const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface); + + if (!PWINDOWOWNER) + return result; + + result.add(&constraint->region); // surface-local coords + + if (!PWINDOWOWNER->m_bIsX11) { + result.translate(PWINDOWOWNER->m_vRealPosition.goalv()); + return result; + } + + const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goalv() : + g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y}); + + const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ? g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) : g_pCompositor->getMonitorFromVector(COORDS); + + if (!PMONITOR) + return CRegion{}; + + result.scale(PMONITOR->xwaylandScale); + + result.translate(COORDS); + + return result; +} + +Vector2D SConstraint::getLogicConstraintPos() { + if (!constraint) + return {}; + + const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface); + + if (!PWINDOWOWNER) + return {}; + + if (!PWINDOWOWNER->m_bIsX11) + return PWINDOWOWNER->m_vRealPosition.goalv(); + + const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goalv() : + g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y}); + + return COORDS; +} + +Vector2D SConstraint::getLogicConstraintSize() { + if (!constraint) + return {}; + + const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface); + + if (!PWINDOWOWNER) + return {}; + + if (!PWINDOWOWNER->m_bIsX11) + return PWINDOWOWNER->m_vRealSize.goalv(); + + const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ? + g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) : + g_pCompositor->getMonitorFromVector(g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y})); + + if (!PMONITOR) + return {}; + + const auto SIZE = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealSize.goalv() : + Vector2D{PWINDOWOWNER->m_uSurface.xwayland->width, PWINDOWOWNER->m_uSurface.xwayland->height} * PMONITOR->xwaylandScale; + + return SIZE; } \ No newline at end of file diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 84f6d898..d66ebdfd 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -174,8 +174,12 @@ struct SConstraint { DYNLISTENER(setConstraintRegion); DYNLISTENER(destroyConstraint); - bool operator==(const SConstraint& b) const { - return constraint == b.constraint; + CRegion getLogicCoordsRegion(); + Vector2D getLogicConstraintPos(); + Vector2D getLogicConstraintSize(); + + bool operator==(const SConstraint& b) const { + return constraint == b.constraint; } }; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 468f2816..ec1534d5 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -144,26 +144,25 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } else { // Native Wayland apps know how 2 constrain themselves. // XWayland, we just have to accept them. Might cause issues, but thats XWayland for ya. - const auto CONSTRAINTPOS = - CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->x, CONSTRAINTWINDOW->m_uSurface.xwayland->y) : CONSTRAINTWINDOW->m_vRealPosition.vec(); - const auto CONSTRAINTSIZE = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->width, CONSTRAINTWINDOW->m_uSurface.xwayland->height) : - CONSTRAINTWINDOW->m_vRealSize.vec(); + const auto CONSTRAINTPOS = PCONSTRAINT->getLogicConstraintPos(); + const auto CONSTRAINTSIZE = PCONSTRAINT->getLogicConstraintSize(); if (g_pCompositor->m_sSeat.mouse->currentConstraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) { // we just snap the cursor to where it should be. - Vector2D hint = {PCONSTRAINT->positionHint.x, PCONSTRAINT->positionHint.y}; - - if (hint != Vector2D{-1, -1}) - wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, CONSTRAINTPOS.x + hint.x, CONSTRAINTPOS.y + hint.y); + if (PCONSTRAINT->hintSet) + wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, CONSTRAINTPOS.x + PCONSTRAINT->positionHint.x, + CONSTRAINTPOS.y + PCONSTRAINT->positionHint.y); return; // don't process anything else, the cursor is locked. The surface should not receive any further events. // these are usually FPS games. They will use the relative motion. } else { // we restrict the cursor to the confined region - if (!pixman_region32_contains_point(&PCONSTRAINT->constraint->region, mouseCoords.x - CONSTRAINTPOS.x, mouseCoords.y - CONSTRAINTPOS.y, nullptr)) { + const auto REGION = PCONSTRAINT->getLogicCoordsRegion(); + + if (!REGION.containsPoint(mouseCoords)) { if (g_pCompositor->m_sSeat.mouse->constraintActive) { - const auto CLOSEST = CRegion(&PCONSTRAINT->constraint->region).closestPoint(mouseCoords - CONSTRAINTPOS) + CONSTRAINTPOS; + const auto CLOSEST = REGION.closestPoint(mouseCoords); wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, NULL, CLOSEST.x, CLOSEST.y); mouseCoords = getMouseCoordsInternal(); } @@ -1595,7 +1594,7 @@ void CInputManager::setCursorIconOnBorder(CWindow* w) { wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; eBorderIconDirection direction = BORDERICON_NONE; wlr_box boxFullGrabInput = {box.x - *PEXTENDBORDERGRAB - BORDERSIZE, box.y - *PEXTENDBORDERGRAB - BORDERSIZE, box.width + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE), - box.height + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE)}; + box.height + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE)}; if (!wlr_box_contains_point(&boxFullGrabInput, mouseCoords.x, mouseCoords.y) || (!m_lCurrentlyHeldButtons.empty() && !currentlyDraggedWindow)) { direction = BORDERICON_NONE;