From 86f0d9914e31a410ca9468ef0eca707d0a085d48 Mon Sep 17 00:00:00 2001 From: Michael VanOverbeek Date: Tue, 20 Feb 2024 20:23:35 +0000 Subject: [PATCH] Fix zoom push mouse tracking on multi-monitor workspaces Zoom push tracking now considers the layout of the user's monitors, accounting for situations where the monitor layout doesn't form a perfect rectangle. These changes help prevent the zoom area from being unable to reach certain areas of the workspace depending on which edge of which screen the user pushes against. One known issue is that, if the mouse moves too quickly, the zoom area can sometimes imperfectly track the movement. It will look the same as the original bug (areas of the screen will appear to be cut off/unreachable), but moving the mouse in the opposite direction a tiny bit snaps the zoom area back to where it should be. BUG: 467182 @teams/qa Heads-up that I'm very blind, and this is the first time I've ever contributed to a KDE project. I've tested the changes on my system and they fix the bug, but I want to make sure I didn't break anything in the process. --- src/plugins/zoom/zoom.cpp | 49 ++++++++++++++++++++++++++++----------- src/plugins/zoom/zoom.h | 3 +++ 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/plugins/zoom/zoom.cpp b/src/plugins/zoom/zoom.cpp index e312e584fb..483e34dd5b 100644 --- a/src/plugins/zoom/zoom.cpp +++ b/src/plugins/zoom/zoom.cpp @@ -326,25 +326,42 @@ void ZoomEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewp break; case MouseTrackingPush: { // touching an edge of the screen moves the zoom-area in that direction. - int x = cursorPoint.x() * zoom - prevPoint.x() * (zoom - 1.0); - int y = cursorPoint.y() * zoom - prevPoint.y() * (zoom - 1.0); - int threshold = 4; + const int x = cursorPoint.x() * zoom - prevPoint.x() * (zoom - 1.0); + const int y = cursorPoint.y() * zoom - prevPoint.y() * (zoom - 1.0); + const int threshold = 4; + const QRectF currScreen = effects->screenAt(QPoint(x, y))->geometry(); + + // bounds of the screen the cursor's on + const int screenTop = currScreen.top(); + const int screenLeft = currScreen.left(); + const int screenRight = currScreen.right(); + const int screenBottom = currScreen.bottom(); + const int screenCenterX = currScreen.center().x(); + const int screenCenterY = currScreen.center().y(); + + // figure out whether we have adjacent displays in all 4 directions + // We pan within the screen in directions where there are no adjacent screens. + const bool adjacentLeft = screenExistsAt(QPoint(screenLeft - 1, screenCenterY)); + const bool adjacentRight = screenExistsAt(QPoint(screenRight + 1, screenCenterY)); + const bool adjacentTop = screenExistsAt(QPoint(screenCenterX, screenTop - 1)); + const bool adjacentBottom = screenExistsAt(QPoint(screenCenterX, screenBottom + 1)); + xMove = yMove = 0; - if (x < threshold) { - xMove = (x - threshold) / zoom; - } else if (x + threshold > screenSize.width()) { - xMove = (x + threshold - screenSize.width()) / zoom; + if (x < screenLeft + threshold && !adjacentLeft) { + xMove = (x - threshold - screenLeft) / zoom; + } else if (x > screenRight - threshold && !adjacentRight) { + xMove = (x + threshold - screenRight) / zoom; } - if (y < threshold) { - yMove = (y - threshold) / zoom; - } else if (y + threshold > screenSize.height()) { - yMove = (y + threshold - screenSize.height()) / zoom; + if (y < screenTop + threshold && !adjacentTop) { + yMove = (y - threshold - screenTop) / zoom; + } else if (y > screenBottom - threshold && !adjacentBottom) { + yMove = (y + threshold - screenBottom) / zoom; } if (xMove) { - prevPoint.setX(std::max(0, std::min(screenSize.width(), prevPoint.x() + xMove))); + prevPoint.setX(prevPoint.x() + xMove); } if (yMove) { - prevPoint.setY(std::max(0, std::min(screenSize.height(), prevPoint.y() + yMove))); + prevPoint.setY(prevPoint.y() + yMove); } xTranslation = -int(prevPoint.x() * (zoom - 1.0)); yTranslation = -int(prevPoint.y() * (zoom - 1.0)); @@ -624,6 +641,12 @@ qreal ZoomEffect::targetZoom() const return target_zoom; } +bool ZoomEffect::screenExistsAt(const QPoint &point) const +{ + const Output *output = effects->screenAt(point); + return output && output->geometry().contains(point); +} + } // namespace #include "moc_zoom.cpp" diff --git a/src/plugins/zoom/zoom.h b/src/plugins/zoom/zoom.h index 324327de5e..94dff2c7f9 100644 --- a/src/plugins/zoom/zoom.h +++ b/src/plugins/zoom/zoom.h @@ -57,6 +57,9 @@ public: int configuredFocusDelay() const; qreal configuredMoveFactor() const; qreal targetZoom() const; + +private: + bool screenExistsAt(const QPoint &point) const; private Q_SLOTS: inline void zoomIn() {