23#include <KDecoration2/DecoratedClient>
24#include <KDecoration2/Decoration>
25#include <KDecoration2/DecorationSettings>
27#include <KWayland/Client/compositor.h>
28#include <KWayland/Client/connection_thread.h>
29#include <KWayland/Client/surface.h>
31#include <QDBusConnection>
32#include <QDBusMessage>
33#include <QDBusPendingCall>
34#include <QTemporaryFile>
38#include <xcb/xcb_icccm.h>
40#include <linux/input.h>
48static const QString s_socketName = QStringLiteral(
"wayland_test_kwin_quick_tiling-0");
57 void testQuickTiling_data();
58 void testQuickTiling();
59 void testQuickMaximizing_data();
60 void testQuickMaximizing();
61 void testQuickTilingKeyboardMove_data();
62 void testQuickTilingKeyboardMove();
63 void testQuickTilingPointerMove_data();
64 void testQuickTilingPointerMove();
65 void testQuickTilingTouchMove_data();
66 void testQuickTilingTouchMove();
67 void testX11QuickTiling_data();
68 void testX11QuickTiling();
69 void testX11QuickTilingAfterVertMaximize_data();
70 void testX11QuickTilingAfterVertMaximize();
71 void testShortcut_data();
73 void testScript_data();
77 KWayland::Client::ConnectionThread *m_connection =
nullptr;
78 KWayland::Client::Compositor *m_compositor =
nullptr;
81void QuickTilingTest::initTestCase()
83 qRegisterMetaType<KWin::Window *>();
84 qRegisterMetaType<KWin::MaximizeMode>(
"MaximizeMode");
88 QRect(0, 0, 1280, 1024),
89 QRect(1280, 0, 1280, 1024),
93 KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
94 KConfigGroup group = config->group(QStringLiteral(
"Outline"));
95 group.writeEntry(QStringLiteral(
"QmlPath"), QString(
"/does/not/exist.qml"));
98 kwinApp()->setConfig(config);
100 qputenv(
"XKB_DEFAULT_RULES",
"evdev");
103 QVERIFY(applicationStartedSpy.wait());
106 QCOMPARE(outputs.count(), 2);
107 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
108 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
111void QuickTilingTest::init()
121void QuickTilingTest::cleanup()
126void QuickTilingTest::testQuickTiling_data()
128 QTest::addColumn<QuickTileMode>(
"mode");
129 QTest::addColumn<QRectF>(
"expectedGeometry");
130 QTest::addColumn<QRectF>(
"secondScreen");
131 QTest::addColumn<QuickTileMode>(
"expectedModeAfterToggle");
133#define FLAG(name) QuickTileMode(QuickTileFlag::name)
135 QTest::newRow(
"left") <<
FLAG(
Left) << QRectF(0, 0, 640, 1024) << QRectF(1280, 0, 640, 1024) <<
FLAG(
Right);
136 QTest::newRow(
"top") <<
FLAG(
Top) << QRectF(0, 0, 1280, 512) << QRectF(1280, 0, 1280, 512) << QuickTileMode();
137 QTest::newRow(
"right") <<
FLAG(
Right) << QRectF(640, 0, 640, 1024) << QRectF(1920, 0, 640, 1024) << QuickTileMode();
138 QTest::newRow(
"bottom") <<
FLAG(
Bottom) << QRectF(0, 512, 1280, 512) << QRectF(1280, 512, 1280, 512) << QuickTileMode();
141 QTest::newRow(
"top right") << (
FLAG(
Right) |
FLAG(
Top)) << QRectF(640, 0, 640, 512) << QRectF(1920, 0, 640, 512) << QuickTileMode();
143 QTest::newRow(
"bottom right") << (
FLAG(
Right) |
FLAG(
Bottom)) << QRectF(640, 512, 640, 512) << QRectF(1920, 512, 640, 512) << QuickTileMode();
145 QTest::newRow(
"maximize") <<
FLAG(
Maximize) << QRectF(0, 0, 1280, 1024) << QRectF(1280, 0, 1280, 1024) << QuickTileMode();
150void QuickTilingTest::testQuickTiling()
153 QVERIFY(surface !=
nullptr);
155 QVERIFY(shellSurface !=
nullptr);
160 QCOMPARE(
workspace()->activeWindow(), window);
161 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
167 QVERIFY(surfaceConfigureRequestedSpy.wait());
168 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
173 QFETCH(QuickTileMode, mode);
174 QFETCH(QRectF, expectedGeometry);
175 window->setQuickTileMode(mode,
true);
176 QCOMPARE(quickTileChangedSpy.count(), 1);
178 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
180 QCOMPARE(window->quickTileMode(), mode);
183 QVERIFY(surfaceConfigureRequestedSpy.wait());
184 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
185 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), expectedGeometry.size());
188 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
189 Test::render(surface.get(), expectedGeometry.size().toSize(), Qt::red);
191 QVERIFY(frameGeometryChangedSpy.wait());
192 QCOMPARE(frameGeometryChangedSpy.count(), 1);
193 QCOMPARE(window->frameGeometry(), expectedGeometry);
197 QCOMPARE(window->output(), outputs[0]);
198 window->sendToOutput(outputs[1]);
199 QCOMPARE(window->output(), outputs[1]);
201 QCOMPARE(window->quickTileMode(), mode);
202 QTEST(window->frameGeometry(),
"secondScreen");
205 window->setQuickTileMode(mode,
true);
206 QTEST(window->quickTileMode(),
"expectedModeAfterToggle");
209void QuickTilingTest::testQuickMaximizing_data()
211 QTest::addColumn<QuickTileMode>(
"mode");
213#define FLAG(name) QuickTileMode(QuickTileFlag::name)
216 QTest::newRow(
"none") <<
FLAG(
None);
221void QuickTilingTest::testQuickMaximizing()
224 QVERIFY(surface !=
nullptr);
226 QVERIFY(shellSurface !=
nullptr);
231 QCOMPARE(
workspace()->activeWindow(), window);
232 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
239 QVERIFY(surfaceConfigureRequestedSpy.wait());
240 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
247 QCOMPARE(quickTileChangedSpy.count(), 1);
250 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
253 QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50));
256 QVERIFY(surfaceConfigureRequestedSpy.wait());
257 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
258 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024));
261 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
262 Test::render(surface.get(), QSize(1280, 1024), Qt::red);
264 QVERIFY(frameGeometryChangedSpy.wait());
265 QCOMPARE(frameGeometryChangedSpy.count(), 1);
266 QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
267 QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50));
270 QCOMPARE(maximizeChangedSpy.count(), 1);
272 QCOMPARE(window->tile(),
nullptr);
275 QFETCH(QuickTileMode, mode);
276 window->setQuickTileMode(mode,
true);
278 QCOMPARE(quickTileChangedSpy.count(), 2);
280 QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
281 QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50));
283 QVERIFY(surfaceConfigureRequestedSpy.wait());
284 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
285 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(100, 50));
288 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
289 Test::render(surface.get(), QSize(100, 50), Qt::yellow);
291 QVERIFY(frameGeometryChangedSpy.wait());
292 QCOMPARE(frameGeometryChangedSpy.count(), 2);
293 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
294 QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50));
295 QCOMPARE(maximizeChangedSpy.count(), 2);
298void QuickTilingTest::testQuickTilingKeyboardMove_data()
300 QTest::addColumn<QPoint>(
"targetPos");
301 QTest::addColumn<QuickTileMode>(
"expectedMode");
311void QuickTilingTest::testQuickTilingKeyboardMove()
314 QVERIFY(surface !=
nullptr);
317 QVERIFY(shellSurface !=
nullptr);
322 QCOMPARE(
workspace()->activeWindow(), window);
323 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
330 QCOMPARE(window,
workspace()->moveResizeWindow());
333 QFETCH(QPoint, targetPos);
334 quint32 timestamp = 1;
336 while (
Cursors::self()->mouse()->pos().x() > targetPos.x()) {
340 while (
Cursors::self()->mouse()->pos().x() < targetPos.x()) {
344 while (
Cursors::self()->mouse()->pos().y() < targetPos.y()) {
348 while (
Cursors::self()->mouse()->pos().y() > targetPos.y()) {
356 QVERIFY(!
workspace()->moveResizeWindow());
358 QCOMPARE(quickTileChangedSpy.count(), 1);
359 QTEST(window->quickTileMode(),
"expectedMode");
362void QuickTilingTest::testQuickTilingPointerMove_data()
364 QTest::addColumn<QPoint>(
"pointerPos");
365 QTest::addColumn<QSize>(
"tileSize");
366 QTest::addColumn<QuickTileMode>(
"expectedMode");
369 QTest::newRow(
"right") << QPoint(2559, 512) << QSize(640, 1024) << QuickTileMode(
QuickTileFlag::Right);
372 QTest::newRow(
"Left") << QPoint(0, 512) << QSize(640, 1024) << QuickTileMode(
QuickTileFlag::Left);
376void QuickTilingTest::testQuickTilingPointerMove()
384 QCOMPARE(
workspace()->activeWindow(), window);
385 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
393 QVERIFY(surfaceConfigureRequestedSpy.wait());
394 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
400 QCOMPARE(window,
workspace()->moveResizeWindow());
403 QFETCH(QPoint, pointerPos);
404 QFETCH(QSize, tileSize);
405 quint32 timestamp = 1;
409 QCOMPARE(quickTileChangedSpy.count(), 1);
410 QTEST(window->quickTileMode(),
"expectedMode");
411 QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50));
412 QVERIFY(surfaceConfigureRequestedSpy.wait());
413 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
414 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), tileSize);
417 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
419 QVERIFY(frameGeometryChangedSpy.wait());
420 QCOMPARE(window->frameGeometry().size(), tileSize);
425 QCOMPARE(window,
workspace()->moveResizeWindow());
429 QCOMPARE(quickTileChangedSpy.count(), 2);
431 QVERIFY(surfaceConfigureRequestedSpy.wait());
432 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
433 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(100, 50));
436 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
438 QVERIFY(frameGeometryChangedSpy.wait());
439 QCOMPARE(window->frameGeometry().size(), QSize(100, 50));
443 QCOMPARE(quickTileChangedSpy.count(), 3);
444 QTEST(window->quickTileMode(),
"expectedMode");
445 QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50));
446 QVERIFY(surfaceConfigureRequestedSpy.wait());
447 QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
448 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), tileSize);
451void QuickTilingTest::testQuickTilingTouchMove_data()
453 QTest::addColumn<QPoint>(
"targetPos");
454 QTest::addColumn<QuickTileMode>(
"expectedMode");
464void QuickTilingTest::testQuickTilingTouchMove()
477 surface->commit(KWayland::Client::Surface::CommitFlag::None);
478 QVERIFY(surfaceConfigureRequestedSpy.wait());
479 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
482 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
486 QVERIFY(window->isDecorated());
487 const auto decoration = window->decoration();
488 QCOMPARE(
workspace()->activeWindow(), window);
489 QCOMPARE(window->frameGeometry(), QRect(-decoration->borderLeft(), 0, 1000 + decoration->borderLeft() + decoration->borderRight(), 50 + decoration->borderTop() + decoration->borderBottom()));
494 QVERIFY(surfaceConfigureRequestedSpy.wait());
495 QTRY_COMPARE(surfaceConfigureRequestedSpy.count(), 2);
500 quint32 timestamp = 1;
502 Test::touchDown(0, QPointF(window->frameGeometry().center().x(), window->frameGeometry().y() + decoration->borderTop() / 2), timestamp++);
503 QVERIFY(interactiveMoveResizeStartedSpy.wait());
504 QCOMPARE(window,
workspace()->moveResizeWindow());
506 QFETCH(QPoint, targetPos);
509 QVERIFY(!
workspace()->moveResizeWindow());
515 QCOMPARE(quickTileChangedSpy.count(), 1);
516 QTEST(window->quickTileMode(),
"expectedMode");
517 QVERIFY(surfaceConfigureRequestedSpy.wait());
518 QTRY_COMPARE(surfaceConfigureRequestedSpy.count(), hasBorders ? 4 : 3);
519 QCOMPARE(
false, toplevelConfigureRequestedSpy.last().first().toSize().isEmpty());
522void QuickTilingTest::testX11QuickTiling_data()
524 QTest::addColumn<QuickTileMode>(
"mode");
525 QTest::addColumn<QRectF>(
"expectedGeometry");
526 QTest::addColumn<int>(
"screenId");
527 QTest::addColumn<QuickTileMode>(
"modeAfterToggle");
529#define FLAG(name) QuickTileMode(QuickTileFlag::name)
531 QTest::newRow(
"left") <<
FLAG(
Left) << QRectF(0, 0, 640, 1024) << 0 << QuickTileMode();
532 QTest::newRow(
"top") <<
FLAG(
Top) << QRectF(0, 0, 1280, 512) << 0 << QuickTileMode();
533 QTest::newRow(
"right") <<
FLAG(
Right) << QRectF(640, 0, 640, 1024) << 1 <<
FLAG(
Left);
534 QTest::newRow(
"bottom") <<
FLAG(
Bottom) << QRectF(0, 512, 1280, 512) << 0 << QuickTileMode();
536 QTest::newRow(
"top left") << (
FLAG(
Left) |
FLAG(
Top)) << QRectF(0, 0, 640, 512) << 0 << QuickTileMode();
538 QTest::newRow(
"bottom left") << (
FLAG(
Left) |
FLAG(
Bottom)) << QRectF(0, 512, 640, 512) << 0 << QuickTileMode();
541 QTest::newRow(
"maximize") <<
FLAG(
Maximize) << QRectF(0, 0, 1280, 1024) << 0 << QuickTileMode();
545void QuickTilingTest::testX11QuickTiling()
548 QVERIFY(!xcb_connection_has_error(c.get()));
549 const QRect windowGeometry(0, 0, 100, 200);
550 xcb_window_t windowId = xcb_generate_id(c.get());
551 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
554 windowGeometry.width(),
555 windowGeometry.height(),
556 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
557 xcb_size_hints_t hints;
558 memset(&hints, 0,
sizeof(hints));
559 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
560 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
561 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
562 xcb_map_window(c.get(), windowId);
567 QVERIFY(windowCreatedSpy.wait());
568 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
570 QCOMPARE(window->window(), windowId);
574 const QRectF origGeo = window->frameGeometry();
575 QFETCH(QuickTileMode, mode);
576 window->setQuickTileMode(mode,
true);
577 QCOMPARE(window->quickTileMode(), mode);
578 QTEST(window->frameGeometry(),
"expectedGeometry");
579 QCOMPARE(window->geometryRestore(), origGeo);
580 QEXPECT_FAIL(
"maximize",
"For maximize we get two changed signals", Continue);
581 QCOMPARE(quickTileChangedSpy.count(), 1);
586 QCOMPARE(window->output(), outputs[0]);
587 window->setQuickTileMode(mode,
true);
588 QFETCH(
int, screenId);
589 QCOMPARE(window->output(), outputs[screenId]);
590 QTEST(window->quickTileMode(),
"modeAfterToggle");
591 QCOMPARE(window->geometryRestore(), origGeo);
594 xcb_unmap_window(c.get(), windowId);
595 xcb_destroy_window(c.get(), windowId);
600 QVERIFY(windowClosedSpy.wait());
603void QuickTilingTest::testX11QuickTilingAfterVertMaximize_data()
605 QTest::addColumn<QuickTileMode>(
"mode");
606 QTest::addColumn<QRectF>(
"expectedGeometry");
608#define FLAG(name) QuickTileMode(QuickTileFlag::name)
610 QTest::newRow(
"left") <<
FLAG(
Left) << QRectF(0, 0, 640, 1024);
611 QTest::newRow(
"top") <<
FLAG(
Top) << QRectF(0, 0, 1280, 512);
612 QTest::newRow(
"right") <<
FLAG(
Right) << QRectF(640, 0, 640, 1024);
613 QTest::newRow(
"bottom") <<
FLAG(
Bottom) << QRectF(0, 512, 1280, 512);
615 QTest::newRow(
"top left") << (
FLAG(
Left) |
FLAG(
Top)) << QRectF(0, 0, 640, 512);
616 QTest::newRow(
"top right") << (
FLAG(
Right) |
FLAG(
Top)) << QRectF(640, 0, 640, 512);
617 QTest::newRow(
"bottom left") << (
FLAG(
Left) |
FLAG(
Bottom)) << QRectF(0, 512, 640, 512);
618 QTest::newRow(
"bottom right") << (
FLAG(
Right) |
FLAG(
Bottom)) << QRectF(640, 512, 640, 512);
620 QTest::newRow(
"maximize") <<
FLAG(
Maximize) << QRectF(0, 0, 1280, 1024);
625void QuickTilingTest::testX11QuickTilingAfterVertMaximize()
628 QVERIFY(!xcb_connection_has_error(c.get()));
629 const QRect windowGeometry(0, 0, 100, 200);
630 xcb_window_t windowId = xcb_generate_id(c.get());
631 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId,
rootWindow(),
634 windowGeometry.width(),
635 windowGeometry.height(),
636 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0,
nullptr);
637 xcb_size_hints_t hints;
638 memset(&hints, 0,
sizeof(hints));
639 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
640 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
641 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
642 xcb_map_window(c.get(), windowId);
647 QVERIFY(windowCreatedSpy.wait());
648 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
650 QCOMPARE(window->window(), windowId);
652 const QRectF origGeo = window->frameGeometry();
656 QCOMPARE(window->frameGeometry().width(), origGeo.width());
657 QCOMPARE(window->height(), window->output()->geometry().height());
658 QCOMPARE(window->geometryRestore(), origGeo);
662 QFETCH(QuickTileMode, mode);
663 window->setQuickTileMode(mode,
true);
664 QCOMPARE(window->quickTileMode(), mode);
665 QTEST(window->frameGeometry(),
"expectedGeometry");
666 QEXPECT_FAIL(
"",
"We get two changed events", Continue);
667 QCOMPARE(quickTileChangedSpy.count(), 1);
670 xcb_unmap_window(c.get(), windowId);
671 xcb_destroy_window(c.get(), windowId);
676 QVERIFY(windowClosedSpy.wait());
679void QuickTilingTest::testShortcut_data()
681 QTest::addColumn<QStringList>(
"shortcutList");
682 QTest::addColumn<QuickTileMode>(
"expectedMode");
683 QTest::addColumn<QRect>(
"expectedGeometry");
685#define FLAG(name) QuickTileMode(QuickTileFlag::name)
686 QTest::newRow(
"top") << QStringList{QStringLiteral(
"Window Quick Tile Top")} <<
FLAG(
Top) << QRect(0, 0, 1280, 512);
687 QTest::newRow(
"bottom") << QStringList{QStringLiteral(
"Window Quick Tile Bottom")} <<
FLAG(
Bottom) << QRect(0, 512, 1280, 512);
688 QTest::newRow(
"top right") << QStringList{QStringLiteral(
"Window Quick Tile Top Right")} << (
FLAG(
Top) |
FLAG(
Right)) << QRect(640, 0, 640, 512);
689 QTest::newRow(
"top left") << QStringList{QStringLiteral(
"Window Quick Tile Top Left")} << (
FLAG(
Top) |
FLAG(
Left)) << QRect(0, 0, 640, 512);
690 QTest::newRow(
"bottom right") << QStringList{QStringLiteral(
"Window Quick Tile Bottom Right")} << (
FLAG(
Bottom) |
FLAG(
Right)) << QRect(640, 512, 640, 512);
691 QTest::newRow(
"bottom left") << QStringList{QStringLiteral(
"Window Quick Tile Bottom Left")} << (
FLAG(
Bottom) |
FLAG(
Left)) << QRect(0, 512, 640, 512);
692 QTest::newRow(
"left") << QStringList{QStringLiteral(
"Window Quick Tile Left")} <<
FLAG(
Left) << QRect(0, 0, 640, 1024);
693 QTest::newRow(
"right") << QStringList{QStringLiteral(
"Window Quick Tile Right")} <<
FLAG(
Right) << QRect(640, 0, 640, 1024);
696 QTest::newRow(
"top left combined") << QStringList{QStringLiteral(
"Window Quick Tile Left"), QStringLiteral(
"Window Quick Tile Top")} << (
FLAG(
Top) |
FLAG(
Left)) << QRect(0, 0, 640, 512);
697 QTest::newRow(
"top right combined") << QStringList{QStringLiteral(
"Window Quick Tile Right"), QStringLiteral(
"Window Quick Tile Top")} << (
FLAG(
Top) |
FLAG(
Right)) << QRect(640, 0, 640, 512);
698 QTest::newRow(
"bottom left combined") << QStringList{QStringLiteral(
"Window Quick Tile Left"), QStringLiteral(
"Window Quick Tile Bottom")} << (
FLAG(
Bottom) |
FLAG(
Left)) << QRect(0, 512, 640, 512);
699 QTest::newRow(
"bottom right combined") << QStringList{QStringLiteral(
"Window Quick Tile Right"), QStringLiteral(
"Window Quick Tile Bottom")} << (
FLAG(
Bottom) |
FLAG(
Right)) << QRect(640, 512, 640, 512);
703void QuickTilingTest::testShortcut()
705#if !KWIN_BUILD_GLOBALSHORTCUTS
706 QSKIP(
"Can't test shortcuts without shortcuts");
711 QVERIFY(surface !=
nullptr);
713 QVERIFY(shellSurface !=
nullptr);
718 QCOMPARE(
workspace()->activeWindow(), window);
719 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
725 QVERIFY(surfaceConfigureRequestedSpy.wait());
726 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
728 QFETCH(QStringList, shortcutList);
729 QFETCH(QRect, expectedGeometry);
731 const int numberOfQuickTileActions = shortcutList.count();
733 for (QString shortcut : shortcutList) {
735 auto msg = QDBusMessage::createMethodCall(
736 QStringLiteral(
"org.kde.kglobalaccel"),
737 QStringLiteral(
"/component/kwin"),
738 QStringLiteral(
"org.kde.kglobalaccel.Component"),
739 QStringLiteral(
"invokeShortcut"));
740 msg.setArguments(QList<QVariant>{shortcut});
741 QDBusConnection::sessionBus().asyncCall(msg);
745 QTRY_COMPARE(quickTileChangedSpy.count(), numberOfQuickTileActions);
747 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
749 QTEST(window->quickTileMode(),
"expectedMode");
752 QVERIFY(surfaceConfigureRequestedSpy.wait());
753 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
754 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), expectedGeometry.size());
758 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
759 Test::render(surface.get(), expectedGeometry.size(), Qt::red);
761 QVERIFY(frameGeometryChangedSpy.wait());
762 QEXPECT_FAIL(
"maximize",
"Geometry changed called twice for maximize", Continue);
763 QCOMPARE(frameGeometryChangedSpy.count(), 1);
764 QCOMPARE(window->frameGeometry(), expectedGeometry);
767void QuickTilingTest::testScript_data()
769 QTest::addColumn<QString>(
"action");
770 QTest::addColumn<QuickTileMode>(
"expectedMode");
771 QTest::addColumn<QRect>(
"expectedGeometry");
773#define FLAG(name) QuickTileMode(QuickTileFlag::name)
774 QTest::newRow(
"top") << QStringLiteral(
"Top") <<
FLAG(
Top) << QRect(0, 0, 1280, 512);
775 QTest::newRow(
"bottom") << QStringLiteral(
"Bottom") <<
FLAG(
Bottom) << QRect(0, 512, 1280, 512);
776 QTest::newRow(
"top right") << QStringLiteral(
"TopRight") << (
FLAG(
Top) |
FLAG(
Right)) << QRect(640, 0, 640, 512);
777 QTest::newRow(
"top left") << QStringLiteral(
"TopLeft") << (
FLAG(
Top) |
FLAG(
Left)) << QRect(0, 0, 640, 512);
778 QTest::newRow(
"bottom right") << QStringLiteral(
"BottomRight") << (
FLAG(
Bottom) |
FLAG(
Right)) << QRect(640, 512, 640, 512);
779 QTest::newRow(
"bottom left") << QStringLiteral(
"BottomLeft") << (
FLAG(
Bottom) |
FLAG(
Left)) << QRect(0, 512, 640, 512);
780 QTest::newRow(
"left") << QStringLiteral(
"Left") <<
FLAG(
Left) << QRect(0, 0, 640, 1024);
781 QTest::newRow(
"right") << QStringLiteral(
"Right") <<
FLAG(
Right) << QRect(640, 0, 640, 1024);
785void QuickTilingTest::testScript()
788 QVERIFY(surface !=
nullptr);
790 QVERIFY(shellSurface !=
nullptr);
795 QCOMPARE(
workspace()->activeWindow(), window);
796 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
802 QVERIFY(surfaceConfigureRequestedSpy.wait());
803 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
809 QTemporaryFile tmpFile;
810 QVERIFY(tmpFile.open());
811 QTextStream out(&tmpFile);
813 QFETCH(QString, action);
814 out <<
"workspace.slotWindowQuickTile" << action <<
"()";
817 QFETCH(QuickTileMode, expectedMode);
818 QFETCH(QRect, expectedGeometry);
828 QVERIFY(quickTileChangedSpy.wait());
829 QCOMPARE(quickTileChangedSpy.count(), 1);
831 QCOMPARE(runningChangedSpy.count(), 1);
832 QCOMPARE(runningChangedSpy.first().first().toBool(),
true);
835 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
837 QCOMPARE(window->quickTileMode(), expectedMode);
840 QVERIFY(surfaceConfigureRequestedSpy.wait());
841 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
842 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), expectedGeometry.size());
845 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
846 Test::render(surface.get(), expectedGeometry.size(), Qt::red);
848 QVERIFY(frameGeometryChangedSpy.wait());
849 QEXPECT_FAIL(
"maximize",
"Geometry changed called twice for maximize", Continue);
850 QCOMPARE(frameGeometryChangedSpy.count(), 1);
851 QCOMPARE(window->frameGeometry(), expectedGeometry);
857#include "quick_tiling_test.moc"
void runningChanged(bool)
std::unique_ptr< KDecoration2::DecorationSettingsPrivate > settings(KDecoration2::DecorationSettings *parent) override
AbstractScript * findScript(const QString &pluginName) const
Q_SCRIPTABLE Q_INVOKABLE int loadScript(const QString &filePath, const QString &pluginName=QString())
static Scripting * self()
void configureRequested(quint32 serial)
void configureRequested(QtWayland::zxdg_toplevel_decoration_v1::mode mode)
void configureRequested(const QSize &size, KWin::Test::XdgToplevel::States states)
void interactiveMoveResizeStarted()
void quickTileModeChanged()
void frameGeometryChanged(const QRectF &oldGeometry)
void performWindowOperation(KWin::Window *window, Options::WindowOperation op)
Decoration::DecorationBridge * decorationBridge() const
static Workspace * self()
void windowAdded(KWin::Window *)
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 keyboardKeyReleased(quint32 key, quint32 time)
void destroyWaylandConnection()
void setOutputConfig(const QList< QRect > &geometries)
void touchDown(qint32 id, const QPointF &pos, quint32 time)
void keyboardKeyPressed(quint32 key, quint32 time)
bool setupWaylandConnection(AdditionalWaylandInterfaces flags=AdditionalWaylandInterfaces())
void touchMotion(qint32 id, const QPointF &pos, quint32 time)
KWayland::Client::Compositor * waylandCompositor()
void render(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32_Premultiplied)
void pointerButtonPressed(quint32 button, quint32 time)
XcbConnectionPtr createX11Connection()
QList< KWayland::Client::Output * > outputs
void pointerMotion(const QPointF &position, quint32 time)
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
XdgToplevelDecorationV1 * createXdgToplevelDecorationV1(XdgToplevel *toplevel, QObject *parent=nullptr)
KWayland::Client::ConnectionThread * waylandConnection()
void pointerButtonReleased(quint32 button, quint32 time)
void touchUp(qint32 id, quint32 time)
std::unique_ptr< xcb_connection_t, XcbConnectionDeleter > XcbConnectionPtr
KWIN_EXPORT xcb_window_t rootWindow()
@ MaximizeVertical
The window is maximized vertically.
@ MaximizeRestore
The window is not maximized in any direction.
@ MaximizeFull
Equal to MaximizeVertical | MaximizeHorizontal.
WaylandServer * waylandServer()
InputRedirection * input()