2020-03-15 15:19:28 +00:00
|
|
|
/*
|
|
|
|
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
2014-11-06 09:02:49 +00:00
|
|
|
|
2020-03-15 15:19:28 +00:00
|
|
|
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
|
|
|
*/
|
2014-11-06 09:02:49 +00:00
|
|
|
// Qt
|
2018-11-06 06:22:36 +00:00
|
|
|
#include <QtTest>
|
2014-11-06 09:02:49 +00:00
|
|
|
// KWayland
|
2020-04-29 13:59:23 +00:00
|
|
|
#include "KWayland/Client/connection_thread.h"
|
|
|
|
#include "KWayland/Client/event_queue.h"
|
|
|
|
#include "KWayland/Client/datadevice.h"
|
|
|
|
#include "KWayland/Client/datadevicemanager.h"
|
|
|
|
#include "KWayland/Client/datasource.h"
|
|
|
|
#include "KWayland/Client/compositor.h"
|
|
|
|
#include "KWayland/Client/keyboard.h"
|
|
|
|
#include "KWayland/Client/pointer.h"
|
|
|
|
#include "KWayland/Client/registry.h"
|
|
|
|
#include "KWayland/Client/seat.h"
|
|
|
|
#include "KWayland/Client/surface.h"
|
2014-11-06 09:02:49 +00:00
|
|
|
#include "../../src/server/display.h"
|
|
|
|
#include "../../src/server/datadevicemanager_interface.h"
|
|
|
|
#include "../../src/server/datasource_interface.h"
|
|
|
|
#include "../../src/server/compositor_interface.h"
|
2014-11-25 12:52:40 +00:00
|
|
|
#include "../../src/server/pointer_interface.h"
|
2014-11-06 09:02:49 +00:00
|
|
|
#include "../../src/server/seat_interface.h"
|
|
|
|
#include "../../src/server/surface_interface.h"
|
|
|
|
// Wayland
|
|
|
|
#include <wayland-client.h>
|
|
|
|
|
2020-06-25 15:27:52 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
|
2014-11-06 09:02:49 +00:00
|
|
|
class TestDataDevice : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
private Q_SLOTS:
|
|
|
|
void init();
|
|
|
|
void cleanup();
|
|
|
|
|
|
|
|
void testCreate();
|
2018-08-25 10:36:29 +00:00
|
|
|
void testDrag_data();
|
2014-11-06 09:02:49 +00:00
|
|
|
void testDrag();
|
2018-08-25 10:36:29 +00:00
|
|
|
void testDragInternally_data();
|
2014-11-06 09:02:49 +00:00
|
|
|
void testDragInternally();
|
|
|
|
void testSetSelection();
|
2016-06-14 12:46:39 +00:00
|
|
|
void testSendSelectionOnSeat();
|
2016-09-12 06:57:07 +00:00
|
|
|
void testReplaceSource();
|
2014-11-06 09:02:49 +00:00
|
|
|
void testDestroy();
|
|
|
|
|
|
|
|
private:
|
2020-04-29 14:56:38 +00:00
|
|
|
KWaylandServer::Display *m_display = nullptr;
|
|
|
|
KWaylandServer::DataDeviceManagerInterface *m_dataDeviceManagerInterface = nullptr;
|
|
|
|
KWaylandServer::CompositorInterface *m_compositorInterface = nullptr;
|
|
|
|
KWaylandServer::SeatInterface *m_seatInterface = nullptr;
|
2014-11-06 09:02:49 +00:00
|
|
|
KWayland::Client::ConnectionThread *m_connection = nullptr;
|
|
|
|
KWayland::Client::DataDeviceManager *m_dataDeviceManager = nullptr;
|
|
|
|
KWayland::Client::Compositor *m_compositor = nullptr;
|
|
|
|
KWayland::Client::Seat *m_seat = nullptr;
|
|
|
|
KWayland::Client::EventQueue *m_queue = nullptr;
|
|
|
|
QThread *m_thread = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const QString s_socketName = QStringLiteral("kwayland-test-wayland-datadevice-0");
|
|
|
|
|
|
|
|
void TestDataDevice::init()
|
|
|
|
{
|
2020-04-29 14:56:38 +00:00
|
|
|
qRegisterMetaType<KWaylandServer::DataSourceInterface*>();
|
|
|
|
using namespace KWaylandServer;
|
2014-11-06 09:02:49 +00:00
|
|
|
delete m_display;
|
|
|
|
m_display = new Display(this);
|
2020-10-19 15:52:56 +00:00
|
|
|
m_display->addSocketName(s_socketName);
|
2014-11-06 09:02:49 +00:00
|
|
|
m_display->start();
|
|
|
|
QVERIFY(m_display->isRunning());
|
|
|
|
|
|
|
|
// setup connection
|
|
|
|
m_connection = new KWayland::Client::ConnectionThread;
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
|
2014-11-06 09:02:49 +00:00
|
|
|
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 KWayland::Client::EventQueue(this);
|
|
|
|
QVERIFY(!m_queue->isValid());
|
|
|
|
m_queue->setup(m_connection);
|
|
|
|
QVERIFY(m_queue->isValid());
|
|
|
|
|
|
|
|
KWayland::Client::Registry registry;
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy dataDeviceManagerSpy(®istry, &KWayland::Client::Registry::dataDeviceManagerAnnounced);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(dataDeviceManagerSpy.isValid());
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy seatSpy(®istry, &KWayland::Client::Registry::seatAnnounced);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(seatSpy.isValid());
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy compositorSpy(®istry, &KWayland::Client::Registry::compositorAnnounced);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(compositorSpy.isValid());
|
|
|
|
QVERIFY(!registry.eventQueue());
|
|
|
|
registry.setEventQueue(m_queue);
|
|
|
|
QCOMPARE(registry.eventQueue(), m_queue);
|
|
|
|
registry.create(m_connection->display());
|
|
|
|
QVERIFY(registry.isValid());
|
|
|
|
registry.setup();
|
|
|
|
|
2020-12-09 20:13:19 +00:00
|
|
|
m_dataDeviceManagerInterface = new DataDeviceManagerInterface(m_display, m_display);
|
2014-11-06 09:02:49 +00:00
|
|
|
|
|
|
|
QVERIFY(dataDeviceManagerSpy.wait());
|
|
|
|
m_dataDeviceManager = registry.createDataDeviceManager(dataDeviceManagerSpy.first().first().value<quint32>(),
|
|
|
|
dataDeviceManagerSpy.first().last().value<quint32>(), this);
|
|
|
|
|
2020-12-09 20:13:19 +00:00
|
|
|
m_seatInterface = new SeatInterface(m_display, m_display);
|
2014-11-06 09:02:49 +00:00
|
|
|
m_seatInterface->setHasPointer(true);
|
|
|
|
|
|
|
|
QVERIFY(seatSpy.wait());
|
|
|
|
m_seat = registry.createSeat(seatSpy.first().first().value<quint32>(),
|
|
|
|
seatSpy.first().last().value<quint32>(), this);
|
|
|
|
QVERIFY(m_seat->isValid());
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy pointerChangedSpy(m_seat, &KWayland::Client::Seat::hasPointerChanged);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(pointerChangedSpy.isValid());
|
|
|
|
QVERIFY(pointerChangedSpy.wait());
|
|
|
|
|
2020-12-09 20:13:19 +00:00
|
|
|
m_compositorInterface = new CompositorInterface(m_display, m_display);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(compositorSpy.wait());
|
|
|
|
m_compositor = registry.createCompositor(compositorSpy.first().first().value<quint32>(),
|
|
|
|
compositorSpy.first().last().value<quint32>(), this);
|
|
|
|
QVERIFY(m_compositor->isValid());
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestDataDevice::cleanup()
|
|
|
|
{
|
|
|
|
if (m_dataDeviceManager) {
|
|
|
|
delete m_dataDeviceManager;
|
|
|
|
m_dataDeviceManager = nullptr;
|
|
|
|
}
|
|
|
|
if (m_seat) {
|
|
|
|
delete m_seat;
|
|
|
|
m_seat = nullptr;
|
|
|
|
}
|
|
|
|
if (m_compositor) {
|
|
|
|
delete m_compositor;
|
|
|
|
m_compositor = nullptr;
|
|
|
|
}
|
|
|
|
if (m_queue) {
|
|
|
|
delete m_queue;
|
|
|
|
m_queue = nullptr;
|
|
|
|
}
|
|
|
|
if (m_thread) {
|
|
|
|
m_thread->quit();
|
|
|
|
m_thread->wait();
|
|
|
|
delete m_thread;
|
|
|
|
m_thread = nullptr;
|
|
|
|
}
|
|
|
|
delete m_connection;
|
|
|
|
m_connection = nullptr;
|
|
|
|
|
|
|
|
delete m_display;
|
|
|
|
m_display = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestDataDevice::testCreate()
|
|
|
|
{
|
|
|
|
using namespace KWayland::Client;
|
2020-04-29 14:56:38 +00:00
|
|
|
using namespace KWaylandServer;
|
2014-11-06 09:02:49 +00:00
|
|
|
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy dataDeviceCreatedSpy(m_dataDeviceManagerInterface, &KWaylandServer::DataDeviceManagerInterface::dataDeviceCreated);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(dataDeviceCreatedSpy.isValid());
|
|
|
|
|
|
|
|
QScopedPointer<DataDevice> dataDevice(m_dataDeviceManager->getDataDevice(m_seat));
|
|
|
|
QVERIFY(dataDevice->isValid());
|
|
|
|
|
|
|
|
QVERIFY(dataDeviceCreatedSpy.wait());
|
|
|
|
QCOMPARE(dataDeviceCreatedSpy.count(), 1);
|
|
|
|
auto deviceInterface = dataDeviceCreatedSpy.first().first().value<DataDeviceInterface*>();
|
|
|
|
QVERIFY(deviceInterface);
|
|
|
|
QCOMPARE(deviceInterface->seat(), m_seatInterface);
|
|
|
|
QVERIFY(!deviceInterface->dragSource());
|
|
|
|
QVERIFY(!deviceInterface->origin());
|
|
|
|
QVERIFY(!deviceInterface->icon());
|
|
|
|
QVERIFY(!deviceInterface->selection());
|
2020-05-18 13:43:38 +00:00
|
|
|
|
|
|
|
// this will probably fail, we need to make a selection client side
|
2016-06-21 09:14:46 +00:00
|
|
|
QVERIFY(!m_seatInterface->selection());
|
2020-05-18 13:43:38 +00:00
|
|
|
m_seatInterface->setSelection(deviceInterface->selection());
|
|
|
|
QCOMPARE(m_seatInterface->selection(), deviceInterface->selection());
|
2016-06-21 09:14:46 +00:00
|
|
|
|
2016-05-25 08:04:17 +00:00
|
|
|
// and destroy
|
|
|
|
QSignalSpy destroyedSpy(deviceInterface, &QObject::destroyed);
|
|
|
|
QVERIFY(destroyedSpy.isValid());
|
|
|
|
dataDevice.reset();
|
|
|
|
QVERIFY(destroyedSpy.wait());
|
2016-06-21 09:14:46 +00:00
|
|
|
QVERIFY(!m_seatInterface->selection());
|
2014-11-06 09:02:49 +00:00
|
|
|
}
|
|
|
|
|
2018-08-25 10:36:29 +00:00
|
|
|
void TestDataDevice::testDrag_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<bool>("hasGrab");
|
|
|
|
QTest::addColumn<bool>("hasPointerFocus");
|
|
|
|
QTest::addColumn<bool>("success");
|
|
|
|
|
|
|
|
QTest::newRow("grab and focus") << true << true << true;
|
|
|
|
QTest::newRow("no grab") << false << true << false;
|
|
|
|
QTest::newRow("no focus") << true << false << false;
|
|
|
|
QTest::newRow("no grab, no focus") << false << false << false;
|
|
|
|
}
|
|
|
|
|
2014-11-06 09:02:49 +00:00
|
|
|
void TestDataDevice::testDrag()
|
|
|
|
{
|
|
|
|
using namespace KWayland::Client;
|
2020-04-29 14:56:38 +00:00
|
|
|
using namespace KWaylandServer;
|
2014-11-06 09:02:49 +00:00
|
|
|
QScopedPointer<Pointer> pointer(m_seat->createPointer());
|
|
|
|
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy dataDeviceCreatedSpy(m_dataDeviceManagerInterface, &KWaylandServer::DataDeviceManagerInterface::dataDeviceCreated);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(dataDeviceCreatedSpy.isValid());
|
|
|
|
|
|
|
|
QScopedPointer<DataDevice> dataDevice(m_dataDeviceManager->getDataDevice(m_seat));
|
|
|
|
QVERIFY(dataDevice->isValid());
|
|
|
|
|
|
|
|
QVERIFY(dataDeviceCreatedSpy.wait());
|
|
|
|
QCOMPARE(dataDeviceCreatedSpy.count(), 1);
|
|
|
|
auto deviceInterface = dataDeviceCreatedSpy.first().first().value<DataDeviceInterface*>();
|
|
|
|
QVERIFY(deviceInterface);
|
|
|
|
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy dataSourceCreatedSpy(m_dataDeviceManagerInterface, &KWaylandServer::DataDeviceManagerInterface::dataSourceCreated);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(dataDeviceCreatedSpy.isValid());
|
|
|
|
|
|
|
|
QScopedPointer<DataSource> dataSource(m_dataDeviceManager->createDataSource());
|
|
|
|
QVERIFY(dataSource->isValid());
|
|
|
|
|
|
|
|
QVERIFY(dataSourceCreatedSpy.wait());
|
|
|
|
QCOMPARE(dataSourceCreatedSpy.count(), 1);
|
|
|
|
auto sourceInterface = dataSourceCreatedSpy.first().first().value<DataSourceInterface*>();
|
|
|
|
QVERIFY(sourceInterface);
|
|
|
|
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWaylandServer::CompositorInterface::surfaceCreated);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(surfaceCreatedSpy.isValid());
|
|
|
|
|
|
|
|
QScopedPointer<Surface> surface(m_compositor->createSurface());
|
|
|
|
QVERIFY(surface->isValid());
|
|
|
|
|
|
|
|
QVERIFY(surfaceCreatedSpy.wait());
|
|
|
|
QCOMPARE(surfaceCreatedSpy.count(), 1);
|
|
|
|
auto surfaceInterface = surfaceCreatedSpy.first().first().value<SurfaceInterface*>();
|
|
|
|
|
|
|
|
// now we have all we need to start a drag operation
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy dragStartedSpy(deviceInterface, &KWaylandServer::DataDeviceInterface::dragStarted);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(dragStartedSpy.isValid());
|
|
|
|
|
|
|
|
// first we need to fake the pointer enter
|
2018-08-25 10:36:29 +00:00
|
|
|
QFETCH(bool, hasGrab);
|
|
|
|
QFETCH(bool, hasPointerFocus);
|
|
|
|
QFETCH(bool, success);
|
|
|
|
if (!hasGrab) {
|
|
|
|
// in case we don't have grab, still generate a pointer serial to make it more interesting
|
2021-03-11 08:24:47 +00:00
|
|
|
m_seatInterface->notifyPointerPress(Qt::LeftButton);
|
|
|
|
m_seatInterface->notifyPointerFrame();
|
2018-08-25 10:36:29 +00:00
|
|
|
}
|
|
|
|
if (hasPointerFocus) {
|
|
|
|
m_seatInterface->setFocusedPointerSurface(surfaceInterface);
|
|
|
|
}
|
|
|
|
if (hasGrab) {
|
2021-03-11 08:24:47 +00:00
|
|
|
m_seatInterface->notifyPointerPress(Qt::LeftButton);
|
|
|
|
m_seatInterface->notifyPointerFrame();
|
2018-08-25 10:36:29 +00:00
|
|
|
}
|
2014-11-06 09:02:49 +00:00
|
|
|
|
2018-08-25 10:36:29 +00:00
|
|
|
// TODO: This test would be better, if it could also test that a client trying to guess
|
|
|
|
// the last serial of a different client can't start a drag.
|
|
|
|
const quint32 pointerButtonSerial = success ? m_seatInterface->pointerButtonSerial(Qt::LeftButton) : 0;
|
2014-11-06 09:02:49 +00:00
|
|
|
|
2018-08-25 10:36:29 +00:00
|
|
|
QCoreApplication::processEvents();
|
|
|
|
// finally start the drag
|
|
|
|
dataDevice->startDrag(pointerButtonSerial, dataSource.data(), surface.data());
|
|
|
|
QCOMPARE(dragStartedSpy.wait(500), success);
|
[autotests] Compare booleans to booleans
Summary:
Compiler errors:
17:06:23 /usr/lib64/gcc/x86_64-suse-linux/8/../../../../x86_64-suse-linux/bin/ld: CMakeFiles/testDataDevice.dir/test_datadevice.cpp.o: in function `TestDataDevice::testDrag()':
17:06:23 /home/jenkins/workspace/Frameworks kwayland kf5-qt5 SUSEQt5.9/autotests/client/test_datadevice.cpp:290: undefined reference to `bool QTest::qCompare<int, bool>(int const&, bool const&, char const*, char const*, char const*, int)'
17:06:23 /usr/lib64/gcc/x86_64-suse-linux/8/../../../../x86_64-suse-linux/bin/ld: CMakeFiles/testDataDevice.dir/test_datadevice.cpp.o: in function `TestDataDevice::testDragInternally()':
17:06:23 /home/jenkins/workspace/Frameworks kwayland kf5-qt5 SUSEQt5.9/autotests/client/test_datadevice.cpp:369: undefined reference to `bool QTest::qCompare<int, bool>(int const&, bool const&, char const*, char const*, char const*, int)'
Test Plan: Ran testDataDevice, still passes.
Reviewers: #kwin, romangg, broulik
Reviewed By: broulik
Subscribers: kde-frameworks-devel
Tags: #frameworks
Differential Revision: https://phabricator.kde.org/D15330
2018-09-07 11:25:19 +00:00
|
|
|
QCOMPARE(!dragStartedSpy.isEmpty(), success);
|
2018-08-25 10:36:29 +00:00
|
|
|
QCOMPARE(deviceInterface->dragSource(), success ? sourceInterface : nullptr);
|
|
|
|
QCOMPARE(deviceInterface->origin(), success ? surfaceInterface : nullptr);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(!deviceInterface->icon());
|
|
|
|
}
|
|
|
|
|
2018-08-25 10:36:29 +00:00
|
|
|
void TestDataDevice::testDragInternally_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<bool>("hasGrab");
|
|
|
|
QTest::addColumn<bool>("hasPointerFocus");
|
|
|
|
QTest::addColumn<bool>("success");
|
|
|
|
|
|
|
|
QTest::newRow("grab and focus") << true << true << true;
|
|
|
|
QTest::newRow("no grab") << false << true << false;
|
|
|
|
QTest::newRow("no focus") << true << false << false;
|
|
|
|
QTest::newRow("no grab, no focus") << false << false << false;
|
|
|
|
}
|
|
|
|
|
2014-11-06 09:02:49 +00:00
|
|
|
void TestDataDevice::testDragInternally()
|
|
|
|
{
|
|
|
|
using namespace KWayland::Client;
|
2020-04-29 14:56:38 +00:00
|
|
|
using namespace KWaylandServer;
|
2014-11-06 09:02:49 +00:00
|
|
|
QScopedPointer<Pointer> pointer(m_seat->createPointer());
|
|
|
|
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy dataDeviceCreatedSpy(m_dataDeviceManagerInterface, &KWaylandServer::DataDeviceManagerInterface::dataDeviceCreated);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(dataDeviceCreatedSpy.isValid());
|
|
|
|
|
|
|
|
QScopedPointer<DataDevice> dataDevice(m_dataDeviceManager->getDataDevice(m_seat));
|
|
|
|
QVERIFY(dataDevice->isValid());
|
|
|
|
|
|
|
|
QVERIFY(dataDeviceCreatedSpy.wait());
|
|
|
|
QCOMPARE(dataDeviceCreatedSpy.count(), 1);
|
|
|
|
auto deviceInterface = dataDeviceCreatedSpy.first().first().value<DataDeviceInterface*>();
|
|
|
|
QVERIFY(deviceInterface);
|
|
|
|
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWaylandServer::CompositorInterface::surfaceCreated);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(surfaceCreatedSpy.isValid());
|
|
|
|
|
|
|
|
QScopedPointer<Surface> surface(m_compositor->createSurface());
|
|
|
|
QVERIFY(surface->isValid());
|
|
|
|
|
|
|
|
QVERIFY(surfaceCreatedSpy.wait());
|
|
|
|
QCOMPARE(surfaceCreatedSpy.count(), 1);
|
|
|
|
auto surfaceInterface = surfaceCreatedSpy.first().first().value<SurfaceInterface*>();
|
|
|
|
|
|
|
|
QScopedPointer<Surface> iconSurface(m_compositor->createSurface());
|
|
|
|
QVERIFY(iconSurface->isValid());
|
|
|
|
|
|
|
|
QVERIFY(surfaceCreatedSpy.wait());
|
|
|
|
QCOMPARE(surfaceCreatedSpy.count(), 2);
|
|
|
|
auto iconSurfaceInterface = surfaceCreatedSpy.last().first().value<SurfaceInterface*>();
|
|
|
|
|
|
|
|
// now we have all we need to start a drag operation
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy dragStartedSpy(deviceInterface, &KWaylandServer::DataDeviceInterface::dragStarted);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(dragStartedSpy.isValid());
|
|
|
|
|
|
|
|
// first we need to fake the pointer enter
|
2018-08-25 10:36:29 +00:00
|
|
|
QFETCH(bool, hasGrab);
|
|
|
|
QFETCH(bool, hasPointerFocus);
|
|
|
|
QFETCH(bool, success);
|
|
|
|
if (!hasGrab) {
|
|
|
|
// in case we don't have grab, still generate a pointer serial to make it more interesting
|
2021-03-11 08:24:47 +00:00
|
|
|
m_seatInterface->notifyPointerPress(Qt::LeftButton);
|
|
|
|
m_seatInterface->notifyPointerFrame();
|
2018-08-25 10:36:29 +00:00
|
|
|
}
|
|
|
|
if (hasPointerFocus) {
|
|
|
|
m_seatInterface->setFocusedPointerSurface(surfaceInterface);
|
|
|
|
}
|
|
|
|
if (hasGrab) {
|
2021-03-11 08:24:47 +00:00
|
|
|
m_seatInterface->notifyPointerPress(Qt::LeftButton);
|
|
|
|
m_seatInterface->notifyPointerFrame();
|
2018-08-25 10:36:29 +00:00
|
|
|
}
|
2014-11-06 09:02:49 +00:00
|
|
|
|
2018-08-25 10:36:29 +00:00
|
|
|
// TODO: This test would be better, if it could also test that a client trying to guess
|
|
|
|
// the last serial of a different client can't start a drag.
|
|
|
|
const quint32 pointerButtonSerial = success ? m_seatInterface->pointerButtonSerial(Qt::LeftButton) : 0;
|
2014-11-06 09:02:49 +00:00
|
|
|
|
2018-08-25 10:36:29 +00:00
|
|
|
QCoreApplication::processEvents();
|
|
|
|
// finally start the internal drag
|
|
|
|
dataDevice->startDragInternally(pointerButtonSerial, surface.data(), iconSurface.data());
|
|
|
|
QCOMPARE(dragStartedSpy.wait(500), success);
|
[autotests] Compare booleans to booleans
Summary:
Compiler errors:
17:06:23 /usr/lib64/gcc/x86_64-suse-linux/8/../../../../x86_64-suse-linux/bin/ld: CMakeFiles/testDataDevice.dir/test_datadevice.cpp.o: in function `TestDataDevice::testDrag()':
17:06:23 /home/jenkins/workspace/Frameworks kwayland kf5-qt5 SUSEQt5.9/autotests/client/test_datadevice.cpp:290: undefined reference to `bool QTest::qCompare<int, bool>(int const&, bool const&, char const*, char const*, char const*, int)'
17:06:23 /usr/lib64/gcc/x86_64-suse-linux/8/../../../../x86_64-suse-linux/bin/ld: CMakeFiles/testDataDevice.dir/test_datadevice.cpp.o: in function `TestDataDevice::testDragInternally()':
17:06:23 /home/jenkins/workspace/Frameworks kwayland kf5-qt5 SUSEQt5.9/autotests/client/test_datadevice.cpp:369: undefined reference to `bool QTest::qCompare<int, bool>(int const&, bool const&, char const*, char const*, char const*, int)'
Test Plan: Ran testDataDevice, still passes.
Reviewers: #kwin, romangg, broulik
Reviewed By: broulik
Subscribers: kde-frameworks-devel
Tags: #frameworks
Differential Revision: https://phabricator.kde.org/D15330
2018-09-07 11:25:19 +00:00
|
|
|
QCOMPARE(!dragStartedSpy.isEmpty(), success);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(!deviceInterface->dragSource());
|
2018-08-25 10:36:29 +00:00
|
|
|
QCOMPARE(deviceInterface->origin(), success ? surfaceInterface : nullptr);
|
2020-10-29 08:29:30 +00:00
|
|
|
|
|
|
|
if (success) {
|
|
|
|
QCOMPARE(deviceInterface->icon()->surface(), iconSurfaceInterface);
|
|
|
|
} else {
|
|
|
|
QCOMPARE(deviceInterface->icon(), nullptr);
|
|
|
|
}
|
2014-11-06 09:02:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestDataDevice::testSetSelection()
|
|
|
|
{
|
|
|
|
using namespace KWayland::Client;
|
2020-04-29 14:56:38 +00:00
|
|
|
using namespace KWaylandServer;
|
2014-11-06 09:02:49 +00:00
|
|
|
QScopedPointer<Pointer> pointer(m_seat->createPointer());
|
|
|
|
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy dataDeviceCreatedSpy(m_dataDeviceManagerInterface, &KWaylandServer::DataDeviceManagerInterface::dataDeviceCreated);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(dataDeviceCreatedSpy.isValid());
|
|
|
|
|
|
|
|
QScopedPointer<DataDevice> dataDevice(m_dataDeviceManager->getDataDevice(m_seat));
|
|
|
|
QVERIFY(dataDevice->isValid());
|
|
|
|
|
|
|
|
QVERIFY(dataDeviceCreatedSpy.wait());
|
|
|
|
QCOMPARE(dataDeviceCreatedSpy.count(), 1);
|
|
|
|
auto deviceInterface = dataDeviceCreatedSpy.first().first().value<DataDeviceInterface*>();
|
|
|
|
QVERIFY(deviceInterface);
|
|
|
|
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy dataSourceCreatedSpy(m_dataDeviceManagerInterface, &KWaylandServer::DataDeviceManagerInterface::dataSourceCreated);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(dataDeviceCreatedSpy.isValid());
|
|
|
|
|
|
|
|
QScopedPointer<DataSource> dataSource(m_dataDeviceManager->createDataSource());
|
|
|
|
QVERIFY(dataSource->isValid());
|
2014-11-06 15:56:50 +00:00
|
|
|
dataSource->offer(QStringLiteral("text/plain"));
|
2014-11-06 09:02:49 +00:00
|
|
|
|
|
|
|
QVERIFY(dataSourceCreatedSpy.wait());
|
|
|
|
QCOMPARE(dataSourceCreatedSpy.count(), 1);
|
|
|
|
auto sourceInterface = dataSourceCreatedSpy.first().first().value<DataSourceInterface*>();
|
|
|
|
QVERIFY(sourceInterface);
|
|
|
|
|
|
|
|
// everything setup, now we can test setting the selection
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy selectionChangedSpy(deviceInterface, &KWaylandServer::DataDeviceInterface::selectionChanged);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(selectionChangedSpy.isValid());
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy selectionClearedSpy(deviceInterface, &KWaylandServer::DataDeviceInterface::selectionCleared);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(selectionClearedSpy.isValid());
|
|
|
|
|
|
|
|
QVERIFY(!deviceInterface->selection());
|
|
|
|
dataDevice->setSelection(1, dataSource.data());
|
|
|
|
QVERIFY(selectionChangedSpy.wait());
|
|
|
|
QCOMPARE(selectionChangedSpy.count(), 1);
|
|
|
|
QCOMPARE(selectionClearedSpy.count(), 0);
|
|
|
|
QCOMPARE(selectionChangedSpy.first().first().value<DataSourceInterface*>(), sourceInterface);
|
|
|
|
QCOMPARE(deviceInterface->selection(), sourceInterface);
|
|
|
|
|
2014-11-06 15:56:50 +00:00
|
|
|
// send selection to datadevice
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy selectionOfferedSpy(dataDevice.data(), &KWayland::Client::DataDevice::selectionOffered);
|
2014-11-06 15:56:50 +00:00
|
|
|
QVERIFY(selectionOfferedSpy.isValid());
|
2020-05-18 13:43:38 +00:00
|
|
|
deviceInterface->sendSelection(deviceInterface->selection());
|
2014-11-06 15:56:50 +00:00
|
|
|
QVERIFY(selectionOfferedSpy.wait());
|
|
|
|
QCOMPARE(selectionOfferedSpy.count(), 1);
|
|
|
|
auto dataOffer = selectionOfferedSpy.first().first().value<DataOffer*>();
|
|
|
|
QVERIFY(dataOffer);
|
|
|
|
QCOMPARE(dataOffer->offeredMimeTypes().count(), 1);
|
|
|
|
QCOMPARE(dataOffer->offeredMimeTypes().first().name(), QStringLiteral("text/plain"));
|
|
|
|
|
|
|
|
// sending a new mimetype to the selection, should be announced in the offer
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy mimeTypeAddedSpy(dataOffer, &KWayland::Client::DataOffer::mimeTypeOffered);
|
2014-11-06 15:56:50 +00:00
|
|
|
QVERIFY(mimeTypeAddedSpy.isValid());
|
|
|
|
dataSource->offer(QStringLiteral("text/html"));
|
|
|
|
QVERIFY(mimeTypeAddedSpy.wait());
|
|
|
|
QCOMPARE(mimeTypeAddedSpy.count(), 1);
|
|
|
|
QCOMPARE(mimeTypeAddedSpy.first().first().toString(), QStringLiteral("text/html"));
|
|
|
|
QCOMPARE(dataOffer->offeredMimeTypes().count(), 2);
|
|
|
|
QCOMPARE(dataOffer->offeredMimeTypes().first().name(), QStringLiteral("text/plain"));
|
|
|
|
QCOMPARE(dataOffer->offeredMimeTypes().last().name(), QStringLiteral("text/html"));
|
|
|
|
|
2014-11-06 09:02:49 +00:00
|
|
|
// now clear the selection
|
|
|
|
dataDevice->clearSelection(1);
|
|
|
|
QVERIFY(selectionClearedSpy.wait());
|
|
|
|
QCOMPARE(selectionChangedSpy.count(), 1);
|
|
|
|
QCOMPARE(selectionClearedSpy.count(), 1);
|
|
|
|
QVERIFY(!deviceInterface->selection());
|
2016-06-15 07:33:10 +00:00
|
|
|
|
|
|
|
// set another selection
|
|
|
|
dataDevice->setSelection(2, dataSource.data());
|
|
|
|
QVERIFY(selectionChangedSpy.wait());
|
|
|
|
// now unbind the dataDevice
|
2020-06-25 15:27:52 +00:00
|
|
|
QSignalSpy unboundSpy(deviceInterface, &QObject::destroyed);
|
2016-06-15 07:33:10 +00:00
|
|
|
QVERIFY(unboundSpy.isValid());
|
|
|
|
dataDevice.reset();
|
|
|
|
QVERIFY(unboundSpy.wait());
|
2014-11-06 09:02:49 +00:00
|
|
|
}
|
|
|
|
|
2016-06-14 12:46:39 +00:00
|
|
|
void TestDataDevice::testSendSelectionOnSeat()
|
|
|
|
{
|
|
|
|
// this test verifies that the selection is sent when setting a focused keyboard
|
|
|
|
using namespace KWayland::Client;
|
2020-04-29 14:56:38 +00:00
|
|
|
using namespace KWaylandServer;
|
2016-06-14 12:46:39 +00:00
|
|
|
// first add keyboard support to Seat
|
|
|
|
QSignalSpy keyboardChangedSpy(m_seat, &Seat::hasKeyboardChanged);
|
|
|
|
QVERIFY(keyboardChangedSpy.isValid());
|
|
|
|
m_seatInterface->setHasKeyboard(true);
|
|
|
|
QVERIFY(keyboardChangedSpy.wait());
|
|
|
|
// now create DataDevice, Keyboard and a Surface
|
|
|
|
QSignalSpy dataDeviceCreatedSpy(m_dataDeviceManagerInterface, &DataDeviceManagerInterface::dataDeviceCreated);
|
|
|
|
QVERIFY(dataDeviceCreatedSpy.isValid());
|
|
|
|
QScopedPointer<DataDevice> dataDevice(m_dataDeviceManager->getDataDevice(m_seat));
|
|
|
|
QVERIFY(dataDevice->isValid());
|
|
|
|
QVERIFY(dataDeviceCreatedSpy.wait());
|
|
|
|
auto serverDataDevice = dataDeviceCreatedSpy.first().first().value<DataDeviceInterface*>();
|
|
|
|
QVERIFY(serverDataDevice);
|
|
|
|
QScopedPointer<Keyboard> keyboard(m_seat->createKeyboard());
|
|
|
|
QVERIFY(keyboard->isValid());
|
|
|
|
QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
|
|
|
|
QVERIFY(surfaceCreatedSpy.isValid());
|
|
|
|
QScopedPointer<Surface> surface(m_compositor->createSurface());
|
|
|
|
QVERIFY(surface->isValid());
|
|
|
|
QVERIFY(surfaceCreatedSpy.wait());
|
|
|
|
|
|
|
|
auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface*>();
|
|
|
|
QVERIFY(serverSurface);
|
|
|
|
m_seatInterface->setFocusedKeyboardSurface(serverSurface);
|
|
|
|
|
|
|
|
// now set the selection
|
|
|
|
QScopedPointer<DataSource> dataSource(m_dataDeviceManager->createDataSource());
|
|
|
|
QVERIFY(dataSource->isValid());
|
|
|
|
dataSource->offer(QStringLiteral("text/plain"));
|
|
|
|
dataDevice->setSelection(1, dataSource.data());
|
|
|
|
// we should get a selection offered for that on the data device
|
|
|
|
QSignalSpy selectionOfferedSpy(dataDevice.data(), &DataDevice::selectionOffered);
|
|
|
|
QVERIFY(selectionOfferedSpy.isValid());
|
|
|
|
QVERIFY(selectionOfferedSpy.wait());
|
|
|
|
QCOMPARE(selectionOfferedSpy.count(), 1);
|
|
|
|
|
|
|
|
// now unfocus the keyboard
|
|
|
|
m_seatInterface->setFocusedKeyboardSurface(nullptr);
|
|
|
|
// if setting the same surface again, we should get another offer
|
|
|
|
m_seatInterface->setFocusedKeyboardSurface(serverSurface);
|
|
|
|
QVERIFY(selectionOfferedSpy.wait());
|
|
|
|
QCOMPARE(selectionOfferedSpy.count(), 2);
|
|
|
|
|
|
|
|
// now let's try to destroy the data device and set a focused keyboard just while the data device is being destroyedd
|
|
|
|
m_seatInterface->setFocusedKeyboardSurface(nullptr);
|
2020-06-25 15:27:52 +00:00
|
|
|
QSignalSpy unboundSpy(serverDataDevice, &QObject::destroyed);
|
2016-06-14 12:46:39 +00:00
|
|
|
QVERIFY(unboundSpy.isValid());
|
|
|
|
dataDevice.reset();
|
|
|
|
QVERIFY(unboundSpy.wait());
|
|
|
|
m_seatInterface->setFocusedKeyboardSurface(serverSurface);
|
|
|
|
}
|
|
|
|
|
2016-09-12 06:57:07 +00:00
|
|
|
void TestDataDevice::testReplaceSource()
|
|
|
|
{
|
|
|
|
// this test verifies that replacing a data source cancels the previous source
|
|
|
|
using namespace KWayland::Client;
|
2020-04-29 14:56:38 +00:00
|
|
|
using namespace KWaylandServer;
|
2016-09-12 06:57:07 +00:00
|
|
|
// first add keyboard support to Seat
|
|
|
|
QSignalSpy keyboardChangedSpy(m_seat, &Seat::hasKeyboardChanged);
|
|
|
|
QVERIFY(keyboardChangedSpy.isValid());
|
|
|
|
m_seatInterface->setHasKeyboard(true);
|
|
|
|
QVERIFY(keyboardChangedSpy.wait());
|
|
|
|
// now create DataDevice, Keyboard and a Surface
|
|
|
|
QSignalSpy dataDeviceCreatedSpy(m_dataDeviceManagerInterface, &DataDeviceManagerInterface::dataDeviceCreated);
|
|
|
|
QVERIFY(dataDeviceCreatedSpy.isValid());
|
|
|
|
QScopedPointer<DataDevice> dataDevice(m_dataDeviceManager->getDataDevice(m_seat));
|
|
|
|
QVERIFY(dataDevice->isValid());
|
|
|
|
QVERIFY(dataDeviceCreatedSpy.wait());
|
|
|
|
auto serverDataDevice = dataDeviceCreatedSpy.first().first().value<DataDeviceInterface*>();
|
|
|
|
QVERIFY(serverDataDevice);
|
|
|
|
QScopedPointer<Keyboard> keyboard(m_seat->createKeyboard());
|
|
|
|
QVERIFY(keyboard->isValid());
|
|
|
|
QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
|
|
|
|
QVERIFY(surfaceCreatedSpy.isValid());
|
|
|
|
QScopedPointer<Surface> surface(m_compositor->createSurface());
|
|
|
|
QVERIFY(surface->isValid());
|
|
|
|
QVERIFY(surfaceCreatedSpy.wait());
|
|
|
|
|
|
|
|
auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface*>();
|
|
|
|
QVERIFY(serverSurface);
|
|
|
|
m_seatInterface->setFocusedKeyboardSurface(serverSurface);
|
|
|
|
|
|
|
|
// now set the selection
|
|
|
|
QScopedPointer<DataSource> dataSource(m_dataDeviceManager->createDataSource());
|
|
|
|
QVERIFY(dataSource->isValid());
|
|
|
|
dataSource->offer(QStringLiteral("text/plain"));
|
|
|
|
dataDevice->setSelection(1, dataSource.data());
|
|
|
|
QSignalSpy sourceCancelledSpy(dataSource.data(), &DataSource::cancelled);
|
|
|
|
QVERIFY(sourceCancelledSpy.isValid());
|
|
|
|
// we should get a selection offered for that on the data device
|
|
|
|
QSignalSpy selectionOfferedSpy(dataDevice.data(), &DataDevice::selectionOffered);
|
|
|
|
QVERIFY(selectionOfferedSpy.isValid());
|
|
|
|
QVERIFY(selectionOfferedSpy.wait());
|
|
|
|
QCOMPARE(selectionOfferedSpy.count(), 1);
|
|
|
|
|
|
|
|
// create a second data source and replace previous one
|
|
|
|
QScopedPointer<DataSource> dataSource2(m_dataDeviceManager->createDataSource());
|
|
|
|
QVERIFY(dataSource2->isValid());
|
|
|
|
dataSource2->offer(QStringLiteral("text/plain"));
|
|
|
|
QSignalSpy sourceCancelled2Spy(dataSource2.data(), &DataSource::cancelled);
|
|
|
|
QVERIFY(sourceCancelled2Spy.isValid());
|
|
|
|
dataDevice->setSelection(1, dataSource2.data());
|
|
|
|
QCOMPARE(selectionOfferedSpy.count(), 1);
|
|
|
|
QVERIFY(sourceCancelledSpy.wait());
|
2018-06-14 12:21:41 +00:00
|
|
|
QCOMPARE(selectionOfferedSpy.count(), 2);
|
|
|
|
QVERIFY(sourceCancelled2Spy.isEmpty());
|
|
|
|
|
|
|
|
// replace the data source with itself, ensure that it did not get cancelled
|
|
|
|
dataDevice->setSelection(1, dataSource2.data());
|
|
|
|
QVERIFY(!sourceCancelled2Spy.wait(500));
|
2016-09-12 06:57:07 +00:00
|
|
|
QCOMPARE(selectionOfferedSpy.count(), 2);
|
|
|
|
QVERIFY(sourceCancelled2Spy.isEmpty());
|
|
|
|
|
|
|
|
// create a new DataDevice and replace previous one
|
|
|
|
QScopedPointer<DataDevice> dataDevice2(m_dataDeviceManager->getDataDevice(m_seat));
|
|
|
|
QVERIFY(dataDevice2->isValid());
|
|
|
|
QScopedPointer<DataSource> dataSource3(m_dataDeviceManager->createDataSource());
|
|
|
|
QVERIFY(dataSource3->isValid());
|
|
|
|
dataSource3->offer(QStringLiteral("text/plain"));
|
|
|
|
dataDevice2->setSelection(1, dataSource3.data());
|
|
|
|
QVERIFY(sourceCancelled2Spy.wait());
|
|
|
|
|
|
|
|
// try to crash by first destroying dataSource3 and setting a new DataSource
|
|
|
|
QScopedPointer<DataSource> dataSource4(m_dataDeviceManager->createDataSource());
|
|
|
|
QVERIFY(dataSource4->isValid());
|
|
|
|
dataSource4->offer(QStringLiteral("text/plain"));
|
|
|
|
dataSource3.reset();
|
|
|
|
dataDevice2->setSelection(1, dataSource4.data());
|
|
|
|
QVERIFY(selectionOfferedSpy.wait());
|
2020-06-25 15:27:52 +00:00
|
|
|
|
|
|
|
auto dataOffer = selectionOfferedSpy.last()[0].value<DataOffer*>();
|
|
|
|
|
|
|
|
// try to crash by destroying the data source, then requesting data
|
|
|
|
dataSource4.reset();
|
|
|
|
int pipeFds[2];
|
|
|
|
Q_ASSERT(pipe(pipeFds) == 0);
|
|
|
|
|
|
|
|
dataOffer->receive(QStringLiteral("text/plain"), pipeFds[1]);
|
|
|
|
close(pipeFds[1]);
|
|
|
|
|
|
|
|
//spin the event loop, nothing should explode
|
|
|
|
QTest::qWait(10);
|
|
|
|
|
|
|
|
close(pipeFds[0]);
|
2016-09-12 06:57:07 +00:00
|
|
|
}
|
|
|
|
|
2014-11-06 09:02:49 +00:00
|
|
|
void TestDataDevice::testDestroy()
|
|
|
|
{
|
|
|
|
using namespace KWayland::Client;
|
|
|
|
|
|
|
|
QScopedPointer<DataDevice> dataDevice(m_dataDeviceManager->getDataDevice(m_seat));
|
|
|
|
QVERIFY(dataDevice->isValid());
|
|
|
|
|
|
|
|
connect(m_connection, &ConnectionThread::connectionDied, m_dataDeviceManager, &DataDeviceManager::destroy);
|
|
|
|
connect(m_connection, &ConnectionThread::connectionDied, m_seat, &Seat::destroy);
|
|
|
|
connect(m_connection, &ConnectionThread::connectionDied, m_compositor, &Compositor::destroy);
|
|
|
|
connect(m_connection, &ConnectionThread::connectionDied, dataDevice.data(), &DataDevice::destroy);
|
|
|
|
connect(m_connection, &ConnectionThread::connectionDied, m_queue, &EventQueue::destroy);
|
|
|
|
|
2021-02-25 13:48:11 +00:00
|
|
|
QSignalSpy connectionDiedSpy(m_connection, &KWayland::Client::ConnectionThread::connectionDied);
|
2014-11-06 09:02:49 +00:00
|
|
|
QVERIFY(connectionDiedSpy.isValid());
|
|
|
|
delete m_display;
|
|
|
|
m_display = nullptr;
|
|
|
|
QVERIFY(connectionDiedSpy.wait());
|
|
|
|
|
|
|
|
// now the data device should be destroyed;
|
|
|
|
QVERIFY(!dataDevice->isValid());
|
|
|
|
|
|
|
|
// calling destroy again should not fail
|
|
|
|
dataDevice->destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
QTEST_GUILESS_MAIN(TestDataDevice)
|
|
|
|
#include "test_datadevice.moc"
|