From 3aeec88449d1e7f3aca16b4b9e3b9ec2caa0fee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Thu, 11 Feb 2016 12:48:42 +0100 Subject: [PATCH] [autotest] Add test for internal pointer warping When warping a pointer through Cursor::setPos it should be processed just like any other pointer event. It should generate enter/leave event, create motion events, etc. This is currently not the case as the test shows. --- autotests/wayland/CMakeLists.txt | 9 + autotests/wayland/pointer_input.cpp | 279 ++++++++++++++++++++++++++++ 2 files changed, 288 insertions(+) create mode 100644 autotests/wayland/pointer_input.cpp diff --git a/autotests/wayland/CMakeLists.txt b/autotests/wayland/CMakeLists.txt index 3a0cffbd8a..c1084d2bac 100644 --- a/autotests/wayland/CMakeLists.txt +++ b/autotests/wayland/CMakeLists.txt @@ -89,3 +89,12 @@ add_executable(testInputStackingOrder ${testInputStackingOrder_SRCS}) target_link_libraries( testInputStackingOrder kwin Qt5::Test) add_test(kwin-testInputStackingOrder testInputStackingOrder) ecm_mark_as_test(testInputStackingOrder) + +######################################################## +# Pointer Input Test +######################################################## +set( testPointerInput_SRCS pointer_input.cpp kwin_wayland_test.cpp ) +add_executable(testPointerInput ${testPointerInput_SRCS}) +target_link_libraries( testPointerInput kwin Qt5::Test) +add_test(kwin-testPointerInput testPointerInput) +ecm_mark_as_test(testPointerInput) diff --git a/autotests/wayland/pointer_input.cpp b/autotests/wayland/pointer_input.cpp new file mode 100644 index 0000000000..486b8c17f8 --- /dev/null +++ b/autotests/wayland/pointer_input.cpp @@ -0,0 +1,279 @@ +/******************************************************************** +KWin - the KDE window manager +This file is part of the KDE project. + +Copyright (C) 2016 Martin Gräßlin + +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 . +*********************************************************************/ +#include "kwin_wayland_test.h" +#include "abstract_backend.h" +#include "abstract_client.h" +#include "cursor.h" +#include "deleted.h" +#include "screenedge.h" +#include "screens.h" +#include "wayland_server.h" +#include "workspace.h" +#include "shell_client.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace KWin +{ + +static const QString s_socketName = QStringLiteral("wayland_test_kwin_pointer_input-0"); + +class PointerInputTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void init(); + void cleanup(); + void testWarpingUpdatesFocus(); + void testWarpingGeneratesPointerMotion(); + +private: + void render(KWayland::Client::Surface *surface); + 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; + KWayland::Client::EventQueue *m_queue = nullptr; + QThread *m_thread = nullptr; +}; + +void PointerInputTest::initTestCase() +{ + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated); + QVERIFY(workspaceCreatedSpy.isValid()); + waylandServer()->backend()->setInitialWindowSize(QSize(1280, 1024)); + QMetaObject::invokeMethod(waylandServer()->backend(), "setOutputCount", Qt::DirectConnection, Q_ARG(int, 2)); + waylandServer()->init(s_socketName.toLocal8Bit()); + + 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(); +} + +void PointerInputTest::init() +{ + using namespace KWayland::Client; + // setup connection + m_connection = new ConnectionThread; + QSignalSpy connectedSpy(m_connection, &ConnectionThread::connected); + QVERIFY(connectedSpy.isValid()); + m_connection->setSocketName(s_socketName); + + m_thread = new QThread(this); + m_connection->moveToThread(m_thread); + m_thread->start(); + + m_connection->initConnection(); + QVERIFY(connectedSpy.wait()); + + m_queue = new EventQueue(this); + QVERIFY(!m_queue->isValid()); + m_queue->setup(m_connection); + QVERIFY(m_queue->isValid()); + + Registry registry; + registry.setEventQueue(m_queue); + QSignalSpy compositorSpy(®istry, &Registry::compositorAnnounced); + QSignalSpy shmSpy(®istry, &Registry::shmAnnounced); + QSignalSpy shellSpy(®istry, &Registry::shellAnnounced); + QSignalSpy seatSpy(®istry, &Registry::seatAnnounced); + QSignalSpy allAnnounced(®istry, &Registry::interfacesAnnounced); + QVERIFY(allAnnounced.isValid()); + QVERIFY(shmSpy.isValid()); + QVERIFY(shellSpy.isValid()); + QVERIFY(compositorSpy.isValid()); + QVERIFY(seatSpy.isValid()); + registry.create(m_connection->display()); + QVERIFY(registry.isValid()); + registry.setup(); + QVERIFY(allAnnounced.wait()); + QVERIFY(!compositorSpy.isEmpty()); + QVERIFY(!shmSpy.isEmpty()); + QVERIFY(!shellSpy.isEmpty()); + QVERIFY(!seatSpy.isEmpty()); + + m_compositor = registry.createCompositor(compositorSpy.first().first().value(), compositorSpy.first().last().value(), this); + QVERIFY(m_compositor->isValid()); + m_shm = registry.createShmPool(shmSpy.first().first().value(), shmSpy.first().last().value(), this); + QVERIFY(m_shm->isValid()); + m_shell = registry.createShell(shellSpy.first().first().value(), shellSpy.first().last().value(), this); + QVERIFY(m_shell->isValid()); + m_seat = registry.createSeat(seatSpy.first().first().value(), seatSpy.first().last().value(), this); + QVERIFY(m_seat->isValid()); + QSignalSpy hasPointerSpy(m_seat, &Seat::hasPointerChanged); + QVERIFY(hasPointerSpy.isValid()); + QVERIFY(hasPointerSpy.wait()); + + screens()->setCurrent(0); + Cursor::setPos(QPoint(640, 512)); +} + +void PointerInputTest::cleanup() +{ + delete m_compositor; + m_compositor = nullptr; + delete m_seat; + m_seat = nullptr; + delete m_shm; + m_shm = nullptr; + delete m_shell; + m_shell = nullptr; + delete m_queue; + m_queue = nullptr; + if (m_thread) { + m_connection->deleteLater(); + m_thread->quit(); + m_thread->wait(); + delete m_thread; + m_thread = nullptr; + m_connection = nullptr; + } +} + +void PointerInputTest::render(KWayland::Client::Surface *surface) +{ + QImage img(QSize(100, 50), QImage::Format_ARGB32); + img.fill(Qt::blue); + surface->attachBuffer(m_shm->createBuffer(img)); + surface->damage(QRect(0, 0, 100, 50)); + surface->commit(KWayland::Client::Surface::CommitFlag::None); + m_connection->flush(); +} + +void PointerInputTest::testWarpingUpdatesFocus() +{ + // this test verifies that warping the pointer creates pointer enter and leave events + using namespace KWayland::Client; + // create pointer and signal spy for enter and leave signals + auto pointer = m_seat->createPointer(m_seat); + QVERIFY(pointer); + QVERIFY(pointer->isValid()); + QSignalSpy enteredSpy(pointer, &Pointer::entered); + QVERIFY(enteredSpy.isValid()); + QSignalSpy leftSpy(pointer, &Pointer::left); + QVERIFY(leftSpy.isValid()); + + // create a window + QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded); + QVERIFY(clientAddedSpy.isValid()); + Surface *surface = m_compositor->createSurface(m_compositor); + QVERIFY(surface); + ShellSurface *shellSurface = m_shell->createSurface(surface, surface); + QVERIFY(shellSurface); + render(surface); + QVERIFY(clientAddedSpy.wait()); + AbstractClient *window = workspace()->activeClient(); + QVERIFY(window); + + // currently there should not be a focused pointer surface + QVERIFY(!waylandServer()->seat()->focusedPointerSurface()); + QVERIFY(!pointer->enteredSurface()); + + // enter + Cursor::setPos(QPoint(25, 25)); + QEXPECT_FAIL("", "Not yet imlemented", Continue); + QVERIFY(enteredSpy.wait()); + QEXPECT_FAIL("", "Not yet imlemented", Continue); + QCOMPARE(enteredSpy.count(), 1); + // window should have focus + QEXPECT_FAIL("", "Not yet imlemented", Continue); + QCOMPARE(pointer->enteredSurface(), surface); + // also on the server + QEXPECT_FAIL("", "Not yet imlemented", Continue); + QCOMPARE(waylandServer()->seat()->focusedPointerSurface(), window->surface()); + + // and out again + Cursor::setPos(QPoint(250, 250));; + QEXPECT_FAIL("", "Not yet imlemented", Continue); + QVERIFY(leftSpy.wait()); + QEXPECT_FAIL("", "Not yet imlemented", Continue); + QCOMPARE(leftSpy.count(), 1); + // there should not be a focused pointer surface anymore + QVERIFY(!waylandServer()->seat()->focusedPointerSurface()); + QVERIFY(!pointer->enteredSurface()); +} + +void PointerInputTest::testWarpingGeneratesPointerMotion() +{ + // this test verifies that warping the pointer creates pointer motion events + using namespace KWayland::Client; + // create pointer and signal spy for enter and motion + auto pointer = m_seat->createPointer(m_seat); + QVERIFY(pointer); + QVERIFY(pointer->isValid()); + QSignalSpy enteredSpy(pointer, &Pointer::entered); + QVERIFY(enteredSpy.isValid()); + QSignalSpy movedSpy(pointer, &Pointer::motion); + QVERIFY(movedSpy.isValid()); + + // create a window + QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded); + QVERIFY(clientAddedSpy.isValid()); + Surface *surface = m_compositor->createSurface(m_compositor); + QVERIFY(surface); + ShellSurface *shellSurface = m_shell->createSurface(surface, surface); + QVERIFY(shellSurface); + render(surface); + QVERIFY(clientAddedSpy.wait()); + AbstractClient *window = workspace()->activeClient(); + QVERIFY(window); + + // enter + waylandServer()->backend()->pointerMotion(QPointF(25, 25), 1); + QVERIFY(enteredSpy.wait()); + // we get a move event together with the enter, that's actually wrong but also shouldn't harm + QVERIFY(movedSpy.wait()); + QCOMPARE(movedSpy.count(), 1); + QCOMPARE(movedSpy.first().first().toPointF(), QPointF(25, 25)); + + // now warp + Cursor::setPos(QPoint(26, 26)); + QEXPECT_FAIL("", "Not yet imlemented", Continue); + QVERIFY(movedSpy.wait()); + QEXPECT_FAIL("", "Not yet imlemented", Continue); + QCOMPARE(movedSpy.count(), 2); + QEXPECT_FAIL("", "Not yet imlemented", Continue); + QCOMPARE(movedSpy.last().first().toPointF(), QPointF(26, 26)); +} + +} + +WAYLANDTEST_MAIN(KWin::PointerInputTest) +#include "pointer_input.moc"