1 /********************************************************************
2 Copyright © 2016 Martin Gräßlin <mgraesslin@kde.org>
3 Copyright © 2020 Roman Gilg <subdiff@gmail.com>
4 
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) version 3, or any
9 later version accepted by the membership of KDE e.V. (or its
10 successor approved by the membership of KDE e.V.), which shall
11 act as a proxy defined in Section 6 of version 3 of the license.
12 
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 Lesser General Public License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library.  If not, see <http://www.gnu.org/licenses/>.
20 *********************************************************************/
21 #include <QtTest>
22 
23 #include "../../src/client/compositor.h"
24 #include "../../src/client/connection_thread.h"
25 #include "../../src/client/datadevice.h"
26 #include "../../src/client/datadevicemanager.h"
27 #include "../../src/client/datasource.h"
28 #include "../../src/client/event_queue.h"
29 #include "../../src/client/pointer.h"
30 #include "../../src/client/registry.h"
31 #include "../../src/client/seat.h"
32 #include "../../src/client/shm_pool.h"
33 #include "../../src/client/surface.h"
34 #include "../../src/client/touch.h"
35 
36 #include "../../server/compositor.h"
37 #include "../../server/data_device.h"
38 #include "../../server/data_device_manager.h"
39 #include "../../server/data_source.h"
40 #include "../../server/display.h"
41 #include "../../server/drag_pool.h"
42 #include "../../server/pointer_pool.h"
43 #include "../../server/seat.h"
44 #include "../../server/surface.h"
45 #include "../../server/touch_pool.h"
46 
47 class TestDragAndDrop : public QObject
48 {
49     Q_OBJECT
50 
51 private Q_SLOTS:
52     void init();
53     void cleanup();
54 
55     void test_pointer();
56     void test_touch();
57     void test_cancel_by_destroyed_data_source();
58     void test_target_removed();
59     void test_pointer_events_ignored();
60 
61 private:
62     struct Client;
63     Wrapland::Client::Surface* create_surface(Client& client);
64     Wrapland::Server::Surface* get_server_surface();
65 
66     Wrapland::Server::Display* m_display = nullptr;
67     Wrapland::Server::Compositor* m_server_compositor = nullptr;
68     Wrapland::Server::DataDeviceManager* m_server_device_manager = nullptr;
69     Wrapland::Server::Seat* m_server_seat = nullptr;
70 
71     struct Client {
72         Wrapland::Client::ConnectionThread* connection = nullptr;
73         QThread* thread = nullptr;
74         Wrapland::Client::EventQueue* queue = nullptr;
75         Wrapland::Client::Compositor* compositor = nullptr;
76         Wrapland::Client::Registry* registry = nullptr;
77         Wrapland::Client::DataDevice* device = nullptr;
78         Wrapland::Server::DataDevice* server_device{nullptr};
79         Wrapland::Client::DataSource* source = nullptr;
80         Wrapland::Client::Seat* seat = nullptr;
81         Wrapland::Client::Pointer* pointer = nullptr;
82         Wrapland::Client::Touch* touch = nullptr;
83         Wrapland::Client::DataDeviceManager* ddm = nullptr;
84         Wrapland::Client::ShmPool* shm = nullptr;
85     } c_1, c_2;
86     Client* clients[2] = {&c_1, &c_2};
87 };
88 
89 static const QString s_socketName = QStringLiteral("wrapland-test-wayland-drag-n-drop-0");
90 
init()91 void TestDragAndDrop::init()
92 {
93     qRegisterMetaType<Wrapland::Server::DataDevice*>();
94     qRegisterMetaType<Wrapland::Server::Surface*>();
95 
96     m_display = new Wrapland::Server::Display(this);
97     m_display->setSocketName(s_socketName);
98     m_display->start();
99 
100     m_server_compositor = m_display->createCompositor(m_display);
101     m_server_seat = m_display->createSeat(m_display);
102     m_server_seat->setHasPointer(true);
103     m_server_seat->setHasTouch(true);
104 
105     m_server_device_manager = m_display->createDataDeviceManager(m_display);
106     m_display->createShm();
107 
108     for (auto client : clients) {
109         // setup connection
110         client->connection = new Wrapland::Client::ConnectionThread;
111         QSignalSpy connected_spy(client->connection,
112                                  &Wrapland::Client::ConnectionThread::establishedChanged);
113         QVERIFY(connected_spy.isValid());
114         client->connection->setSocketName(s_socketName);
115 
116         client->thread = new QThread(this);
117         client->connection->moveToThread(client->thread);
118         client->thread->start();
119 
120         client->connection->establishConnection();
121         QVERIFY(connected_spy.count() || connected_spy.wait());
122         QCOMPARE(connected_spy.count(), 1);
123 
124         client->queue = new Wrapland::Client::EventQueue(this);
125         QVERIFY(!client->queue->isValid());
126         client->queue->setup(client->connection);
127         QVERIFY(client->queue->isValid());
128 
129         client->registry = new Wrapland::Client::Registry();
130         QSignalSpy interfaces_announced_spy(client->registry,
131                                             &Wrapland::Client::Registry::interfaceAnnounced);
132         QVERIFY(interfaces_announced_spy.isValid());
133 
134         QVERIFY(!client->registry->eventQueue());
135         client->registry->setEventQueue(client->queue);
136         QCOMPARE(client->registry->eventQueue(), client->queue);
137         client->registry->create(client->connection);
138         QVERIFY(client->registry->isValid());
139         client->registry->setup();
140 
141         QVERIFY(interfaces_announced_spy.wait());
142 #define CREATE(variable, factory, iface)                                                           \
143     variable = client->registry->create##factory(                                                  \
144         client->registry->interface(Wrapland::Client::Registry::Interface::iface).name,            \
145         client->registry->interface(Wrapland::Client::Registry::Interface::iface).version,         \
146         this);                                                                                     \
147     QVERIFY(variable);
148 
149         CREATE(client->compositor, Compositor, Compositor)
150         CREATE(client->seat, Seat, Seat)
151         CREATE(client->ddm, DataDeviceManager, DataDeviceManager)
152         CREATE(client->shm, ShmPool, Shm)
153 
154 #undef CREATE
155 
156         QSignalSpy pointerSpy(client->seat, &Wrapland::Client::Seat::hasPointerChanged);
157         QVERIFY(pointerSpy.isValid());
158         QVERIFY(pointerSpy.wait());
159         client->pointer = client->seat->createPointer(client->seat);
160         QVERIFY(client->pointer->isValid());
161         client->touch = client->seat->createTouch(client->seat);
162         QVERIFY(client->touch->isValid());
163 
164         QSignalSpy device_created_spy(m_server_device_manager,
165                                       &Wrapland::Server::DataDeviceManager::deviceCreated);
166         QVERIFY(device_created_spy.isValid());
167         client->device = client->ddm->getDevice(client->seat, this);
168         QVERIFY(client->device->isValid());
169 
170         QVERIFY(device_created_spy.wait());
171         QCOMPARE(device_created_spy.count(), 1);
172         client->server_device
173             = device_created_spy.first().first().value<Wrapland::Server::DataDevice*>();
174         QVERIFY(client->server_device);
175 
176         client->source = client->ddm->createSource(this);
177         QVERIFY(client->source->isValid());
178         client->source->offer(QStringLiteral("text/plain"));
179     }
180 }
181 
cleanup()182 void TestDragAndDrop::cleanup()
183 {
184     for (auto client : clients) {
185 #define DELETE(name)                                                                               \
186     if (name) {                                                                                    \
187         delete name;                                                                               \
188         name = nullptr;                                                                            \
189     }
190         DELETE(client->source)
191         DELETE(client->device)
192         DELETE(client->shm)
193         DELETE(client->compositor)
194         DELETE(client->ddm)
195         DELETE(client->seat)
196         DELETE(client->queue)
197         DELETE(client->registry)
198 #undef DELETE
199         if (client->thread) {
200             client->thread->quit();
201             client->thread->wait();
202             delete client->thread;
203             client->thread = nullptr;
204         }
205         delete client->connection;
206         client->connection = nullptr;
207     }
208 
209     delete m_display;
210     m_display = nullptr;
211 }
212 
create_surface(Client & client)213 Wrapland::Client::Surface* TestDragAndDrop::create_surface(Client& client)
214 {
215     auto surface = client.compositor->createSurface();
216 
217     QImage img(QSize(100, 200), QImage::Format_RGB32);
218     img.fill(Qt::red);
219     surface->attachBuffer(client.shm->createBuffer(img));
220     surface->damage(QRect(0, 0, 100, 200));
221     surface->commit(Wrapland::Client::Surface::CommitFlag::None);
222     return surface;
223 }
224 
get_server_surface()225 Wrapland::Server::Surface* TestDragAndDrop::get_server_surface()
226 {
227     QSignalSpy surface_created_spy(m_server_compositor,
228                                    &Wrapland::Server::Compositor::surfaceCreated);
229     if (!surface_created_spy.isValid()) {
230         return nullptr;
231     }
232     if (!surface_created_spy.wait(500)) {
233         return nullptr;
234     }
235     return surface_created_spy.first().first().value<Wrapland::Server::Surface*>();
236 }
237 
test_pointer()238 void TestDragAndDrop::test_pointer()
239 {
240     // This test verifies the very basic drag and drop on one surface, an enter, a move and the
241     // drop.
242 
243     // First create a window.
244     std::unique_ptr<Wrapland::Client::Surface> surface(create_surface(c_1));
245     auto server_surface = get_server_surface();
246     QVERIFY(server_surface);
247 
248     QSignalSpy source_selected_action_changed_spy(
249         c_1.source, &Wrapland::Client::DataSource::selectedDragAndDropActionChanged);
250     QVERIFY(source_selected_action_changed_spy.isValid());
251 
252     // now we need to pass pointer focus to the Surface and simulate a button press
253     QSignalSpy button_press_spy(c_1.pointer, &Wrapland::Client::Pointer::buttonStateChanged);
254     QVERIFY(button_press_spy.isValid());
255     m_server_seat->pointers().set_focused_surface(server_surface);
256     m_server_seat->setTimestamp(2);
257     m_server_seat->pointers().button_pressed(1);
258     QVERIFY(button_press_spy.wait());
259     QCOMPARE(button_press_spy.first().at(1).value<quint32>(), quint32(2));
260 
261     // add some signal spies for client side
262     QSignalSpy drag_entered_spy(c_1.device, &Wrapland::Client::DataDevice::dragEntered);
263     QVERIFY(drag_entered_spy.isValid());
264     QSignalSpy drag_motion_spy(c_1.device, &Wrapland::Client::DataDevice::dragMotion);
265     QVERIFY(drag_motion_spy.isValid());
266     QSignalSpy pointer_motion_spy(c_1.pointer, &Wrapland::Client::Pointer::motion);
267     QVERIFY(pointer_motion_spy.isValid());
268     QSignalSpy source_drop_spy(c_1.source, &Wrapland::Client::DataSource::dragAndDropPerformed);
269     QVERIFY(source_drop_spy.isValid());
270 
271     // now we can start the drag and drop
272     QSignalSpy drag_started_spy(m_server_seat, &Wrapland::Server::Seat::dragStarted);
273     QVERIFY(drag_started_spy.isValid());
274     c_1.source->setDragAndDropActions(Wrapland::Client::DataDeviceManager::DnDAction::Copy
275                                       | Wrapland::Client::DataDeviceManager::DnDAction::Move);
276     c_1.device->startDrag(
277         button_press_spy.first().first().value<quint32>(), c_1.source, surface.get());
278     QVERIFY(drag_started_spy.wait());
279 
280     auto& server_drags = m_server_seat->drags();
281     QCOMPARE(server_drags.get_target().surface, server_surface);
282     QCOMPARE(server_drags.get_target().transformation, QMatrix4x4());
283     QVERIFY(!server_drags.get_source().dev->icon());
284     QCOMPARE(server_drags.get_source().dev->dragImplicitGrabSerial(),
285              button_press_spy.first().first().value<quint32>());
286     QVERIFY(drag_entered_spy.wait());
287     QCOMPARE(drag_entered_spy.count(), 1);
288     QCOMPARE(drag_entered_spy.first().first().value<quint32>(), m_display->serial());
289     QCOMPARE(drag_entered_spy.first().last().toPointF(), QPointF(0, 0));
290     QCOMPARE(c_1.device->dragSurface().data(), surface.get());
291 
292     auto offer = c_1.device->dragOffer();
293     QVERIFY(offer);
294     QCOMPARE(offer->selectedDragAndDropAction(),
295              Wrapland::Client::DataDeviceManager::DnDAction::None);
296     QSignalSpy offer_action_changed_spy(
297         offer, &Wrapland::Client::DataOffer::selectedDragAndDropActionChanged);
298     QVERIFY(offer_action_changed_spy.isValid());
299     QCOMPARE(c_1.device->dragOffer()->offeredMimeTypes().count(), 1);
300     QCOMPARE(c_1.device->dragOffer()->offeredMimeTypes().first().name(),
301              QStringLiteral("text/plain"));
302     QTRY_COMPARE(offer->sourceDragAndDropActions(),
303                  Wrapland::Client::DataDeviceManager::DnDAction::Copy
304                      | Wrapland::Client::DataDeviceManager::DnDAction::Move);
305 
306     offer->setDragAndDropActions(Wrapland::Client::DataDeviceManager::DnDAction::Copy
307                                      | Wrapland::Client::DataDeviceManager::DnDAction::Move,
308                                  Wrapland::Client::DataDeviceManager::DnDAction::Move);
309     QVERIFY(offer_action_changed_spy.wait());
310     QCOMPARE(offer_action_changed_spy.count(), 1);
311     QCOMPARE(offer->selectedDragAndDropAction(),
312              Wrapland::Client::DataDeviceManager::DnDAction::Move);
313     QCOMPARE(source_selected_action_changed_spy.count(), 1);
314     QCOMPARE(c_1.source->selectedDragAndDropAction(),
315              Wrapland::Client::DataDeviceManager::DnDAction::Move);
316 
317     // Simulate motion.
318     m_server_seat->setTimestamp(3);
319     m_server_seat->pointers().set_position(QPointF(3, 3));
320     QVERIFY(drag_motion_spy.wait());
321     QCOMPARE(drag_motion_spy.count(), 1);
322     QCOMPARE(drag_motion_spy.first().first().toPointF(), QPointF(3, 3));
323     QCOMPARE(drag_motion_spy.first().last().toUInt(), 3u);
324 
325     // Simulate drop.
326     QSignalSpy server_drag_ended_spy(m_server_seat, &Wrapland::Server::Seat::dragEnded);
327     QVERIFY(server_drag_ended_spy.isValid());
328     QSignalSpy dropped_spy(c_1.device, &Wrapland::Client::DataDevice::dropped);
329     QVERIFY(dropped_spy.isValid());
330     m_server_seat->setTimestamp(4);
331     m_server_seat->pointers().button_released(1);
332     QVERIFY(source_drop_spy.isEmpty());
333     QVERIFY(dropped_spy.wait());
334     QCOMPARE(source_drop_spy.count(), 1);
335     QCOMPARE(server_drag_ended_spy.count(), 1);
336 
337     QSignalSpy finished_spy(c_1.source, &Wrapland::Client::DataSource::dragAndDropFinished);
338     QVERIFY(finished_spy.isValid());
339     offer->dragAndDropFinished();
340     QVERIFY(finished_spy.wait());
341     delete offer;
342 
343     // Verify that we did not get any further input events.
344     QVERIFY(pointer_motion_spy.isEmpty());
345     QCOMPARE(button_press_spy.count(), 1);
346 }
347 
test_touch()348 void TestDragAndDrop::test_touch()
349 {
350     // This test verifies the very basic drag and drop on one surface, an enter, a move and the
351     // drop.
352 
353     // First create a window.
354     std::unique_ptr<Wrapland::Client::Surface> s(create_surface(c_1));
355     s->setSize(QSize(100, 100));
356     auto server_surface = get_server_surface();
357     QVERIFY(server_surface);
358 
359     QSignalSpy source_selected_action_changed_spy(
360         c_1.source, &Wrapland::Client::DataSource::selectedDragAndDropActionChanged);
361     QVERIFY(source_selected_action_changed_spy.isValid());
362 
363     // now we need to pass touch focus to the Surface and simulate a touch down
364     QSignalSpy sequence_started_spy(c_1.touch, &Wrapland::Client::Touch::sequenceStarted);
365     QVERIFY(sequence_started_spy.isValid());
366     QSignalSpy point_added_spy(c_1.touch, &Wrapland::Client::Touch::pointAdded);
367     QVERIFY(point_added_spy.isValid());
368 
369     auto& server_touches = m_server_seat->touches();
370     server_touches.set_focused_surface(server_surface);
371     m_server_seat->setTimestamp(2);
372     auto const touchId = server_touches.touch_down(QPointF(50, 50));
373     QVERIFY(sequence_started_spy.wait());
374 
375     auto tp{sequence_started_spy.first().at(0).value<Wrapland::Client::TouchPoint*>()};
376     QVERIFY(tp);
377     QCOMPARE(tp->time(), quint32(2));
378 
379     // add some signal spies for client side
380     QSignalSpy drag_entered_spy(c_1.device, &Wrapland::Client::DataDevice::dragEntered);
381     QVERIFY(drag_entered_spy.isValid());
382     QSignalSpy drag_motion_spy(c_1.device, &Wrapland::Client::DataDevice::dragMotion);
383     QVERIFY(drag_motion_spy.isValid());
384     QSignalSpy touch_motion_spy(c_1.touch, &Wrapland::Client::Touch::pointMoved);
385     QVERIFY(touch_motion_spy.isValid());
386     QSignalSpy source_drop_spy(c_1.source, &Wrapland::Client::DataSource::dragAndDropPerformed);
387     QVERIFY(source_drop_spy.isValid());
388 
389     // now we can start the drag and drop
390     QSignalSpy drag_started_spy(m_server_seat, &Wrapland::Server::Seat::dragStarted);
391     QVERIFY(drag_started_spy.isValid());
392     c_1.source->setDragAndDropActions(Wrapland::Client::DataDeviceManager::DnDAction::Copy
393                                       | Wrapland::Client::DataDeviceManager::DnDAction::Move);
394     c_1.device->startDrag(tp->downSerial(), c_1.source, s.get());
395     QVERIFY(drag_started_spy.wait());
396 
397     auto& server_drags = m_server_seat->drags();
398     QCOMPARE(server_drags.get_target().surface, server_surface);
399     QCOMPARE(server_drags.get_target().transformation, QMatrix4x4());
400     QVERIFY(!server_drags.get_source().dev->icon());
401     QCOMPARE(server_drags.get_source().dev->dragImplicitGrabSerial(), tp->downSerial());
402     QVERIFY(drag_entered_spy.wait());
403     QCOMPARE(drag_entered_spy.count(), 1);
404     QCOMPARE(drag_entered_spy.first().first().value<quint32>(), m_display->serial());
405     QCOMPARE(drag_entered_spy.first().last().toPointF(), QPointF(0, 0));
406     QCOMPARE(c_1.device->dragSurface().data(), s.get());
407     auto offer = c_1.device->dragOffer();
408     QVERIFY(offer);
409     QCOMPARE(offer->selectedDragAndDropAction(),
410              Wrapland::Client::DataDeviceManager::DnDAction::None);
411     QSignalSpy offer_action_changed_spy(
412         offer, &Wrapland::Client::DataOffer::selectedDragAndDropActionChanged);
413     QVERIFY(offer_action_changed_spy.isValid());
414     QCOMPARE(c_1.device->dragOffer()->offeredMimeTypes().count(), 1);
415     QCOMPARE(c_1.device->dragOffer()->offeredMimeTypes().first().name(),
416              QStringLiteral("text/plain"));
417     QTRY_COMPARE(offer->sourceDragAndDropActions(),
418                  Wrapland::Client::DataDeviceManager::DnDAction::Copy
419                      | Wrapland::Client::DataDeviceManager::DnDAction::Move);
420     offer->setDragAndDropActions(Wrapland::Client::DataDeviceManager::DnDAction::Copy
421                                      | Wrapland::Client::DataDeviceManager::DnDAction::Move,
422                                  Wrapland::Client::DataDeviceManager::DnDAction::Move);
423     QVERIFY(offer_action_changed_spy.wait());
424     QCOMPARE(offer_action_changed_spy.count(), 1);
425     QCOMPARE(offer->selectedDragAndDropAction(),
426              Wrapland::Client::DataDeviceManager::DnDAction::Move);
427     QCOMPARE(source_selected_action_changed_spy.count(), 1);
428     QCOMPARE(c_1.source->selectedDragAndDropAction(),
429              Wrapland::Client::DataDeviceManager::DnDAction::Move);
430 
431     // simulate motion
432     m_server_seat->setTimestamp(3);
433     server_touches.touch_move(touchId, QPointF(75, 75));
434     QVERIFY(drag_motion_spy.wait());
435     QCOMPARE(drag_motion_spy.count(), 1);
436     QCOMPARE(drag_motion_spy.first().first().toPointF(), QPointF(75, 75));
437     QCOMPARE(drag_motion_spy.first().last().toUInt(), 3u);
438 
439     // simulate drop
440     QSignalSpy server_drag_ended_spy(m_server_seat, &Wrapland::Server::Seat::dragEnded);
441     QVERIFY(server_drag_ended_spy.isValid());
442     QSignalSpy dropped_spy(c_1.device, &Wrapland::Client::DataDevice::dropped);
443     QVERIFY(dropped_spy.isValid());
444     m_server_seat->setTimestamp(4);
445     server_touches.touch_up(touchId);
446     QVERIFY(source_drop_spy.isEmpty());
447     QVERIFY(dropped_spy.wait());
448     QCOMPARE(source_drop_spy.count(), 1);
449     QCOMPARE(server_drag_ended_spy.count(), 1);
450 
451     QSignalSpy finished_spy(c_1.source, &Wrapland::Client::DataSource::dragAndDropFinished);
452     QVERIFY(finished_spy.isValid());
453     offer->dragAndDropFinished();
454     QVERIFY(finished_spy.wait());
455     delete offer;
456 
457     // verify that we did not get any further input events
458     QVERIFY(touch_motion_spy.isEmpty());
459     QCOMPARE(point_added_spy.count(), 0);
460 }
461 
test_cancel_by_destroyed_data_source()462 void TestDragAndDrop::test_cancel_by_destroyed_data_source()
463 {
464     // This test simulates the problem from BUG 389221.
465 
466     // First create a window.
467     std::unique_ptr<Wrapland::Client::Surface> s(create_surface(c_1));
468     auto server_surface = get_server_surface();
469     QVERIFY(server_surface);
470 
471     QSignalSpy source_selected_action_changed_spy(
472         c_1.source, &Wrapland::Client::DataSource::selectedDragAndDropActionChanged);
473     QVERIFY(source_selected_action_changed_spy.isValid());
474 
475     // Now we need to pass pointer focus to the Surface and simulate a button press.
476     QSignalSpy button_press_spy(c_1.pointer, &Wrapland::Client::Pointer::buttonStateChanged);
477     QVERIFY(button_press_spy.isValid());
478     m_server_seat->pointers().set_focused_surface(server_surface);
479     m_server_seat->setTimestamp(2);
480     m_server_seat->pointers().button_pressed(1);
481     QVERIFY(button_press_spy.wait());
482     QCOMPARE(button_press_spy.first().at(1).value<quint32>(), quint32(2));
483 
484     // Add some signal spies for client side.
485     QSignalSpy drag_entered_spy(c_1.device, &Wrapland::Client::DataDevice::dragEntered);
486     QVERIFY(drag_entered_spy.isValid());
487     QSignalSpy drag_motion_spy(c_1.device, &Wrapland::Client::DataDevice::dragMotion);
488     QVERIFY(drag_motion_spy.isValid());
489     QSignalSpy pointer_motion_spy(c_1.pointer, &Wrapland::Client::Pointer::motion);
490     QVERIFY(pointer_motion_spy.isValid());
491     QSignalSpy drag_left_spy(c_1.device, &Wrapland::Client::DataDevice::dragLeft);
492     QVERIFY(drag_left_spy.isValid());
493 
494     // Now we can start the drag and drop.
495     QSignalSpy drag_started_spy(m_server_seat, &Wrapland::Server::Seat::dragStarted);
496     QVERIFY(drag_started_spy.isValid());
497 
498     c_1.source->setDragAndDropActions(Wrapland::Client::DataDeviceManager::DnDAction::Copy
499                                       | Wrapland::Client::DataDeviceManager::DnDAction::Move);
500     c_1.device->startDrag(button_press_spy.first().first().value<quint32>(), c_1.source, s.get());
501 
502     QVERIFY(drag_started_spy.wait());
503 
504     auto& server_drags = m_server_seat->drags();
505     QCOMPARE(server_drags.get_target().surface, server_surface);
506     QCOMPARE(server_drags.get_target().transformation, QMatrix4x4());
507     QVERIFY(!server_drags.get_source().dev->icon());
508     QCOMPARE(server_drags.get_source().dev->dragImplicitGrabSerial(),
509              button_press_spy.first().first().value<quint32>());
510 
511     QVERIFY(drag_entered_spy.wait());
512     QCOMPARE(drag_entered_spy.count(), 1);
513     QCOMPARE(drag_entered_spy.first().first().value<quint32>(), m_display->serial());
514     QCOMPARE(drag_entered_spy.first().last().toPointF(), QPointF(0, 0));
515     QCOMPARE(c_1.device->dragSurface().data(), s.get());
516 
517     auto offer = c_1.device->dragOffer();
518     QVERIFY(offer);
519     QCOMPARE(offer->selectedDragAndDropAction(),
520              Wrapland::Client::DataDeviceManager::DnDAction::None);
521     QSignalSpy offer_action_changed_spy(
522         offer, &Wrapland::Client::DataOffer::selectedDragAndDropActionChanged);
523     QVERIFY(offer_action_changed_spy.isValid());
524     QCOMPARE(c_1.device->dragOffer()->offeredMimeTypes().count(), 1);
525     QCOMPARE(c_1.device->dragOffer()->offeredMimeTypes().first().name(),
526              QStringLiteral("text/plain"));
527     QTRY_COMPARE(offer->sourceDragAndDropActions(),
528                  Wrapland::Client::DataDeviceManager::DnDAction::Copy
529                      | Wrapland::Client::DataDeviceManager::DnDAction::Move);
530 
531     offer->setDragAndDropActions(Wrapland::Client::DataDeviceManager::DnDAction::Copy
532                                      | Wrapland::Client::DataDeviceManager::DnDAction::Move,
533                                  Wrapland::Client::DataDeviceManager::DnDAction::Move);
534     QVERIFY(offer_action_changed_spy.wait());
535     QCOMPARE(offer_action_changed_spy.count(), 1);
536     QCOMPARE(offer->selectedDragAndDropAction(),
537              Wrapland::Client::DataDeviceManager::DnDAction::Move);
538     QCOMPARE(source_selected_action_changed_spy.count(), 1);
539     QCOMPARE(c_1.source->selectedDragAndDropAction(),
540              Wrapland::Client::DataDeviceManager::DnDAction::Move);
541 
542     // Simulate motion.
543     m_server_seat->setTimestamp(3);
544     m_server_seat->pointers().set_position(QPointF(3, 3));
545     QVERIFY(drag_motion_spy.wait());
546     QCOMPARE(drag_motion_spy.count(), 1);
547     QCOMPARE(drag_motion_spy.first().first().toPointF(), QPointF(3, 3));
548     QCOMPARE(drag_motion_spy.first().last().toUInt(), 3u);
549 
550     // Now delete the DataSource.
551     delete c_1.source;
552     c_1.source = nullptr;
553     QSignalSpy server_drag_ended_spy(m_server_seat, &Wrapland::Server::Seat::dragEnded);
554     QVERIFY(server_drag_ended_spy.isValid());
555     QVERIFY(drag_left_spy.isEmpty());
556     QVERIFY(drag_left_spy.wait());
557     QTRY_COMPARE(drag_left_spy.count(), 1);
558     QTRY_COMPARE(server_drag_ended_spy.count(), 1);
559 
560     // Simulate drop.
561     QSignalSpy dropped_spy(c_1.device, &Wrapland::Client::DataDevice::dropped);
562     QVERIFY(dropped_spy.isValid());
563     m_server_seat->setTimestamp(4);
564     m_server_seat->pointers().button_released(1);
565     QVERIFY(!dropped_spy.wait(500));
566 
567     // Verify that we did not get any further input events.
568     QVERIFY(pointer_motion_spy.isEmpty());
569     QCOMPARE(button_press_spy.count(), 2);
570 }
571 
test_target_removed()572 void TestDragAndDrop::test_target_removed()
573 {
574     // Checks that if target goes away mid-drag server handles this correctly.
575 
576     std::unique_ptr<Wrapland::Client::Surface> surface_1(create_surface(c_1));
577     auto server_surface_1 = get_server_surface();
578     QVERIFY(server_surface_1);
579     std::unique_ptr<Wrapland::Client::Surface> surface_2(create_surface(c_2));
580     auto server_surface_2 = get_server_surface();
581     QVERIFY(server_surface_2);
582 
583     QSignalSpy source_selected_action_changed_spy(
584         c_1.source, &Wrapland::Client::DataSource::selectedDragAndDropActionChanged);
585     QVERIFY(source_selected_action_changed_spy.isValid());
586 
587     // Now we need to pass pointer focus to the Surface and simulate a button press.
588     QSignalSpy button_press_spy(c_1.pointer, &Wrapland::Client::Pointer::buttonStateChanged);
589     QVERIFY(button_press_spy.isValid());
590     m_server_seat->pointers().set_focused_surface(server_surface_1);
591     m_server_seat->setTimestamp(2);
592     m_server_seat->pointers().button_pressed(1);
593     QVERIFY(button_press_spy.wait());
594     QCOMPARE(button_press_spy.first().at(1).value<quint32>(), quint32(2));
595 
596     // Now we can start the drag and drop.
597     QSignalSpy drag_started_spy(m_server_seat, &Wrapland::Server::Seat::dragStarted);
598     QVERIFY(drag_started_spy.isValid());
599 
600     c_1.source->setDragAndDropActions(Wrapland::Client::DataDeviceManager::DnDAction::Copy
601                                       | Wrapland::Client::DataDeviceManager::DnDAction::Move);
602     c_1.device->startDrag(
603         button_press_spy.first().first().value<quint32>(), c_1.source, surface_1.get());
604 
605     QVERIFY(drag_started_spy.wait());
606 
607     auto& server_drags = m_server_seat->drags();
608     QCOMPARE(server_drags.get_target().surface, server_surface_1);
609     QCOMPARE(server_drags.get_target().transformation, QMatrix4x4());
610     QVERIFY(!server_drags.get_source().dev->icon());
611     QCOMPARE(server_drags.get_source().dev->dragImplicitGrabSerial(),
612              button_press_spy.first().first().value<quint32>());
613 
614     QSignalSpy drag_entered_spy(c_2.device, &Wrapland::Client::DataDevice::dragEntered);
615     QVERIFY(drag_entered_spy.isValid());
616 
617     // Now move drag to the second client.
618     server_drags.set_target(server_surface_2);
619     QCOMPARE(server_drags.get_target().surface, server_surface_2);
620 
621     QVERIFY(drag_entered_spy.wait());
622     QCOMPARE(drag_entered_spy.count(), 1);
623     QCOMPARE(drag_entered_spy.first().first().value<quint32>(), m_display->serial());
624     QCOMPARE(drag_entered_spy.first().last().toPointF(), QPointF(0, 0));
625     QCOMPARE(c_2.device->dragSurface().data(), surface_2.get());
626 
627     auto offer = c_2.device->dragOffer();
628     QVERIFY(offer);
629     QCOMPARE(offer->selectedDragAndDropAction(),
630              Wrapland::Client::DataDeviceManager::DnDAction::None);
631     QSignalSpy offer_action_changed_spy(
632         offer, &Wrapland::Client::DataOffer::selectedDragAndDropActionChanged);
633     QVERIFY(offer_action_changed_spy.isValid());
634     QCOMPARE(c_2.device->dragOffer()->offeredMimeTypes().count(), 1);
635     QCOMPARE(c_2.device->dragOffer()->offeredMimeTypes().first().name(),
636              QStringLiteral("text/plain"));
637     QTRY_COMPARE(offer->sourceDragAndDropActions(),
638                  Wrapland::Client::DataDeviceManager::DnDAction::Copy
639                      | Wrapland::Client::DataDeviceManager::DnDAction::Move);
640 
641     offer->setDragAndDropActions(Wrapland::Client::DataDeviceManager::DnDAction::Copy
642                                      | Wrapland::Client::DataDeviceManager::DnDAction::Move,
643                                  Wrapland::Client::DataDeviceManager::DnDAction::Move);
644     QVERIFY(offer_action_changed_spy.wait());
645     QCOMPARE(offer_action_changed_spy.count(), 1);
646     QCOMPARE(offer->selectedDragAndDropAction(),
647              Wrapland::Client::DataDeviceManager::DnDAction::Move);
648     QVERIFY(source_selected_action_changed_spy.count() == 1
649             || source_selected_action_changed_spy.wait());
650     QCOMPARE(source_selected_action_changed_spy.count(), 1);
651     QCOMPARE(c_1.source->selectedDragAndDropAction(),
652              Wrapland::Client::DataDeviceManager::DnDAction::Move);
653 
654     // Now delete the second client's data device.
655     QSignalSpy device_destroyed_spy(c_2.server_device,
656                                     &Wrapland::Server::DataDevice::resourceDestroyed);
657     QVERIFY(device_destroyed_spy.isValid());
658     delete c_2.device;
659     c_2.device = nullptr;
660     QVERIFY(device_destroyed_spy.wait());
661 
662     // Simulate drop.
663     QSignalSpy dropped_spy(c_1.source, &Wrapland::Client::DataSource::dragAndDropPerformed);
664     QVERIFY(dropped_spy.isValid());
665     m_server_seat->setTimestamp(4);
666     m_server_seat->pointers().button_released(1);
667     QVERIFY(dropped_spy.wait(500));
668 }
669 
test_pointer_events_ignored()670 void TestDragAndDrop::test_pointer_events_ignored()
671 {
672     // This test verifies that all pointer events are ignored on the focused Pointer device during
673     // drag.
674 
675     // First create a window.
676     std::unique_ptr<Wrapland::Client::Surface> s(create_surface(c_1));
677     auto server_surface = get_server_surface();
678     QVERIFY(server_surface);
679 
680     // pass it pointer focus
681     m_server_seat->pointers().set_focused_surface(server_surface);
682 
683     // create signal spies for all the pointer events
684     QSignalSpy pointer_entered_spy(c_1.pointer, &Wrapland::Client::Pointer::entered);
685     QVERIFY(pointer_entered_spy.isValid());
686     QSignalSpy pointer_left_spy(c_1.pointer, &Wrapland::Client::Pointer::left);
687     QVERIFY(pointer_left_spy.isValid());
688     QSignalSpy pointer_motion_spy(c_1.pointer, &Wrapland::Client::Pointer::motion);
689     QVERIFY(pointer_motion_spy.isValid());
690     QSignalSpy axis_spy(c_1.pointer, &Wrapland::Client::Pointer::axisChanged);
691     QVERIFY(axis_spy.isValid());
692     QSignalSpy button_spy(c_1.pointer, &Wrapland::Client::Pointer::buttonStateChanged);
693     QVERIFY(button_spy.isValid());
694     QSignalSpy drag_entered_spy(c_1.device, &Wrapland::Client::DataDevice::dragEntered);
695     QVERIFY(drag_entered_spy.isValid());
696 
697     // first simulate a few things
698     quint32 timestamp = 1;
699     m_server_seat->setTimestamp(timestamp++);
700     m_server_seat->pointers().set_position(QPointF(10, 10));
701     m_server_seat->setTimestamp(timestamp++);
702     m_server_seat->pointers().send_axis(Qt::Vertical, 5);
703     // verify that we have those
704     QVERIFY(axis_spy.wait());
705     QCOMPARE(axis_spy.count(), 1);
706     QCOMPARE(pointer_motion_spy.count(), 1);
707     QCOMPARE(pointer_entered_spy.count(), 1);
708     QVERIFY(button_spy.isEmpty());
709     QVERIFY(pointer_left_spy.isEmpty());
710 
711     // let's start the drag
712     m_server_seat->setTimestamp(timestamp++);
713     m_server_seat->pointers().button_pressed(1);
714     QVERIFY(button_spy.wait());
715     QCOMPARE(button_spy.count(), 1);
716     c_1.device->startDrag(button_spy.first().first().value<quint32>(), c_1.source, s.get());
717     QVERIFY(drag_entered_spy.wait());
718 
719     // now simulate all the possible pointer interactions
720     m_server_seat->setTimestamp(timestamp++);
721     m_server_seat->pointers().button_pressed(2);
722     m_server_seat->setTimestamp(timestamp++);
723     m_server_seat->pointers().button_released(2);
724     m_server_seat->setTimestamp(timestamp++);
725     m_server_seat->pointers().send_axis(Qt::Vertical, 5);
726     m_server_seat->setTimestamp(timestamp++);
727     m_server_seat->pointers().send_axis(Qt::Horizontal, 5);
728     m_server_seat->setTimestamp(timestamp++);
729     m_server_seat->pointers().set_focused_surface(nullptr);
730     m_server_seat->setTimestamp(timestamp++);
731     m_server_seat->pointers().set_focused_surface(server_surface);
732     m_server_seat->setTimestamp(timestamp++);
733     m_server_seat->pointers().set_position(QPointF(50, 50));
734 
735     // last but not least, simulate the drop
736     QSignalSpy dropped_spy(c_1.device, &Wrapland::Client::DataDevice::dropped);
737     QVERIFY(dropped_spy.isValid());
738     m_server_seat->setTimestamp(timestamp++);
739     m_server_seat->pointers().button_released(1);
740     QVERIFY(dropped_spy.wait());
741 
742     // all the changes should have been ignored
743     QCOMPARE(axis_spy.count(), 1);
744     QCOMPARE(pointer_motion_spy.count(), 1);
745     QCOMPARE(pointer_entered_spy.count(), 1);
746     QCOMPARE(button_spy.count(), 1);
747     QVERIFY(pointer_left_spy.isEmpty());
748 }
749 
750 QTEST_GUILESS_MAIN(TestDragAndDrop)
751 #include "drag_and_drop.moc"
752