[wayland] Confine pointer to screen geometry
Summary: If the new pointer position is "off screen", PointerInputRedirection just ignores that new position. So, pointer remains on its previous position. In some particular cases, like reaching default panel, it degrades desktop experience because one have to slowly move pointer in order to reach what he/she wants. This change addresses that problem by confining the new pointer position to screen geometry. BUG: 374867 FIXED-IN: 5.13.4 Test Plan: Ran tests Reviewers: #kwin, graesslin Reviewed By: #kwin, graesslin Subscribers: kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D14036
This commit is contained in:
parent
18507d7129
commit
1e4703a719
2 changed files with 105 additions and 6 deletions
|
@ -76,6 +76,8 @@ private Q_SLOTS:
|
|||
void testPopup();
|
||||
void testDecoCancelsPopup();
|
||||
void testWindowUnderCursorWhileButtonPressed();
|
||||
void testConfineToScreenGeometry_data();
|
||||
void testConfineToScreenGeometry();
|
||||
|
||||
private:
|
||||
void render(KWayland::Client::Surface *surface, const QSize &size = QSize(100, 50));
|
||||
|
@ -1192,6 +1194,97 @@ void PointerInputTest::testWindowUnderCursorWhileButtonPressed()
|
|||
QCOMPARE(enteredSpy.count(), 2);
|
||||
}
|
||||
|
||||
void PointerInputTest::testConfineToScreenGeometry_data()
|
||||
{
|
||||
QTest::addColumn<QPoint>("startPos");
|
||||
QTest::addColumn<QPoint>("targetPos");
|
||||
QTest::addColumn<QPoint>("expectedPos");
|
||||
|
||||
// screen layout:
|
||||
//
|
||||
// +----------+----------+---------+
|
||||
// | left | top | right |
|
||||
// +----------+----------+---------+
|
||||
// | bottom |
|
||||
// +----------+
|
||||
//
|
||||
|
||||
QTest::newRow("move top-left - left screen") << QPoint(640, 512) << QPoint(-100, -100) << QPoint(0, 0);
|
||||
QTest::newRow("move top - left screen") << QPoint(640, 512) << QPoint(640, -100) << QPoint(640, 0);
|
||||
QTest::newRow("move top-right - left screen") << QPoint(640, 512) << QPoint(1380, -100) << QPoint(1380, 0);
|
||||
QTest::newRow("move right - left screen") << QPoint(640, 512) << QPoint(1380, 512) << QPoint(1380, 512);
|
||||
QTest::newRow("move bottom-right - left screen") << QPoint(640, 512) << QPoint(1380, 1124) << QPoint(1380, 1124);
|
||||
QTest::newRow("move bottom - left screen") << QPoint(640, 512) << QPoint(640, 1124) << QPoint(640, 1023);
|
||||
QTest::newRow("move bottom-left - left screen") << QPoint(640, 512) << QPoint(-100, 1124) << QPoint(0, 1023);
|
||||
QTest::newRow("move left - left screen") << QPoint(640, 512) << QPoint(-100, 512) << QPoint(0, 512);
|
||||
|
||||
QTest::newRow("move top-left - top screen") << QPoint(1920, 512) << QPoint(1180, -100) << QPoint(1180, 0);
|
||||
QTest::newRow("move top - top screen") << QPoint(1920, 512) << QPoint(1920, -100) << QPoint(1920, 0);
|
||||
QTest::newRow("move top-right - top screen") << QPoint(1920, 512) << QPoint(2660, -100) << QPoint(2660, 0);
|
||||
QTest::newRow("move right - top screen") << QPoint(1920, 512) << QPoint(2660, 512) << QPoint(2660, 512);
|
||||
QTest::newRow("move bottom-right - top screen") << QPoint(1920, 512) << QPoint(2660, 1124) << QPoint(2559, 1023);
|
||||
QTest::newRow("move bottom - top screen") << QPoint(1920, 512) << QPoint(1920, 1124) << QPoint(1920, 1124);
|
||||
QTest::newRow("move bottom-left - top screen") << QPoint(1920, 512) << QPoint(1180, 1124) << QPoint(1280, 1023);
|
||||
QTest::newRow("move left - top screen") << QPoint(1920, 512) << QPoint(1180, 512) << QPoint(1180, 512);
|
||||
|
||||
QTest::newRow("move top-left - right screen") << QPoint(3200, 512) << QPoint(2460, -100) << QPoint(2460, 0);
|
||||
QTest::newRow("move top - right screen") << QPoint(3200, 512) << QPoint(3200, -100) << QPoint(3200, 0);
|
||||
QTest::newRow("move top-right - right screen") << QPoint(3200, 512) << QPoint(3940, -100) << QPoint(3839, 0);
|
||||
QTest::newRow("move right - right screen") << QPoint(3200, 512) << QPoint(3940, 512) << QPoint(3839, 512);
|
||||
QTest::newRow("move bottom-right - right screen") << QPoint(3200, 512) << QPoint(3940, 1124) << QPoint(3839, 1023);
|
||||
QTest::newRow("move bottom - right screen") << QPoint(3200, 512) << QPoint(3200, 1124) << QPoint(3200, 1023);
|
||||
QTest::newRow("move bottom-left - right screen") << QPoint(3200, 512) << QPoint(2460, 1124) << QPoint(2460, 1124);
|
||||
QTest::newRow("move left - right screen") << QPoint(3200, 512) << QPoint(2460, 512) << QPoint(2460, 512);
|
||||
|
||||
QTest::newRow("move top-left - bottom screen") << QPoint(1920, 1536) << QPoint(1180, 924) << QPoint(1180, 924);
|
||||
QTest::newRow("move top - bottom screen") << QPoint(1920, 1536) << QPoint(1920, 924) << QPoint(1920, 924);
|
||||
QTest::newRow("move top-right - bottom screen") << QPoint(1920, 1536) << QPoint(2660, 924) << QPoint(2660, 924);
|
||||
QTest::newRow("move right - bottom screen") << QPoint(1920, 1536) << QPoint(2660, 1536) << QPoint(2559, 1536);
|
||||
QTest::newRow("move bottom-right - bottom screen") << QPoint(1920, 1536) << QPoint(2660, 2148) << QPoint(2559, 2047);
|
||||
QTest::newRow("move bottom - bottom screen") << QPoint(1920, 1536) << QPoint(1920, 2148) << QPoint(1920, 2047);
|
||||
QTest::newRow("move bottom-left - bottom screen") << QPoint(1920, 1536) << QPoint(1180, 2148) << QPoint(1280, 2047);
|
||||
QTest::newRow("move left - bottom screen") << QPoint(1920, 1536) << QPoint(1180, 1536) << QPoint(1280, 1536);
|
||||
}
|
||||
|
||||
void PointerInputTest::testConfineToScreenGeometry()
|
||||
{
|
||||
// this test verifies that pointer belongs to at least one screen
|
||||
// after moving it to off-screen area
|
||||
|
||||
// unload the Present Windows effect because it pushes back
|
||||
// pointer if it's at (0, 0)
|
||||
static_cast<EffectsHandlerImpl*>(effects)->unloadEffect(QStringLiteral("presentwindows"));
|
||||
|
||||
// setup screen layout
|
||||
const QVector<QRect> geometries {
|
||||
QRect(0, 0, 1280, 1024),
|
||||
QRect(1280, 0, 1280, 1024),
|
||||
QRect(2560, 0, 1280, 1024),
|
||||
QRect(1280, 1024, 1280, 1024)
|
||||
};
|
||||
QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs",
|
||||
Qt::DirectConnection,
|
||||
Q_ARG(int, geometries.count()),
|
||||
Q_ARG(QVector<QRect>, geometries));
|
||||
QCOMPARE(screens()->count(), geometries.count());
|
||||
QCOMPARE(screens()->geometry(0), geometries.at(0));
|
||||
QCOMPARE(screens()->geometry(1), geometries.at(1));
|
||||
QCOMPARE(screens()->geometry(2), geometries.at(2));
|
||||
QCOMPARE(screens()->geometry(3), geometries.at(3));
|
||||
|
||||
// move pointer to initial position
|
||||
QFETCH(QPoint, startPos);
|
||||
Cursor::setPos(startPos);
|
||||
QCOMPARE(Cursor::pos(), startPos);
|
||||
|
||||
// perform movement
|
||||
QFETCH(QPoint, targetPos);
|
||||
kwinApp()->platform()->pointerMotion(targetPos, 1);
|
||||
|
||||
QFETCH(QPoint, expectedPos);
|
||||
QCOMPARE(Cursor::pos(), expectedPos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WAYLANDTEST_MAIN(KWin::PointerInputTest)
|
||||
|
|
|
@ -113,6 +113,14 @@ static bool screenContainsPos(const QPointF &pos)
|
|||
return false;
|
||||
}
|
||||
|
||||
static QPointF confineToBoundingBox(const QPointF &pos, const QRectF &boundingBox)
|
||||
{
|
||||
return QPointF(
|
||||
qBound(boundingBox.left(), pos.x(), boundingBox.right() - 1.0),
|
||||
qBound(boundingBox.top(), pos.y(), boundingBox.bottom() - 1.0)
|
||||
);
|
||||
}
|
||||
|
||||
PointerInputRedirection::PointerInputRedirection(InputRedirection* parent)
|
||||
: InputDeviceHandler(parent)
|
||||
, m_cursor(nullptr)
|
||||
|
@ -745,13 +753,11 @@ void PointerInputRedirection::updatePosition(const QPointF &pos)
|
|||
// verify that at least one screen contains the pointer position
|
||||
QPointF p = pos;
|
||||
if (!screenContainsPos(p)) {
|
||||
// allow either x or y to pass
|
||||
p = QPointF(m_pos.x(), pos.y());
|
||||
const QRectF unitedScreensGeometry = screens()->geometry();
|
||||
p = confineToBoundingBox(p, unitedScreensGeometry);
|
||||
if (!screenContainsPos(p)) {
|
||||
p = QPointF(pos.x(), m_pos.y());
|
||||
if (!screenContainsPos(p)) {
|
||||
return;
|
||||
}
|
||||
const QRectF currentScreenGeometry = screens()->geometry(screens()->number(m_pos.toPoint()));
|
||||
p = confineToBoundingBox(p, currentScreenGeometry);
|
||||
}
|
||||
}
|
||||
p = applyPointerConfinement(p);
|
||||
|
|
Loading…
Reference in a new issue