diff --git a/autotests/integration/shell_client_test.cpp b/autotests/integration/shell_client_test.cpp --- a/autotests/integration/shell_client_test.cpp +++ b/autotests/integration/shell_client_test.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,8 @@ void testMapUnmapMap(); void testDesktopPresenceChanged(); void testTransientPositionAfterRemap(); + void testWindowOutputs_data(); + void testWindowOutputs(); void testMinimizeActiveWindow_data(); void testMinimizeActiveWindow(); void testFullscreen_data(); @@ -81,6 +84,8 @@ { qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); + QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated); QVERIFY(workspaceCreatedSpy.isValid()); kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024)); @@ -269,6 +274,52 @@ QCOMPARE(transient->geometry(), QRect(c->geometry().topLeft() + QPoint(5, 10), QSize(50, 40))); } +void TestShellClient::testWindowOutputs_data() +{ + QTest::addColumn("type"); + + QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell; + QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5; +} + +void TestShellClient::testWindowOutputs() +{ + QScopedPointer surface(Test::createSurface()); + QFETCH(Test::ShellSurfaceType, type); + QScopedPointer shellSurface(Test::createShellSurface(type, surface.data())); + auto size = QSize(200,200); + + QSignalSpy outputEnteredSpy(surface.data(), &Surface::outputEntered); + QSignalSpy outputLeftSpy(surface.data(), &Surface::outputLeft); + + auto c = Test::renderAndWaitForShown(surface.data(), size, Qt::blue); + //move to be in the first screen + c->setGeometry(QRect(QPoint(100,100), size)); + //we don't don't know where the compositor first placed this window, + //this might fire, it might not + outputEnteredSpy.wait(5); + outputEnteredSpy.clear(); + + QCOMPARE(surface->outputs().count(), 1); + QCOMPARE(surface->outputs().first()->globalPosition(), QPoint(0,0)); + + //move to overlapping both first and second screen + c->setGeometry(QRect(QPoint(1250,100), size)); + QVERIFY(outputEnteredSpy.wait()); + QCOMPARE(outputEnteredSpy.count(), 1); + QCOMPARE(outputLeftSpy.count(), 0); + QCOMPARE(surface->outputs().count(), 2); + QVERIFY(surface->outputs()[0] != surface->outputs()[1]); + + //move entirely into second screen + c->setGeometry(QRect(QPoint(1400,100), size)); + QVERIFY(outputLeftSpy.wait()); + QCOMPARE(outputEnteredSpy.count(), 1); + QCOMPARE(outputLeftSpy.count(), 1); + QCOMPARE(surface->outputs().count(), 1); + QCOMPARE(surface->outputs().first()->globalPosition(), QPoint(1280,0)); +} + void TestShellClient::testMinimizeActiveWindow_data() { QTest::addColumn("type"); diff --git a/shell_client.h b/shell_client.h --- a/shell_client.h +++ b/shell_client.h @@ -185,6 +185,7 @@ void markAsMapped(); void setTransient(); bool shouldExposeToWindowManagement(); + void updateClientOutputs(); KWayland::Server::XdgShellSurfaceInterface::States xdgSurfaceStates() const; void updateShowOnScreenEdge(); static void deleteClient(ShellClient *c); diff --git a/shell_client.cpp b/shell_client.cpp --- a/shell_client.cpp +++ b/shell_client.cpp @@ -28,12 +28,14 @@ #include "workspace.h" #include "virtualdesktops.h" #include "workspace.h" +#include "screens.h" #include "decorations/decorationbridge.h" #include "decorations/decoratedclient.h" #include #include #include +#include #include #include #include @@ -173,6 +175,9 @@ connect(shellSurface, &T::fullscreenChanged, this, &ShellClient::clientFullScreenChanged); connect(shellSurface, &T::transientForChanged, this, &ShellClient::setTransient); + + connect(this, &ShellClient::geometryChanged, this, &ShellClient::updateClientOutputs); + connect(screens(), &Screens::changed, this, &ShellClient::updateClientOutputs); } void ShellClient::init() @@ -1522,4 +1527,17 @@ } } +void ShellClient::updateClientOutputs() +{ + QVector clientOutputs; + const auto outputs = waylandServer()->display()->outputs(); + for (OutputInterface* output: qAsConst(outputs)) { + const QRect outputGeom(output->globalPosition(), output->pixelSize() / output->scale()); + if (geometry().intersects(outputGeom)) { + clientOutputs << output; + } + } + surface()->setOutputs(clientOutputs); +} + }