Changeset View
Changeset View
Standalone View
Standalone View
autotests/client/test_drag_drop.cpp
Show All 21 Lines | |||||
22 | // KWin | 22 | // KWin | ||
23 | #include "../../src/client/compositor.h" | 23 | #include "../../src/client/compositor.h" | ||
24 | #include "../../src/client/connection_thread.h" | 24 | #include "../../src/client/connection_thread.h" | ||
25 | #include "../../src/client/datadevice.h" | 25 | #include "../../src/client/datadevice.h" | ||
26 | #include "../../src/client/datadevicemanager.h" | 26 | #include "../../src/client/datadevicemanager.h" | ||
27 | #include "../../src/client/datasource.h" | 27 | #include "../../src/client/datasource.h" | ||
28 | #include "../../src/client/event_queue.h" | 28 | #include "../../src/client/event_queue.h" | ||
29 | #include "../../src/client/pointer.h" | 29 | #include "../../src/client/pointer.h" | ||
30 | #include "../../src/client/touch.h" | ||||
30 | #include "../../src/client/registry.h" | 31 | #include "../../src/client/registry.h" | ||
31 | #include "../../src/client/seat.h" | 32 | #include "../../src/client/seat.h" | ||
32 | #include "../../src/client/shell.h" | 33 | #include "../../src/client/shell.h" | ||
33 | #include "../../src/client/shm_pool.h" | 34 | #include "../../src/client/shm_pool.h" | ||
34 | #include "../../src/client/surface.h" | 35 | #include "../../src/client/surface.h" | ||
35 | #include "../../src/server/display.h" | 36 | #include "../../src/server/display.h" | ||
36 | #include "../../src/server/compositor_interface.h" | 37 | #include "../../src/server/compositor_interface.h" | ||
37 | #include "../../src/server/datadevicemanager_interface.h" | 38 | #include "../../src/server/datadevicemanager_interface.h" | ||
38 | #include "../../src/server/datasource_interface.h" | 39 | #include "../../src/server/datasource_interface.h" | ||
39 | #include "../../src/server/seat_interface.h" | 40 | #include "../../src/server/seat_interface.h" | ||
40 | #include "../../src/server/shell_interface.h" | 41 | #include "../../src/server/shell_interface.h" | ||
41 | 42 | | |||
42 | class TestDragAndDrop : public QObject | 43 | class TestDragAndDrop : public QObject | ||
43 | { | 44 | { | ||
44 | Q_OBJECT | 45 | Q_OBJECT | ||
45 | 46 | | |||
46 | private Q_SLOTS: | 47 | private Q_SLOTS: | ||
47 | void init(); | 48 | void init(); | ||
48 | void cleanup(); | 49 | void cleanup(); | ||
49 | 50 | | |||
50 | void testDragAndDrop(); | 51 | void testPointerDragAndDrop(); | ||
52 | void testTouchDragAndDrop(); | ||||
51 | void testDragAndDropWithCancelByDestroyDataSource(); | 53 | void testDragAndDropWithCancelByDestroyDataSource(); | ||
52 | void testPointerEventsIgnored(); | 54 | void testPointerEventsIgnored(); | ||
53 | 55 | | |||
54 | private: | 56 | private: | ||
55 | KWayland::Client::Surface *createSurface(); | 57 | KWayland::Client::Surface *createSurface(); | ||
56 | KWayland::Server::SurfaceInterface *getServerSurface(); | 58 | KWayland::Server::SurfaceInterface *getServerSurface(); | ||
57 | 59 | | |||
58 | KWayland::Server::Display *m_display = nullptr; | 60 | KWayland::Server::Display *m_display = nullptr; | ||
59 | KWayland::Server::CompositorInterface *m_compositorInterface = nullptr; | 61 | KWayland::Server::CompositorInterface *m_compositorInterface = nullptr; | ||
60 | KWayland::Server::DataDeviceManagerInterface *m_dataDeviceManagerInterface = nullptr; | 62 | KWayland::Server::DataDeviceManagerInterface *m_dataDeviceManagerInterface = nullptr; | ||
61 | KWayland::Server::SeatInterface *m_seatInterface = nullptr; | 63 | KWayland::Server::SeatInterface *m_seatInterface = nullptr; | ||
62 | KWayland::Server::ShellInterface *m_shellInterface = nullptr; | 64 | KWayland::Server::ShellInterface *m_shellInterface = nullptr; | ||
63 | KWayland::Client::ConnectionThread *m_connection = nullptr; | 65 | KWayland::Client::ConnectionThread *m_connection = nullptr; | ||
64 | KWayland::Client::Compositor *m_compositor = nullptr; | 66 | KWayland::Client::Compositor *m_compositor = nullptr; | ||
65 | KWayland::Client::EventQueue *m_queue = nullptr; | 67 | KWayland::Client::EventQueue *m_queue = nullptr; | ||
66 | KWayland::Client::DataDevice *m_dataDevice = nullptr; | 68 | KWayland::Client::DataDevice *m_dataDevice = nullptr; | ||
67 | KWayland::Client::DataSource *m_dataSource = nullptr; | 69 | KWayland::Client::DataSource *m_dataSource = nullptr; | ||
68 | QThread *m_thread = nullptr; | 70 | QThread *m_thread = nullptr; | ||
69 | KWayland::Client::Registry *m_registry = nullptr; | 71 | KWayland::Client::Registry *m_registry = nullptr; | ||
70 | KWayland::Client::Seat *m_seat = nullptr; | 72 | KWayland::Client::Seat *m_seat = nullptr; | ||
71 | KWayland::Client::Pointer *m_pointer = nullptr; | 73 | KWayland::Client::Pointer *m_pointer = nullptr; | ||
74 | KWayland::Client::Touch *m_touch = nullptr; | ||||
72 | KWayland::Client::DataDeviceManager *m_ddm = nullptr; | 75 | KWayland::Client::DataDeviceManager *m_ddm = nullptr; | ||
73 | KWayland::Client::ShmPool *m_shm = nullptr; | 76 | KWayland::Client::ShmPool *m_shm = nullptr; | ||
74 | KWayland::Client::Shell *m_shell = nullptr; | 77 | KWayland::Client::Shell *m_shell = nullptr; | ||
75 | }; | 78 | }; | ||
76 | 79 | | |||
77 | static const QString s_socketName = QStringLiteral("kwayland-test-wayland-drag-n-drop-0"); | 80 | static const QString s_socketName = QStringLiteral("kwayland-test-wayland-drag-n-drop-0"); | ||
78 | 81 | | |||
79 | void TestDragAndDrop::init() | 82 | void TestDragAndDrop::init() | ||
Show All 12 Lines | 83 | { | |||
92 | QVERIFY(connectedSpy.isValid()); | 95 | QVERIFY(connectedSpy.isValid()); | ||
93 | m_connection->setSocketName(s_socketName); | 96 | m_connection->setSocketName(s_socketName); | ||
94 | 97 | | |||
95 | m_compositorInterface = m_display->createCompositor(m_display); | 98 | m_compositorInterface = m_display->createCompositor(m_display); | ||
96 | m_compositorInterface->create(); | 99 | m_compositorInterface->create(); | ||
97 | QVERIFY(m_compositorInterface->isValid()); | 100 | QVERIFY(m_compositorInterface->isValid()); | ||
98 | m_seatInterface = m_display->createSeat(m_display); | 101 | m_seatInterface = m_display->createSeat(m_display); | ||
99 | m_seatInterface->setHasPointer(true); | 102 | m_seatInterface->setHasPointer(true); | ||
103 | m_seatInterface->setHasTouch(true); | ||||
100 | m_seatInterface->create(); | 104 | m_seatInterface->create(); | ||
101 | QVERIFY(m_seatInterface->isValid()); | 105 | QVERIFY(m_seatInterface->isValid()); | ||
102 | m_dataDeviceManagerInterface = m_display->createDataDeviceManager(m_display); | 106 | m_dataDeviceManagerInterface = m_display->createDataDeviceManager(m_display); | ||
103 | m_dataDeviceManagerInterface->create(); | 107 | m_dataDeviceManagerInterface->create(); | ||
104 | QVERIFY(m_dataDeviceManagerInterface->isValid()); | 108 | QVERIFY(m_dataDeviceManagerInterface->isValid()); | ||
105 | m_display->createShm(); | 109 | m_display->createShm(); | ||
106 | m_shellInterface = m_display->createShell(m_display); | 110 | m_shellInterface = m_display->createShell(m_display); | ||
107 | m_shellInterface->create(); | 111 | m_shellInterface->create(); | ||
Show All 34 Lines | |||||
142 | 146 | | |||
143 | #undef CREATE | 147 | #undef CREATE | ||
144 | 148 | | |||
145 | QSignalSpy pointerSpy(m_seat, &Seat::hasPointerChanged); | 149 | QSignalSpy pointerSpy(m_seat, &Seat::hasPointerChanged); | ||
146 | QVERIFY(pointerSpy.isValid()); | 150 | QVERIFY(pointerSpy.isValid()); | ||
147 | QVERIFY(pointerSpy.wait()); | 151 | QVERIFY(pointerSpy.wait()); | ||
148 | m_pointer = m_seat->createPointer(m_seat); | 152 | m_pointer = m_seat->createPointer(m_seat); | ||
149 | QVERIFY(m_pointer->isValid()); | 153 | QVERIFY(m_pointer->isValid()); | ||
154 | m_touch = m_seat->createTouch(m_seat); | ||||
155 | QVERIFY(m_touch->isValid()); | ||||
150 | m_dataDevice = m_ddm->getDataDevice(m_seat, this); | 156 | m_dataDevice = m_ddm->getDataDevice(m_seat, this); | ||
151 | QVERIFY(m_dataDevice->isValid()); | 157 | QVERIFY(m_dataDevice->isValid()); | ||
152 | m_dataSource = m_ddm->createDataSource(this); | 158 | m_dataSource = m_ddm->createDataSource(this); | ||
153 | QVERIFY(m_dataSource->isValid()); | 159 | QVERIFY(m_dataSource->isValid()); | ||
154 | m_dataSource->offer(QStringLiteral("text/plain")); | 160 | m_dataSource->offer(QStringLiteral("text/plain")); | ||
155 | } | 161 | } | ||
156 | 162 | | |||
157 | void TestDragAndDrop::cleanup() | 163 | void TestDragAndDrop::cleanup() | ||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Line(s) | 210 | if (!surfaceCreatedSpy.isValid()) { | |||
205 | return nullptr; | 211 | return nullptr; | ||
206 | } | 212 | } | ||
207 | if (!surfaceCreatedSpy.wait(500)) { | 213 | if (!surfaceCreatedSpy.wait(500)) { | ||
208 | return nullptr; | 214 | return nullptr; | ||
209 | } | 215 | } | ||
210 | return surfaceCreatedSpy.first().first().value<SurfaceInterface*>(); | 216 | return surfaceCreatedSpy.first().first().value<SurfaceInterface*>(); | ||
211 | } | 217 | } | ||
212 | 218 | | |||
213 | void TestDragAndDrop::testDragAndDrop() | 219 | void TestDragAndDrop::testPointerDragAndDrop() | ||
214 | { | 220 | { | ||
215 | // this test verifies the very basic drag and drop on one surface, an enter, a move and the drop | 221 | // this test verifies the very basic drag and drop on one surface, an enter, a move and the drop | ||
216 | using namespace KWayland::Server; | 222 | using namespace KWayland::Server; | ||
217 | using namespace KWayland::Client; | 223 | using namespace KWayland::Client; | ||
218 | // first create a window | 224 | // first create a window | ||
219 | QScopedPointer<Surface> s(createSurface()); | 225 | QScopedPointer<Surface> s(createSurface()); | ||
220 | auto serverSurface = getServerSurface(); | 226 | auto serverSurface = getServerSurface(); | ||
221 | QVERIFY(serverSurface); | 227 | QVERIFY(serverSurface); | ||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Line(s) | |||||
298 | QVERIFY(finishedSpy.wait()); | 304 | QVERIFY(finishedSpy.wait()); | ||
299 | delete offer; | 305 | delete offer; | ||
300 | 306 | | |||
301 | // verify that we did not get any further input events | 307 | // verify that we did not get any further input events | ||
302 | QVERIFY(pointerMotionSpy.isEmpty()); | 308 | QVERIFY(pointerMotionSpy.isEmpty()); | ||
303 | QCOMPARE(buttonPressSpy.count(), 1); | 309 | QCOMPARE(buttonPressSpy.count(), 1); | ||
304 | } | 310 | } | ||
305 | 311 | | |||
312 | void TestDragAndDrop::testTouchDragAndDrop() | ||||
313 | { | ||||
314 | // this test verifies the very basic drag and drop on one surface, an enter, a move and the drop | ||||
315 | using namespace KWayland::Server; | ||||
316 | using namespace KWayland::Client; | ||||
317 | // first create a window | ||||
318 | QScopedPointer<Surface> s(createSurface()); | ||||
319 | s->setSize(QSize(100,100)); | ||||
320 | auto serverSurface = getServerSurface(); | ||||
321 | QVERIFY(serverSurface); | ||||
322 | | ||||
323 | QSignalSpy dataSourceSelectedActionChangedSpy(m_dataSource, &DataSource::selectedDragAndDropActionChanged); | ||||
324 | QVERIFY(dataSourceSelectedActionChangedSpy.isValid()); | ||||
325 | | ||||
326 | // now we need to pass touch focus to the Surface and simulate a touch down | ||||
327 | QSignalSpy sequenceStartedSpy(m_touch, &Touch::sequenceStarted); | ||||
328 | QVERIFY(sequenceStartedSpy.isValid()); | ||||
329 | QSignalSpy pointAddedSpy(m_touch, &Touch::pointAdded); | ||||
330 | QVERIFY(pointAddedSpy.isValid()); | ||||
331 | m_seatInterface->setFocusedTouchSurface(serverSurface); | ||||
332 | m_seatInterface->setTimestamp(2); | ||||
333 | const qint32 touchId = m_seatInterface->touchDown(QPointF(50,50)); | ||||
334 | QVERIFY(sequenceStartedSpy.wait()); | ||||
335 | | ||||
336 | QScopedPointer<TouchPoint> tp(sequenceStartedSpy.first().at(0).value<TouchPoint*>()); | ||||
337 | QVERIFY(!tp.isNull()); | ||||
338 | QCOMPARE(tp->time(), quint32(2)); | ||||
339 | | ||||
340 | // add some signal spies for client side | ||||
341 | QSignalSpy dragEnteredSpy(m_dataDevice, &DataDevice::dragEntered); | ||||
342 | QVERIFY(dragEnteredSpy.isValid()); | ||||
343 | QSignalSpy dragMotionSpy(m_dataDevice, &DataDevice::dragMotion); | ||||
344 | QVERIFY(dragMotionSpy.isValid()); | ||||
345 | QSignalSpy touchMotionSpy(m_touch, &Touch::pointMoved); | ||||
346 | QVERIFY(touchMotionSpy.isValid()); | ||||
347 | QSignalSpy sourceDropSpy(m_dataSource, &DataSource::dragAndDropPerformed); | ||||
348 | QVERIFY(sourceDropSpy.isValid()); | ||||
349 | | ||||
350 | // now we can start the drag and drop | ||||
351 | QSignalSpy dragStartedSpy(m_seatInterface, &SeatInterface::dragStarted); | ||||
352 | QVERIFY(dragStartedSpy.isValid()); | ||||
353 | m_dataSource->setDragAndDropActions(DataDeviceManager::DnDAction::Copy | DataDeviceManager::DnDAction::Move); | ||||
354 | m_dataDevice->startDrag(tp->downSerial(), m_dataSource, s.data()); | ||||
355 | QVERIFY(dragStartedSpy.wait()); | ||||
356 | QCOMPARE(m_seatInterface->dragSurface(), serverSurface); | ||||
357 | QCOMPARE(m_seatInterface->dragSurfaceTransformation(), QMatrix4x4()); | ||||
358 | QVERIFY(!m_seatInterface->dragSource()->icon()); | ||||
359 | QCOMPARE(m_seatInterface->dragSource()->dragImplicitGrabSerial(), tp->downSerial()); | ||||
360 | QVERIFY(dragEnteredSpy.wait()); | ||||
361 | QCOMPARE(dragEnteredSpy.count(), 1); | ||||
362 | QCOMPARE(dragEnteredSpy.first().first().value<quint32>(), m_display->serial()); | ||||
363 | QCOMPARE(dragEnteredSpy.first().last().toPointF(), QPointF(0, 0)); | ||||
364 | QCOMPARE(m_dataDevice->dragSurface().data(), s.data()); | ||||
365 | auto offer = m_dataDevice->dragOffer(); | ||||
366 | QVERIFY(offer); | ||||
367 | QCOMPARE(offer->selectedDragAndDropAction(), DataDeviceManager::DnDAction::None); | ||||
368 | QSignalSpy offerActionChangedSpy(offer, &DataOffer::selectedDragAndDropActionChanged); | ||||
369 | QVERIFY(offerActionChangedSpy.isValid()); | ||||
370 | QCOMPARE(m_dataDevice->dragOffer()->offeredMimeTypes().count(), 1); | ||||
371 | QCOMPARE(m_dataDevice->dragOffer()->offeredMimeTypes().first().name(), QStringLiteral("text/plain")); | ||||
372 | QTRY_COMPARE(offer->sourceDragAndDropActions(), DataDeviceManager::DnDAction::Copy | DataDeviceManager::DnDAction::Move); | ||||
373 | offer->setDragAndDropActions(DataDeviceManager::DnDAction::Copy | DataDeviceManager::DnDAction::Move, DataDeviceManager::DnDAction::Move); | ||||
374 | QVERIFY(offerActionChangedSpy.wait()); | ||||
375 | QCOMPARE(offerActionChangedSpy.count(), 1); | ||||
376 | QCOMPARE(offer->selectedDragAndDropAction(), DataDeviceManager::DnDAction::Move); | ||||
377 | QCOMPARE(dataSourceSelectedActionChangedSpy.count(), 1); | ||||
378 | QCOMPARE(m_dataSource->selectedDragAndDropAction(), DataDeviceManager::DnDAction::Move); | ||||
379 | | ||||
380 | // simulate motion | ||||
381 | m_seatInterface->setTimestamp(3); | ||||
382 | m_seatInterface->touchMove(touchId, QPointF(75, 75)); | ||||
383 | QVERIFY(dragMotionSpy.wait()); | ||||
384 | QCOMPARE(dragMotionSpy.count(), 1); | ||||
385 | QCOMPARE(dragMotionSpy.first().first().toPointF(), QPointF(75, 75)); | ||||
386 | QCOMPARE(dragMotionSpy.first().last().toUInt(), 3u); | ||||
387 | | ||||
388 | // simulate drop | ||||
389 | QSignalSpy serverDragEndedSpy(m_seatInterface, &SeatInterface::dragEnded); | ||||
390 | QVERIFY(serverDragEndedSpy.isValid()); | ||||
391 | QSignalSpy droppedSpy(m_dataDevice, &DataDevice::dropped); | ||||
392 | QVERIFY(droppedSpy.isValid()); | ||||
393 | m_seatInterface->setTimestamp(4); | ||||
394 | m_seatInterface->touchUp(touchId); | ||||
395 | QVERIFY(sourceDropSpy.isEmpty()); | ||||
396 | QVERIFY(droppedSpy.wait()); | ||||
397 | QCOMPARE(sourceDropSpy.count(), 1); | ||||
398 | QCOMPARE(serverDragEndedSpy.count(), 1); | ||||
399 | | ||||
400 | QSignalSpy finishedSpy(m_dataSource, &DataSource::dragAndDropFinished); | ||||
401 | QVERIFY(finishedSpy.isValid()); | ||||
402 | offer->dragAndDropFinished(); | ||||
403 | QVERIFY(finishedSpy.wait()); | ||||
404 | delete offer; | ||||
405 | | ||||
406 | // verify that we did not get any further input events | ||||
407 | QVERIFY(touchMotionSpy.isEmpty()); | ||||
408 | QCOMPARE(pointAddedSpy.count(), 0); | ||||
409 | } | ||||
410 | | ||||
306 | 411 | | |||
307 | void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource() | 412 | void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource() | ||
308 | { | 413 | { | ||
309 | // this test simulates the problem from BUG 389221 | 414 | // this test simulates the problem from BUG 389221 | ||
310 | using namespace KWayland::Server; | 415 | using namespace KWayland::Server; | ||
311 | using namespace KWayland::Client; | 416 | using namespace KWayland::Client; | ||
312 | // first create a window | 417 | // first create a window | ||
313 | QScopedPointer<Surface> s(createSurface()); | 418 | QScopedPointer<Surface> s(createSurface()); | ||
▲ Show 20 Lines • Show All 167 Lines • Show Last 20 Lines |