File indexing completed on 2025-03-23 13:48:01
0001 /* 0002 SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kwin_wayland_test.h" 0008 0009 #include "core/output.h" 0010 #include "core/outputbackend.h" 0011 #include "core/outputconfiguration.h" 0012 #include "cursor.h" 0013 #include "wayland_server.h" 0014 #include "window.h" 0015 #include "workspace.h" 0016 0017 #include <KWayland/Client/surface.h> 0018 0019 namespace KWin 0020 { 0021 0022 static const QString s_socketName = QStringLiteral("wayland_test_output_changes-0"); 0023 0024 class OutputChangesTest : public QObject 0025 { 0026 Q_OBJECT 0027 0028 private Q_SLOTS: 0029 void initTestCase(); 0030 void init(); 0031 void cleanup(); 0032 0033 void testWindowSticksToOutputAfterOutputIsDisabled(); 0034 void testWindowSticksToOutputAfterAnotherOutputIsDisabled(); 0035 void testWindowSticksToOutputAfterOutputIsMoved(); 0036 void testWindowSticksToOutputAfterOutputsAreSwappedLeftToRight(); 0037 void testWindowSticksToOutputAfterOutputsAreSwappedRightToLeft(); 0038 0039 void testWindowRestoredAfterEnablingOutput(); 0040 void testMaximizedWindowRestoredAfterEnablingOutput(); 0041 void testFullScreenWindowRestoredAfterEnablingOutput(); 0042 void testWindowRestoredAfterChangingScale(); 0043 void testMaximizeStateRestoredAfterEnablingOutput(); 0044 0045 void testWindowNotRestoredAfterMovingWindowAndEnablingOutput(); 0046 }; 0047 0048 void OutputChangesTest::initTestCase() 0049 { 0050 qRegisterMetaType<Window *>(); 0051 0052 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); 0053 QVERIFY(waylandServer()->init(s_socketName)); 0054 QMetaObject::invokeMethod(kwinApp()->outputBackend(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(QVector<QRect>, QVector<QRect>() << QRect(0, 0, 1280, 1024) << QRect(1280, 0, 1280, 1024))); 0055 0056 kwinApp()->start(); 0057 QVERIFY(applicationStartedSpy.wait()); 0058 const auto outputs = workspace()->outputs(); 0059 QCOMPARE(outputs.count(), 2); 0060 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024)); 0061 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024)); 0062 } 0063 0064 void OutputChangesTest::init() 0065 { 0066 QMetaObject::invokeMethod(kwinApp()->outputBackend(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(QVector<QRect>, QVector<QRect>() << QRect(0, 0, 1280, 1024) << QRect(1280, 0, 1280, 1024))); 0067 QVERIFY(Test::setupWaylandConnection()); 0068 0069 workspace()->setActiveOutput(QPoint(640, 512)); 0070 Cursors::self()->mouse()->setPos(QPoint(640, 512)); 0071 } 0072 0073 void OutputChangesTest::cleanup() 0074 { 0075 Test::destroyWaylandConnection(); 0076 } 0077 0078 void OutputChangesTest::testWindowSticksToOutputAfterOutputIsDisabled() 0079 { 0080 auto outputs = kwinApp()->outputBackend()->outputs(); 0081 0082 // Create a window. 0083 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0084 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0085 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0086 QVERIFY(window); 0087 0088 // Move the window to some predefined position so the test is more robust. 0089 window->move(QPoint(42, 67)); 0090 QCOMPARE(window->frameGeometry(), QRect(42, 67, 100, 50)); 0091 0092 // Disable the output where the window is on. 0093 OutputConfiguration config; 0094 { 0095 auto changeSet = config.changeSet(outputs[0]); 0096 changeSet->enabled = false; 0097 } 0098 workspace()->applyOutputConfiguration(config); 0099 0100 // The window will be sent to the second output, which is at (1280, 0). 0101 QCOMPARE(window->frameGeometry(), QRect(1280 + 42, 0 + 67, 100, 50)); 0102 } 0103 0104 void OutputChangesTest::testWindowSticksToOutputAfterAnotherOutputIsDisabled() 0105 { 0106 auto outputs = kwinApp()->outputBackend()->outputs(); 0107 0108 // Create a window. 0109 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0110 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0111 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0112 QVERIFY(window); 0113 0114 // Move the window to the second output. 0115 window->move(QPoint(1280 + 42, 67)); 0116 QCOMPARE(window->frameGeometry(), QRect(1280 + 42, 67, 100, 50)); 0117 0118 // Disable the first output. 0119 OutputConfiguration config; 0120 { 0121 auto changeSet = config.changeSet(outputs[0]); 0122 changeSet->enabled = false; 0123 } 0124 { 0125 auto changeSet = config.changeSet(outputs[1]); 0126 changeSet->pos = QPoint(0, 0); 0127 } 0128 workspace()->applyOutputConfiguration(config); 0129 0130 // The position of the window relative to its output should remain the same. 0131 QCOMPARE(window->frameGeometry(), QRect(42, 67, 100, 50)); 0132 } 0133 0134 void OutputChangesTest::testWindowSticksToOutputAfterOutputIsMoved() 0135 { 0136 auto outputs = kwinApp()->outputBackend()->outputs(); 0137 0138 // Create a window. 0139 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0140 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0141 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0142 QVERIFY(window); 0143 0144 // Move the window to some predefined position so the test is more robust. 0145 window->move(QPoint(42, 67)); 0146 QCOMPARE(window->frameGeometry(), QRect(42, 67, 100, 50)); 0147 0148 // Disable the first output. 0149 OutputConfiguration config; 0150 { 0151 auto changeSet = config.changeSet(outputs[0]); 0152 changeSet->pos = QPoint(-10, 20); 0153 } 0154 workspace()->applyOutputConfiguration(config); 0155 0156 // The position of the window relative to its output should remain the same. 0157 QCOMPARE(window->frameGeometry(), QRect(-10 + 42, 20 + 67, 100, 50)); 0158 } 0159 0160 void OutputChangesTest::testWindowSticksToOutputAfterOutputsAreSwappedLeftToRight() 0161 { 0162 // This test verifies that a window placed on the left monitor sticks 0163 // to that monitor even after the monitors are swapped horizontally. 0164 0165 const auto outputs = kwinApp()->outputBackend()->outputs(); 0166 0167 // Create a window. 0168 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0169 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0170 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0171 QVERIFY(window); 0172 0173 // Move the window to the left output. 0174 window->move(QPointF(0, 0)); 0175 QCOMPARE(window->output(), outputs[0]); 0176 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 100, 50)); 0177 0178 // Swap outputs. 0179 OutputConfiguration config; 0180 { 0181 auto changeSet1 = config.changeSet(outputs[0]); 0182 changeSet1->pos = QPoint(1280, 0); 0183 auto changeSet2 = config.changeSet(outputs[1]); 0184 changeSet2->pos = QPoint(0, 0); 0185 } 0186 workspace()->applyOutputConfiguration(config); 0187 0188 // The window should be still on its original output. 0189 QCOMPARE(window->output(), outputs[0]); 0190 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 100, 50)); 0191 } 0192 0193 void OutputChangesTest::testWindowSticksToOutputAfterOutputsAreSwappedRightToLeft() 0194 { 0195 // This test verifies that a window placed on the right monitor sticks 0196 // to that monitor even after the monitors are swapped horizontally. 0197 0198 const auto outputs = kwinApp()->outputBackend()->outputs(); 0199 0200 // Create a window. 0201 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0202 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0203 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0204 QVERIFY(window); 0205 0206 // Move the window to the right output. 0207 window->move(QPointF(1280, 0)); 0208 QCOMPARE(window->output(), outputs[1]); 0209 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 100, 50)); 0210 0211 // Swap outputs. 0212 OutputConfiguration config; 0213 { 0214 auto changeSet1 = config.changeSet(outputs[0]); 0215 changeSet1->pos = QPoint(1280, 0); 0216 auto changeSet2 = config.changeSet(outputs[1]); 0217 changeSet2->pos = QPoint(0, 0); 0218 } 0219 workspace()->applyOutputConfiguration(config); 0220 0221 // The window should be still on its original output. 0222 QCOMPARE(window->output(), outputs[1]); 0223 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 100, 50)); 0224 } 0225 0226 void OutputChangesTest::testWindowRestoredAfterEnablingOutput() 0227 { 0228 // This test verifies that a window will be moved back to its original output when it's hotplugged. 0229 0230 const auto outputs = kwinApp()->outputBackend()->outputs(); 0231 0232 // Create a window. 0233 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0234 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0235 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0236 QVERIFY(window); 0237 0238 // Move the window to the right output. 0239 window->move(QPointF(1280 + 50, 100)); 0240 QCOMPARE(window->output(), outputs[1]); 0241 QCOMPARE(window->frameGeometry(), QRectF(1280 + 50, 100, 100, 50)); 0242 0243 // Disable the right output. 0244 OutputConfiguration config1; 0245 { 0246 auto changeSet = config1.changeSet(outputs[1]); 0247 changeSet->enabled = false; 0248 } 0249 workspace()->applyOutputConfiguration(config1); 0250 0251 // The window will be moved to the left monitor. 0252 QCOMPARE(window->output(), outputs[0]); 0253 QCOMPARE(window->frameGeometry(), QRectF(50, 100, 100, 50)); 0254 0255 // Enable the right monitor. 0256 OutputConfiguration config2; 0257 { 0258 auto changeSet = config2.changeSet(outputs[1]); 0259 changeSet->enabled = true; 0260 } 0261 workspace()->applyOutputConfiguration(config2); 0262 0263 // The window will be moved back to the right monitor. 0264 QCOMPARE(window->output(), outputs[1]); 0265 QCOMPARE(window->frameGeometry(), QRectF(1280 + 50, 100, 100, 50)); 0266 } 0267 0268 void OutputChangesTest::testWindowNotRestoredAfterMovingWindowAndEnablingOutput() 0269 { 0270 // This test verifies that a window won't be moved to its original output when it's 0271 // hotplugged because the window was moved manually by the user. 0272 0273 const auto outputs = kwinApp()->outputBackend()->outputs(); 0274 0275 // Create a window. 0276 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0277 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0278 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0279 QVERIFY(window); 0280 0281 // Move the window to the right output. 0282 window->move(QPointF(1280 + 50, 100)); 0283 QCOMPARE(window->output(), outputs[1]); 0284 QCOMPARE(window->frameGeometry(), QRectF(1280 + 50, 100, 100, 50)); 0285 0286 // Disable the right output. 0287 OutputConfiguration config1; 0288 { 0289 auto changeSet = config1.changeSet(outputs[1]); 0290 changeSet->enabled = false; 0291 } 0292 workspace()->applyOutputConfiguration(config1); 0293 0294 // The window will be moved to the left monitor. 0295 QCOMPARE(window->output(), outputs[0]); 0296 QCOMPARE(window->frameGeometry(), QRectF(50, 100, 100, 50)); 0297 0298 // Pretend that the user moved the window. 0299 workspace()->slotWindowMove(); 0300 QVERIFY(window->isInteractiveMove()); 0301 window->keyPressEvent(Qt::Key_Right); 0302 window->keyPressEvent(Qt::Key_Enter); 0303 QCOMPARE(window->frameGeometry(), QRectF(58, 100, 100, 50)); 0304 0305 // Enable the right monitor. 0306 OutputConfiguration config2; 0307 { 0308 auto changeSet = config2.changeSet(outputs[1]); 0309 changeSet->enabled = true; 0310 } 0311 workspace()->applyOutputConfiguration(config2); 0312 0313 // The window is still on the left monitor because user manually moved it. 0314 QCOMPARE(window->output(), outputs[0]); 0315 QCOMPARE(window->frameGeometry(), QRectF(58, 100, 100, 50)); 0316 } 0317 0318 void OutputChangesTest::testMaximizedWindowRestoredAfterEnablingOutput() 0319 { 0320 // This test verifies that a maximized window will be moved to its original 0321 // output when it's re-enabled. 0322 0323 const auto outputs = kwinApp()->outputBackend()->outputs(); 0324 0325 // Create a window. 0326 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0327 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0328 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0329 QVERIFY(window); 0330 0331 // kwin will send a configure event with the actived state. 0332 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested); 0333 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); 0334 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0335 0336 // Move the window to the right monitor and make it maximized. 0337 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged); 0338 window->move(QPointF(1280 + 50, 100)); 0339 window->maximize(MaximizeFull); 0340 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0341 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024)); 0342 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0343 Test::render(surface.get(), QSize(1280, 1024), Qt::blue); 0344 QVERIFY(frameGeometryChangedSpy.wait()); 0345 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024)); 0346 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024)); 0347 QCOMPARE(window->output(), outputs[1]); 0348 QCOMPARE(window->maximizeMode(), MaximizeFull); 0349 QCOMPARE(window->requestedMaximizeMode(), MaximizeFull); 0350 QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50)); 0351 0352 // Disable the right output. 0353 OutputConfiguration config1; 0354 { 0355 auto changeSet = config1.changeSet(outputs[1]); 0356 changeSet->enabled = false; 0357 } 0358 workspace()->applyOutputConfiguration(config1); 0359 0360 // The window will be moved to the left monitor, the geometry restore will be updated too. 0361 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 1280, 1024)); 0362 QCOMPARE(window->moveResizeGeometry(), QRectF(0, 0, 1280, 1024)); 0363 QCOMPARE(window->output(), outputs[0]); 0364 QCOMPARE(window->maximizeMode(), MaximizeFull); 0365 QCOMPARE(window->requestedMaximizeMode(), MaximizeFull); 0366 QCOMPARE(window->geometryRestore(), QRectF(50, 100, 100, 50)); 0367 0368 // Enable the right monitor. 0369 OutputConfiguration config2; 0370 { 0371 auto changeSet = config2.changeSet(outputs[1]); 0372 changeSet->enabled = true; 0373 } 0374 workspace()->applyOutputConfiguration(config2); 0375 0376 // The window will be moved back to the right monitor, the geometry restore will be updated too. 0377 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024)); 0378 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024)); 0379 QCOMPARE(window->output(), outputs[1]); 0380 QCOMPARE(window->maximizeMode(), MaximizeFull); 0381 QCOMPARE(window->requestedMaximizeMode(), MaximizeFull); 0382 QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50)); 0383 } 0384 0385 void OutputChangesTest::testFullScreenWindowRestoredAfterEnablingOutput() 0386 { 0387 // This test verifies that a fullscreen window will be moved to its original 0388 // output when it's re-enabled. 0389 0390 const auto outputs = kwinApp()->outputBackend()->outputs(); 0391 0392 // Create a window. 0393 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0394 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0395 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0396 QVERIFY(window); 0397 0398 // kwin will send a configure event with the actived state. 0399 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested); 0400 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); 0401 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0402 0403 // Move the window to the right monitor and make it fullscreen. 0404 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged); 0405 window->move(QPointF(1280 + 50, 100)); 0406 window->setFullScreen(true); 0407 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0408 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024)); 0409 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0410 Test::render(surface.get(), QSize(1280, 1024), Qt::blue); 0411 QVERIFY(frameGeometryChangedSpy.wait()); 0412 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024)); 0413 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024)); 0414 QCOMPARE(window->output(), outputs[1]); 0415 QCOMPARE(window->isFullScreen(), true); 0416 QCOMPARE(window->isRequestedFullScreen(), true); 0417 QCOMPARE(window->fullscreenGeometryRestore(), QRectF(1280 + 50, 100, 100, 50)); 0418 0419 // Disable the right output. 0420 OutputConfiguration config1; 0421 { 0422 auto changeSet = config1.changeSet(outputs[1]); 0423 changeSet->enabled = false; 0424 } 0425 workspace()->applyOutputConfiguration(config1); 0426 0427 // The window will be moved to the left monitor, the geometry restore will be updated too. 0428 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 1280, 1024)); 0429 QCOMPARE(window->moveResizeGeometry(), QRectF(0, 0, 1280, 1024)); 0430 QCOMPARE(window->output(), outputs[0]); 0431 QCOMPARE(window->isFullScreen(), true); 0432 QCOMPARE(window->isRequestedFullScreen(), true); 0433 QCOMPARE(window->fullscreenGeometryRestore(), QRectF(50, 100, 100, 50)); 0434 0435 // Enable the right monitor. 0436 OutputConfiguration config2; 0437 { 0438 auto changeSet = config2.changeSet(outputs[1]); 0439 changeSet->enabled = true; 0440 } 0441 workspace()->applyOutputConfiguration(config2); 0442 0443 // The window will be moved back to the right monitor, the geometry restore will be updated too. 0444 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024)); 0445 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024)); 0446 QCOMPARE(window->output(), outputs[1]); 0447 QCOMPARE(window->isFullScreen(), true); 0448 QCOMPARE(window->isRequestedFullScreen(), true); 0449 QCOMPARE(window->fullscreenGeometryRestore(), QRectF(1280 + 50, 100, 100, 50)); 0450 } 0451 0452 void OutputChangesTest::testWindowRestoredAfterChangingScale() 0453 { 0454 // This test verifies that a window will be moved to its original position after changing the scale of an output 0455 0456 const auto output = kwinApp()->outputBackend()->outputs().front(); 0457 0458 // Create a window. 0459 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0460 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0461 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0462 QVERIFY(window); 0463 0464 // Move the window to the bottom right 0465 const QPointF originalPosition(output->geometry().width() - window->width(), output->geometry().height() - window->height()); 0466 window->move(originalPosition); 0467 QCOMPARE(window->pos(), originalPosition); 0468 QCOMPARE(window->output(), output); 0469 0470 // change the scale of the output 0471 OutputConfiguration config1; 0472 { 0473 auto changeSet = config1.changeSet(output); 0474 changeSet->scale = 2; 0475 } 0476 workspace()->applyOutputConfiguration(config1); 0477 0478 // The window will be moved to still be in the monitor 0479 QCOMPARE(window->pos(), QPointF(output->geometry().width() - window->width(), output->geometry().height() - window->height())); 0480 QCOMPARE(window->output(), output); 0481 0482 // Change scale back 0483 OutputConfiguration config2; 0484 { 0485 auto changeSet = config2.changeSet(output); 0486 changeSet->scale = 1; 0487 } 0488 workspace()->applyOutputConfiguration(config2); 0489 0490 // The window will be moved back to where it was before 0491 QCOMPARE(window->pos(), originalPosition); 0492 QCOMPARE(window->output(), output); 0493 } 0494 0495 void OutputChangesTest::testMaximizeStateRestoredAfterEnablingOutput() 0496 { 0497 // This test verifies that the window state will get restored after disabling and enabling an output, 0498 // even if its maximize state changed in the process 0499 0500 const auto outputs = kwinApp()->outputBackend()->outputs(); 0501 0502 // Disable the right output 0503 { 0504 OutputConfiguration config; 0505 auto changeSet = config.changeSet(outputs[1]); 0506 changeSet->enabled = false; 0507 workspace()->applyOutputConfiguration(config); 0508 } 0509 0510 // Create a window. 0511 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0512 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0513 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0514 QVERIFY(window); 0515 0516 // kwin will send a configure event with the actived state. 0517 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested); 0518 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); 0519 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0520 0521 const QRectF originalGeometry = window->moveResizeGeometry(); 0522 0523 // Enable the right output 0524 { 0525 OutputConfiguration config; 0526 auto changeSet = config.changeSet(outputs[1]); 0527 changeSet->enabled = true; 0528 workspace()->applyOutputConfiguration(config); 0529 } 0530 0531 // Move the window to the right monitor and make it maximized. 0532 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged); 0533 window->move(QPointF(1280 + 50, 100)); 0534 window->maximize(MaximizeFull); 0535 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0536 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024)); 0537 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0538 Test::render(surface.get(), QSize(1280, 1024), Qt::blue); 0539 QVERIFY(frameGeometryChangedSpy.wait()); 0540 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024)); 0541 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024)); 0542 QCOMPARE(window->output(), outputs[1]); 0543 QCOMPARE(window->maximizeMode(), MaximizeFull); 0544 QCOMPARE(window->requestedMaximizeMode(), MaximizeFull); 0545 QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50)); 0546 0547 // Disable the right output 0548 { 0549 OutputConfiguration config; 0550 auto changeSet = config.changeSet(outputs[1]); 0551 changeSet->enabled = false; 0552 workspace()->applyOutputConfiguration(config); 0553 } 0554 0555 // The window will be moved to its prior position on the left monitor and unmaximized 0556 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0557 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), originalGeometry.size().toSize()); 0558 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0559 Test::render(surface.get(), originalGeometry.size().toSize(), Qt::blue); 0560 QVERIFY(frameGeometryChangedSpy.wait()); 0561 QCOMPARE(window->frameGeometry(), originalGeometry); 0562 QCOMPARE(window->moveResizeGeometry(), originalGeometry); 0563 QCOMPARE(window->output(), outputs[0]); 0564 QCOMPARE(window->maximizeMode(), MaximizeRestore); 0565 QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore); 0566 0567 // Enable the right output again 0568 { 0569 OutputConfiguration config; 0570 auto changeSet = config.changeSet(outputs[1]); 0571 changeSet->enabled = true; 0572 workspace()->applyOutputConfiguration(config); 0573 } 0574 0575 // The window will be moved back to the right monitor, maximized and the geometry restore will be updated 0576 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0577 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), outputs[1]->geometry().size()); 0578 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0579 Test::render(surface.get(), outputs[1]->geometry().size(), Qt::blue); 0580 QVERIFY(frameGeometryChangedSpy.wait()); 0581 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024)); 0582 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024)); 0583 QCOMPARE(window->output(), outputs[1]); 0584 QCOMPARE(window->maximizeMode(), MaximizeFull); 0585 QCOMPARE(window->requestedMaximizeMode(), MaximizeFull); 0586 QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50)); 0587 } 0588 0589 } // namespace KWin 0590 0591 WAYLANDTEST_MAIN(KWin::OutputChangesTest) 0592 #include "outputchanges_test.moc"