Improve Workspace::outputAt()

Workspace::outputAt() casts vectors to four rectangle corners and uses
the shortest one to decide which output is the closest to the given
point.

This works poorly on dual monitor setups where on the left side you have
a monitor with landscape orientation and one with portrait orientation
on the right hand side. In that case, outputAt() will prefer the left
monitor even though the right monitor is the closest one if you cast a
perpendicular from the given point to the right monitor.

In order to improve the handling of that case, this change makes
Workspace::outputAt() compute the closest point to the output geometry
rectangle and use the squared distance as the score.
This commit is contained in:
Vlad Zahorodnii 2023-03-25 21:59:05 +02:00
parent cbd50a1e08
commit a9ad59b32a
2 changed files with 8 additions and 9 deletions

View file

@ -1520,7 +1520,7 @@ void PointerInputTest::testConfineToScreenGeometry_data()
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(2660, 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(1180, 1023);
QTest::newRow("move bottom-left - top screen") << QPoint(1920, 512) << QPoint(1180, 1124) << QPoint(1280, 1124);
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);

View file

@ -1231,14 +1231,13 @@ Output *Workspace::outputAt(const QPointF &pos) const
qreal minDistance;
for (Output *output : std::as_const(m_outputs)) {
const QRect &geo = output->geometry();
if (geo.contains(pos.toPoint())) {
return output;
}
qreal distance = QPointF(geo.topLeft() - pos).manhattanLength();
distance = std::min(distance, QPointF(geo.topRight() - pos).manhattanLength());
distance = std::min(distance, QPointF(geo.bottomRight() - pos).manhattanLength());
distance = std::min(distance, QPointF(geo.bottomLeft() - pos).manhattanLength());
const QRectF geo = output->geometry();
const QPointF closestPoint(std::clamp(pos.x(), geo.x(), geo.x() + geo.width() - 1),
std::clamp(pos.y(), geo.y(), geo.y() + geo.height() - 1));
const QPointF ray = closestPoint - pos;
const qreal distance = ray.x() * ray.x() + ray.y() * ray.y();
if (!bestOutput || distance < minDistance) {
minDistance = distance;
bestOutput = output;