File indexing completed on 2025-03-23 13:47:59
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2016 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 "composite.h" 0012 #include "core/output.h" 0013 #include "core/outputbackend.h" 0014 #include "core/renderbackend.h" 0015 #include "cursor.h" 0016 #include "screenedge.h" 0017 #include "wayland/keyboard_interface.h" 0018 #include "wayland/seat_interface.h" 0019 #include "wayland_server.h" 0020 #include "window.h" 0021 #include "workspace.h" 0022 #include <kwineffects.h> 0023 0024 #include <KWayland/Client/compositor.h> 0025 #include <KWayland/Client/connection_thread.h> 0026 #include <KWayland/Client/keyboard.h> 0027 #include <KWayland/Client/pointer.h> 0028 #include <KWayland/Client/registry.h> 0029 #include <KWayland/Client/seat.h> 0030 #include <KWayland/Client/shm_pool.h> 0031 #include <KWayland/Client/surface.h> 0032 #include <KWayland/Client/touch.h> 0033 0034 // screenlocker 0035 #include <KScreenLocker/KsldApp> 0036 0037 #include <KGlobalAccel> 0038 0039 #include <QAction> 0040 0041 #include <linux/input.h> 0042 0043 Q_DECLARE_METATYPE(Qt::Orientation) 0044 0045 namespace KWin 0046 { 0047 0048 static const QString s_socketName = QStringLiteral("wayland_test_kwin_lock_screen-0"); 0049 0050 class LockScreenTest : public QObject 0051 { 0052 Q_OBJECT 0053 private Q_SLOTS: 0054 void initTestCase(); 0055 void init(); 0056 void cleanup(); 0057 void testStackingOrder(); 0058 void testPointer(); 0059 void testPointerButton(); 0060 void testPointerAxis(); 0061 void testKeyboard(); 0062 void testScreenEdge(); 0063 void testEffects(); 0064 void testEffectsKeyboard(); 0065 void testEffectsKeyboardAutorepeat(); 0066 void testMoveWindow(); 0067 void testPointerShortcut(); 0068 void testAxisShortcut_data(); 0069 void testAxisShortcut(); 0070 void testKeyboardShortcut(); 0071 void testTouch(); 0072 0073 private: 0074 void unlock(); 0075 std::pair<Window *, std::unique_ptr<KWayland::Client::Surface>> showWindow(); 0076 KWayland::Client::ConnectionThread *m_connection = nullptr; 0077 KWayland::Client::Compositor *m_compositor = nullptr; 0078 KWayland::Client::Seat *m_seat = nullptr; 0079 KWayland::Client::ShmPool *m_shm = nullptr; 0080 }; 0081 0082 class HelperEffect : public Effect 0083 { 0084 Q_OBJECT 0085 public: 0086 HelperEffect() 0087 { 0088 } 0089 ~HelperEffect() override 0090 { 0091 } 0092 0093 void windowInputMouseEvent(QEvent *) override 0094 { 0095 Q_EMIT inputEvent(); 0096 } 0097 void grabbedKeyboardEvent(QKeyEvent *e) override 0098 { 0099 Q_EMIT keyEvent(e->text()); 0100 } 0101 0102 Q_SIGNALS: 0103 void inputEvent(); 0104 void keyEvent(const QString &); 0105 }; 0106 0107 #define LOCK \ 0108 do { \ 0109 QVERIFY(!waylandServer()->isScreenLocked()); \ 0110 QSignalSpy lockStateChangedSpy(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged); \ 0111 ScreenLocker::KSldApp::self()->lock(ScreenLocker::EstablishLock::Immediate); \ 0112 QTRY_COMPARE(ScreenLocker::KSldApp::self()->lockState(), ScreenLocker::KSldApp::Locked); \ 0113 QVERIFY(waylandServer()->isScreenLocked()); \ 0114 } while (false) 0115 0116 #define UNLOCK \ 0117 do { \ 0118 QSignalSpy lockStateChangedSpy(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged); \ 0119 unlock(); \ 0120 if (lockStateChangedSpy.count() != 1) { \ 0121 QVERIFY(lockStateChangedSpy.wait()); \ 0122 } \ 0123 QCOMPARE(lockStateChangedSpy.count(), 1); \ 0124 QVERIFY(!waylandServer()->isScreenLocked()); \ 0125 } while (false) 0126 0127 #define MOTION(target) Test::pointerMotion(target, timestamp++) 0128 0129 #define PRESS Test::pointerButtonPressed(BTN_LEFT, timestamp++) 0130 0131 #define RELEASE Test::pointerButtonReleased(BTN_LEFT, timestamp++) 0132 0133 #define KEYPRESS(key) Test::keyboardKeyPressed(key, timestamp++) 0134 0135 #define KEYRELEASE(key) Test::keyboardKeyReleased(key, timestamp++) 0136 0137 void LockScreenTest::unlock() 0138 { 0139 using namespace ScreenLocker; 0140 const auto children = KSldApp::self()->children(); 0141 for (auto it = children.begin(); it != children.end(); ++it) { 0142 if (qstrcmp((*it)->metaObject()->className(), "LogindIntegration") != 0) { 0143 continue; 0144 } 0145 QMetaObject::invokeMethod(*it, "requestUnlock"); 0146 break; 0147 } 0148 } 0149 0150 std::pair<Window *, std::unique_ptr<KWayland::Client::Surface>> LockScreenTest::showWindow() 0151 { 0152 #define VERIFY(statement) \ 0153 if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) \ 0154 return {nullptr, nullptr}; 0155 #define COMPARE(actual, expected) \ 0156 if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__)) \ 0157 return {nullptr, nullptr}; 0158 0159 std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface(); 0160 VERIFY(surface.get()); 0161 Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get()); 0162 VERIFY(shellSurface); 0163 // let's render 0164 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0165 0166 VERIFY(window); 0167 COMPARE(workspace()->activeWindow(), window); 0168 0169 #undef VERIFY 0170 #undef COMPARE 0171 0172 return {window, std::move(surface)}; 0173 } 0174 0175 void LockScreenTest::initTestCase() 0176 { 0177 qRegisterMetaType<KWin::Window *>(); 0178 qRegisterMetaType<KWin::ElectricBorder>("ElectricBorder"); 0179 0180 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); 0181 QVERIFY(waylandServer()->init(s_socketName)); 0182 QMetaObject::invokeMethod(kwinApp()->outputBackend(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(QVector<QRect>, QVector<QRect>() << QRect(0, 0, 1280, 1024) << QRect(1280, 0, 1280, 1024))); 0183 0184 qputenv("KWIN_COMPOSE", QByteArrayLiteral("O2")); 0185 kwinApp()->start(); 0186 QVERIFY(applicationStartedSpy.wait()); 0187 const auto outputs = workspace()->outputs(); 0188 QCOMPARE(outputs.count(), 2); 0189 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024)); 0190 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024)); 0191 setenv("QT_QPA_PLATFORM", "wayland", true); 0192 0193 QCOMPARE(Compositor::self()->backend()->compositingType(), KWin::OpenGLCompositing); 0194 } 0195 0196 void LockScreenTest::init() 0197 { 0198 QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat)); 0199 QVERIFY(Test::waitForWaylandPointer()); 0200 m_connection = Test::waylandConnection(); 0201 m_compositor = Test::waylandCompositor(); 0202 m_shm = Test::waylandShmPool(); 0203 m_seat = Test::waylandSeat(); 0204 0205 workspace()->setActiveOutput(QPoint(640, 512)); 0206 Cursors::self()->mouse()->setPos(QPoint(640, 512)); 0207 } 0208 0209 void LockScreenTest::cleanup() 0210 { 0211 Test::destroyWaylandConnection(); 0212 } 0213 0214 void LockScreenTest::testStackingOrder() 0215 { 0216 // This test verifies that the lockscreen greeter is placed above other windows. 0217 0218 QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded); 0219 0220 LOCK; 0221 QVERIFY(windowAddedSpy.wait()); 0222 0223 Window *window = windowAddedSpy.first().first().value<Window *>(); 0224 QVERIFY(window); 0225 QVERIFY(window->isLockScreen()); 0226 QCOMPARE(window->layer(), UnmanagedLayer); 0227 0228 UNLOCK; 0229 } 0230 0231 void LockScreenTest::testPointer() 0232 { 0233 std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer()); 0234 QVERIFY(pointer != nullptr); 0235 QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered); 0236 QSignalSpy leftSpy(pointer.get(), &KWayland::Client::Pointer::left); 0237 0238 auto [window, surface] = showWindow(); 0239 QVERIFY(window); 0240 0241 // first move cursor into the center of the window 0242 quint32 timestamp = 1; 0243 MOTION(window->frameGeometry().center()); 0244 QVERIFY(enteredSpy.wait()); 0245 0246 LOCK; 0247 0248 QVERIFY(leftSpy.wait()); 0249 QCOMPARE(leftSpy.count(), 1); 0250 0251 // simulate moving out in and out again 0252 MOTION(window->frameGeometry().center()); 0253 MOTION(window->frameGeometry().bottomRight() + QPoint(100, 100)); 0254 MOTION(window->frameGeometry().bottomRight() + QPoint(100, 100)); 0255 QVERIFY(!leftSpy.wait(10)); 0256 QCOMPARE(leftSpy.count(), 1); 0257 QCOMPARE(enteredSpy.count(), 1); 0258 0259 // go back on the window 0260 MOTION(window->frameGeometry().center()); 0261 // and unlock 0262 UNLOCK; 0263 0264 QVERIFY(enteredSpy.wait()); 0265 QCOMPARE(enteredSpy.count(), 2); 0266 // move on the window 0267 MOTION(window->frameGeometry().center() + QPoint(100, 100)); 0268 QVERIFY(leftSpy.wait()); 0269 MOTION(window->frameGeometry().center()); 0270 QVERIFY(enteredSpy.wait()); 0271 QCOMPARE(enteredSpy.count(), 3); 0272 } 0273 0274 void LockScreenTest::testPointerButton() 0275 { 0276 std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer()); 0277 QVERIFY(pointer != nullptr); 0278 QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered); 0279 QSignalSpy buttonChangedSpy(pointer.get(), &KWayland::Client::Pointer::buttonStateChanged); 0280 0281 auto [window, surface] = showWindow(); 0282 QVERIFY(window); 0283 0284 // first move cursor into the center of the window 0285 quint32 timestamp = 1; 0286 MOTION(window->frameGeometry().center()); 0287 QVERIFY(enteredSpy.wait()); 0288 // and simulate a click 0289 PRESS; 0290 QVERIFY(buttonChangedSpy.wait()); 0291 RELEASE; 0292 QVERIFY(buttonChangedSpy.wait()); 0293 0294 LOCK; 0295 0296 // and simulate a click 0297 PRESS; 0298 QVERIFY(!buttonChangedSpy.wait(10)); 0299 RELEASE; 0300 QVERIFY(!buttonChangedSpy.wait(10)); 0301 0302 UNLOCK; 0303 QVERIFY(enteredSpy.wait()); 0304 QCOMPARE(enteredSpy.count(), 2); 0305 0306 // and click again 0307 PRESS; 0308 QVERIFY(buttonChangedSpy.wait()); 0309 RELEASE; 0310 QVERIFY(buttonChangedSpy.wait()); 0311 } 0312 0313 void LockScreenTest::testPointerAxis() 0314 { 0315 std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer()); 0316 QVERIFY(pointer != nullptr); 0317 QSignalSpy axisChangedSpy(pointer.get(), &KWayland::Client::Pointer::axisChanged); 0318 QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered); 0319 0320 auto [window, surface] = showWindow(); 0321 QVERIFY(window); 0322 0323 // first move cursor into the center of the window 0324 quint32 timestamp = 1; 0325 MOTION(window->frameGeometry().center()); 0326 QVERIFY(enteredSpy.wait()); 0327 // and simulate axis 0328 Test::pointerAxisHorizontal(5.0, timestamp++); 0329 QVERIFY(axisChangedSpy.wait()); 0330 0331 LOCK; 0332 0333 // and simulate axis 0334 Test::pointerAxisHorizontal(5.0, timestamp++); 0335 QVERIFY(!axisChangedSpy.wait(10)); 0336 Test::pointerAxisVertical(5.0, timestamp++); 0337 QVERIFY(!axisChangedSpy.wait(10)); 0338 0339 // and unlock 0340 UNLOCK; 0341 QVERIFY(enteredSpy.wait()); 0342 QCOMPARE(enteredSpy.count(), 2); 0343 0344 // and move axis again 0345 Test::pointerAxisHorizontal(5.0, timestamp++); 0346 QVERIFY(axisChangedSpy.wait()); 0347 Test::pointerAxisVertical(5.0, timestamp++); 0348 QVERIFY(axisChangedSpy.wait()); 0349 } 0350 0351 void LockScreenTest::testKeyboard() 0352 { 0353 std::unique_ptr<KWayland::Client::Keyboard> keyboard(m_seat->createKeyboard()); 0354 QVERIFY(keyboard != nullptr); 0355 QSignalSpy enteredSpy(keyboard.get(), &KWayland::Client::Keyboard::entered); 0356 QSignalSpy leftSpy(keyboard.get(), &KWayland::Client::Keyboard::left); 0357 QSignalSpy keyChangedSpy(keyboard.get(), &KWayland::Client::Keyboard::keyChanged); 0358 0359 auto [window, surface] = showWindow(); 0360 QVERIFY(window); 0361 QVERIFY(enteredSpy.wait()); 0362 QTRY_COMPARE(enteredSpy.count(), 1); 0363 0364 quint32 timestamp = 1; 0365 KEYPRESS(KEY_A); 0366 QVERIFY(keyChangedSpy.wait()); 0367 QCOMPARE(keyChangedSpy.count(), 1); 0368 QCOMPARE(keyChangedSpy.at(0).at(0).value<quint32>(), quint32(KEY_A)); 0369 QCOMPARE(keyChangedSpy.at(0).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Pressed); 0370 QCOMPARE(keyChangedSpy.at(0).at(2).value<quint32>(), quint32(1)); 0371 KEYRELEASE(KEY_A); 0372 QVERIFY(keyChangedSpy.wait()); 0373 QCOMPARE(keyChangedSpy.count(), 2); 0374 QCOMPARE(keyChangedSpy.at(1).at(0).value<quint32>(), quint32(KEY_A)); 0375 QCOMPARE(keyChangedSpy.at(1).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Released); 0376 QCOMPARE(keyChangedSpy.at(1).at(2).value<quint32>(), quint32(2)); 0377 0378 LOCK; 0379 QVERIFY(leftSpy.wait()); 0380 KEYPRESS(KEY_B); 0381 KEYRELEASE(KEY_B); 0382 QCOMPARE(leftSpy.count(), 1); 0383 QCOMPARE(keyChangedSpy.count(), 2); 0384 0385 UNLOCK; 0386 QVERIFY(enteredSpy.wait()); 0387 QCOMPARE(enteredSpy.count(), 2); 0388 KEYPRESS(KEY_C); 0389 QVERIFY(keyChangedSpy.wait()); 0390 QCOMPARE(keyChangedSpy.count(), 3); 0391 KEYRELEASE(KEY_C); 0392 QVERIFY(keyChangedSpy.wait()); 0393 QCOMPARE(keyChangedSpy.count(), 4); 0394 QCOMPARE(enteredSpy.count(), 2); 0395 QCOMPARE(keyChangedSpy.at(2).at(0).value<quint32>(), quint32(KEY_C)); 0396 QCOMPARE(keyChangedSpy.at(3).at(0).value<quint32>(), quint32(KEY_C)); 0397 QCOMPARE(keyChangedSpy.at(2).at(2).value<quint32>(), quint32(5)); 0398 QCOMPARE(keyChangedSpy.at(3).at(2).value<quint32>(), quint32(6)); 0399 QCOMPARE(keyChangedSpy.at(2).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Pressed); 0400 QCOMPARE(keyChangedSpy.at(3).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Released); 0401 } 0402 0403 void LockScreenTest::testScreenEdge() 0404 { 0405 QSignalSpy screenEdgeSpy(workspace()->screenEdges(), &ScreenEdges::approaching); 0406 QCOMPARE(screenEdgeSpy.count(), 0); 0407 0408 quint32 timestamp = 1; 0409 MOTION(QPoint(5, 5)); 0410 QCOMPARE(screenEdgeSpy.count(), 1); 0411 0412 LOCK; 0413 0414 MOTION(QPoint(4, 4)); 0415 QCOMPARE(screenEdgeSpy.count(), 1); 0416 0417 // and unlock 0418 UNLOCK; 0419 0420 MOTION(QPoint(5, 5)); 0421 QCOMPARE(screenEdgeSpy.count(), 2); 0422 } 0423 0424 void LockScreenTest::testEffects() 0425 { 0426 std::unique_ptr<HelperEffect> effect(new HelperEffect); 0427 QSignalSpy inputSpy(effect.get(), &HelperEffect::inputEvent); 0428 effects->startMouseInterception(effect.get(), Qt::ArrowCursor); 0429 0430 quint32 timestamp = 1; 0431 QCOMPARE(inputSpy.count(), 0); 0432 MOTION(QPoint(5, 5)); 0433 QCOMPARE(inputSpy.count(), 1); 0434 // simlate click 0435 PRESS; 0436 QCOMPARE(inputSpy.count(), 2); 0437 RELEASE; 0438 QCOMPARE(inputSpy.count(), 3); 0439 0440 LOCK; 0441 0442 MOTION(QPoint(6, 6)); 0443 QCOMPARE(inputSpy.count(), 3); 0444 // simlate click 0445 PRESS; 0446 QCOMPARE(inputSpy.count(), 3); 0447 RELEASE; 0448 QCOMPARE(inputSpy.count(), 3); 0449 0450 UNLOCK; 0451 0452 MOTION(QPoint(5, 5)); 0453 QCOMPARE(inputSpy.count(), 4); 0454 // simlate click 0455 PRESS; 0456 QCOMPARE(inputSpy.count(), 5); 0457 RELEASE; 0458 QCOMPARE(inputSpy.count(), 6); 0459 0460 effects->stopMouseInterception(effect.get()); 0461 } 0462 0463 void LockScreenTest::testEffectsKeyboard() 0464 { 0465 std::unique_ptr<HelperEffect> effect(new HelperEffect); 0466 QSignalSpy inputSpy(effect.get(), &HelperEffect::keyEvent); 0467 effects->grabKeyboard(effect.get()); 0468 0469 quint32 timestamp = 1; 0470 KEYPRESS(KEY_A); 0471 QCOMPARE(inputSpy.count(), 1); 0472 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a")); 0473 KEYRELEASE(KEY_A); 0474 QCOMPARE(inputSpy.count(), 2); 0475 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a")); 0476 QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral("a")); 0477 0478 LOCK; 0479 KEYPRESS(KEY_B); 0480 QCOMPARE(inputSpy.count(), 2); 0481 KEYRELEASE(KEY_B); 0482 QCOMPARE(inputSpy.count(), 2); 0483 0484 UNLOCK; 0485 KEYPRESS(KEY_C); 0486 QCOMPARE(inputSpy.count(), 3); 0487 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a")); 0488 QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral("a")); 0489 QCOMPARE(inputSpy.at(2).first().toString(), QStringLiteral("c")); 0490 KEYRELEASE(KEY_C); 0491 QCOMPARE(inputSpy.count(), 4); 0492 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a")); 0493 QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral("a")); 0494 QCOMPARE(inputSpy.at(2).first().toString(), QStringLiteral("c")); 0495 QCOMPARE(inputSpy.at(3).first().toString(), QStringLiteral("c")); 0496 0497 effects->ungrabKeyboard(); 0498 } 0499 0500 void LockScreenTest::testEffectsKeyboardAutorepeat() 0501 { 0502 // this test is just like testEffectsKeyboard, but tests auto repeat key events 0503 // while the key is pressed the Effect should get auto repeated events 0504 // but the lock screen should filter them out 0505 std::unique_ptr<HelperEffect> effect(new HelperEffect); 0506 QSignalSpy inputSpy(effect.get(), &HelperEffect::keyEvent); 0507 effects->grabKeyboard(effect.get()); 0508 0509 // we need to configure the key repeat first. It is only enabled on libinput 0510 waylandServer()->seat()->keyboard()->setRepeatInfo(25, 300); 0511 0512 quint32 timestamp = 1; 0513 KEYPRESS(KEY_A); 0514 QCOMPARE(inputSpy.count(), 1); 0515 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a")); 0516 QVERIFY(inputSpy.wait()); 0517 QVERIFY(inputSpy.count() > 1); 0518 // and still more events 0519 QVERIFY(inputSpy.wait()); 0520 QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral("a")); 0521 0522 // now release 0523 inputSpy.clear(); 0524 KEYRELEASE(KEY_A); 0525 QCOMPARE(inputSpy.count(), 1); 0526 0527 // while locked key repeat should not pass any events to the Effect 0528 LOCK; 0529 KEYPRESS(KEY_B); 0530 QVERIFY(!inputSpy.wait(10)); 0531 KEYRELEASE(KEY_B); 0532 QVERIFY(!inputSpy.wait(10)); 0533 0534 UNLOCK; 0535 // don't test again, that's covered by testEffectsKeyboard 0536 0537 effects->ungrabKeyboard(); 0538 } 0539 0540 void LockScreenTest::testMoveWindow() 0541 { 0542 auto [window, surface] = showWindow(); 0543 QVERIFY(window); 0544 QSignalSpy clientStepUserMovedResizedSpy(window, &Window::clientStepUserMovedResized); 0545 quint32 timestamp = 1; 0546 0547 workspace()->slotWindowMove(); 0548 QCOMPARE(workspace()->moveResizeWindow(), window); 0549 QVERIFY(window->isInteractiveMove()); 0550 Test::keyboardKeyPressed(KEY_RIGHT, timestamp++); 0551 Test::keyboardKeyReleased(KEY_RIGHT, timestamp++); 0552 QEXPECT_FAIL("", "First event is ignored", Continue); 0553 QCOMPARE(clientStepUserMovedResizedSpy.count(), 1); 0554 0555 // TODO adjust once the expected fail is fixed 0556 Test::keyboardKeyPressed(KEY_RIGHT, timestamp++); 0557 Test::keyboardKeyReleased(KEY_RIGHT, timestamp++); 0558 QCOMPARE(clientStepUserMovedResizedSpy.count(), 1); 0559 0560 // while locking our window should continue to be in move resize 0561 LOCK; 0562 QCOMPARE(workspace()->moveResizeWindow(), window); 0563 QVERIFY(window->isInteractiveMove()); 0564 Test::keyboardKeyPressed(KEY_RIGHT, timestamp++); 0565 Test::keyboardKeyReleased(KEY_RIGHT, timestamp++); 0566 QCOMPARE(clientStepUserMovedResizedSpy.count(), 1); 0567 0568 UNLOCK; 0569 QCOMPARE(workspace()->moveResizeWindow(), window); 0570 QVERIFY(window->isInteractiveMove()); 0571 Test::keyboardKeyPressed(KEY_RIGHT, timestamp++); 0572 Test::keyboardKeyReleased(KEY_RIGHT, timestamp++); 0573 QCOMPARE(clientStepUserMovedResizedSpy.count(), 2); 0574 Test::keyboardKeyPressed(KEY_ESC, timestamp++); 0575 Test::keyboardKeyReleased(KEY_ESC, timestamp++); 0576 QVERIFY(!window->isInteractiveMove()); 0577 } 0578 0579 void LockScreenTest::testPointerShortcut() 0580 { 0581 std::unique_ptr<QAction> action(new QAction(nullptr)); 0582 QSignalSpy actionSpy(action.get(), &QAction::triggered); 0583 input()->registerPointerShortcut(Qt::MetaModifier, Qt::LeftButton, action.get()); 0584 0585 // try to trigger the shortcut 0586 quint32 timestamp = 1; 0587 #define PERFORM(expectedCount) \ 0588 do { \ 0589 Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++); \ 0590 PRESS; \ 0591 QCoreApplication::instance()->processEvents(); \ 0592 QCOMPARE(actionSpy.count(), expectedCount); \ 0593 RELEASE; \ 0594 Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++); \ 0595 QCoreApplication::instance()->processEvents(); \ 0596 QCOMPARE(actionSpy.count(), expectedCount); \ 0597 } while (false) 0598 0599 PERFORM(1); 0600 0601 // now the same thing with a locked screen 0602 LOCK; 0603 PERFORM(1); 0604 0605 // and as unlocked 0606 UNLOCK; 0607 PERFORM(2); 0608 #undef PERFORM 0609 } 0610 0611 void LockScreenTest::testAxisShortcut_data() 0612 { 0613 QTest::addColumn<Qt::Orientation>("direction"); 0614 QTest::addColumn<int>("sign"); 0615 0616 QTest::newRow("up") << Qt::Vertical << 1; 0617 QTest::newRow("down") << Qt::Vertical << -1; 0618 QTest::newRow("left") << Qt::Horizontal << 1; 0619 QTest::newRow("right") << Qt::Horizontal << -1; 0620 } 0621 0622 void LockScreenTest::testAxisShortcut() 0623 { 0624 std::unique_ptr<QAction> action(new QAction(nullptr)); 0625 QSignalSpy actionSpy(action.get(), &QAction::triggered); 0626 QFETCH(Qt::Orientation, direction); 0627 QFETCH(int, sign); 0628 PointerAxisDirection axisDirection = PointerAxisUp; 0629 if (direction == Qt::Vertical) { 0630 axisDirection = sign > 0 ? PointerAxisUp : PointerAxisDown; 0631 } else { 0632 axisDirection = sign > 0 ? PointerAxisLeft : PointerAxisRight; 0633 } 0634 input()->registerAxisShortcut(Qt::MetaModifier, axisDirection, action.get()); 0635 0636 // try to trigger the shortcut 0637 quint32 timestamp = 1; 0638 #define PERFORM(expectedCount) \ 0639 do { \ 0640 Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++); \ 0641 if (direction == Qt::Vertical) \ 0642 Test::pointerAxisVertical(sign * 5.0, timestamp++); \ 0643 else \ 0644 Test::pointerAxisHorizontal(sign * 5.0, timestamp++); \ 0645 QCoreApplication::instance()->processEvents(); \ 0646 QCOMPARE(actionSpy.count(), expectedCount); \ 0647 Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++); \ 0648 QCoreApplication::instance()->processEvents(); \ 0649 QCOMPARE(actionSpy.count(), expectedCount); \ 0650 } while (false) 0651 0652 PERFORM(1); 0653 0654 // now the same thing with a locked screen 0655 LOCK; 0656 PERFORM(1); 0657 0658 // and as unlocked 0659 UNLOCK; 0660 PERFORM(2); 0661 #undef PERFORM 0662 } 0663 0664 void LockScreenTest::testKeyboardShortcut() 0665 { 0666 std::unique_ptr<QAction> action(new QAction(nullptr)); 0667 QSignalSpy actionSpy(action.get(), &QAction::triggered); 0668 action->setProperty("componentName", QStringLiteral("kwin")); 0669 action->setObjectName("LockScreenTest::testKeyboardShortcut"); 0670 KGlobalAccel::self()->setDefaultShortcut(action.get(), QList<QKeySequence>{Qt::CTRL | Qt::META | Qt::ALT | Qt::Key_Space}); 0671 KGlobalAccel::self()->setShortcut(action.get(), QList<QKeySequence>{Qt::CTRL | Qt::META | Qt::ALT | Qt::Key_Space}, 0672 KGlobalAccel::NoAutoloading); 0673 0674 // try to trigger the shortcut 0675 quint32 timestamp = 1; 0676 KEYPRESS(KEY_LEFTCTRL); 0677 KEYPRESS(KEY_LEFTMETA); 0678 KEYPRESS(KEY_LEFTALT); 0679 KEYPRESS(KEY_SPACE); 0680 QVERIFY(actionSpy.wait()); 0681 QCOMPARE(actionSpy.count(), 1); 0682 KEYRELEASE(KEY_SPACE); 0683 QVERIFY(!actionSpy.wait(10)); 0684 QCOMPARE(actionSpy.count(), 1); 0685 0686 LOCK; 0687 KEYPRESS(KEY_SPACE); 0688 QVERIFY(!actionSpy.wait(10)); 0689 QCOMPARE(actionSpy.count(), 1); 0690 KEYRELEASE(KEY_SPACE); 0691 QVERIFY(!actionSpy.wait(10)); 0692 QCOMPARE(actionSpy.count(), 1); 0693 0694 UNLOCK; 0695 KEYPRESS(KEY_SPACE); 0696 QVERIFY(actionSpy.wait()); 0697 QCOMPARE(actionSpy.count(), 2); 0698 KEYRELEASE(KEY_SPACE); 0699 QVERIFY(!actionSpy.wait(10)); 0700 QCOMPARE(actionSpy.count(), 2); 0701 KEYRELEASE(KEY_LEFTCTRL); 0702 KEYRELEASE(KEY_LEFTMETA); 0703 KEYRELEASE(KEY_LEFTALT); 0704 } 0705 0706 void LockScreenTest::testTouch() 0707 { 0708 auto touch = m_seat->createTouch(m_seat); 0709 QVERIFY(touch); 0710 QVERIFY(touch->isValid()); 0711 auto [window, surface] = showWindow(); 0712 QVERIFY(window); 0713 QSignalSpy sequenceStartedSpy(touch, &KWayland::Client::Touch::sequenceStarted); 0714 QSignalSpy cancelSpy(touch, &KWayland::Client::Touch::sequenceCanceled); 0715 QSignalSpy pointRemovedSpy(touch, &KWayland::Client::Touch::pointRemoved); 0716 0717 quint32 timestamp = 1; 0718 Test::touchDown(1, QPointF(25, 25), timestamp++); 0719 QVERIFY(sequenceStartedSpy.wait()); 0720 QCOMPARE(sequenceStartedSpy.count(), 1); 0721 0722 LOCK; 0723 QVERIFY(cancelSpy.wait()); 0724 0725 Test::touchUp(1, timestamp++); 0726 QVERIFY(!pointRemovedSpy.wait(10)); 0727 Test::touchDown(1, QPointF(25, 25), timestamp++); 0728 Test::touchMotion(1, QPointF(26, 26), timestamp++); 0729 Test::touchUp(1, timestamp++); 0730 0731 UNLOCK; 0732 Test::touchDown(1, QPointF(25, 25), timestamp++); 0733 QVERIFY(sequenceStartedSpy.wait()); 0734 QCOMPARE(sequenceStartedSpy.count(), 2); 0735 Test::touchUp(1, timestamp++); 0736 QVERIFY(pointRemovedSpy.wait()); 0737 QCOMPARE(pointRemovedSpy.count(), 1); 0738 } 0739 0740 } 0741 0742 WAYLANDTEST_MAIN(KWin::LockScreenTest) 0743 #include "lockscreen.moc"