File indexing completed on 2024-11-10 04:56:05
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #include "kwin_wayland_test.h" 0010 0011 #include "core/output.h" 0012 #include "cursor.h" 0013 #include "decorations/decorationbridge.h" 0014 #include "decorations/settings.h" 0015 #include "pointer_input.h" 0016 #include "scripting/scripting.h" 0017 #include "utils/common.h" 0018 #include "wayland_server.h" 0019 #include "window.h" 0020 #include "workspace.h" 0021 #include "x11window.h" 0022 0023 #include <KDecoration2/DecoratedClient> 0024 #include <KDecoration2/Decoration> 0025 #include <KDecoration2/DecorationSettings> 0026 0027 #include <KWayland/Client/compositor.h> 0028 #include <KWayland/Client/connection_thread.h> 0029 #include <KWayland/Client/surface.h> 0030 0031 #include <QDBusConnection> 0032 #include <QDBusMessage> 0033 #include <QDBusPendingCall> 0034 #include <QTemporaryFile> 0035 #include <QTextStream> 0036 0037 #include <netwm.h> 0038 #include <xcb/xcb_icccm.h> 0039 0040 #include <linux/input.h> 0041 0042 Q_DECLARE_METATYPE(KWin::QuickTileMode) 0043 Q_DECLARE_METATYPE(KWin::MaximizeMode) 0044 0045 namespace KWin 0046 { 0047 0048 static const QString s_socketName = QStringLiteral("wayland_test_kwin_quick_tiling-0"); 0049 0050 class QuickTilingTest : public QObject 0051 { 0052 Q_OBJECT 0053 private Q_SLOTS: 0054 void initTestCase(); 0055 void init(); 0056 void cleanup(); 0057 void testQuickTiling_data(); 0058 void testQuickTiling(); 0059 void testQuickMaximizing_data(); 0060 void testQuickMaximizing(); 0061 void testQuickTilingKeyboardMove_data(); 0062 void testQuickTilingKeyboardMove(); 0063 void testQuickTilingPointerMove_data(); 0064 void testQuickTilingPointerMove(); 0065 void testQuickTilingTouchMove_data(); 0066 void testQuickTilingTouchMove(); 0067 void testX11QuickTiling_data(); 0068 void testX11QuickTiling(); 0069 void testX11QuickTilingAfterVertMaximize_data(); 0070 void testX11QuickTilingAfterVertMaximize(); 0071 void testShortcut_data(); 0072 void testShortcut(); 0073 void testScript_data(); 0074 void testScript(); 0075 0076 private: 0077 KWayland::Client::ConnectionThread *m_connection = nullptr; 0078 KWayland::Client::Compositor *m_compositor = nullptr; 0079 }; 0080 0081 void QuickTilingTest::initTestCase() 0082 { 0083 qRegisterMetaType<KWin::Window *>(); 0084 qRegisterMetaType<KWin::MaximizeMode>("MaximizeMode"); 0085 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); 0086 QVERIFY(waylandServer()->init(s_socketName)); 0087 Test::setOutputConfig({ 0088 QRect(0, 0, 1280, 1024), 0089 QRect(1280, 0, 1280, 1024), 0090 }); 0091 0092 // set custom config which disables the Outline 0093 KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); 0094 KConfigGroup group = config->group(QStringLiteral("Outline")); 0095 group.writeEntry(QStringLiteral("QmlPath"), QString("/does/not/exist.qml")); 0096 group.sync(); 0097 0098 kwinApp()->setConfig(config); 0099 0100 qputenv("XKB_DEFAULT_RULES", "evdev"); 0101 0102 kwinApp()->start(); 0103 QVERIFY(applicationStartedSpy.wait()); 0104 0105 const auto outputs = workspace()->outputs(); 0106 QCOMPARE(outputs.count(), 2); 0107 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024)); 0108 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024)); 0109 } 0110 0111 void QuickTilingTest::init() 0112 { 0113 QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::XdgDecorationV1)); 0114 m_connection = Test::waylandConnection(); 0115 m_compositor = Test::waylandCompositor(); 0116 0117 workspace()->setActiveOutput(QPoint(640, 512)); 0118 input()->pointer()->warp(QPoint(640, 512)); 0119 } 0120 0121 void QuickTilingTest::cleanup() 0122 { 0123 Test::destroyWaylandConnection(); 0124 } 0125 0126 void QuickTilingTest::testQuickTiling_data() 0127 { 0128 QTest::addColumn<QuickTileMode>("mode"); 0129 QTest::addColumn<QRectF>("expectedGeometry"); 0130 QTest::addColumn<QRectF>("secondScreen"); 0131 QTest::addColumn<QuickTileMode>("expectedModeAfterToggle"); 0132 0133 #define FLAG(name) QuickTileMode(QuickTileFlag::name) 0134 0135 QTest::newRow("left") << FLAG(Left) << QRectF(0, 0, 640, 1024) << QRectF(1280, 0, 640, 1024) << FLAG(Right); 0136 QTest::newRow("top") << FLAG(Top) << QRectF(0, 0, 1280, 512) << QRectF(1280, 0, 1280, 512) << QuickTileMode(); 0137 QTest::newRow("right") << FLAG(Right) << QRectF(640, 0, 640, 1024) << QRectF(1920, 0, 640, 1024) << QuickTileMode(); 0138 QTest::newRow("bottom") << FLAG(Bottom) << QRectF(0, 512, 1280, 512) << QRectF(1280, 512, 1280, 512) << QuickTileMode(); 0139 0140 QTest::newRow("top left") << (FLAG(Left) | FLAG(Top)) << QRectF(0, 0, 640, 512) << QRectF(1280, 0, 640, 512) << (FLAG(Right) | FLAG(Top)); 0141 QTest::newRow("top right") << (FLAG(Right) | FLAG(Top)) << QRectF(640, 0, 640, 512) << QRectF(1920, 0, 640, 512) << QuickTileMode(); 0142 QTest::newRow("bottom left") << (FLAG(Left) | FLAG(Bottom)) << QRectF(0, 512, 640, 512) << QRectF(1280, 512, 640, 512) << (FLAG(Right) | FLAG(Bottom)); 0143 QTest::newRow("bottom right") << (FLAG(Right) | FLAG(Bottom)) << QRectF(640, 512, 640, 512) << QRectF(1920, 512, 640, 512) << QuickTileMode(); 0144 0145 QTest::newRow("maximize") << FLAG(Maximize) << QRectF(0, 0, 1280, 1024) << QRectF(1280, 0, 1280, 1024) << QuickTileMode(); 0146 0147 #undef FLAG 0148 } 0149 0150 void QuickTilingTest::testQuickTiling() 0151 { 0152 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0153 QVERIFY(surface != nullptr); 0154 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0155 QVERIFY(shellSurface != nullptr); 0156 0157 // Map the window. 0158 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0159 QVERIFY(window); 0160 QCOMPARE(workspace()->activeWindow(), window); 0161 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50)); 0162 QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None)); 0163 0164 // We have to receive a configure event when the window becomes active. 0165 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested); 0166 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); 0167 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0168 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1); 0169 0170 QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged); 0171 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged); 0172 0173 QFETCH(QuickTileMode, mode); 0174 QFETCH(QRectF, expectedGeometry); 0175 window->setQuickTileMode(mode, true); 0176 QCOMPARE(quickTileChangedSpy.count(), 1); 0177 // at this point the geometry did not yet change 0178 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50)); 0179 // but quick tile mode already changed 0180 QCOMPARE(window->quickTileMode(), mode); 0181 0182 // but we got requested a new geometry 0183 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0184 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2); 0185 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), expectedGeometry.size()); 0186 0187 // attach a new image 0188 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0189 Test::render(surface.get(), expectedGeometry.size().toSize(), Qt::red); 0190 0191 QVERIFY(frameGeometryChangedSpy.wait()); 0192 QCOMPARE(frameGeometryChangedSpy.count(), 1); 0193 QCOMPARE(window->frameGeometry(), expectedGeometry); 0194 0195 // send window to other screen 0196 QList<Output *> outputs = workspace()->outputs(); 0197 QCOMPARE(window->output(), outputs[0]); 0198 window->sendToOutput(outputs[1]); 0199 QCOMPARE(window->output(), outputs[1]); 0200 // quick tile should not be changed 0201 QCOMPARE(window->quickTileMode(), mode); 0202 QTEST(window->frameGeometry(), "secondScreen"); 0203 0204 // now try to toggle again 0205 window->setQuickTileMode(mode, true); 0206 QTEST(window->quickTileMode(), "expectedModeAfterToggle"); 0207 } 0208 0209 void QuickTilingTest::testQuickMaximizing_data() 0210 { 0211 QTest::addColumn<QuickTileMode>("mode"); 0212 0213 #define FLAG(name) QuickTileMode(QuickTileFlag::name) 0214 0215 QTest::newRow("maximize") << FLAG(Maximize); 0216 QTest::newRow("none") << FLAG(None); 0217 0218 #undef FLAG 0219 } 0220 0221 void QuickTilingTest::testQuickMaximizing() 0222 { 0223 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0224 QVERIFY(surface != nullptr); 0225 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0226 QVERIFY(shellSurface != nullptr); 0227 0228 // Map the window. 0229 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0230 QVERIFY(window); 0231 QCOMPARE(workspace()->activeWindow(), window); 0232 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50)); 0233 QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None)); 0234 QCOMPARE(window->maximizeMode(), MaximizeRestore); 0235 0236 // We have to receive a configure event upon becoming active. 0237 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested); 0238 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); 0239 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0240 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1); 0241 0242 QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged); 0243 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged); 0244 QSignalSpy maximizeChangedSpy(window, &Window::maximizedChanged); 0245 0246 window->setQuickTileMode(QuickTileFlag::Maximize, true); 0247 QCOMPARE(quickTileChangedSpy.count(), 1); 0248 0249 // at this point the geometry did not yet change 0250 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50)); 0251 // but quick tile mode already changed 0252 QCOMPARE(window->quickTileMode(), QuickTileFlag::Maximize); 0253 QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50)); 0254 0255 // but we got requested a new geometry 0256 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0257 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2); 0258 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024)); 0259 0260 // attach a new image 0261 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0262 Test::render(surface.get(), QSize(1280, 1024), Qt::red); 0263 0264 QVERIFY(frameGeometryChangedSpy.wait()); 0265 QCOMPARE(frameGeometryChangedSpy.count(), 1); 0266 QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024)); 0267 QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50)); 0268 0269 // window is now set to maximised 0270 QCOMPARE(maximizeChangedSpy.count(), 1); 0271 QCOMPARE(window->maximizeMode(), MaximizeFull); 0272 QCOMPARE(window->tile(), nullptr); 0273 0274 // go back to quick tile none 0275 QFETCH(QuickTileMode, mode); 0276 window->setQuickTileMode(mode, true); 0277 QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None)); 0278 QCOMPARE(quickTileChangedSpy.count(), 2); 0279 // geometry not yet changed 0280 QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024)); 0281 QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50)); 0282 // we got requested a new geometry 0283 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0284 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3); 0285 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(100, 50)); 0286 0287 // render again 0288 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0289 Test::render(surface.get(), QSize(100, 50), Qt::yellow); 0290 0291 QVERIFY(frameGeometryChangedSpy.wait()); 0292 QCOMPARE(frameGeometryChangedSpy.count(), 2); 0293 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50)); 0294 QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50)); 0295 QCOMPARE(maximizeChangedSpy.count(), 2); 0296 } 0297 0298 void QuickTilingTest::testQuickTilingKeyboardMove_data() 0299 { 0300 QTest::addColumn<QPoint>("targetPos"); 0301 QTest::addColumn<QuickTileMode>("expectedMode"); 0302 0303 QTest::newRow("topRight") << QPoint(2559, 24) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Right); 0304 QTest::newRow("right") << QPoint(2559, 512) << QuickTileMode(QuickTileFlag::Right); 0305 QTest::newRow("bottomRight") << QPoint(2559, 1023) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Right); 0306 QTest::newRow("bottomLeft") << QPoint(0, 1023) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Left); 0307 QTest::newRow("Left") << QPoint(0, 512) << QuickTileMode(QuickTileFlag::Left); 0308 QTest::newRow("topLeft") << QPoint(0, 24) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Left); 0309 } 0310 0311 void QuickTilingTest::testQuickTilingKeyboardMove() 0312 { 0313 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0314 QVERIFY(surface != nullptr); 0315 0316 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0317 QVERIFY(shellSurface != nullptr); 0318 // let's render 0319 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0320 0321 QVERIFY(window); 0322 QCOMPARE(workspace()->activeWindow(), window); 0323 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50)); 0324 QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None)); 0325 QCOMPARE(window->maximizeMode(), MaximizeRestore); 0326 0327 QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged); 0328 0329 workspace()->performWindowOperation(window, Options::UnrestrictedMoveOp); 0330 QCOMPARE(window, workspace()->moveResizeWindow()); 0331 QCOMPARE(Cursors::self()->mouse()->pos(), QPoint(50, 25)); 0332 0333 QFETCH(QPoint, targetPos); 0334 quint32 timestamp = 1; 0335 Test::keyboardKeyPressed(KEY_LEFTCTRL, timestamp++); 0336 while (Cursors::self()->mouse()->pos().x() > targetPos.x()) { 0337 Test::keyboardKeyPressed(KEY_LEFT, timestamp++); 0338 Test::keyboardKeyReleased(KEY_LEFT, timestamp++); 0339 } 0340 while (Cursors::self()->mouse()->pos().x() < targetPos.x()) { 0341 Test::keyboardKeyPressed(KEY_RIGHT, timestamp++); 0342 Test::keyboardKeyReleased(KEY_RIGHT, timestamp++); 0343 } 0344 while (Cursors::self()->mouse()->pos().y() < targetPos.y()) { 0345 Test::keyboardKeyPressed(KEY_DOWN, timestamp++); 0346 Test::keyboardKeyReleased(KEY_DOWN, timestamp++); 0347 } 0348 while (Cursors::self()->mouse()->pos().y() > targetPos.y()) { 0349 Test::keyboardKeyPressed(KEY_UP, timestamp++); 0350 Test::keyboardKeyReleased(KEY_UP, timestamp++); 0351 } 0352 Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++); 0353 Test::keyboardKeyPressed(KEY_ENTER, timestamp++); 0354 Test::keyboardKeyReleased(KEY_ENTER, timestamp++); 0355 QCOMPARE(Cursors::self()->mouse()->pos(), targetPos); 0356 QVERIFY(!workspace()->moveResizeWindow()); 0357 0358 QCOMPARE(quickTileChangedSpy.count(), 1); 0359 QTEST(window->quickTileMode(), "expectedMode"); 0360 } 0361 0362 void QuickTilingTest::testQuickTilingPointerMove_data() 0363 { 0364 QTest::addColumn<QPoint>("pointerPos"); 0365 QTest::addColumn<QSize>("tileSize"); 0366 QTest::addColumn<QuickTileMode>("expectedMode"); 0367 0368 QTest::newRow("topRight") << QPoint(2559, 24) << QSize(640, 512) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Right); 0369 QTest::newRow("right") << QPoint(2559, 512) << QSize(640, 1024) << QuickTileMode(QuickTileFlag::Right); 0370 QTest::newRow("bottomRight") << QPoint(2559, 1023) << QSize(640, 512) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Right); 0371 QTest::newRow("bottomLeft") << QPoint(0, 1023) << QSize(640, 512) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Left); 0372 QTest::newRow("Left") << QPoint(0, 512) << QSize(640, 1024) << QuickTileMode(QuickTileFlag::Left); 0373 QTest::newRow("topLeft") << QPoint(0, 24) << QSize(640, 512) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Left); 0374 } 0375 0376 void QuickTilingTest::testQuickTilingPointerMove() 0377 { 0378 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0379 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0380 0381 // let's render 0382 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0383 QVERIFY(window); 0384 QCOMPARE(workspace()->activeWindow(), window); 0385 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50)); 0386 QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None)); 0387 QCOMPARE(window->maximizeMode(), MaximizeRestore); 0388 0389 // we have to receive a configure event when the window becomes active 0390 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested); 0391 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); 0392 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged); 0393 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0394 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1); 0395 0396 // verify that basic quick tile mode works as expected, i.e. the window is going to be 0397 // tiled if the user drags it to a screen edge or a corner 0398 QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged); 0399 workspace()->performWindowOperation(window, Options::UnrestrictedMoveOp); 0400 QCOMPARE(window, workspace()->moveResizeWindow()); 0401 QCOMPARE(Cursors::self()->mouse()->pos(), QPoint(50, 25)); 0402 0403 QFETCH(QPoint, pointerPos); 0404 QFETCH(QSize, tileSize); 0405 quint32 timestamp = 1; 0406 Test::pointerButtonPressed(BTN_LEFT, timestamp++); 0407 Test::pointerMotion(pointerPos, timestamp++); 0408 Test::pointerButtonReleased(BTN_LEFT, timestamp++); 0409 QCOMPARE(quickTileChangedSpy.count(), 1); 0410 QTEST(window->quickTileMode(), "expectedMode"); 0411 QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50)); 0412 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0413 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2); 0414 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), tileSize); 0415 0416 // attach a new image 0417 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0418 Test::render(surface.get(), tileSize, Qt::red); 0419 QVERIFY(frameGeometryChangedSpy.wait()); 0420 QCOMPARE(window->frameGeometry().size(), tileSize); 0421 0422 // verify that geometry restore is correct after user untiles the window, but changes 0423 // their mind and tiles the window again while still holding left button 0424 workspace()->performWindowOperation(window, Options::UnrestrictedMoveOp); 0425 QCOMPARE(window, workspace()->moveResizeWindow()); 0426 0427 Test::pointerButtonPressed(BTN_LEFT, timestamp++); // untile the window 0428 Test::pointerMotion(QPoint(1280, 1024) / 2, timestamp++); 0429 QCOMPARE(quickTileChangedSpy.count(), 2); 0430 QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None)); 0431 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0432 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3); 0433 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(100, 50)); 0434 0435 // attach a new image 0436 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0437 Test::render(surface.get(), QSize(100, 50), Qt::red); 0438 QVERIFY(frameGeometryChangedSpy.wait()); 0439 QCOMPARE(window->frameGeometry().size(), QSize(100, 50)); 0440 0441 Test::pointerMotion(pointerPos, timestamp++); // tile the window again 0442 Test::pointerButtonReleased(BTN_LEFT, timestamp++); 0443 QCOMPARE(quickTileChangedSpy.count(), 3); 0444 QTEST(window->quickTileMode(), "expectedMode"); 0445 QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50)); 0446 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0447 QCOMPARE(surfaceConfigureRequestedSpy.count(), 4); 0448 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), tileSize); 0449 } 0450 0451 void QuickTilingTest::testQuickTilingTouchMove_data() 0452 { 0453 QTest::addColumn<QPoint>("targetPos"); 0454 QTest::addColumn<QuickTileMode>("expectedMode"); 0455 0456 QTest::newRow("topRight") << QPoint(2559, 24) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Right); 0457 QTest::newRow("right") << QPoint(2559, 512) << QuickTileMode(QuickTileFlag::Right); 0458 QTest::newRow("bottomRight") << QPoint(2559, 1023) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Right); 0459 QTest::newRow("bottomLeft") << QPoint(0, 1023) << QuickTileMode(QuickTileFlag::Bottom | QuickTileFlag::Left); 0460 QTest::newRow("Left") << QPoint(0, 512) << QuickTileMode(QuickTileFlag::Left); 0461 QTest::newRow("topLeft") << QPoint(0, 24) << QuickTileMode(QuickTileFlag::Top | QuickTileFlag::Left); 0462 } 0463 0464 void QuickTilingTest::testQuickTilingTouchMove() 0465 { 0466 // test verifies that touch on decoration also allows quick tiling 0467 // see BUG: 390113 0468 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0469 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly)); 0470 std::unique_ptr<Test::XdgToplevelDecorationV1> deco(Test::createXdgToplevelDecorationV1(shellSurface.get())); 0471 0472 QSignalSpy decorationConfigureRequestedSpy(deco.get(), &Test::XdgToplevelDecorationV1::configureRequested); 0473 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); 0474 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested); 0475 0476 // wait for the initial configure event 0477 surface->commit(KWayland::Client::Surface::CommitFlag::None); 0478 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0479 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1); 0480 0481 // let's render 0482 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0483 auto window = Test::renderAndWaitForShown(surface.get(), QSize(1000, 50), Qt::blue); 0484 0485 QVERIFY(window); 0486 QVERIFY(window->isDecorated()); 0487 const auto decoration = window->decoration(); 0488 QCOMPARE(workspace()->activeWindow(), window); 0489 QCOMPARE(window->frameGeometry(), QRect(-decoration->borderLeft(), 0, 1000 + decoration->borderLeft() + decoration->borderRight(), 50 + decoration->borderTop() + decoration->borderBottom())); 0490 QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None)); 0491 QCOMPARE(window->maximizeMode(), MaximizeRestore); 0492 0493 // we have to receive a configure event when the window becomes active 0494 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0495 QTRY_COMPARE(surfaceConfigureRequestedSpy.count(), 2); 0496 0497 QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged); 0498 0499 // Note that interactive move will be started with a delay. 0500 quint32 timestamp = 1; 0501 QSignalSpy interactiveMoveResizeStartedSpy(window, &Window::interactiveMoveResizeStarted); 0502 Test::touchDown(0, QPointF(window->frameGeometry().center().x(), window->frameGeometry().y() + decoration->borderTop() / 2), timestamp++); 0503 QVERIFY(interactiveMoveResizeStartedSpy.wait()); 0504 QCOMPARE(window, workspace()->moveResizeWindow()); 0505 0506 QFETCH(QPoint, targetPos); 0507 Test::touchMotion(0, targetPos, timestamp++); 0508 Test::touchUp(0, timestamp++); 0509 QVERIFY(!workspace()->moveResizeWindow()); 0510 0511 // When there are no borders, there is no change to them when quick-tiling. 0512 // TODO: we should test both cases with fixed fake decoration for autotests. 0513 const bool hasBorders = Workspace::self()->decorationBridge()->settings()->borderSize() != KDecoration2::BorderSize::None; 0514 0515 QCOMPARE(quickTileChangedSpy.count(), 1); 0516 QTEST(window->quickTileMode(), "expectedMode"); 0517 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0518 QTRY_COMPARE(surfaceConfigureRequestedSpy.count(), hasBorders ? 4 : 3); 0519 QCOMPARE(false, toplevelConfigureRequestedSpy.last().first().toSize().isEmpty()); 0520 } 0521 0522 void QuickTilingTest::testX11QuickTiling_data() 0523 { 0524 QTest::addColumn<QuickTileMode>("mode"); 0525 QTest::addColumn<QRectF>("expectedGeometry"); 0526 QTest::addColumn<int>("screenId"); 0527 QTest::addColumn<QuickTileMode>("modeAfterToggle"); 0528 0529 #define FLAG(name) QuickTileMode(QuickTileFlag::name) 0530 0531 QTest::newRow("left") << FLAG(Left) << QRectF(0, 0, 640, 1024) << 0 << QuickTileMode(); 0532 QTest::newRow("top") << FLAG(Top) << QRectF(0, 0, 1280, 512) << 0 << QuickTileMode(); 0533 QTest::newRow("right") << FLAG(Right) << QRectF(640, 0, 640, 1024) << 1 << FLAG(Left); 0534 QTest::newRow("bottom") << FLAG(Bottom) << QRectF(0, 512, 1280, 512) << 0 << QuickTileMode(); 0535 0536 QTest::newRow("top left") << (FLAG(Left) | FLAG(Top)) << QRectF(0, 0, 640, 512) << 0 << QuickTileMode(); 0537 QTest::newRow("top right") << (FLAG(Right) | FLAG(Top)) << QRectF(640, 0, 640, 512) << 1 << (FLAG(Left) | FLAG(Top)); 0538 QTest::newRow("bottom left") << (FLAG(Left) | FLAG(Bottom)) << QRectF(0, 512, 640, 512) << 0 << QuickTileMode(); 0539 QTest::newRow("bottom right") << (FLAG(Right) | FLAG(Bottom)) << QRectF(640, 512, 640, 512) << 1 << (FLAG(Left) | FLAG(Bottom)); 0540 0541 QTest::newRow("maximize") << FLAG(Maximize) << QRectF(0, 0, 1280, 1024) << 0 << QuickTileMode(); 0542 0543 #undef FLAG 0544 } 0545 void QuickTilingTest::testX11QuickTiling() 0546 { 0547 Test::XcbConnectionPtr c = Test::createX11Connection(); 0548 QVERIFY(!xcb_connection_has_error(c.get())); 0549 const QRect windowGeometry(0, 0, 100, 200); 0550 xcb_window_t windowId = xcb_generate_id(c.get()); 0551 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(), 0552 windowGeometry.x(), 0553 windowGeometry.y(), 0554 windowGeometry.width(), 0555 windowGeometry.height(), 0556 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr); 0557 xcb_size_hints_t hints; 0558 memset(&hints, 0, sizeof(hints)); 0559 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y()); 0560 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height()); 0561 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints); 0562 xcb_map_window(c.get(), windowId); 0563 xcb_flush(c.get()); 0564 0565 // we should get a window for it 0566 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded); 0567 QVERIFY(windowCreatedSpy.wait()); 0568 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>(); 0569 QVERIFY(window); 0570 QCOMPARE(window->window(), windowId); 0571 0572 // now quick tile 0573 QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged); 0574 const QRectF origGeo = window->frameGeometry(); 0575 QFETCH(QuickTileMode, mode); 0576 window->setQuickTileMode(mode, true); 0577 QCOMPARE(window->quickTileMode(), mode); 0578 QTEST(window->frameGeometry(), "expectedGeometry"); 0579 QCOMPARE(window->geometryRestore(), origGeo); 0580 QEXPECT_FAIL("maximize", "For maximize we get two changed signals", Continue); 0581 QCOMPARE(quickTileChangedSpy.count(), 1); 0582 0583 // quick tile to same edge again should also act like send to screen 0584 // if screen is on the same edge 0585 const auto outputs = workspace()->outputs(); 0586 QCOMPARE(window->output(), outputs[0]); 0587 window->setQuickTileMode(mode, true); 0588 QFETCH(int, screenId); 0589 QCOMPARE(window->output(), outputs[screenId]); 0590 QTEST(window->quickTileMode(), "modeAfterToggle"); 0591 QCOMPARE(window->geometryRestore(), origGeo); 0592 0593 // and destroy the window again 0594 xcb_unmap_window(c.get(), windowId); 0595 xcb_destroy_window(c.get(), windowId); 0596 xcb_flush(c.get()); 0597 c.reset(); 0598 0599 QSignalSpy windowClosedSpy(window, &X11Window::closed); 0600 QVERIFY(windowClosedSpy.wait()); 0601 } 0602 0603 void QuickTilingTest::testX11QuickTilingAfterVertMaximize_data() 0604 { 0605 QTest::addColumn<QuickTileMode>("mode"); 0606 QTest::addColumn<QRectF>("expectedGeometry"); 0607 0608 #define FLAG(name) QuickTileMode(QuickTileFlag::name) 0609 0610 QTest::newRow("left") << FLAG(Left) << QRectF(0, 0, 640, 1024); 0611 QTest::newRow("top") << FLAG(Top) << QRectF(0, 0, 1280, 512); 0612 QTest::newRow("right") << FLAG(Right) << QRectF(640, 0, 640, 1024); 0613 QTest::newRow("bottom") << FLAG(Bottom) << QRectF(0, 512, 1280, 512); 0614 0615 QTest::newRow("top left") << (FLAG(Left) | FLAG(Top)) << QRectF(0, 0, 640, 512); 0616 QTest::newRow("top right") << (FLAG(Right) | FLAG(Top)) << QRectF(640, 0, 640, 512); 0617 QTest::newRow("bottom left") << (FLAG(Left) | FLAG(Bottom)) << QRectF(0, 512, 640, 512); 0618 QTest::newRow("bottom right") << (FLAG(Right) | FLAG(Bottom)) << QRectF(640, 512, 640, 512); 0619 0620 QTest::newRow("maximize") << FLAG(Maximize) << QRectF(0, 0, 1280, 1024); 0621 0622 #undef FLAG 0623 } 0624 0625 void QuickTilingTest::testX11QuickTilingAfterVertMaximize() 0626 { 0627 Test::XcbConnectionPtr c = Test::createX11Connection(); 0628 QVERIFY(!xcb_connection_has_error(c.get())); 0629 const QRect windowGeometry(0, 0, 100, 200); 0630 xcb_window_t windowId = xcb_generate_id(c.get()); 0631 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(), 0632 windowGeometry.x(), 0633 windowGeometry.y(), 0634 windowGeometry.width(), 0635 windowGeometry.height(), 0636 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr); 0637 xcb_size_hints_t hints; 0638 memset(&hints, 0, sizeof(hints)); 0639 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y()); 0640 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height()); 0641 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints); 0642 xcb_map_window(c.get(), windowId); 0643 xcb_flush(c.get()); 0644 0645 // we should get a window for it 0646 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded); 0647 QVERIFY(windowCreatedSpy.wait()); 0648 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>(); 0649 QVERIFY(window); 0650 QCOMPARE(window->window(), windowId); 0651 0652 const QRectF origGeo = window->frameGeometry(); 0653 QCOMPARE(window->maximizeMode(), MaximizeRestore); 0654 // vertically maximize the window 0655 window->maximize(window->maximizeMode() ^ MaximizeVertical); 0656 QCOMPARE(window->frameGeometry().width(), origGeo.width()); 0657 QCOMPARE(window->height(), window->output()->geometry().height()); 0658 QCOMPARE(window->geometryRestore(), origGeo); 0659 0660 // now quick tile 0661 QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged); 0662 QFETCH(QuickTileMode, mode); 0663 window->setQuickTileMode(mode, true); 0664 QCOMPARE(window->quickTileMode(), mode); 0665 QTEST(window->frameGeometry(), "expectedGeometry"); 0666 QEXPECT_FAIL("", "We get two changed events", Continue); 0667 QCOMPARE(quickTileChangedSpy.count(), 1); 0668 0669 // and destroy the window again 0670 xcb_unmap_window(c.get(), windowId); 0671 xcb_destroy_window(c.get(), windowId); 0672 xcb_flush(c.get()); 0673 c.reset(); 0674 0675 QSignalSpy windowClosedSpy(window, &X11Window::closed); 0676 QVERIFY(windowClosedSpy.wait()); 0677 } 0678 0679 void QuickTilingTest::testShortcut_data() 0680 { 0681 QTest::addColumn<QStringList>("shortcutList"); 0682 QTest::addColumn<QuickTileMode>("expectedMode"); 0683 QTest::addColumn<QRect>("expectedGeometry"); 0684 0685 #define FLAG(name) QuickTileMode(QuickTileFlag::name) 0686 QTest::newRow("top") << QStringList{QStringLiteral("Window Quick Tile Top")} << FLAG(Top) << QRect(0, 0, 1280, 512); 0687 QTest::newRow("bottom") << QStringList{QStringLiteral("Window Quick Tile Bottom")} << FLAG(Bottom) << QRect(0, 512, 1280, 512); 0688 QTest::newRow("top right") << QStringList{QStringLiteral("Window Quick Tile Top Right")} << (FLAG(Top) | FLAG(Right)) << QRect(640, 0, 640, 512); 0689 QTest::newRow("top left") << QStringList{QStringLiteral("Window Quick Tile Top Left")} << (FLAG(Top) | FLAG(Left)) << QRect(0, 0, 640, 512); 0690 QTest::newRow("bottom right") << QStringList{QStringLiteral("Window Quick Tile Bottom Right")} << (FLAG(Bottom) | FLAG(Right)) << QRect(640, 512, 640, 512); 0691 QTest::newRow("bottom left") << QStringList{QStringLiteral("Window Quick Tile Bottom Left")} << (FLAG(Bottom) | FLAG(Left)) << QRect(0, 512, 640, 512); 0692 QTest::newRow("left") << QStringList{QStringLiteral("Window Quick Tile Left")} << FLAG(Left) << QRect(0, 0, 640, 1024); 0693 QTest::newRow("right") << QStringList{QStringLiteral("Window Quick Tile Right")} << FLAG(Right) << QRect(640, 0, 640, 1024); 0694 0695 // Test combined actions for corner tiling 0696 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); 0697 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); 0698 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); 0699 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); 0700 #undef FLAG 0701 } 0702 0703 void QuickTilingTest::testShortcut() 0704 { 0705 #if !KWIN_BUILD_GLOBALSHORTCUTS 0706 QSKIP("Can't test shortcuts without shortcuts"); 0707 return; 0708 #endif 0709 0710 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0711 QVERIFY(surface != nullptr); 0712 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0713 QVERIFY(shellSurface != nullptr); 0714 0715 // Map the window. 0716 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0717 QVERIFY(window); 0718 QCOMPARE(workspace()->activeWindow(), window); 0719 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50)); 0720 QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None)); 0721 0722 // We have to receive a configure event when the window becomes active. 0723 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested); 0724 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); 0725 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0726 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1); 0727 0728 QFETCH(QStringList, shortcutList); 0729 QFETCH(QRect, expectedGeometry); 0730 0731 const int numberOfQuickTileActions = shortcutList.count(); 0732 0733 for (QString shortcut : shortcutList) { 0734 // invoke global shortcut through dbus 0735 auto msg = QDBusMessage::createMethodCall( 0736 QStringLiteral("org.kde.kglobalaccel"), 0737 QStringLiteral("/component/kwin"), 0738 QStringLiteral("org.kde.kglobalaccel.Component"), 0739 QStringLiteral("invokeShortcut")); 0740 msg.setArguments(QList<QVariant>{shortcut}); 0741 QDBusConnection::sessionBus().asyncCall(msg); 0742 } 0743 0744 QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged); 0745 QTRY_COMPARE(quickTileChangedSpy.count(), numberOfQuickTileActions); 0746 // at this point the geometry did not yet change 0747 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50)); 0748 // but quick tile mode already changed 0749 QTEST(window->quickTileMode(), "expectedMode"); 0750 0751 // but we got requested a new geometry 0752 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0753 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2); 0754 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), expectedGeometry.size()); 0755 0756 // attach a new image 0757 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged); 0758 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0759 Test::render(surface.get(), expectedGeometry.size(), Qt::red); 0760 0761 QVERIFY(frameGeometryChangedSpy.wait()); 0762 QEXPECT_FAIL("maximize", "Geometry changed called twice for maximize", Continue); 0763 QCOMPARE(frameGeometryChangedSpy.count(), 1); 0764 QCOMPARE(window->frameGeometry(), expectedGeometry); 0765 } 0766 0767 void QuickTilingTest::testScript_data() 0768 { 0769 QTest::addColumn<QString>("action"); 0770 QTest::addColumn<QuickTileMode>("expectedMode"); 0771 QTest::addColumn<QRect>("expectedGeometry"); 0772 0773 #define FLAG(name) QuickTileMode(QuickTileFlag::name) 0774 QTest::newRow("top") << QStringLiteral("Top") << FLAG(Top) << QRect(0, 0, 1280, 512); 0775 QTest::newRow("bottom") << QStringLiteral("Bottom") << FLAG(Bottom) << QRect(0, 512, 1280, 512); 0776 QTest::newRow("top right") << QStringLiteral("TopRight") << (FLAG(Top) | FLAG(Right)) << QRect(640, 0, 640, 512); 0777 QTest::newRow("top left") << QStringLiteral("TopLeft") << (FLAG(Top) | FLAG(Left)) << QRect(0, 0, 640, 512); 0778 QTest::newRow("bottom right") << QStringLiteral("BottomRight") << (FLAG(Bottom) | FLAG(Right)) << QRect(640, 512, 640, 512); 0779 QTest::newRow("bottom left") << QStringLiteral("BottomLeft") << (FLAG(Bottom) | FLAG(Left)) << QRect(0, 512, 640, 512); 0780 QTest::newRow("left") << QStringLiteral("Left") << FLAG(Left) << QRect(0, 0, 640, 1024); 0781 QTest::newRow("right") << QStringLiteral("Right") << FLAG(Right) << QRect(640, 0, 640, 1024); 0782 #undef FLAG 0783 } 0784 0785 void QuickTilingTest::testScript() 0786 { 0787 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0788 QVERIFY(surface != nullptr); 0789 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0790 QVERIFY(shellSurface != nullptr); 0791 0792 // Map the window. 0793 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0794 QVERIFY(window); 0795 QCOMPARE(workspace()->activeWindow(), window); 0796 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50)); 0797 QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None)); 0798 0799 // We have to receive a configure event upon the window becoming active. 0800 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested); 0801 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); 0802 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0803 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1); 0804 0805 QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged); 0806 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged); 0807 0808 QVERIFY(Scripting::self()); 0809 QTemporaryFile tmpFile; 0810 QVERIFY(tmpFile.open()); 0811 QTextStream out(&tmpFile); 0812 0813 QFETCH(QString, action); 0814 out << "workspace.slotWindowQuickTile" << action << "()"; 0815 out.flush(); 0816 0817 QFETCH(QuickTileMode, expectedMode); 0818 QFETCH(QRect, expectedGeometry); 0819 0820 const int id = Scripting::self()->loadScript(tmpFile.fileName()); 0821 QVERIFY(id != -1); 0822 QVERIFY(Scripting::self()->isScriptLoaded(tmpFile.fileName())); 0823 auto s = Scripting::self()->findScript(tmpFile.fileName()); 0824 QVERIFY(s); 0825 QSignalSpy runningChangedSpy(s, &AbstractScript::runningChanged); 0826 s->run(); 0827 0828 QVERIFY(quickTileChangedSpy.wait()); 0829 QCOMPARE(quickTileChangedSpy.count(), 1); 0830 0831 QCOMPARE(runningChangedSpy.count(), 1); 0832 QCOMPARE(runningChangedSpy.first().first().toBool(), true); 0833 0834 // at this point the geometry did not yet change 0835 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50)); 0836 // but quick tile mode already changed 0837 QCOMPARE(window->quickTileMode(), expectedMode); 0838 0839 // but we got requested a new geometry 0840 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0841 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2); 0842 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), expectedGeometry.size()); 0843 0844 // attach a new image 0845 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0846 Test::render(surface.get(), expectedGeometry.size(), Qt::red); 0847 0848 QVERIFY(frameGeometryChangedSpy.wait()); 0849 QEXPECT_FAIL("maximize", "Geometry changed called twice for maximize", Continue); 0850 QCOMPARE(frameGeometryChangedSpy.count(), 1); 0851 QCOMPARE(window->frameGeometry(), expectedGeometry); 0852 } 0853 0854 } 0855 0856 WAYLANDTEST_MAIN(KWin::QuickTilingTest) 0857 #include "quick_tiling_test.moc"