File indexing completed on 2024-11-10 04:56:01
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 "compositor.h" 0012 #include "core/output.h" 0013 #include "core/renderbackend.h" 0014 #include "effect/effecthandler.h" 0015 #include "pointer_input.h" 0016 #include "screenedge.h" 0017 #include "wayland/keyboard.h" 0018 #include "wayland/seat.h" 0019 #include "wayland_server.h" 0020 #include "window.h" 0021 #include "workspace.h" 0022 0023 #include <KWayland/Client/compositor.h> 0024 #include <KWayland/Client/connection_thread.h> 0025 #include <KWayland/Client/keyboard.h> 0026 #include <KWayland/Client/pointer.h> 0027 #include <KWayland/Client/registry.h> 0028 #include <KWayland/Client/seat.h> 0029 #include <KWayland/Client/shm_pool.h> 0030 #include <KWayland/Client/surface.h> 0031 #include <KWayland/Client/touch.h> 0032 0033 // screenlocker 0034 #include <KScreenLocker/KsldApp> 0035 0036 #include <KGlobalAccel> 0037 0038 #include <QAction> 0039 #include <QSignalSpy> 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 Test::setOutputConfig({ 0183 QRect(0, 0, 1280, 1024), 0184 QRect(1280, 0, 1280, 1024), 0185 }); 0186 0187 kwinApp()->start(); 0188 QVERIFY(applicationStartedSpy.wait()); 0189 const auto outputs = workspace()->outputs(); 0190 QCOMPARE(outputs.count(), 2); 0191 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024)); 0192 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024)); 0193 setenv("QT_QPA_PLATFORM", "wayland", true); 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 input()->pointer()->warp(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(), OverlayLayer); 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 class TestObject : public QObject 0404 { 0405 Q_OBJECT 0406 0407 public Q_SLOTS: 0408 bool callback(ElectricBorder border) 0409 { 0410 return true; 0411 } 0412 }; 0413 0414 void LockScreenTest::testScreenEdge() 0415 { 0416 QSignalSpy screenEdgeSpy(workspace()->screenEdges(), &ScreenEdges::approaching); 0417 QCOMPARE(screenEdgeSpy.count(), 0); 0418 0419 TestObject callback; 0420 workspace()->screenEdges()->reserve(ElectricTopLeft, &callback, "callback"); 0421 0422 quint32 timestamp = 1; 0423 MOTION(QPoint(5, 5)); 0424 QCOMPARE(screenEdgeSpy.count(), 1); 0425 0426 LOCK; 0427 0428 MOTION(QPoint(4, 4)); 0429 QCOMPARE(screenEdgeSpy.count(), 1); 0430 0431 // and unlock 0432 UNLOCK; 0433 0434 MOTION(QPoint(5, 5)); 0435 QCOMPARE(screenEdgeSpy.count(), 2); 0436 } 0437 0438 void LockScreenTest::testEffects() 0439 { 0440 std::unique_ptr<HelperEffect> effect(new HelperEffect); 0441 QSignalSpy inputSpy(effect.get(), &HelperEffect::inputEvent); 0442 effects->startMouseInterception(effect.get(), Qt::ArrowCursor); 0443 0444 quint32 timestamp = 1; 0445 QCOMPARE(inputSpy.count(), 0); 0446 MOTION(QPoint(5, 5)); 0447 QCOMPARE(inputSpy.count(), 1); 0448 // simlate click 0449 PRESS; 0450 QCOMPARE(inputSpy.count(), 2); 0451 RELEASE; 0452 QCOMPARE(inputSpy.count(), 3); 0453 0454 LOCK; 0455 0456 MOTION(QPoint(6, 6)); 0457 QCOMPARE(inputSpy.count(), 3); 0458 // simlate click 0459 PRESS; 0460 QCOMPARE(inputSpy.count(), 3); 0461 RELEASE; 0462 QCOMPARE(inputSpy.count(), 3); 0463 0464 UNLOCK; 0465 0466 MOTION(QPoint(5, 5)); 0467 QCOMPARE(inputSpy.count(), 4); 0468 // simlate click 0469 PRESS; 0470 QCOMPARE(inputSpy.count(), 5); 0471 RELEASE; 0472 QCOMPARE(inputSpy.count(), 6); 0473 0474 effects->stopMouseInterception(effect.get()); 0475 } 0476 0477 void LockScreenTest::testEffectsKeyboard() 0478 { 0479 std::unique_ptr<HelperEffect> effect(new HelperEffect); 0480 QSignalSpy inputSpy(effect.get(), &HelperEffect::keyEvent); 0481 effects->grabKeyboard(effect.get()); 0482 0483 quint32 timestamp = 1; 0484 KEYPRESS(KEY_A); 0485 QCOMPARE(inputSpy.count(), 1); 0486 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a")); 0487 KEYRELEASE(KEY_A); 0488 QCOMPARE(inputSpy.count(), 2); 0489 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a")); 0490 QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral("a")); 0491 0492 LOCK; 0493 KEYPRESS(KEY_B); 0494 QCOMPARE(inputSpy.count(), 2); 0495 KEYRELEASE(KEY_B); 0496 QCOMPARE(inputSpy.count(), 2); 0497 0498 UNLOCK; 0499 KEYPRESS(KEY_C); 0500 QCOMPARE(inputSpy.count(), 3); 0501 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a")); 0502 QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral("a")); 0503 QCOMPARE(inputSpy.at(2).first().toString(), QStringLiteral("c")); 0504 KEYRELEASE(KEY_C); 0505 QCOMPARE(inputSpy.count(), 4); 0506 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a")); 0507 QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral("a")); 0508 QCOMPARE(inputSpy.at(2).first().toString(), QStringLiteral("c")); 0509 QCOMPARE(inputSpy.at(3).first().toString(), QStringLiteral("c")); 0510 0511 effects->ungrabKeyboard(); 0512 } 0513 0514 void LockScreenTest::testEffectsKeyboardAutorepeat() 0515 { 0516 // this test is just like testEffectsKeyboard, but tests auto repeat key events 0517 // while the key is pressed the Effect should get auto repeated events 0518 // but the lock screen should filter them out 0519 std::unique_ptr<HelperEffect> effect(new HelperEffect); 0520 QSignalSpy inputSpy(effect.get(), &HelperEffect::keyEvent); 0521 effects->grabKeyboard(effect.get()); 0522 0523 // we need to configure the key repeat first. It is only enabled on libinput 0524 waylandServer()->seat()->keyboard()->setRepeatInfo(25, 300); 0525 0526 quint32 timestamp = 1; 0527 KEYPRESS(KEY_A); 0528 QCOMPARE(inputSpy.count(), 1); 0529 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a")); 0530 QVERIFY(inputSpy.wait()); 0531 QVERIFY(inputSpy.count() > 1); 0532 // and still more events 0533 QVERIFY(inputSpy.wait()); 0534 QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral("a")); 0535 0536 // now release 0537 inputSpy.clear(); 0538 KEYRELEASE(KEY_A); 0539 QCOMPARE(inputSpy.count(), 1); 0540 0541 // while locked key repeat should not pass any events to the Effect 0542 LOCK; 0543 KEYPRESS(KEY_B); 0544 QVERIFY(!inputSpy.wait(10)); 0545 KEYRELEASE(KEY_B); 0546 QVERIFY(!inputSpy.wait(10)); 0547 0548 UNLOCK; 0549 // don't test again, that's covered by testEffectsKeyboard 0550 0551 effects->ungrabKeyboard(); 0552 } 0553 0554 void LockScreenTest::testMoveWindow() 0555 { 0556 auto [window, surface] = showWindow(); 0557 QVERIFY(window); 0558 QSignalSpy interactiveMoveResizeSteppedSpy(window, &Window::interactiveMoveResizeStepped); 0559 quint32 timestamp = 1; 0560 0561 workspace()->slotWindowMove(); 0562 QCOMPARE(workspace()->moveResizeWindow(), window); 0563 QVERIFY(window->isInteractiveMove()); 0564 Test::keyboardKeyPressed(KEY_RIGHT, timestamp++); 0565 Test::keyboardKeyReleased(KEY_RIGHT, timestamp++); 0566 QEXPECT_FAIL("", "First event is ignored", Continue); 0567 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1); 0568 0569 // TODO adjust once the expected fail is fixed 0570 Test::keyboardKeyPressed(KEY_RIGHT, timestamp++); 0571 Test::keyboardKeyReleased(KEY_RIGHT, timestamp++); 0572 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1); 0573 0574 // while locking our window should continue to be in move resize 0575 LOCK; 0576 QCOMPARE(workspace()->moveResizeWindow(), window); 0577 QVERIFY(window->isInteractiveMove()); 0578 Test::keyboardKeyPressed(KEY_RIGHT, timestamp++); 0579 Test::keyboardKeyReleased(KEY_RIGHT, timestamp++); 0580 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1); 0581 0582 UNLOCK; 0583 QCOMPARE(workspace()->moveResizeWindow(), window); 0584 QVERIFY(window->isInteractiveMove()); 0585 Test::keyboardKeyPressed(KEY_RIGHT, timestamp++); 0586 Test::keyboardKeyReleased(KEY_RIGHT, timestamp++); 0587 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 2); 0588 Test::keyboardKeyPressed(KEY_ESC, timestamp++); 0589 Test::keyboardKeyReleased(KEY_ESC, timestamp++); 0590 QVERIFY(!window->isInteractiveMove()); 0591 } 0592 0593 void LockScreenTest::testPointerShortcut() 0594 { 0595 #if !KWIN_BUILD_GLOBALSHORTCUTS 0596 QSKIP("Can't test shortcuts without shortcuts"); 0597 return; 0598 #endif 0599 0600 std::unique_ptr<QAction> action(new QAction(nullptr)); 0601 QSignalSpy actionSpy(action.get(), &QAction::triggered); 0602 input()->registerPointerShortcut(Qt::MetaModifier, Qt::LeftButton, action.get()); 0603 0604 // try to trigger the shortcut 0605 quint32 timestamp = 1; 0606 #define PERFORM(expectedCount) \ 0607 do { \ 0608 Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++); \ 0609 PRESS; \ 0610 QCoreApplication::instance()->processEvents(); \ 0611 QCOMPARE(actionSpy.count(), expectedCount); \ 0612 RELEASE; \ 0613 Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++); \ 0614 QCoreApplication::instance()->processEvents(); \ 0615 QCOMPARE(actionSpy.count(), expectedCount); \ 0616 } while (false) 0617 0618 PERFORM(1); 0619 0620 // now the same thing with a locked screen 0621 LOCK; 0622 PERFORM(1); 0623 0624 // and as unlocked 0625 UNLOCK; 0626 PERFORM(2); 0627 #undef PERFORM 0628 } 0629 0630 void LockScreenTest::testAxisShortcut_data() 0631 { 0632 #if !KWIN_BUILD_GLOBALSHORTCUTS 0633 QSKIP("Can't test shortcuts without shortcuts"); 0634 return; 0635 #endif 0636 0637 QTest::addColumn<Qt::Orientation>("direction"); 0638 QTest::addColumn<int>("sign"); 0639 0640 QTest::newRow("up") << Qt::Vertical << 1; 0641 QTest::newRow("down") << Qt::Vertical << -1; 0642 QTest::newRow("left") << Qt::Horizontal << 1; 0643 QTest::newRow("right") << Qt::Horizontal << -1; 0644 } 0645 0646 void LockScreenTest::testAxisShortcut() 0647 { 0648 std::unique_ptr<QAction> action(new QAction(nullptr)); 0649 QSignalSpy actionSpy(action.get(), &QAction::triggered); 0650 QFETCH(Qt::Orientation, direction); 0651 QFETCH(int, sign); 0652 PointerAxisDirection axisDirection = PointerAxisUp; 0653 if (direction == Qt::Vertical) { 0654 axisDirection = sign > 0 ? PointerAxisUp : PointerAxisDown; 0655 } else { 0656 axisDirection = sign > 0 ? PointerAxisLeft : PointerAxisRight; 0657 } 0658 input()->registerAxisShortcut(Qt::MetaModifier, axisDirection, action.get()); 0659 0660 // try to trigger the shortcut 0661 quint32 timestamp = 1; 0662 #define PERFORM(expectedCount) \ 0663 do { \ 0664 Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++); \ 0665 if (direction == Qt::Vertical) \ 0666 Test::pointerAxisVertical(sign * 5.0, timestamp++); \ 0667 else \ 0668 Test::pointerAxisHorizontal(sign * 5.0, timestamp++); \ 0669 QCoreApplication::instance()->processEvents(); \ 0670 QCOMPARE(actionSpy.count(), expectedCount); \ 0671 Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++); \ 0672 QCoreApplication::instance()->processEvents(); \ 0673 QCOMPARE(actionSpy.count(), expectedCount); \ 0674 } while (false) 0675 0676 PERFORM(1); 0677 0678 // now the same thing with a locked screen 0679 LOCK; 0680 PERFORM(1); 0681 0682 // and as unlocked 0683 UNLOCK; 0684 PERFORM(2); 0685 #undef PERFORM 0686 } 0687 0688 void LockScreenTest::testKeyboardShortcut() 0689 { 0690 #if !KWIN_BUILD_GLOBALSHORTCUTS 0691 QSKIP("Can't test shortcuts without shortcuts"); 0692 return; 0693 #endif 0694 0695 std::unique_ptr<QAction> action(new QAction(nullptr)); 0696 QSignalSpy actionSpy(action.get(), &QAction::triggered); 0697 action->setProperty("componentName", QStringLiteral("kwin")); 0698 action->setObjectName("LockScreenTest::testKeyboardShortcut"); 0699 KGlobalAccel::self()->setDefaultShortcut(action.get(), QList<QKeySequence>{Qt::CTRL | Qt::META | Qt::ALT | Qt::Key_Space}); 0700 KGlobalAccel::self()->setShortcut(action.get(), QList<QKeySequence>{Qt::CTRL | Qt::META | Qt::ALT | Qt::Key_Space}, 0701 KGlobalAccel::NoAutoloading); 0702 0703 // try to trigger the shortcut 0704 quint32 timestamp = 1; 0705 KEYPRESS(KEY_LEFTCTRL); 0706 KEYPRESS(KEY_LEFTMETA); 0707 KEYPRESS(KEY_LEFTALT); 0708 KEYPRESS(KEY_SPACE); 0709 QVERIFY(actionSpy.wait()); 0710 QCOMPARE(actionSpy.count(), 1); 0711 KEYRELEASE(KEY_SPACE); 0712 QVERIFY(!actionSpy.wait(10)); 0713 QCOMPARE(actionSpy.count(), 1); 0714 0715 LOCK; 0716 KEYPRESS(KEY_SPACE); 0717 QVERIFY(!actionSpy.wait(10)); 0718 QCOMPARE(actionSpy.count(), 1); 0719 KEYRELEASE(KEY_SPACE); 0720 QVERIFY(!actionSpy.wait(10)); 0721 QCOMPARE(actionSpy.count(), 1); 0722 0723 UNLOCK; 0724 KEYPRESS(KEY_SPACE); 0725 QVERIFY(actionSpy.wait()); 0726 QCOMPARE(actionSpy.count(), 2); 0727 KEYRELEASE(KEY_SPACE); 0728 QVERIFY(!actionSpy.wait(10)); 0729 QCOMPARE(actionSpy.count(), 2); 0730 KEYRELEASE(KEY_LEFTCTRL); 0731 KEYRELEASE(KEY_LEFTMETA); 0732 KEYRELEASE(KEY_LEFTALT); 0733 } 0734 0735 void LockScreenTest::testTouch() 0736 { 0737 auto touch = m_seat->createTouch(m_seat); 0738 QVERIFY(touch); 0739 QVERIFY(touch->isValid()); 0740 auto [window, surface] = showWindow(); 0741 QVERIFY(window); 0742 QSignalSpy sequenceStartedSpy(touch, &KWayland::Client::Touch::sequenceStarted); 0743 QSignalSpy cancelSpy(touch, &KWayland::Client::Touch::sequenceCanceled); 0744 QSignalSpy pointRemovedSpy(touch, &KWayland::Client::Touch::pointRemoved); 0745 0746 quint32 timestamp = 1; 0747 Test::touchDown(1, QPointF(25, 25), timestamp++); 0748 QVERIFY(sequenceStartedSpy.wait()); 0749 QCOMPARE(sequenceStartedSpy.count(), 1); 0750 0751 LOCK; 0752 QVERIFY(cancelSpy.wait()); 0753 0754 Test::touchUp(1, timestamp++); 0755 QVERIFY(!pointRemovedSpy.wait(10)); 0756 Test::touchDown(1, QPointF(25, 25), timestamp++); 0757 Test::touchMotion(1, QPointF(26, 26), timestamp++); 0758 Test::touchUp(1, timestamp++); 0759 0760 UNLOCK; 0761 Test::touchDown(1, QPointF(25, 25), timestamp++); 0762 QVERIFY(sequenceStartedSpy.wait()); 0763 QCOMPARE(sequenceStartedSpy.count(), 2); 0764 Test::touchUp(1, timestamp++); 0765 QVERIFY(pointRemovedSpy.wait()); 0766 QCOMPARE(pointRemovedSpy.count(), 1); 0767 } 0768 0769 } 0770 0771 WAYLANDTEST_MAIN(KWin::LockScreenTest) 0772 #include "lockscreen.moc"