From f0971532c90b9b04bf4ac084cef0ecf4fe61b7d2 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Thu, 24 Aug 2017 17:57:30 +0100 Subject: [PATCH] Send output enter/leave events to surfaces Summary: A surface has an API to know which screen(s) it's on, this is useful especially for knowing the scale it should render at. In practice Qt currently doesn't do anything with this information; but that's set to change. Test_helpers is changed as we need to create output objects in order for wl_surface to map them. Closes task T4467 Test Plan: Attached unit test. As mentioned above, it doesn't have any real world impact currently, so not a lot to test. Reviewers: #plasma, graesslin Reviewed By: #plasma, graesslin Subscribers: johanhelsing, graesslin, plasma-devel, kwin, #kwin Tags: #kwin Maniphest Tasks: T4467 Differential Revision: https://phabricator.kde.org/D7359 --- autotests/integration/shell_client_test.cpp | 51 +++++++++++++++++++++ shell_client.cpp | 18 ++++++++ shell_client.h | 1 + 3 files changed, 70 insertions(+) diff --git a/autotests/integration/shell_client_test.cpp b/autotests/integration/shell_client_test.cpp index edfefc2720..a0573537f1 100644 --- a/autotests/integration/shell_client_test.cpp +++ b/autotests/integration/shell_client_test.cpp @@ -29,6 +29,7 @@ along with this program. If not, see . #include #include #include +#include #include #include #include @@ -59,6 +60,8 @@ private Q_SLOTS: void testMapUnmapMap(); void testDesktopPresenceChanged(); void testTransientPositionAfterRemap(); + void testWindowOutputs_data(); + void testWindowOutputs(); void testMinimizeActiveWindow_data(); void testMinimizeActiveWindow(); void testFullscreen_data(); @@ -81,6 +84,8 @@ void TestShellClient::initTestCase() { qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); + QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated); QVERIFY(workspaceCreatedSpy.isValid()); kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024)); @@ -269,6 +274,52 @@ void TestShellClient::testTransientPositionAfterRemap() 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.cpp b/shell_client.cpp index 82e6bb8753..6f11b225d4 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -28,12 +28,14 @@ along with this program. If not, see . #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 @@ void ShellClient::initSurface(T *shellSurface) 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::popupDone() } } +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); +} + } diff --git a/shell_client.h b/shell_client.h index 1328ad747f..401de11ae0 100644 --- a/shell_client.h +++ b/shell_client.h @@ -185,6 +185,7 @@ private: void markAsMapped(); void setTransient(); bool shouldExposeToWindowManagement(); + void updateClientOutputs(); KWayland::Server::XdgShellSurfaceInterface::States xdgSurfaceStates() const; void updateShowOnScreenEdge(); static void deleteClient(ShellClient *c);