11#include "compositor.h"
23#include <KWayland/Client/compositor.h>
24#include <KWayland/Client/connection_thread.h>
25#include <KWayland/Client/keyboard.h>
26#include <KWayland/Client/pointer.h>
27#include <KWayland/Client/registry.h>
28#include <KWayland/Client/seat.h>
29#include <KWayland/Client/shm_pool.h>
30#include <KWayland/Client/surface.h>
31#include <KWayland/Client/touch.h>
34#include <KScreenLocker/KsldApp>
36#include <KGlobalAccel>
41#include <linux/input.h>
48static const QString s_socketName = QStringLiteral(
"wayland_test_kwin_lock_screen-0");
57 void testStackingOrder();
59 void testPointerButton();
60 void testPointerAxis();
62 void testScreenEdge();
64 void testEffectsKeyboard();
65 void testEffectsKeyboardAutorepeat();
66 void testMoveWindow();
67 void testPointerShortcut();
68 void testAxisShortcut_data();
69 void testAxisShortcut();
70 void testKeyboardShortcut();
75 std::pair<Window *, std::unique_ptr<KWayland::Client::Surface>> showWindow();
76 KWayland::Client::ConnectionThread *m_connection =
nullptr;
77 KWayland::Client::Compositor *m_compositor =
nullptr;
78 KWayland::Client::Seat *m_seat =
nullptr;
79 KWayland::Client::ShmPool *m_shm =
nullptr;
109 QVERIFY(!waylandServer()->isScreenLocked()); \
110 QSignalSpy lockStateChangedSpy(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged); \
111 ScreenLocker::KSldApp::self()->lock(ScreenLocker::EstablishLock::Immediate); \
112 QTRY_COMPARE(ScreenLocker::KSldApp::self()->lockState(), ScreenLocker::KSldApp::Locked); \
113 QVERIFY(waylandServer()->isScreenLocked()); \
118 QSignalSpy lockStateChangedSpy(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged); \
120 if (lockStateChangedSpy.count() != 1) { \
121 QVERIFY(lockStateChangedSpy.wait()); \
123 QCOMPARE(lockStateChangedSpy.count(), 1); \
124 QVERIFY(!waylandServer()->isScreenLocked()); \
127#define MOTION(target) Test::pointerMotion(target, timestamp++)
129#define PRESS Test::pointerButtonPressed(BTN_LEFT, timestamp++)
131#define RELEASE Test::pointerButtonReleased(BTN_LEFT, timestamp++)
133#define KEYPRESS(key) Test::keyboardKeyPressed(key, timestamp++)
135#define KEYRELEASE(key) Test::keyboardKeyReleased(key, timestamp++)
137void LockScreenTest::unlock()
139 using namespace ScreenLocker;
140 const auto children = KSldApp::self()->children();
141 for (
auto it = children.begin(); it != children.end(); ++it) {
142 if (qstrcmp((*it)->metaObject()->className(),
"LogindIntegration") != 0) {
145 QMetaObject::invokeMethod(*it,
"requestUnlock");
150std::pair<Window *, std::unique_ptr<KWayland::Client::Surface>> LockScreenTest::showWindow()
152#define VERIFY(statement) \
153 if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) \
154 return {nullptr, nullptr};
155#define COMPARE(actual, expected) \
156 if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__)) \
157 return {nullptr, nullptr};
172 return {window, std::move(surface)};
175void LockScreenTest::initTestCase()
177 qRegisterMetaType<KWin::Window *>();
178 qRegisterMetaType<KWin::ElectricBorder>(
"ElectricBorder");
183 QRect(0, 0, 1280, 1024),
184 QRect(1280, 0, 1280, 1024),
188 QVERIFY(applicationStartedSpy.wait());
191 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
192 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
193 setenv(
"QT_QPA_PLATFORM",
"wayland",
true);
196void LockScreenTest::init()
209void LockScreenTest::cleanup()
214void LockScreenTest::testStackingOrder()
221 QVERIFY(windowAddedSpy.wait());
223 Window *window = windowAddedSpy.first().first().value<
Window *>();
225 QVERIFY(window->isLockScreen());
231void LockScreenTest::testPointer()
233 std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer());
234 QVERIFY(pointer !=
nullptr);
235 QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered);
236 QSignalSpy leftSpy(pointer.get(), &KWayland::Client::Pointer::left);
238 auto [window, surface] = showWindow();
242 quint32 timestamp = 1;
243 MOTION(window->frameGeometry().center());
244 QVERIFY(enteredSpy.wait());
248 QVERIFY(leftSpy.wait());
249 QCOMPARE(leftSpy.count(), 1);
252 MOTION(window->frameGeometry().center());
253 MOTION(window->frameGeometry().bottomRight() + QPoint(100, 100));
254 MOTION(window->frameGeometry().bottomRight() + QPoint(100, 100));
255 QVERIFY(!leftSpy.wait(10));
256 QCOMPARE(leftSpy.count(), 1);
257 QCOMPARE(enteredSpy.count(), 1);
260 MOTION(window->frameGeometry().center());
264 QVERIFY(enteredSpy.wait());
265 QCOMPARE(enteredSpy.count(), 2);
267 MOTION(window->frameGeometry().center() + QPoint(100, 100));
268 QVERIFY(leftSpy.wait());
269 MOTION(window->frameGeometry().center());
270 QVERIFY(enteredSpy.wait());
271 QCOMPARE(enteredSpy.count(), 3);
274void LockScreenTest::testPointerButton()
276 std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer());
277 QVERIFY(pointer !=
nullptr);
278 QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered);
279 QSignalSpy buttonChangedSpy(pointer.get(), &KWayland::Client::Pointer::buttonStateChanged);
281 auto [window, surface] = showWindow();
285 quint32 timestamp = 1;
286 MOTION(window->frameGeometry().center());
287 QVERIFY(enteredSpy.wait());
290 QVERIFY(buttonChangedSpy.wait());
292 QVERIFY(buttonChangedSpy.wait());
298 QVERIFY(!buttonChangedSpy.wait(10));
300 QVERIFY(!buttonChangedSpy.wait(10));
303 QVERIFY(enteredSpy.wait());
304 QCOMPARE(enteredSpy.count(), 2);
308 QVERIFY(buttonChangedSpy.wait());
310 QVERIFY(buttonChangedSpy.wait());
313void LockScreenTest::testPointerAxis()
315 std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer());
316 QVERIFY(pointer !=
nullptr);
317 QSignalSpy axisChangedSpy(pointer.get(), &KWayland::Client::Pointer::axisChanged);
318 QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered);
320 auto [window, surface] = showWindow();
324 quint32 timestamp = 1;
325 MOTION(window->frameGeometry().center());
326 QVERIFY(enteredSpy.wait());
329 QVERIFY(axisChangedSpy.wait());
335 QVERIFY(!axisChangedSpy.wait(10));
337 QVERIFY(!axisChangedSpy.wait(10));
341 QVERIFY(enteredSpy.wait());
342 QCOMPARE(enteredSpy.count(), 2);
346 QVERIFY(axisChangedSpy.wait());
348 QVERIFY(axisChangedSpy.wait());
351void LockScreenTest::testKeyboard()
353 std::unique_ptr<KWayland::Client::Keyboard> keyboard(m_seat->createKeyboard());
354 QVERIFY(keyboard !=
nullptr);
355 QSignalSpy enteredSpy(keyboard.get(), &KWayland::Client::Keyboard::entered);
356 QSignalSpy leftSpy(keyboard.get(), &KWayland::Client::Keyboard::left);
357 QSignalSpy keyChangedSpy(keyboard.get(), &KWayland::Client::Keyboard::keyChanged);
359 auto [window, surface] = showWindow();
361 QVERIFY(enteredSpy.wait());
362 QTRY_COMPARE(enteredSpy.count(), 1);
364 quint32 timestamp = 1;
366 QVERIFY(keyChangedSpy.wait());
367 QCOMPARE(keyChangedSpy.count(), 1);
368 QCOMPARE(keyChangedSpy.at(0).at(0).value<quint32>(), quint32(KEY_A));
369 QCOMPARE(keyChangedSpy.at(0).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Pressed);
370 QCOMPARE(keyChangedSpy.at(0).at(2).value<quint32>(), quint32(1));
372 QVERIFY(keyChangedSpy.wait());
373 QCOMPARE(keyChangedSpy.count(), 2);
374 QCOMPARE(keyChangedSpy.at(1).at(0).value<quint32>(), quint32(KEY_A));
375 QCOMPARE(keyChangedSpy.at(1).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Released);
376 QCOMPARE(keyChangedSpy.at(1).at(2).value<quint32>(), quint32(2));
379 QVERIFY(leftSpy.wait());
382 QCOMPARE(leftSpy.count(), 1);
383 QCOMPARE(keyChangedSpy.count(), 2);
386 QVERIFY(enteredSpy.wait());
387 QCOMPARE(enteredSpy.count(), 2);
389 QVERIFY(keyChangedSpy.wait());
390 QCOMPARE(keyChangedSpy.count(), 3);
392 QVERIFY(keyChangedSpy.wait());
393 QCOMPARE(keyChangedSpy.count(), 4);
394 QCOMPARE(enteredSpy.count(), 2);
395 QCOMPARE(keyChangedSpy.at(2).at(0).value<quint32>(), quint32(KEY_C));
396 QCOMPARE(keyChangedSpy.at(3).at(0).value<quint32>(), quint32(KEY_C));
397 QCOMPARE(keyChangedSpy.at(2).at(2).value<quint32>(), quint32(5));
398 QCOMPARE(keyChangedSpy.at(3).at(2).value<quint32>(), quint32(6));
399 QCOMPARE(keyChangedSpy.at(2).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Pressed);
400 QCOMPARE(keyChangedSpy.at(3).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Released);
414void LockScreenTest::testScreenEdge()
417 QCOMPARE(screenEdgeSpy.count(), 0);
422 quint32 timestamp = 1;
424 QCOMPARE(screenEdgeSpy.count(), 1);
429 QCOMPARE(screenEdgeSpy.count(), 1);
435 QCOMPARE(screenEdgeSpy.count(), 2);
438void LockScreenTest::testEffects()
440 std::unique_ptr<HelperEffect> effect(
new HelperEffect);
444 quint32 timestamp = 1;
445 QCOMPARE(inputSpy.count(), 0);
447 QCOMPARE(inputSpy.count(), 1);
450 QCOMPARE(inputSpy.count(), 2);
452 QCOMPARE(inputSpy.count(), 3);
457 QCOMPARE(inputSpy.count(), 3);
460 QCOMPARE(inputSpy.count(), 3);
462 QCOMPARE(inputSpy.count(), 3);
467 QCOMPARE(inputSpy.count(), 4);
470 QCOMPARE(inputSpy.count(), 5);
472 QCOMPARE(inputSpy.count(), 6);
477void LockScreenTest::testEffectsKeyboard()
479 std::unique_ptr<HelperEffect> effect(
new HelperEffect);
483 quint32 timestamp = 1;
485 QCOMPARE(inputSpy.count(), 1);
486 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral(
"a"));
488 QCOMPARE(inputSpy.count(), 2);
489 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral(
"a"));
490 QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral(
"a"));
494 QCOMPARE(inputSpy.count(), 2);
496 QCOMPARE(inputSpy.count(), 2);
500 QCOMPARE(inputSpy.count(), 3);
501 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral(
"a"));
502 QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral(
"a"));
503 QCOMPARE(inputSpy.at(2).first().toString(), QStringLiteral(
"c"));
505 QCOMPARE(inputSpy.count(), 4);
506 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral(
"a"));
507 QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral(
"a"));
508 QCOMPARE(inputSpy.at(2).first().toString(), QStringLiteral(
"c"));
509 QCOMPARE(inputSpy.at(3).first().toString(), QStringLiteral(
"c"));
514void LockScreenTest::testEffectsKeyboardAutorepeat()
519 std::unique_ptr<HelperEffect> effect(
new HelperEffect);
526 quint32 timestamp = 1;
528 QCOMPARE(inputSpy.count(), 1);
529 QCOMPARE(inputSpy.first().first().toString(), QStringLiteral(
"a"));
530 QVERIFY(inputSpy.wait());
531 QVERIFY(inputSpy.count() > 1);
533 QVERIFY(inputSpy.wait());
534 QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral(
"a"));
539 QCOMPARE(inputSpy.count(), 1);
544 QVERIFY(!inputSpy.wait(10));
546 QVERIFY(!inputSpy.wait(10));
554void LockScreenTest::testMoveWindow()
556 auto [window, surface] = showWindow();
559 quint32 timestamp = 1;
562 QCOMPARE(
workspace()->moveResizeWindow(), window);
563 QVERIFY(window->isInteractiveMove());
566 QEXPECT_FAIL(
"",
"First event is ignored", Continue);
567 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
572 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
576 QCOMPARE(
workspace()->moveResizeWindow(), window);
577 QVERIFY(window->isInteractiveMove());
580 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
583 QCOMPARE(
workspace()->moveResizeWindow(), window);
584 QVERIFY(window->isInteractiveMove());
587 QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 2);
590 QVERIFY(!window->isInteractiveMove());
593void LockScreenTest::testPointerShortcut()
595#if !KWIN_BUILD_GLOBALSHORTCUTS
596 QSKIP(
"Can't test shortcuts without shortcuts");
600 std::unique_ptr<QAction> action(
new QAction(
nullptr));
601 QSignalSpy actionSpy(action.get(), &QAction::triggered);
605 quint32 timestamp = 1;
606#define PERFORM(expectedCount) \
608 Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++); \
610 QCoreApplication::instance()->processEvents(); \
611 QCOMPARE(actionSpy.count(), expectedCount); \
613 Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++); \
614 QCoreApplication::instance()->processEvents(); \
615 QCOMPARE(actionSpy.count(), expectedCount); \
630void LockScreenTest::testAxisShortcut_data()
632#if !KWIN_BUILD_GLOBALSHORTCUTS
633 QSKIP(
"Can't test shortcuts without shortcuts");
637 QTest::addColumn<Qt::Orientation>(
"direction");
638 QTest::addColumn<int>(
"sign");
640 QTest::newRow(
"up") << Qt::Vertical << 1;
641 QTest::newRow(
"down") << Qt::Vertical << -1;
642 QTest::newRow(
"left") << Qt::Horizontal << 1;
643 QTest::newRow(
"right") << Qt::Horizontal << -1;
646void LockScreenTest::testAxisShortcut()
648 std::unique_ptr<QAction> action(
new QAction(
nullptr));
649 QSignalSpy actionSpy(action.get(), &QAction::triggered);
650 QFETCH(Qt::Orientation, direction);
653 if (direction == Qt::Vertical) {
661 quint32 timestamp = 1;
662#define PERFORM(expectedCount) \
664 Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++); \
665 if (direction == Qt::Vertical) \
666 Test::pointerAxisVertical(sign * 5.0, timestamp++); \
668 Test::pointerAxisHorizontal(sign * 5.0, timestamp++); \
669 QCoreApplication::instance()->processEvents(); \
670 QCOMPARE(actionSpy.count(), expectedCount); \
671 Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++); \
672 QCoreApplication::instance()->processEvents(); \
673 QCOMPARE(actionSpy.count(), expectedCount); \
688void LockScreenTest::testKeyboardShortcut()
690#if !KWIN_BUILD_GLOBALSHORTCUTS
691 QSKIP(
"Can't test shortcuts without shortcuts");
695 std::unique_ptr<QAction> action(
new QAction(
nullptr));
696 QSignalSpy actionSpy(action.get(), &QAction::triggered);
697 action->setProperty(
"componentName", QStringLiteral(
"kwin"));
698 action->setObjectName(
"LockScreenTest::testKeyboardShortcut");
699 KGlobalAccel::self()->setDefaultShortcut(action.get(), QList<QKeySequence>{Qt::CTRL | Qt::META | Qt::ALT | Qt::Key_Space});
700 KGlobalAccel::self()->setShortcut(action.get(), QList<QKeySequence>{Qt::CTRL | Qt::META | Qt::ALT | Qt::Key_Space},
701 KGlobalAccel::NoAutoloading);
704 quint32 timestamp = 1;
709 QVERIFY(actionSpy.wait());
710 QCOMPARE(actionSpy.count(), 1);
712 QVERIFY(!actionSpy.wait(10));
713 QCOMPARE(actionSpy.count(), 1);
717 QVERIFY(!actionSpy.wait(10));
718 QCOMPARE(actionSpy.count(), 1);
720 QVERIFY(!actionSpy.wait(10));
721 QCOMPARE(actionSpy.count(), 1);
725 QVERIFY(actionSpy.wait());
726 QCOMPARE(actionSpy.count(), 2);
728 QVERIFY(!actionSpy.wait(10));
729 QCOMPARE(actionSpy.count(), 2);
735void LockScreenTest::testTouch()
737 auto touch = m_seat->createTouch(m_seat);
739 QVERIFY(touch->isValid());
740 auto [window, surface] = showWindow();
742 QSignalSpy sequenceStartedSpy(touch, &KWayland::Client::Touch::sequenceStarted);
743 QSignalSpy cancelSpy(touch, &KWayland::Client::Touch::sequenceCanceled);
744 QSignalSpy pointRemovedSpy(touch, &KWayland::Client::Touch::pointRemoved);
746 quint32 timestamp = 1;
748 QVERIFY(sequenceStartedSpy.wait());
749 QCOMPARE(sequenceStartedSpy.count(), 1);
752 QVERIFY(cancelSpy.wait());
755 QVERIFY(!pointRemovedSpy.wait(10));
762 QVERIFY(sequenceStartedSpy.wait());
763 QCOMPARE(sequenceStartedSpy.count(), 2);
765 QVERIFY(pointRemovedSpy.wait());
766 QCOMPARE(pointRemovedSpy.count(), 1);
772#include "lockscreen.moc"
Base class for all KWin effects.
void stopMouseInterception(Effect *effect)
void startMouseInterception(Effect *effect, Qt::CursorShape shape)
bool grabKeyboard(Effect *effect)
void grabbedKeyboardEvent(QKeyEvent *e) override
void keyEvent(const QString &)
void windowInputMouseEvent(QEvent *) override
void setRepeatInfo(qint32 charactersPerSecond, qint32 delay)
void approaching(ElectricBorder border, qreal factor, const QRect &geometry)
void reserve(ElectricBorder border, QObject *object, const char *callback)
KeyboardInterface * keyboard() const
bool callback(ElectricBorder border)
SeatInterface * seat() const
void interactiveMoveResizeStepped(const QRectF &geometry)
ScreenEdges * screenEdges() const
void windowAdded(KWin::Window *)
QList< Output * > outputs() const
void setActiveOutput(Output *output)
#define WAYLANDTEST_MAIN(TestObject)
#define PERFORM(expectedCount)
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 pointerAxisVertical(qreal delta, quint32 time, qint32 discreteDelta=0, InputRedirection::PointerAxisSource source=InputRedirection::PointerAxisSourceUnknown)
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 pointerAxisHorizontal(qreal delta, quint32 time, qint32 discreteDelta=0, InputRedirection::PointerAxisSource source=InputRedirection::PointerAxisSourceUnknown)
KWayland::Client::Seat * waylandSeat()
QList< KWayland::Client::Output * > outputs
std::unique_ptr< KWayland::Client::Surface > createSurface()
KWayland::Client::ShmPool * waylandShmPool()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
bool waitForWaylandPointer()
KWayland::Client::ConnectionThread * waylandConnection()
void touchUp(qint32 id, quint32 time)
PointerAxisDirection
The direction in which a pointer axis is moved.
WaylandServer * waylandServer()
InputRedirection * input()