diff --git a/autotests/wayland/client/test_wayland_surface.cpp b/autotests/wayland/client/test_wayland_surface.cpp index 911047b7cf..925c62f6b5 100644 --- a/autotests/wayland/client/test_wayland_surface.cpp +++ b/autotests/wayland/client/test_wayland_surface.cpp @@ -865,7 +865,7 @@ void TestWaylandSurface::testOutput() m_display->dispatchEvents(); // now enter it - serverSurface->setOutputs(QList{serverOutput.get()}); + serverSurface->setOutputs(QList{serverOutput.get()}, serverOutput.get()); QCOMPARE(serverSurface->outputs(), QList{serverOutput.get()}); QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.count(), 1); @@ -873,10 +873,10 @@ void TestWaylandSurface::testOutput() QCOMPARE(s->outputs(), QList{clientOutput.get()}); // adding to same should not trigger - serverSurface->setOutputs(QList{serverOutput.get()}); + serverSurface->setOutputs(QList{serverOutput.get()}, serverOutput.get()); // leave again - serverSurface->setOutputs(QList()); + serverSurface->setOutputs(QList(), nullptr); QCOMPARE(serverSurface->outputs(), QList()); QVERIFY(leftSpy.wait()); QCOMPARE(enteredSpy.count(), 1); @@ -885,10 +885,10 @@ void TestWaylandSurface::testOutput() QCOMPARE(s->outputs(), QList()); // leave again should not trigger - serverSurface->setOutputs(QList()); + serverSurface->setOutputs(QList(), nullptr); // and enter again, just to verify - serverSurface->setOutputs(QList{serverOutput.get()}); + serverSurface->setOutputs(QList{serverOutput.get()}, serverOutput.get()); QCOMPARE(serverSurface->outputs(), QList{serverOutput.get()}); QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.count(), 2); diff --git a/src/pointer_input.cpp b/src/pointer_input.cpp index 322916d0a8..14cad2ebcc 100644 --- a/src/pointer_input.cpp +++ b/src/pointer_input.cpp @@ -920,7 +920,8 @@ void CursorImage::updateCursorOutputs(const QPointF &pos) auto cursorSurface = m_serverCursor.surface->surface(); if (cursorSurface) { const QRectF cursorGeometry(pos - m_currentSource->hotspot(), m_currentSource->size()); - cursorSurface->setOutputs(waylandServer()->display()->outputsIntersecting(cursorGeometry.toAlignedRect())); + cursorSurface->setOutputs(waylandServer()->display()->outputsIntersecting(cursorGeometry.toAlignedRect()), + waylandServer()->display()->largestIntersectingOutput(cursorGeometry.toAlignedRect())); } } } diff --git a/src/wayland/display.cpp b/src/wayland/display.cpp index eb2c255997..b05156d339 100644 --- a/src/wayland/display.cpp +++ b/src/wayland/display.cpp @@ -172,6 +172,21 @@ QList Display::outputsIntersecting(const QRect &rect) const return outputs; } +OutputInterface *Display::largestIntersectingOutput(const QRect &rect) const +{ + OutputInterface *returnOutput = nullptr; + uint64_t biggestArea = 0; + for (auto *output : std::as_const(d->outputs)) { + const QRect intersect = output->handle()->geometry().intersected(rect); + const uint64_t area = intersect.width() * intersect.height(); + if (area > biggestArea) { + biggestArea = area; + returnOutput = output; + } + } + return returnOutput; +} + QList Display::seats() const { return d->seats; diff --git a/src/wayland/display.h b/src/wayland/display.h index e80c8845b6..28adad2657 100644 --- a/src/wayland/display.h +++ b/src/wayland/display.h @@ -102,6 +102,7 @@ public: QList outputDevices() const; QList outputs() const; QList outputsIntersecting(const QRect &rect) const; + OutputInterface *largestIntersectingOutput(const QRect &rect) const; /** * Gets the ClientConnection for the given @p client. diff --git a/src/wayland/surface.cpp b/src/wayland/surface.cpp index 8853a98330..a68672d670 100644 --- a/src/wayland/surface.cpp +++ b/src/wayland/surface.cpp @@ -75,7 +75,7 @@ void SurfaceInterfacePrivate::addChild(SubSurfaceInterface *child) }); } - child->surface()->setOutputs(outputs); + child->surface()->setOutputs(outputs, primaryOutput); if (preferredBufferScale.has_value()) { child->surface()->setPreferredBufferScale(preferredBufferScale.value()); } @@ -947,7 +947,7 @@ QList SurfaceInterface::outputs() const return d->outputs; } -void SurfaceInterface::setOutputs(const QList &outputs) +void SurfaceInterface::setOutputs(const QList &outputs, OutputInterface *primaryOutput) { QList removedOutputs = d->outputs; for (auto it = outputs.constBegin(), end = outputs.constEnd(); it != end; ++it) { @@ -976,7 +976,7 @@ void SurfaceInterface::setOutputs(const QList &outputs) d->outputDestroyedConnections[o] = connect(o, &OutputInterface::removed, this, [this, o] { auto outputs = d->outputs; if (outputs.removeOne(o)) { - setOutputs(outputs); + setOutputs(outputs, d->primaryOutput); } }); @@ -990,11 +990,12 @@ void SurfaceInterface::setOutputs(const QList &outputs) } d->outputs = outputs; + d->primaryOutput = primaryOutput; for (auto child : std::as_const(d->current->subsurface.below)) { - child->surface()->setOutputs(outputs); + child->surface()->setOutputs(outputs, primaryOutput); } for (auto child : std::as_const(d->current->subsurface.above)) { - child->surface()->setOutputs(outputs); + child->surface()->setOutputs(outputs, primaryOutput); } } diff --git a/src/wayland/surface.h b/src/wayland/surface.h index 5d14344f81..ebdc2fb3a2 100644 --- a/src/wayland/surface.h +++ b/src/wayland/surface.h @@ -281,7 +281,7 @@ public: * * @see outputs */ - void setOutputs(const QList &outputs); + void setOutputs(const QList &outputs, OutputInterface *primaryOutput); /** * @returns All OutputInterfaces the SurfaceInterface is on. diff --git a/src/wayland/surface_p.h b/src/wayland/surface_p.h index 3960f53c5a..b8df505f9b 100644 --- a/src/wayland/surface_p.h +++ b/src/wayland/surface_p.h @@ -146,6 +146,7 @@ public: Transaction *lastTransaction = nullptr; QList outputs; + OutputInterface *primaryOutput = nullptr; std::optional preferredBufferScale; std::optional preferredBufferTransform; diff --git a/src/waylandwindow.cpp b/src/waylandwindow.cpp index 349d8060bc..751ae706a7 100644 --- a/src/waylandwindow.cpp +++ b/src/waylandwindow.cpp @@ -156,7 +156,8 @@ void WaylandWindow::updateClientOutputs() if (isDeleted()) { return; } - surface()->setOutputs(waylandServer()->display()->outputsIntersecting(frameGeometry().toAlignedRect())); + surface()->setOutputs(waylandServer()->display()->outputsIntersecting(frameGeometry().toAlignedRect()), + waylandServer()->display()->largestIntersectingOutput(frameGeometry().toAlignedRect())); if (output()) { surface()->setPreferredBufferScale(output()->scale()); surface()->setPreferredBufferTransform(output()->transform());