kwin/autotests/integration/lockscreen.cpp
Roman Gilg cd6b69a4d2 [platforms/virtual] Create output devices
Summary:
Create output devices in virtual backend. For that the setVirtualOutputs call
can only come after the Wayland server has been initiliazied such that the
display exists to create the output and output device interfaces. Tests have
been adjusted for that.

Test Plan:
```
98% tests passed, 3 tests failed out of 148

Total Test time (real) = 362.97 sec

The following tests FAILED:
         33 - kwin-testInternalWindow (Failed)
         39 - kwin-testPointerInput (Failed)
        101 - kwin-testMoveResize (Failed)
```
Failing of these tests looks unrelated to the change.

Reviewers: #kwin

Subscribers: kwin

Tags: #kwin

Maniphest Tasks: T11459

Differential Revision: https://phabricator.kde.org/D23477
2019-08-27 12:24:49 +02:00

770 lines
24 KiB
C++

/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2016 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "kwin_wayland_test.h"
#include "platform.h"
#include "abstract_client.h"
#include "composite.h"
#include "cursor.h"
#include "scene.h"
#include "screenedge.h"
#include "screens.h"
#include "wayland_server.h"
#include "workspace.h"
#include "shell_client.h"
#include <kwineffects.h>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/compositor.h>
#include <KWayland/Client/keyboard.h>
#include <KWayland/Client/registry.h>
#include <KWayland/Client/pointer.h>
#include <KWayland/Client/shell.h>
#include <KWayland/Client/seat.h>
#include <KWayland/Client/shm_pool.h>
#include <KWayland/Client/surface.h>
#include <KWayland/Client/touch.h>
#include <KWayland/Server/seat_interface.h>
//screenlocker
#include <KScreenLocker/KsldApp>
#include <KGlobalAccel>
#include <linux/input.h>
Q_DECLARE_METATYPE(Qt::Orientation)
namespace KWin
{
static const QString s_socketName = QStringLiteral("wayland_test_kwin_lock_screen-0");
class LockScreenTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void init();
void cleanup();
void testPointer();
void testPointerButton();
void testPointerAxis();
void testKeyboard();
void testScreenEdge();
void testEffects();
void testEffectsKeyboard();
void testEffectsKeyboardAutorepeat();
void testMoveWindow();
void testPointerShortcut();
void testAxisShortcut_data();
void testAxisShortcut();
void testKeyboardShortcut();
void testTouch();
private:
void unlock();
AbstractClient *showWindow();
KWayland::Client::ConnectionThread *m_connection = nullptr;
KWayland::Client::Compositor *m_compositor = nullptr;
KWayland::Client::Seat *m_seat = nullptr;
KWayland::Client::ShmPool *m_shm = nullptr;
KWayland::Client::Shell *m_shell = nullptr;
};
class HelperEffect : public Effect
{
Q_OBJECT
public:
HelperEffect() {}
~HelperEffect() override {}
void windowInputMouseEvent(QEvent*) override {
emit inputEvent();
}
void grabbedKeyboardEvent(QKeyEvent *e) override {
emit keyEvent(e->text());
}
Q_SIGNALS:
void inputEvent();
void keyEvent(const QString&);
};
#define LOCK \
QVERIFY(!waylandServer()->isScreenLocked()); \
QSignalSpy lockStateChangedSpy(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged); \
QVERIFY(lockStateChangedSpy.isValid()); \
ScreenLocker::KSldApp::self()->lock(ScreenLocker::EstablishLock::Immediate); \
QCOMPARE(lockStateChangedSpy.count(), 1); \
QVERIFY(waylandServer()->isScreenLocked());
#define UNLOCK \
int expectedLockCount = 1; \
if (ScreenLocker::KSldApp::self()->lockState() == ScreenLocker::KSldApp::Locked) { \
expectedLockCount = 2; \
} \
QCOMPARE(lockStateChangedSpy.count(), expectedLockCount); \
unlock(); \
if (lockStateChangedSpy.count() < expectedLockCount + 1) { \
QVERIFY(lockStateChangedSpy.wait()); \
} \
QCOMPARE(lockStateChangedSpy.count(), expectedLockCount + 1); \
QVERIFY(!waylandServer()->isScreenLocked());
#define MOTION(target) \
kwinApp()->platform()->pointerMotion(target, timestamp++)
#define PRESS \
kwinApp()->platform()->pointerButtonPressed(BTN_LEFT, timestamp++)
#define RELEASE \
kwinApp()->platform()->pointerButtonReleased(BTN_LEFT, timestamp++)
#define KEYPRESS( key ) \
kwinApp()->platform()->keyboardKeyPressed(key, timestamp++)
#define KEYRELEASE( key ) \
kwinApp()->platform()->keyboardKeyReleased(key, timestamp++)
void LockScreenTest::unlock()
{
using namespace ScreenLocker;
const auto children = KSldApp::self()->children();
for (auto it = children.begin(); it != children.end(); ++it) {
if (qstrcmp((*it)->metaObject()->className(), "LogindIntegration") != 0) {
continue;
}
QMetaObject::invokeMethod(*it, "requestUnlock");
break;
}
}
AbstractClient *LockScreenTest::showWindow()
{
using namespace KWayland::Client;
#define VERIFY(statement) \
if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__))\
return nullptr;
#define COMPARE(actual, expected) \
if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\
return nullptr;
Surface *surface = Test::createSurface(m_compositor);
VERIFY(surface);
ShellSurface *shellSurface = Test::createShellSurface(surface, surface);
VERIFY(shellSurface);
// let's render
auto c = Test::renderAndWaitForShown(surface, QSize(100, 50), Qt::blue);
VERIFY(c);
COMPARE(workspace()->activeClient(), c);
#undef VERIFY
#undef COMPARE
return c;
}
void LockScreenTest::initTestCase()
{
qRegisterMetaType<KWin::ShellClient*>();
qRegisterMetaType<KWin::AbstractClient*>();
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
QVERIFY(workspaceCreatedSpy.isValid());
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
QVERIFY(waylandServer()->init(s_socketName.toLocal8Bit()));
QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(int, 2));
qputenv("KWIN_COMPOSE", QByteArrayLiteral("O2"));
kwinApp()->start();
QVERIFY(workspaceCreatedSpy.wait());
QCOMPARE(screens()->count(), 2);
QCOMPARE(screens()->geometry(0), QRect(0, 0, 1280, 1024));
QCOMPARE(screens()->geometry(1), QRect(1280, 0, 1280, 1024));
setenv("QT_QPA_PLATFORM", "wayland", true);
waylandServer()->initWorkspace();
auto scene = KWin::Compositor::self()->scene();
QVERIFY(scene);
QCOMPARE(scene->compositingType(), KWin::OpenGL2Compositing);
}
void LockScreenTest::init()
{
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat));
QVERIFY(Test::waitForWaylandPointer());
m_connection = Test::waylandConnection();
m_compositor = Test::waylandCompositor();
m_shell = Test::waylandShell();
m_shm = Test::waylandShmPool();
m_seat = Test::waylandSeat();
screens()->setCurrent(0);
Cursor::setPos(QPoint(640, 512));
}
void LockScreenTest::cleanup()
{
Test::destroyWaylandConnection();
}
void LockScreenTest::testPointer()
{
using namespace KWayland::Client;
QScopedPointer<Pointer> pointer(m_seat->createPointer());
QVERIFY(!pointer.isNull());
QSignalSpy enteredSpy(pointer.data(), &Pointer::entered);
QVERIFY(enteredSpy.isValid());
QSignalSpy leftSpy(pointer.data(), &Pointer::left);
QVERIFY(leftSpy.isValid());
AbstractClient *c = showWindow();
QVERIFY(c);
// first move cursor into the center of the window
quint32 timestamp = 1;
MOTION(c->geometry().center());
QVERIFY(enteredSpy.wait());
LOCK
QVERIFY(leftSpy.wait());
QCOMPARE(leftSpy.count(), 1);
// simulate moving out in and out again
MOTION(c->geometry().center());
MOTION(c->geometry().bottomRight() + QPoint(100, 100));
MOTION(c->geometry().bottomRight() + QPoint(100, 100));
QVERIFY(!leftSpy.wait());
QCOMPARE(leftSpy.count(), 1);
QCOMPARE(enteredSpy.count(), 1);
// go back on the window
MOTION(c->geometry().center());
// and unlock
UNLOCK
QVERIFY(enteredSpy.wait());
QCOMPARE(enteredSpy.count(), 2);
// move on the window
MOTION(c->geometry().center() + QPoint(100, 100));
QVERIFY(leftSpy.wait());
MOTION(c->geometry().center());
QVERIFY(enteredSpy.wait());
QCOMPARE(enteredSpy.count(), 3);
}
void LockScreenTest::testPointerButton()
{
using namespace KWayland::Client;
QScopedPointer<Pointer> pointer(m_seat->createPointer());
QVERIFY(!pointer.isNull());
QSignalSpy enteredSpy(pointer.data(), &Pointer::entered);
QVERIFY(enteredSpy.isValid());
QSignalSpy buttonChangedSpy(pointer.data(), &Pointer::buttonStateChanged);
QVERIFY(buttonChangedSpy.isValid());
AbstractClient *c = showWindow();
QVERIFY(c);
// first move cursor into the center of the window
quint32 timestamp = 1;
MOTION(c->geometry().center());
QVERIFY(enteredSpy.wait());
// and simulate a click
PRESS;
QVERIFY(buttonChangedSpy.wait());
RELEASE;
QVERIFY(buttonChangedSpy.wait());
LOCK
// and simulate a click
PRESS;
QVERIFY(!buttonChangedSpy.wait());
RELEASE;
QVERIFY(!buttonChangedSpy.wait());
UNLOCK
QVERIFY(enteredSpy.wait());
QCOMPARE(enteredSpy.count(), 2);
// and click again
PRESS;
QVERIFY(buttonChangedSpy.wait());
RELEASE;
QVERIFY(buttonChangedSpy.wait());
}
void LockScreenTest::testPointerAxis()
{
using namespace KWayland::Client;
QScopedPointer<Pointer> pointer(m_seat->createPointer());
QVERIFY(!pointer.isNull());
QSignalSpy axisChangedSpy(pointer.data(), &Pointer::axisChanged);
QVERIFY(axisChangedSpy.isValid());
QSignalSpy enteredSpy(pointer.data(), &Pointer::entered);
QVERIFY(enteredSpy.isValid());
AbstractClient *c = showWindow();
QVERIFY(c);
// first move cursor into the center of the window
quint32 timestamp = 1;
MOTION(c->geometry().center());
QVERIFY(enteredSpy.wait());
// and simulate axis
kwinApp()->platform()->pointerAxisHorizontal(5.0, timestamp++);
QVERIFY(axisChangedSpy.wait());
LOCK
// and simulate axis
kwinApp()->platform()->pointerAxisHorizontal(5.0, timestamp++);
QVERIFY(!axisChangedSpy.wait(100));
kwinApp()->platform()->pointerAxisVertical(5.0, timestamp++);
QVERIFY(!axisChangedSpy.wait(100));
// and unlock
UNLOCK
QVERIFY(enteredSpy.wait());
QCOMPARE(enteredSpy.count(), 2);
// and move axis again
kwinApp()->platform()->pointerAxisHorizontal(5.0, timestamp++);
QVERIFY(axisChangedSpy.wait());
kwinApp()->platform()->pointerAxisVertical(5.0, timestamp++);
QVERIFY(axisChangedSpy.wait());
}
void LockScreenTest::testKeyboard()
{
using namespace KWayland::Client;
QScopedPointer<Keyboard> keyboard(m_seat->createKeyboard());
QVERIFY(!keyboard.isNull());
QSignalSpy enteredSpy(keyboard.data(), &Keyboard::entered);
QVERIFY(enteredSpy.isValid());
QSignalSpy leftSpy(keyboard.data(), &Keyboard::left);
QVERIFY(leftSpy.isValid());
QSignalSpy keyChangedSpy(keyboard.data(), &Keyboard::keyChanged);
QVERIFY(keyChangedSpy.isValid());
AbstractClient *c = showWindow();
QVERIFY(c);
QVERIFY(enteredSpy.wait());
QTRY_COMPARE(enteredSpy.count(), 1);
quint32 timestamp = 1;
KEYPRESS(KEY_A);
QVERIFY(keyChangedSpy.wait());
QCOMPARE(keyChangedSpy.count(), 1);
QCOMPARE(keyChangedSpy.at(0).at(0).value<quint32>(), quint32(KEY_A));
QCOMPARE(keyChangedSpy.at(0).at(1).value<Keyboard::KeyState>(), Keyboard::KeyState::Pressed);
QCOMPARE(keyChangedSpy.at(0).at(2).value<quint32>(), quint32(1));
KEYRELEASE(KEY_A);
QVERIFY(keyChangedSpy.wait());
QCOMPARE(keyChangedSpy.count(), 2);
QCOMPARE(keyChangedSpy.at(1).at(0).value<quint32>(), quint32(KEY_A));
QCOMPARE(keyChangedSpy.at(1).at(1).value<Keyboard::KeyState>(), Keyboard::KeyState::Released);
QCOMPARE(keyChangedSpy.at(1).at(2).value<quint32>(), quint32(2));
LOCK
QVERIFY(leftSpy.wait());
KEYPRESS(KEY_B);
KEYRELEASE(KEY_B);
QCOMPARE(leftSpy.count(), 1);
QCOMPARE(keyChangedSpy.count(), 2);
UNLOCK
QVERIFY(enteredSpy.wait());
QCOMPARE(enteredSpy.count(), 2);
KEYPRESS(KEY_C);
QVERIFY(keyChangedSpy.wait());
QCOMPARE(keyChangedSpy.count(), 3);
KEYRELEASE(KEY_C);
QVERIFY(keyChangedSpy.wait());
QCOMPARE(keyChangedSpy.count(), 4);
QCOMPARE(enteredSpy.count(), 2);
QCOMPARE(keyChangedSpy.at(2).at(0).value<quint32>(), quint32(KEY_C));
QCOMPARE(keyChangedSpy.at(3).at(0).value<quint32>(), quint32(KEY_C));
QCOMPARE(keyChangedSpy.at(2).at(2).value<quint32>(), quint32(5));
QCOMPARE(keyChangedSpy.at(3).at(2).value<quint32>(), quint32(6));
QCOMPARE(keyChangedSpy.at(2).at(1).value<Keyboard::KeyState>(), Keyboard::KeyState::Pressed);
QCOMPARE(keyChangedSpy.at(3).at(1).value<Keyboard::KeyState>(), Keyboard::KeyState::Released);
}
void LockScreenTest::testScreenEdge()
{
QSignalSpy screenEdgeSpy(ScreenEdges::self(), &ScreenEdges::approaching);
QVERIFY(screenEdgeSpy.isValid());
QCOMPARE(screenEdgeSpy.count(), 0);
quint32 timestamp = 1;
MOTION(QPoint(5, 5));
QCOMPARE(screenEdgeSpy.count(), 1);
LOCK
MOTION(QPoint(4, 4));
QCOMPARE(screenEdgeSpy.count(), 1);
// and unlock
UNLOCK
MOTION(QPoint(5, 5));
QCOMPARE(screenEdgeSpy.count(), 2);
}
void LockScreenTest::testEffects()
{
QScopedPointer<HelperEffect> effect(new HelperEffect);
QSignalSpy inputSpy(effect.data(), &HelperEffect::inputEvent);
QVERIFY(inputSpy.isValid());
effects->startMouseInterception(effect.data(), Qt::ArrowCursor);
quint32 timestamp = 1;
QCOMPARE(inputSpy.count(), 0);
MOTION(QPoint(5, 5));
QCOMPARE(inputSpy.count(), 1);
// simlate click
PRESS;
QCOMPARE(inputSpy.count(), 2);
RELEASE;
QCOMPARE(inputSpy.count(), 3);
LOCK
MOTION(QPoint(6, 6));
QCOMPARE(inputSpy.count(), 3);
// simlate click
PRESS;
QCOMPARE(inputSpy.count(), 3);
RELEASE;
QCOMPARE(inputSpy.count(), 3);
UNLOCK
MOTION(QPoint(5, 5));
QCOMPARE(inputSpy.count(), 4);
// simlate click
PRESS;
QCOMPARE(inputSpy.count(), 5);
RELEASE;
QCOMPARE(inputSpy.count(), 6);
effects->stopMouseInterception(effect.data());
}
void LockScreenTest::testEffectsKeyboard()
{
QScopedPointer<HelperEffect> effect(new HelperEffect);
QSignalSpy inputSpy(effect.data(), &HelperEffect::keyEvent);
QVERIFY(inputSpy.isValid());
effects->grabKeyboard(effect.data());
quint32 timestamp = 1;
KEYPRESS(KEY_A);
QCOMPARE(inputSpy.count(), 1);
QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a"));
KEYRELEASE(KEY_A);
QCOMPARE(inputSpy.count(), 2);
QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a"));
QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral("a"));
LOCK
KEYPRESS(KEY_B);
QCOMPARE(inputSpy.count(), 2);
KEYRELEASE(KEY_B);
QCOMPARE(inputSpy.count(), 2);
UNLOCK
KEYPRESS(KEY_C);
QCOMPARE(inputSpy.count(), 3);
QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a"));
QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral("a"));
QCOMPARE(inputSpy.at(2).first().toString(), QStringLiteral("c"));
KEYRELEASE(KEY_C);
QCOMPARE(inputSpy.count(), 4);
QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a"));
QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral("a"));
QCOMPARE(inputSpy.at(2).first().toString(), QStringLiteral("c"));
QCOMPARE(inputSpy.at(3).first().toString(), QStringLiteral("c"));
effects->ungrabKeyboard();
}
void LockScreenTest::testEffectsKeyboardAutorepeat()
{
// this test is just like testEffectsKeyboard, but tests auto repeat key events
// while the key is pressed the Effect should get auto repeated events
// but the lock screen should filter them out
QScopedPointer<HelperEffect> effect(new HelperEffect);
QSignalSpy inputSpy(effect.data(), &HelperEffect::keyEvent);
QVERIFY(inputSpy.isValid());
effects->grabKeyboard(effect.data());
// we need to configure the key repeat first. It is only enabled on libinput
waylandServer()->seat()->setKeyRepeatInfo(25, 300);
quint32 timestamp = 1;
KEYPRESS(KEY_A);
QCOMPARE(inputSpy.count(), 1);
QCOMPARE(inputSpy.first().first().toString(), QStringLiteral("a"));
QVERIFY(inputSpy.wait());
QVERIFY(inputSpy.count() > 1);
// and still more events
QVERIFY(inputSpy.wait());
QCOMPARE(inputSpy.at(1).first().toString(), QStringLiteral("a"));
// now release
inputSpy.clear();
KEYRELEASE(KEY_A);
QCOMPARE(inputSpy.count(), 1);
// while locked key repeat should not pass any events to the Effect
LOCK
KEYPRESS(KEY_B);
QVERIFY(!inputSpy.wait(200));
KEYRELEASE(KEY_B);
QVERIFY(!inputSpy.wait(200));
UNLOCK
// don't test again, that's covered by testEffectsKeyboard
effects->ungrabKeyboard();
}
void LockScreenTest::testMoveWindow()
{
using namespace KWayland::Client;
AbstractClient *c = showWindow();
QVERIFY(c);
QSignalSpy clientStepUserMovedResizedSpy(c, &AbstractClient::clientStepUserMovedResized);
QVERIFY(clientStepUserMovedResizedSpy.isValid());
quint32 timestamp = 1;
workspace()->slotWindowMove();
QCOMPARE(workspace()->moveResizeClient(), c);
QVERIFY(c->isMove());
kwinApp()->platform()->keyboardKeyPressed(KEY_RIGHT, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(KEY_RIGHT, timestamp++);
QEXPECT_FAIL("", "First event is ignored", Continue);
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
// TODO adjust once the expected fail is fixed
kwinApp()->platform()->keyboardKeyPressed(KEY_RIGHT, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(KEY_RIGHT, timestamp++);
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
// while locking our window should continue to be in move resize
LOCK
QCOMPARE(workspace()->moveResizeClient(), c);
QVERIFY(c->isMove());
kwinApp()->platform()->keyboardKeyPressed(KEY_RIGHT, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(KEY_RIGHT, timestamp++);
QCOMPARE(clientStepUserMovedResizedSpy.count(), 1);
UNLOCK
QCOMPARE(workspace()->moveResizeClient(), c);
QVERIFY(c->isMove());
kwinApp()->platform()->keyboardKeyPressed(KEY_RIGHT, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(KEY_RIGHT, timestamp++);
QCOMPARE(clientStepUserMovedResizedSpy.count(), 2);
kwinApp()->platform()->keyboardKeyPressed(KEY_ESC, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(KEY_ESC, timestamp++);
QVERIFY(!c->isMove());
}
void LockScreenTest::testPointerShortcut()
{
using namespace KWayland::Client;
QScopedPointer<QAction> action(new QAction(nullptr));
QSignalSpy actionSpy(action.data(), &QAction::triggered);
QVERIFY(actionSpy.isValid());
input()->registerPointerShortcut(Qt::MetaModifier, Qt::LeftButton, action.data());
// try to trigger the shortcut
quint32 timestamp = 1;
#define PERFORM(expectedCount) \
kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTMETA, timestamp++); \
PRESS; \
QCoreApplication::instance()->processEvents(); \
QCOMPARE(actionSpy.count(), expectedCount); \
RELEASE; \
kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTMETA, timestamp++); \
QCoreApplication::instance()->processEvents(); \
QCOMPARE(actionSpy.count(), expectedCount);
PERFORM(1)
// now the same thing with a locked screen
LOCK
PERFORM(1)
// and as unlocked
UNLOCK
PERFORM(2)
#undef PERFORM
}
void LockScreenTest::testAxisShortcut_data()
{
QTest::addColumn<Qt::Orientation>("direction");
QTest::addColumn<int>("sign");
QTest::newRow("up") << Qt::Vertical << 1;
QTest::newRow("down") << Qt::Vertical << -1;
QTest::newRow("left") << Qt::Horizontal << 1;
QTest::newRow("right") << Qt::Horizontal << -1;
}
void LockScreenTest::testAxisShortcut()
{
using namespace KWayland::Client;
QScopedPointer<QAction> action(new QAction(nullptr));
QSignalSpy actionSpy(action.data(), &QAction::triggered);
QVERIFY(actionSpy.isValid());
QFETCH(Qt::Orientation, direction);
QFETCH(int, sign);
PointerAxisDirection axisDirection = PointerAxisUp;
if (direction == Qt::Vertical) {
axisDirection = sign > 0 ? PointerAxisUp : PointerAxisDown;
} else {
axisDirection = sign > 0 ? PointerAxisLeft : PointerAxisRight;
}
input()->registerAxisShortcut(Qt::MetaModifier, axisDirection, action.data());
// try to trigger the shortcut
quint32 timestamp = 1;
#define PERFORM(expectedCount) \
kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTMETA, timestamp++); \
if (direction == Qt::Vertical) \
kwinApp()->platform()->pointerAxisVertical(sign * 5.0, timestamp++); \
else \
kwinApp()->platform()->pointerAxisHorizontal(sign * 5.0, timestamp++); \
QCoreApplication::instance()->processEvents(); \
QCOMPARE(actionSpy.count(), expectedCount); \
kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTMETA, timestamp++); \
QCoreApplication::instance()->processEvents(); \
QCOMPARE(actionSpy.count(), expectedCount);
PERFORM(1)
// now the same thing with a locked screen
LOCK
PERFORM(1)
// and as unlocked
UNLOCK
PERFORM(2)
#undef PERFORM
}
void LockScreenTest::testKeyboardShortcut()
{
using namespace KWayland::Client;
QScopedPointer<QAction> action(new QAction(nullptr));
QSignalSpy actionSpy(action.data(), &QAction::triggered);
QVERIFY(actionSpy.isValid());
action->setProperty("componentName", QStringLiteral(KWIN_NAME));
action->setObjectName("LockScreenTest::testKeyboardShortcut");
KGlobalAccel::self()->setDefaultShortcut(action.data(), QList<QKeySequence>{Qt::CTRL + Qt::META + Qt::ALT + Qt::Key_Space});
KGlobalAccel::self()->setShortcut(action.data(), QList<QKeySequence>{Qt::CTRL + Qt::META + Qt::ALT + Qt::Key_Space},
KGlobalAccel::NoAutoloading);
// try to trigger the shortcut
quint32 timestamp = 1;
KEYPRESS(KEY_LEFTCTRL);
KEYPRESS(KEY_LEFTMETA);
KEYPRESS(KEY_LEFTALT);
KEYPRESS(KEY_SPACE);
QVERIFY(actionSpy.wait());
QCOMPARE(actionSpy.count(), 1);
KEYRELEASE(KEY_SPACE);
QVERIFY(!actionSpy.wait());
QCOMPARE(actionSpy.count(), 1);
LOCK
KEYPRESS(KEY_SPACE);
QVERIFY(!actionSpy.wait());
QCOMPARE(actionSpy.count(), 1);
KEYRELEASE(KEY_SPACE);
QVERIFY(!actionSpy.wait());
QCOMPARE(actionSpy.count(), 1);
UNLOCK
KEYPRESS(KEY_SPACE);
QVERIFY(actionSpy.wait());
QCOMPARE(actionSpy.count(), 2);
KEYRELEASE(KEY_SPACE);
QVERIFY(!actionSpy.wait());
QCOMPARE(actionSpy.count(), 2);
KEYRELEASE(KEY_LEFTCTRL);
KEYRELEASE(KEY_LEFTMETA);
KEYRELEASE(KEY_LEFTALT);
}
void LockScreenTest::testTouch()
{
using namespace KWayland::Client;
auto touch = m_seat->createTouch(m_seat);
QVERIFY(touch);
QVERIFY(touch->isValid());
AbstractClient *c = showWindow();
QVERIFY(c);
QSignalSpy sequenceStartedSpy(touch, &Touch::sequenceStarted);
QVERIFY(sequenceStartedSpy.isValid());
QSignalSpy cancelSpy(touch, &Touch::sequenceCanceled);
QVERIFY(cancelSpy.isValid());
QSignalSpy pointRemovedSpy(touch, &Touch::pointRemoved);
QVERIFY(pointRemovedSpy.isValid());
quint32 timestamp = 1;
kwinApp()->platform()->touchDown(1, QPointF(25, 25), timestamp++);
QVERIFY(sequenceStartedSpy.wait());
QCOMPARE(sequenceStartedSpy.count(), 1);
LOCK
QVERIFY(cancelSpy.wait());
kwinApp()->platform()->touchUp(1, timestamp++);
QVERIFY(!pointRemovedSpy.wait(100));
kwinApp()->platform()->touchDown(1, QPointF(25, 25), timestamp++);
kwinApp()->platform()->touchMotion(1, QPointF(26, 26), timestamp++);
kwinApp()->platform()->touchUp(1, timestamp++);
UNLOCK
kwinApp()->platform()->touchDown(1, QPointF(25, 25), timestamp++);
QVERIFY(sequenceStartedSpy.wait());
QCOMPARE(sequenceStartedSpy.count(), 2);
kwinApp()->platform()->touchUp(1, timestamp++);
QVERIFY(pointRemovedSpy.wait());
QCOMPARE(pointRemovedSpy.count(), 1);
}
}
WAYLANDTEST_MAIN(KWin::LockScreenTest)
#include "lockscreen.moc"