17#include <KWayland/Client/surface.h>
19using namespace std::chrono_literals;
24static const QString s_socketName = QStringLiteral(
"wayland_test_output_changes-0");
35 void testWindowSticksToOutputAfterOutputIsDisabled();
36 void testWindowSticksToOutputAfterAnotherOutputIsDisabled();
37 void testWindowSticksToOutputAfterOutputIsMoved();
38 void testWindowSticksToOutputAfterOutputsAreSwappedLeftToRight();
39 void testWindowSticksToOutputAfterOutputsAreSwappedRightToLeft();
41 void testWindowRestoredAfterEnablingOutput();
42 void testMaximizedWindowRestoredAfterEnablingOutput();
43 void testFullScreenWindowRestoredAfterEnablingOutput();
44 void testWindowRestoredAfterChangingScale();
45 void testMaximizeStateRestoredAfterEnablingOutput();
47 void testWindowNotRestoredAfterMovingWindowAndEnablingOutput();
48 void testLaptopLidClosed();
51void OutputChangesTest::initTestCase()
53 qRegisterMetaType<Window *>();
58 QRect(0, 0, 1280, 1024),
59 QRect(1280, 0, 1280, 1024),
63 QVERIFY(applicationStartedSpy.wait());
65 QCOMPARE(outputs.count(), 2);
66 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
67 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
70void OutputChangesTest::init()
73 QRect(0, 0, 1280, 1024),
74 QRect(1280, 0, 1280, 1024),
82void OutputChangesTest::cleanup()
87void OutputChangesTest::testWindowSticksToOutputAfterOutputIsDisabled()
89 auto outputs = kwinApp()->outputBackend()->outputs();
98 window->move(QPoint(42, 67));
99 QCOMPARE(window->frameGeometry(), QRect(42, 67, 100, 50));
102 OutputConfiguration config;
104 auto changeSet = config.changeSet(outputs[0]);
105 changeSet->enabled =
false;
110 QCOMPARE(window->frameGeometry(), QRect(1280 + 42, 0 + 67, 100, 50));
113void OutputChangesTest::testWindowSticksToOutputAfterAnotherOutputIsDisabled()
115 auto outputs = kwinApp()->outputBackend()->outputs();
124 window->move(QPoint(1280 + 42, 67));
125 QCOMPARE(window->frameGeometry(), QRect(1280 + 42, 67, 100, 50));
128 OutputConfiguration config;
130 auto changeSet = config.changeSet(outputs[0]);
131 changeSet->enabled =
false;
134 auto changeSet = config.changeSet(outputs[1]);
135 changeSet->pos = QPoint(0, 0);
140 QCOMPARE(window->frameGeometry(), QRect(42, 67, 100, 50));
143void OutputChangesTest::testWindowSticksToOutputAfterOutputIsMoved()
145 auto outputs = kwinApp()->outputBackend()->outputs();
154 window->move(QPoint(42, 67));
155 QCOMPARE(window->frameGeometry(), QRect(42, 67, 100, 50));
158 OutputConfiguration config;
160 auto changeSet = config.changeSet(outputs[0]);
161 changeSet->pos = QPoint(-10, 20);
166 QCOMPARE(window->frameGeometry(), QRect(-10 + 42, 20 + 67, 100, 50));
169void OutputChangesTest::testWindowSticksToOutputAfterOutputsAreSwappedLeftToRight()
174 const auto outputs = kwinApp()->outputBackend()->outputs();
183 window->move(QPointF(0, 0));
184 QCOMPARE(window->output(), outputs[0]);
185 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 100, 50));
188 OutputConfiguration config;
190 auto changeSet1 = config.changeSet(outputs[0]);
191 changeSet1->pos = QPoint(1280, 0);
192 auto changeSet2 = config.changeSet(outputs[1]);
193 changeSet2->pos = QPoint(0, 0);
198 QCOMPARE(window->output(), outputs[0]);
199 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 100, 50));
202void OutputChangesTest::testWindowSticksToOutputAfterOutputsAreSwappedRightToLeft()
207 const auto outputs = kwinApp()->outputBackend()->outputs();
216 window->move(QPointF(1280, 0));
217 QCOMPARE(window->output(), outputs[1]);
218 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 100, 50));
221 OutputConfiguration config;
223 auto changeSet1 = config.changeSet(outputs[0]);
224 changeSet1->pos = QPoint(1280, 0);
225 auto changeSet2 = config.changeSet(outputs[1]);
226 changeSet2->pos = QPoint(0, 0);
231 QCOMPARE(window->output(), outputs[1]);
232 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 100, 50));
235void OutputChangesTest::testWindowRestoredAfterEnablingOutput()
239 const auto outputs = kwinApp()->outputBackend()->outputs();
248 window->move(QPointF(1280 + 50, 100));
249 QCOMPARE(window->output(), outputs[1]);
250 QCOMPARE(window->frameGeometry(), QRectF(1280 + 50, 100, 100, 50));
253 OutputConfiguration config1;
255 auto changeSet = config1.changeSet(outputs[1]);
256 changeSet->enabled =
false;
261 QCOMPARE(window->output(), outputs[0]);
262 QCOMPARE(window->frameGeometry(), QRectF(50, 100, 100, 50));
265 OutputConfiguration config2;
267 auto changeSet = config2.changeSet(outputs[1]);
268 changeSet->enabled =
true;
273 QCOMPARE(window->output(), outputs[1]);
274 QCOMPARE(window->frameGeometry(), QRectF(1280 + 50, 100, 100, 50));
277void OutputChangesTest::testWindowNotRestoredAfterMovingWindowAndEnablingOutput()
282 const auto outputs = kwinApp()->outputBackend()->outputs();
291 window->move(QPointF(1280 + 50, 100));
292 QCOMPARE(window->output(), outputs[1]);
293 QCOMPARE(window->frameGeometry(), QRectF(1280 + 50, 100, 100, 50));
296 OutputConfiguration config1;
298 auto changeSet = config1.changeSet(outputs[1]);
299 changeSet->enabled =
false;
304 QCOMPARE(window->output(), outputs[0]);
305 QCOMPARE(window->frameGeometry(), QRectF(50, 100, 100, 50));
309 QVERIFY(window->isInteractiveMove());
310 window->keyPressEvent(Qt::Key_Right);
311 window->keyPressEvent(Qt::Key_Enter);
312 QCOMPARE(window->frameGeometry(), QRectF(58, 100, 100, 50));
315 OutputConfiguration config2;
317 auto changeSet = config2.changeSet(outputs[1]);
318 changeSet->enabled =
true;
323 QCOMPARE(window->output(), outputs[0]);
324 QCOMPARE(window->frameGeometry(), QRectF(58, 100, 100, 50));
327void OutputChangesTest::testMaximizedWindowRestoredAfterEnablingOutput()
332 const auto outputs = kwinApp()->outputBackend()->outputs();
343 QVERIFY(surfaceConfigureRequestedSpy.wait());
347 window->move(QPointF(1280 + 50, 100));
349 QVERIFY(surfaceConfigureRequestedSpy.wait());
350 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024));
351 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
352 Test::render(surface.get(), QSize(1280, 1024), Qt::blue);
353 QVERIFY(frameGeometryChangedSpy.wait());
354 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
355 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
356 QCOMPARE(window->output(), outputs[1]);
358 QCOMPARE(window->requestedMaximizeMode(),
MaximizeFull);
359 QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
362 OutputConfiguration config1;
364 auto changeSet = config1.changeSet(outputs[1]);
365 changeSet->enabled =
false;
370 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 1280, 1024));
371 QCOMPARE(window->moveResizeGeometry(), QRectF(0, 0, 1280, 1024));
372 QCOMPARE(window->output(), outputs[0]);
374 QCOMPARE(window->requestedMaximizeMode(),
MaximizeFull);
375 QCOMPARE(window->geometryRestore(), QRectF(50, 100, 100, 50));
378 OutputConfiguration config2;
380 auto changeSet = config2.changeSet(outputs[1]);
381 changeSet->enabled =
true;
386 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
387 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
388 QCOMPARE(window->output(), outputs[1]);
390 QCOMPARE(window->requestedMaximizeMode(),
MaximizeFull);
391 QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
394void OutputChangesTest::testFullScreenWindowRestoredAfterEnablingOutput()
399 const auto outputs = kwinApp()->outputBackend()->outputs();
410 QVERIFY(surfaceConfigureRequestedSpy.wait());
414 window->move(QPointF(1280 + 50, 100));
415 window->setFullScreen(
true);
416 QVERIFY(surfaceConfigureRequestedSpy.wait());
417 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024));
418 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
419 Test::render(surface.get(), QSize(1280, 1024), Qt::blue);
420 QVERIFY(frameGeometryChangedSpy.wait());
421 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
422 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
423 QCOMPARE(window->output(), outputs[1]);
424 QCOMPARE(window->isFullScreen(),
true);
425 QCOMPARE(window->isRequestedFullScreen(),
true);
426 QCOMPARE(window->fullscreenGeometryRestore(), QRectF(1280 + 50, 100, 100, 50));
429 OutputConfiguration config1;
431 auto changeSet = config1.changeSet(outputs[1]);
432 changeSet->enabled =
false;
437 QCOMPARE(window->frameGeometry(), QRectF(0, 0, 1280, 1024));
438 QCOMPARE(window->moveResizeGeometry(), QRectF(0, 0, 1280, 1024));
439 QCOMPARE(window->output(), outputs[0]);
440 QCOMPARE(window->isFullScreen(),
true);
441 QCOMPARE(window->isRequestedFullScreen(),
true);
442 QCOMPARE(window->fullscreenGeometryRestore(), QRectF(50, 100, 100, 50));
445 OutputConfiguration config2;
447 auto changeSet = config2.changeSet(outputs[1]);
448 changeSet->enabled =
true;
453 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
454 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
455 QCOMPARE(window->output(), outputs[1]);
456 QCOMPARE(window->isFullScreen(),
true);
457 QCOMPARE(window->isRequestedFullScreen(),
true);
458 QCOMPARE(window->fullscreenGeometryRestore(), QRectF(1280 + 50, 100, 100, 50));
461void OutputChangesTest::testWindowRestoredAfterChangingScale()
465 const auto output = kwinApp()->outputBackend()->outputs().front();
474 const QPointF originalPosition(output->geometry().width() - window->width(), output->geometry().height() - window->height());
475 window->move(originalPosition);
476 QCOMPARE(window->pos(), originalPosition);
477 QCOMPARE(window->output(), output);
480 OutputConfiguration config1;
482 auto changeSet = config1.changeSet(output);
483 changeSet->scale = 2;
488 QCOMPARE(window->pos(), QPointF(output->geometry().width() - window->width(), output->geometry().height() - window->height()));
489 QCOMPARE(window->output(), output);
492 OutputConfiguration config2;
494 auto changeSet = config2.changeSet(output);
495 changeSet->scale = 1;
500 QCOMPARE(window->pos(), originalPosition);
501 QCOMPARE(window->output(), output);
504void OutputChangesTest::testMaximizeStateRestoredAfterEnablingOutput()
509 const auto outputs = kwinApp()->outputBackend()->outputs();
513 OutputConfiguration config;
514 auto changeSet = config.changeSet(outputs[1]);
515 changeSet->enabled =
false;
528 QVERIFY(surfaceConfigureRequestedSpy.wait());
530 const QRectF originalGeometry = window->moveResizeGeometry();
534 OutputConfiguration config;
535 auto changeSet = config.changeSet(outputs[1]);
536 changeSet->enabled =
true;
542 window->move(QPointF(1280 + 50, 100));
544 QVERIFY(surfaceConfigureRequestedSpy.wait());
545 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024));
546 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
547 Test::render(surface.get(), QSize(1280, 1024), Qt::blue);
548 QVERIFY(frameGeometryChangedSpy.wait());
549 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
550 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
551 QCOMPARE(window->output(), outputs[1]);
553 QCOMPARE(window->requestedMaximizeMode(),
MaximizeFull);
554 QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
558 OutputConfiguration config;
559 auto changeSet = config.changeSet(outputs[1]);
560 changeSet->enabled =
false;
565 QVERIFY(surfaceConfigureRequestedSpy.wait());
566 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), originalGeometry.size().toSize());
567 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
568 Test::render(surface.get(), originalGeometry.size().toSize(), Qt::blue);
569 QVERIFY(frameGeometryChangedSpy.wait());
570 QCOMPARE(window->frameGeometry(), originalGeometry);
571 QCOMPARE(window->moveResizeGeometry(), originalGeometry);
572 QCOMPARE(window->output(), outputs[0]);
578 OutputConfiguration config;
579 auto changeSet = config.changeSet(outputs[1]);
580 changeSet->enabled =
true;
585 QVERIFY(surfaceConfigureRequestedSpy.wait());
586 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), outputs[1]->geometry().size());
587 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
588 Test::render(surface.get(), outputs[1]->geometry().size(), Qt::blue);
589 QVERIFY(frameGeometryChangedSpy.wait());
590 QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
591 QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
592 QCOMPARE(window->output(), outputs[1]);
594 QCOMPARE(window->requestedMaximizeMode(),
MaximizeFull);
595 QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
598void OutputChangesTest::testLaptopLidClosed()
602 .geometry = QRect(0, 0, 1280, 1024),
606 .geometry = QRect(1280, 0, 1280, 1024),
610 const auto outputs = kwinApp()->outputBackend()->outputs();
611 const auto internal =
outputs.front();
612 QVERIFY(internal->isInternal());
613 const auto external =
outputs.back();
614 QVERIFY(!external->isInternal());
616 auto lidSwitch = std::make_unique<Test::VirtualInputDevice>();
617 lidSwitch->setLidSwitch(
true);
618 lidSwitch->setName(
"virtual lid switch");
621 auto timestamp = 1ms;
622 Q_EMIT lidSwitch->switchToggledOff(timestamp++, lidSwitch.get());
623 QVERIFY(internal->isEnabled());
624 QVERIFY(external->isEnabled());
626 Q_EMIT lidSwitch->switchToggledOn(timestamp++, lidSwitch.get());
627 QVERIFY(!internal->isEnabled());
628 QVERIFY(external->isEnabled());
630 Q_EMIT lidSwitch->switchToggledOff(timestamp++, lidSwitch.get());
631 QVERIFY(internal->isEnabled());
632 QVERIFY(external->isEnabled());
640#include "outputchanges_test.moc"
void configureRequested(quint32 serial)
void configureRequested(const QSize &size, KWin::Test::XdgToplevel::States states)
void frameGeometryChanged(const QRectF &oldGeometry)
bool applyOutputConfiguration(const OutputConfiguration &config, const QList< Output * > &outputOrder={})
QList< Output * > outputs() const
void setActiveOutput(Output *output)
#define WAYLANDTEST_MAIN(TestObject)
Window * renderAndWaitForShown(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32, int timeout=5000)
void destroyWaylandConnection()
void setOutputConfig(const QList< QRect > &geometries)
bool setupWaylandConnection(AdditionalWaylandInterfaces flags=AdditionalWaylandInterfaces())
void render(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32_Premultiplied)
QList< KWayland::Client::Output * > outputs
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
@ MaximizeRestore
The window is not maximized in any direction.
@ MaximizeFull
Equal to MaximizeVertical | MaximizeHorizontal.
WaylandServer * waylandServer()
InputRedirection * input()