KWin
Loading...
Searching...
No Matches
test_wayland_seat.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6// Qt
7#include <QMimeType>
8#include <QSignalSpy>
9#include <QTest>
10// KWin
11#include "wayland/compositor.h"
13#include "wayland/datasource.h"
14#include "wayland/display.h"
15#include "wayland/keyboard.h"
16#include "wayland/pointer.h"
19#include "wayland/seat.h"
21#include "wayland/surface.h"
22
23#include "KWayland/Client/compositor.h"
24#include "KWayland/Client/connection_thread.h"
25#include "KWayland/Client/datadevice.h"
26#include "KWayland/Client/datadevicemanager.h"
27#include "KWayland/Client/datasource.h"
28#include "KWayland/Client/event_queue.h"
29#include "KWayland/Client/keyboard.h"
30#include "KWayland/Client/pointer.h"
31#include "KWayland/Client/pointergestures.h"
32#include "KWayland/Client/registry.h"
33#include "KWayland/Client/relativepointer.h"
34#include "KWayland/Client/seat.h"
35#include "KWayland/Client/shm_pool.h"
36#include "KWayland/Client/subcompositor.h"
37#include "KWayland/Client/subsurface.h"
38#include "KWayland/Client/surface.h"
39#include "KWayland/Client/touch.h"
40
41// Wayland
42#include "qwayland-pointer-gestures-unstable-v1.h"
43#include <wayland-client-protocol.h>
44
45#include <linux/input.h>
46// System
47#include <fcntl.h>
48#include <unistd.h>
49
50using namespace std::literals;
51
52class WaylandSyncPoint : public QObject
53{
54 Q_OBJECT
55
56public:
57 explicit WaylandSyncPoint(KWayland::Client::ConnectionThread *connection, KWayland::Client::EventQueue *eventQueue)
58 {
59 static const wl_callback_listener listener = {
60 .done = [](void *data, wl_callback *callback, uint32_t callback_data) {
61 auto syncPoint = static_cast<WaylandSyncPoint *>(data);
62 Q_EMIT syncPoint->done();
63 },
64 };
65
66 m_callback = wl_display_sync(connection->display());
67 eventQueue->addProxy(m_callback);
68 wl_callback_add_listener(m_callback, &listener, this);
69 }
70
72 {
73 wl_callback_destroy(m_callback);
74 }
75
76Q_SIGNALS:
77 void done();
78
79private:
80 wl_callback *m_callback;
81};
82
83class TestWaylandSeat : public QObject
84{
85 Q_OBJECT
86public:
87 explicit TestWaylandSeat(QObject *parent = nullptr);
88private Q_SLOTS:
89 void init();
90 void cleanup();
91
92 void testName();
93 void testCapabilities_data();
94 void testCapabilities();
95 void testPointer();
96 void testPointerTransformation_data();
97 void testPointerTransformation();
98 void testPointerButton_data();
99 void testPointerButton();
100 void testPointerSubSurfaceTree();
101 void testPointerSwipeGesture_data();
102 void testPointerSwipeGesture();
103 void testPointerPinchGesture_data();
104 void testPointerPinchGesture();
105 void testPointerHoldGesture_data();
106 void testPointerHoldGesture();
107 void testPointerAxis();
108 void testCursor();
109 void testKeyboard();
110 void testSelection();
111 void testDataDeviceForKeyboardSurface();
112 void testTouch();
113 void testKeymap();
114
115private:
116 bool sync();
117
118 KWin::Display *m_display;
119 KWin::CompositorInterface *m_compositorInterface;
120 KWin::SeatInterface *m_seatInterface;
121 KWin::SubCompositorInterface *m_subCompositorInterface;
122 KWin::RelativePointerManagerV1Interface *m_relativePointerManagerV1Interface;
123 KWin::PointerGesturesV1Interface *m_pointerGesturesV1Interface;
124 KWayland::Client::ConnectionThread *m_connection;
125 KWayland::Client::Compositor *m_compositor;
126 KWayland::Client::Seat *m_seat;
127 KWayland::Client::ShmPool *m_shm;
128 KWayland::Client::SubCompositor *m_subCompositor;
129 KWayland::Client::RelativePointerManager *m_relativePointerManager;
130 KWayland::Client::PointerGestures *m_pointerGestures;
131 KWayland::Client::EventQueue *m_queue;
132 QThread *m_thread;
133};
134
135static const QString s_socketName = QStringLiteral("kwin-test-wayland-seat-0");
136
138 : QObject(parent)
139 , m_display(nullptr)
140 , m_compositorInterface(nullptr)
141 , m_seatInterface(nullptr)
142 , m_subCompositorInterface(nullptr)
143 , m_relativePointerManagerV1Interface(nullptr)
144 , m_pointerGesturesV1Interface(nullptr)
145 , m_connection(nullptr)
146 , m_compositor(nullptr)
147 , m_seat(nullptr)
148 , m_shm(nullptr)
149 , m_subCompositor(nullptr)
150 , m_relativePointerManager(nullptr)
151 , m_pointerGestures(nullptr)
152 , m_queue(nullptr)
153 , m_thread(nullptr)
154{
155}
156
157void TestWaylandSeat::init()
158{
159 using namespace KWin;
160 delete m_display;
161 m_display = new KWin::Display(this);
162 m_display->addSocketName(s_socketName);
163 m_display->start();
164 QVERIFY(m_display->isRunning());
165 m_display->createShm();
166
167 m_compositorInterface = new CompositorInterface(m_display, m_display);
168 m_subCompositorInterface = new SubCompositorInterface(m_display, m_display);
169 QVERIFY(m_subCompositorInterface);
170
171 m_relativePointerManagerV1Interface = new RelativePointerManagerV1Interface(m_display, m_display);
172 m_pointerGesturesV1Interface = new PointerGesturesV1Interface(m_display, m_display);
173
174 // setup connection
175 m_connection = new KWayland::Client::ConnectionThread;
176 QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
177 m_connection->setSocketName(s_socketName);
178
179 m_thread = new QThread(this);
180 m_connection->moveToThread(m_thread);
181 m_thread->start();
182
183 m_connection->initConnection();
184 QVERIFY(connectedSpy.wait());
185
186 m_queue = new KWayland::Client::EventQueue(this);
187 m_queue->setup(m_connection);
188
189 KWayland::Client::Registry registry;
190 QSignalSpy compositorSpy(&registry, &KWayland::Client::Registry::compositorAnnounced);
191 QSignalSpy seatSpy(&registry, &KWayland::Client::Registry::seatAnnounced);
192 QSignalSpy shmSpy(&registry, &KWayland::Client::Registry::shmAnnounced);
193 registry.setEventQueue(m_queue);
194 registry.create(m_connection->display());
195 QVERIFY(registry.isValid());
196 registry.setup();
197 QVERIFY(compositorSpy.wait());
198
199 m_seatInterface = new SeatInterface(m_display, m_display);
200 QVERIFY(m_seatInterface);
201 m_seatInterface->setName(QStringLiteral("seat0"));
202 QVERIFY(seatSpy.wait());
203
204 m_compositor = new KWayland::Client::Compositor(this);
205 m_compositor->setup(registry.bindCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>()));
206 QVERIFY(m_compositor->isValid());
207
208 m_seat = registry.createSeat(seatSpy.first().first().value<quint32>(), seatSpy.first().last().value<quint32>(), this);
209 QSignalSpy nameSpy(m_seat, &KWayland::Client::Seat::nameChanged);
210 QVERIFY(nameSpy.wait());
211
212 m_shm = new KWayland::Client::ShmPool(this);
213 m_shm->setup(registry.bindShm(shmSpy.first().first().value<quint32>(), shmSpy.first().last().value<quint32>()));
214 QVERIFY(m_shm->isValid());
215
216 m_subCompositor = registry.createSubCompositor(registry.interface(KWayland::Client::Registry::Interface::SubCompositor).name,
217 registry.interface(KWayland::Client::Registry::Interface::SubCompositor).version,
218 this);
219 QVERIFY(m_subCompositor->isValid());
220
221 m_relativePointerManager =
222 registry.createRelativePointerManager(registry.interface(KWayland::Client::Registry::Interface::RelativePointerManagerUnstableV1).name,
223 registry.interface(KWayland::Client::Registry::Interface::RelativePointerManagerUnstableV1).version,
224 this);
225 QVERIFY(m_relativePointerManager->isValid());
226
227 m_pointerGestures = registry.createPointerGestures(registry.interface(KWayland::Client::Registry::Interface::PointerGesturesUnstableV1).name,
228 registry.interface(KWayland::Client::Registry::Interface::PointerGesturesUnstableV1).version,
229 this);
230 QVERIFY(m_pointerGestures->isValid());
231}
232
233void TestWaylandSeat::cleanup()
234{
235 if (m_pointerGestures) {
236 delete m_pointerGestures;
237 m_pointerGestures = nullptr;
238 }
239 if (m_relativePointerManager) {
240 delete m_relativePointerManager;
241 m_relativePointerManager = nullptr;
242 }
243 if (m_subCompositor) {
244 delete m_subCompositor;
245 m_subCompositor = nullptr;
246 }
247 if (m_shm) {
248 delete m_shm;
249 m_shm = nullptr;
250 }
251 if (m_seat) {
252 delete m_seat;
253 m_seat = nullptr;
254 }
255 if (m_compositor) {
256 delete m_compositor;
257 m_compositor = nullptr;
258 }
259 if (m_queue) {
260 delete m_queue;
261 m_queue = nullptr;
262 }
263 if (m_connection) {
264 m_connection->deleteLater();
265 m_connection = nullptr;
266 }
267 if (m_thread) {
268 m_thread->quit();
269 m_thread->wait();
270 delete m_thread;
271 m_thread = nullptr;
272 }
273
274 delete m_display;
275 m_display = nullptr;
276
277 // these are the children of the display
278 m_compositorInterface = nullptr;
279 m_seatInterface = nullptr;
280 m_subCompositorInterface = nullptr;
281 m_relativePointerManagerV1Interface = nullptr;
282 m_pointerGesturesV1Interface = nullptr;
283}
284
285bool TestWaylandSeat::sync()
286{
287 WaylandSyncPoint syncPoint(m_connection, m_queue);
288 QSignalSpy doneSpy(&syncPoint, &WaylandSyncPoint::done);
289 return doneSpy.wait();
290}
291
292void TestWaylandSeat::testName()
293{
294 // no name set yet
295 QCOMPARE(m_seat->name(), QStringLiteral("seat0"));
296
297 QSignalSpy spy(m_seat, &KWayland::Client::Seat::nameChanged);
298
299 const QString name = QStringLiteral("foobar");
300 m_seatInterface->setName(name);
301 QVERIFY(spy.wait());
302 QCOMPARE(m_seat->name(), name);
303 QCOMPARE(spy.count(), 1);
304 QCOMPARE(spy.first().first().toString(), name);
305}
306
307void TestWaylandSeat::testCapabilities_data()
308{
309 QTest::addColumn<bool>("pointer");
310 QTest::addColumn<bool>("keyboard");
311 QTest::addColumn<bool>("touch");
312
313 QTest::newRow("none") << false << false << false;
314 QTest::newRow("pointer") << true << false << false;
315 QTest::newRow("keyboard") << false << true << false;
316 QTest::newRow("touch") << false << false << true;
317 QTest::newRow("pointer/keyboard") << true << true << false;
318 QTest::newRow("pointer/touch") << true << false << true;
319 QTest::newRow("keyboard/touch") << false << true << true;
320 QTest::newRow("all") << true << true << true;
321}
322
323void TestWaylandSeat::testCapabilities()
324{
325 QVERIFY(!m_seat->hasPointer());
326 QVERIFY(!m_seat->hasKeyboard());
327 QVERIFY(!m_seat->hasTouch());
328
329 QFETCH(bool, pointer);
330 QFETCH(bool, keyboard);
331 QFETCH(bool, touch);
332
333 QSignalSpy pointerSpy(m_seat, &KWayland::Client::Seat::hasPointerChanged);
334 QSignalSpy keyboardSpy(m_seat, &KWayland::Client::Seat::hasKeyboardChanged);
335 QSignalSpy touchSpy(m_seat, &KWayland::Client::Seat::hasTouchChanged);
336
337 m_seatInterface->setHasPointer(pointer);
338 m_seatInterface->setHasKeyboard(keyboard);
339 m_seatInterface->setHasTouch(touch);
340
341 QVERIFY(sync());
342
343 // do processing
344 QCOMPARE(pointerSpy.isEmpty(), !pointer);
345 if (!pointerSpy.isEmpty()) {
346 QCOMPARE(pointerSpy.first().first().toBool(), pointer);
347 }
348
349 QCOMPARE(keyboardSpy.isEmpty(), !keyboard);
350 if (!keyboardSpy.isEmpty()) {
351 QCOMPARE(keyboardSpy.first().first().toBool(), keyboard);
352 }
353
354 QCOMPARE(touchSpy.isEmpty(), !touch);
355 if (!touchSpy.isEmpty()) {
356 QCOMPARE(touchSpy.first().first().toBool(), touch);
357 }
358
359 QCOMPARE(m_seat->hasPointer(), pointer);
360 QCOMPARE(m_seat->hasKeyboard(), keyboard);
361 QCOMPARE(m_seat->hasTouch(), touch);
362}
363
364void TestWaylandSeat::testPointer()
365{
366 using namespace KWin;
367
368 QSignalSpy pointerSpy(m_seat, &KWayland::Client::Seat::hasPointerChanged);
369 m_seatInterface->setHasPointer(true);
370 QVERIFY(pointerSpy.wait());
371
372 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
373 KWayland::Client::Surface *s = m_compositor->createSurface(m_compositor);
374 QVERIFY(surfaceCreatedSpy.wait());
375 SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value<KWin::SurfaceInterface *>();
376 QVERIFY(serverSurface);
377
378 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
379 image.fill(Qt::black);
380 s->attachBuffer(m_shm->createBuffer(image));
381 s->damage(image.rect());
382 s->commit(KWayland::Client::Surface::CommitFlag::None);
383 QSignalSpy committedSpy(serverSurface, &KWin::SurfaceInterface::committed);
384 QVERIFY(committedSpy.wait());
385
386 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(20, 18), QPointF(10, 15));
387
388 KWayland::Client::Pointer *p = m_seat->createPointer(m_seat);
389 QSignalSpy frameSpy(p, &KWayland::Client::Pointer::frame);
390 const KWayland::Client::Pointer &cp = *p;
391 QVERIFY(p->isValid());
392 std::unique_ptr<KWayland::Client::RelativePointer> relativePointer(m_relativePointerManager->createRelativePointer(p));
393 QVERIFY(relativePointer->isValid());
394 QVERIFY(frameSpy.wait());
395 QCOMPARE(frameSpy.count(), 1);
396
397 m_seatInterface->notifyPointerLeave();
398 serverSurface->client()->flush();
399 QVERIFY(frameSpy.wait());
400 QCOMPARE(frameSpy.count(), 2);
401
402 QSignalSpy enteredSpy(p, &KWayland::Client::Pointer::entered);
403
404 QSignalSpy leftSpy(p, &KWayland::Client::Pointer::left);
405
406 QSignalSpy motionSpy(p, &KWayland::Client::Pointer::motion);
407
408 QSignalSpy axisSpy(p, &KWayland::Client::Pointer::axisChanged);
409
410 QSignalSpy buttonSpy(p, &KWayland::Client::Pointer::buttonStateChanged);
411
412 QSignalSpy relativeMotionSpy(relativePointer.get(), &KWayland::Client::RelativePointer::relativeMotion);
413
414 QVERIFY(!p->enteredSurface());
415 QVERIFY(!cp.enteredSurface());
416 uint32_t serial = m_display->serial();
417 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(20, 18), QPointF(10, 15));
418 QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface);
419 QVERIFY(enteredSpy.wait());
420 QCOMPARE_GT(enteredSpy.first().first().value<quint32>(), serial);
421 QCOMPARE(enteredSpy.first().last().toPoint(), QPoint(10, 3));
422 QCOMPARE(frameSpy.count(), 3);
423 QCOMPARE(p->enteredSurface(), s);
424 QCOMPARE(cp.enteredSurface(), s);
425
426 auto timestamp = 1ms;
427 // test motion
428 m_seatInterface->setTimestamp(timestamp++);
429 m_seatInterface->notifyPointerMotion(QPoint(10, 16));
430 m_seatInterface->notifyPointerFrame();
431 QVERIFY(motionSpy.wait());
432 QCOMPARE(frameSpy.count(), 4);
433 QCOMPARE(motionSpy.first().first().toPoint(), QPoint(0, 1));
434 QCOMPARE(motionSpy.first().last().value<quint32>(), quint32(1));
435
436 // test relative motion
437 m_seatInterface->relativePointerMotion(QPointF(1, 2), QPointF(3, 4), 1234us);
438 m_seatInterface->notifyPointerFrame();
439 QVERIFY(relativeMotionSpy.wait());
440 QCOMPARE(relativeMotionSpy.count(), 1);
441 QCOMPARE(frameSpy.count(), 5);
442 QCOMPARE(relativeMotionSpy.first().at(0).toSizeF(), QSizeF(1, 2));
443 QCOMPARE(relativeMotionSpy.first().at(1).toSizeF(), QSizeF(3, 4));
444 QCOMPARE(relativeMotionSpy.first().at(2).value<quint64>(), 1234);
445
446 // test axis
447 m_seatInterface->setTimestamp(timestamp++);
448 m_seatInterface->notifyPointerAxis(Qt::Horizontal, 10, 120, PointerAxisSource::Wheel);
449 m_seatInterface->notifyPointerFrame();
450 QVERIFY(axisSpy.wait());
451 QCOMPARE(frameSpy.count(), 6);
452 m_seatInterface->setTimestamp(timestamp++);
453 m_seatInterface->notifyPointerAxis(Qt::Vertical, 20, 240, PointerAxisSource::Wheel);
454 m_seatInterface->notifyPointerFrame();
455 QVERIFY(axisSpy.wait());
456 QCOMPARE(frameSpy.count(), 7);
457 QCOMPARE(axisSpy.first().at(0).value<quint32>(), quint32(2));
458 QCOMPARE(axisSpy.first().at(1).value<KWayland::Client::Pointer::Axis>(), KWayland::Client::Pointer::Axis::Horizontal);
459 QCOMPARE(axisSpy.first().at(2).value<qreal>(), qreal(10));
460
461 QCOMPARE(axisSpy.last().at(0).value<quint32>(), quint32(3));
462 QCOMPARE(axisSpy.last().at(1).value<KWayland::Client::Pointer::Axis>(), KWayland::Client::Pointer::Axis::Vertical);
463 QCOMPARE(axisSpy.last().at(2).value<qreal>(), qreal(20));
464
465 // test button
466 m_seatInterface->setTimestamp(timestamp++);
467 m_seatInterface->notifyPointerButton(1, PointerButtonState::Pressed);
468 m_seatInterface->notifyPointerFrame();
469 QVERIFY(buttonSpy.wait());
470 QCOMPARE(frameSpy.count(), 8);
471 QCOMPARE(buttonSpy.at(0).at(0).value<quint32>(), m_display->serial());
472 m_seatInterface->setTimestamp(timestamp++);
473 m_seatInterface->notifyPointerButton(2, PointerButtonState::Pressed);
474 m_seatInterface->notifyPointerFrame();
475 QVERIFY(buttonSpy.wait());
476 QCOMPARE(frameSpy.count(), 9);
477 QCOMPARE(buttonSpy.at(1).at(0).value<quint32>(), m_display->serial());
478 m_seatInterface->setTimestamp(timestamp++);
479 m_seatInterface->notifyPointerButton(2, PointerButtonState::Released);
480 m_seatInterface->notifyPointerFrame();
481 QVERIFY(buttonSpy.wait());
482 QCOMPARE(frameSpy.count(), 10);
483 QCOMPARE(buttonSpy.at(2).at(0).value<quint32>(), m_display->serial());
484 m_seatInterface->setTimestamp(timestamp++);
485 m_seatInterface->notifyPointerButton(1, PointerButtonState::Released);
486 m_seatInterface->notifyPointerFrame();
487 QVERIFY(buttonSpy.wait());
488 QCOMPARE(frameSpy.count(), 11);
489 QCOMPARE(buttonSpy.count(), 4);
490
491 // timestamp
492 QCOMPARE(buttonSpy.at(0).at(1).value<quint32>(), quint32(4));
493 // button
494 QCOMPARE(buttonSpy.at(0).at(2).value<quint32>(), quint32(1));
495 QCOMPARE(buttonSpy.at(0).at(3).value<KWayland::Client::Pointer::ButtonState>(), KWayland::Client::Pointer::ButtonState::Pressed);
496
497 // timestamp
498 QCOMPARE(buttonSpy.at(1).at(1).value<quint32>(), quint32(5));
499 // button
500 QCOMPARE(buttonSpy.at(1).at(2).value<quint32>(), quint32(2));
501 QCOMPARE(buttonSpy.at(1).at(3).value<KWayland::Client::Pointer::ButtonState>(), KWayland::Client::Pointer::ButtonState::Pressed);
502
503 QCOMPARE(buttonSpy.at(2).at(0).value<quint32>(), m_seatInterface->pointerButtonSerial(2));
504 // timestamp
505 QCOMPARE(buttonSpy.at(2).at(1).value<quint32>(), quint32(6));
506 // button
507 QCOMPARE(buttonSpy.at(2).at(2).value<quint32>(), quint32(2));
508 QCOMPARE(buttonSpy.at(2).at(3).value<KWayland::Client::Pointer::ButtonState>(), KWayland::Client::Pointer::ButtonState::Released);
509
510 QCOMPARE(buttonSpy.at(3).at(0).value<quint32>(), m_seatInterface->pointerButtonSerial(1));
511 // timestamp
512 QCOMPARE(buttonSpy.at(3).at(1).value<quint32>(), quint32(7));
513 // button
514 QCOMPARE(buttonSpy.at(3).at(2).value<quint32>(), quint32(1));
515 QCOMPARE(buttonSpy.at(3).at(3).value<KWayland::Client::Pointer::ButtonState>(), KWayland::Client::Pointer::ButtonState::Released);
516
517 // leave the surface
518 serial = m_display->serial();
519 m_seatInterface->notifyPointerLeave();
520 QVERIFY(leftSpy.wait());
521 QCOMPARE(frameSpy.count(), 12);
522 QCOMPARE_GT(leftSpy.first().first().value<quint32>(), serial);
523 QVERIFY(!p->enteredSurface());
524 QVERIFY(!cp.enteredSurface());
525
526 // now a relative motion should not be sent to the relative pointer
527 m_seatInterface->relativePointerMotion(QPointF(1, 2), QPointF(3, 4), std::chrono::milliseconds::zero());
528 QVERIFY(sync());
529 QCOMPARE(relativeMotionSpy.count(), 1);
530
531 // enter it again
532 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(10, 16), QPointF(0, 0));
533 QVERIFY(enteredSpy.wait());
534 QCOMPARE(frameSpy.count(), 13);
535 QCOMPARE(p->enteredSurface(), s);
536 QCOMPARE(cp.enteredSurface(), s);
537
538 // send another relative motion event
539 m_seatInterface->relativePointerMotion(QPointF(4, 5), QPointF(6, 7), 1234us);
540 QVERIFY(relativeMotionSpy.wait());
541 QCOMPARE(relativeMotionSpy.count(), 2);
542 QCOMPARE(relativeMotionSpy.last().at(0).toSizeF(), QSizeF(4, 5));
543 QCOMPARE(relativeMotionSpy.last().at(1).toSizeF(), QSizeF(6, 7));
544 QCOMPARE(relativeMotionSpy.last().at(2).value<quint64>(), 1234);
545}
546
547void TestWaylandSeat::testPointerTransformation_data()
548{
549 QTest::addColumn<QMatrix4x4>("enterTransformation");
550 // global position at 20/18
551 QTest::addColumn<QPointF>("expectedEnterPoint");
552 // global position at 10/16
553 QTest::addColumn<QPointF>("expectedMovePoint");
554
555 QMatrix4x4 tm;
556 tm.translate(-10, -15);
557 QTest::newRow("translation") << tm << QPointF(10, 3) << QPointF(0, 1);
558 QMatrix4x4 sm;
559 sm.scale(2, 2);
560 QTest::newRow("scale") << sm << QPointF(40, 36) << QPointF(20, 32);
561 QMatrix4x4 rotate;
562 rotate.rotate(90, 0, 0, 1);
563 QTest::newRow("rotate") << rotate << QPointF(-18, 20) << QPointF(-16, 10);
564}
565
566void TestWaylandSeat::testPointerTransformation()
567{
568 using namespace KWin;
569
570 QSignalSpy pointerSpy(m_seat, &KWayland::Client::Seat::hasPointerChanged);
571 m_seatInterface->setHasPointer(true);
572 QVERIFY(pointerSpy.wait());
573
574 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
575 KWayland::Client::Surface *s = m_compositor->createSurface(m_compositor);
576 QVERIFY(surfaceCreatedSpy.wait());
577 SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value<KWin::SurfaceInterface *>();
578 QVERIFY(serverSurface);
579
580 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
581 image.fill(Qt::black);
582 s->attachBuffer(m_shm->createBuffer(image));
583 s->damage(image.rect());
584 s->commit(KWayland::Client::Surface::CommitFlag::None);
585 QSignalSpy committedSpy(serverSurface, &KWin::SurfaceInterface::committed);
586 QVERIFY(committedSpy.wait());
587
588 KWayland::Client::Pointer *p = m_seat->createPointer(m_seat);
589 QVERIFY(p->isValid());
590 const KWayland::Client::Pointer &cp = *p;
591
592 QSignalSpy enteredSpy(p, &KWayland::Client::Pointer::entered);
593 QSignalSpy leftSpy(p, &KWayland::Client::Pointer::left);
594 QSignalSpy motionSpy(p, &KWayland::Client::Pointer::motion);
595
596 QVERIFY(!p->enteredSurface());
597 QVERIFY(!cp.enteredSurface());
598 uint32_t serial = m_display->serial();
599 QFETCH(QMatrix4x4, enterTransformation);
600 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(20, 18), enterTransformation);
601 QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface);
602 QVERIFY(enteredSpy.wait());
603 QCOMPARE_GT(enteredSpy.first().first().value<quint32>(), serial);
604 QTEST(enteredSpy.first().last().toPointF(), "expectedEnterPoint");
605 QCOMPARE(p->enteredSurface(), s);
606 QCOMPARE(cp.enteredSurface(), s);
607
608 // test motion
609 m_seatInterface->setTimestamp(std::chrono::milliseconds(1));
610 m_seatInterface->notifyPointerMotion(QPoint(10, 16));
611 m_seatInterface->notifyPointerFrame();
612 QVERIFY(motionSpy.wait());
613 QTEST(motionSpy.first().first().toPointF(), "expectedMovePoint");
614 QCOMPARE(motionSpy.first().last().value<quint32>(), quint32(1));
615
616 // leave the surface
617 serial = m_display->serial();
618 m_seatInterface->notifyPointerLeave();
619 QVERIFY(leftSpy.wait());
620 QCOMPARE_GT(leftSpy.first().first().value<quint32>(), serial);
621 QVERIFY(!p->enteredSurface());
622 QVERIFY(!cp.enteredSurface());
623
624 // enter it again
625 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(10, 16));
626 QVERIFY(enteredSpy.wait());
627 QCOMPARE(p->enteredSurface(), s);
628 QCOMPARE(cp.enteredSurface(), s);
629
630 QSignalSpy serverSurfaceDestroyedSpy(serverSurface, &QObject::destroyed);
631 delete s;
632 QVERIFY(serverSurfaceDestroyedSpy.wait());
633 QVERIFY(!m_seatInterface->focusedPointerSurface());
634}
635
636Q_DECLARE_METATYPE(Qt::MouseButton)
637
638void TestWaylandSeat::testPointerButton_data()
639{
640 QTest::addColumn<Qt::MouseButton>("qtButton");
641 QTest::addColumn<quint32>("waylandButton");
642
643 QTest::newRow("left") << Qt::LeftButton << quint32(BTN_LEFT);
644 QTest::newRow("right") << Qt::RightButton << quint32(BTN_RIGHT);
645 QTest::newRow("middle") << Qt::MiddleButton << quint32(BTN_MIDDLE);
646 QTest::newRow("back") << Qt::BackButton << quint32(BTN_BACK);
647 QTest::newRow("x1") << Qt::XButton1 << quint32(BTN_BACK);
648 QTest::newRow("extra1") << Qt::ExtraButton1 << quint32(BTN_BACK);
649 QTest::newRow("forward") << Qt::ForwardButton << quint32(BTN_FORWARD);
650 QTest::newRow("x2") << Qt::XButton2 << quint32(BTN_FORWARD);
651 QTest::newRow("extra2") << Qt::ExtraButton2 << quint32(BTN_FORWARD);
652 QTest::newRow("task") << Qt::TaskButton << quint32(BTN_TASK);
653 QTest::newRow("extra3") << Qt::ExtraButton3 << quint32(BTN_TASK);
654 QTest::newRow("extra4") << Qt::ExtraButton4 << quint32(BTN_EXTRA);
655 QTest::newRow("extra5") << Qt::ExtraButton5 << quint32(BTN_SIDE);
656 QTest::newRow("extra6") << Qt::ExtraButton6 << quint32(0x118);
657 QTest::newRow("extra7") << Qt::ExtraButton7 << quint32(0x119);
658 QTest::newRow("extra8") << Qt::ExtraButton8 << quint32(0x11a);
659 QTest::newRow("extra9") << Qt::ExtraButton9 << quint32(0x11b);
660 QTest::newRow("extra10") << Qt::ExtraButton10 << quint32(0x11c);
661 QTest::newRow("extra11") << Qt::ExtraButton11 << quint32(0x11d);
662 QTest::newRow("extra12") << Qt::ExtraButton12 << quint32(0x11e);
663 QTest::newRow("extra13") << Qt::ExtraButton13 << quint32(0x11f);
664}
665
666void TestWaylandSeat::testPointerButton()
667{
668 using namespace KWin;
669
670 QSignalSpy pointerSpy(m_seat, &KWayland::Client::Seat::hasPointerChanged);
671 m_seatInterface->setHasPointer(true);
672 QVERIFY(pointerSpy.wait());
673
674 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
675 KWayland::Client::Surface *s = m_compositor->createSurface(m_compositor);
676 QVERIFY(surfaceCreatedSpy.wait());
677 SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value<KWin::SurfaceInterface *>();
678 QVERIFY(serverSurface);
679
680 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
681 image.fill(Qt::black);
682 s->attachBuffer(m_shm->createBuffer(image));
683 s->damage(image.rect());
684 s->commit(KWayland::Client::Surface::CommitFlag::None);
685 QSignalSpy committedSpy(serverSurface, &KWin::SurfaceInterface::committed);
686 QVERIFY(committedSpy.wait());
687
688 std::unique_ptr<KWayland::Client::Pointer> p(m_seat->createPointer());
689 QVERIFY(p->isValid());
690 QSignalSpy buttonChangedSpy(p.get(), &KWayland::Client::Pointer::buttonStateChanged);
691 wl_display_flush(m_connection->display());
692 QCoreApplication::processEvents();
693
694 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(20, 18), QPointF(10, 15));
695 QVERIFY(m_seatInterface->focusedPointerSurface());
696
697 QCoreApplication::processEvents();
698
699 QFETCH(Qt::MouseButton, qtButton);
700 QFETCH(quint32, waylandButton);
701 std::chrono::milliseconds timestamp(1);
702 QCOMPARE(m_seatInterface->isPointerButtonPressed(waylandButton), false);
703 QCOMPARE(m_seatInterface->isPointerButtonPressed(qtButton), false);
704 m_seatInterface->setTimestamp(timestamp);
705 m_seatInterface->notifyPointerButton(qtButton, PointerButtonState::Pressed);
706 m_seatInterface->notifyPointerFrame();
707 QCOMPARE(m_seatInterface->isPointerButtonPressed(waylandButton), true);
708 QCOMPARE(m_seatInterface->isPointerButtonPressed(qtButton), true);
709 QVERIFY(buttonChangedSpy.wait());
710 QCOMPARE(buttonChangedSpy.count(), 1);
711 QCOMPARE(buttonChangedSpy.last().at(0).value<quint32>(), m_seatInterface->pointerButtonSerial(waylandButton));
712 QCOMPARE(buttonChangedSpy.last().at(0).value<quint32>(), m_seatInterface->pointerButtonSerial(qtButton));
713 QCOMPARE(buttonChangedSpy.last().at(1).value<quint32>(), timestamp.count());
714 QCOMPARE(buttonChangedSpy.last().at(2).value<quint32>(), waylandButton);
715 QCOMPARE(buttonChangedSpy.last().at(3).value<KWayland::Client::Pointer::ButtonState>(), KWayland::Client::Pointer::ButtonState::Pressed);
716 timestamp++;
717 m_seatInterface->setTimestamp(timestamp);
718 m_seatInterface->notifyPointerButton(qtButton, PointerButtonState::Released);
719 m_seatInterface->notifyPointerFrame();
720 QCOMPARE(m_seatInterface->isPointerButtonPressed(waylandButton), false);
721 QCOMPARE(m_seatInterface->isPointerButtonPressed(qtButton), false);
722 QVERIFY(buttonChangedSpy.wait());
723 QCOMPARE(buttonChangedSpy.count(), 2);
724 QCOMPARE(buttonChangedSpy.last().at(0).value<quint32>(), m_seatInterface->pointerButtonSerial(waylandButton));
725 QCOMPARE(buttonChangedSpy.last().at(0).value<quint32>(), m_seatInterface->pointerButtonSerial(qtButton));
726 QCOMPARE(buttonChangedSpy.last().at(1).value<quint32>(), timestamp.count());
727 QCOMPARE(buttonChangedSpy.last().at(2).value<quint32>(), waylandButton);
728 QCOMPARE(buttonChangedSpy.last().at(3).value<KWayland::Client::Pointer::ButtonState>(), KWayland::Client::Pointer::ButtonState::Released);
729}
730
731void TestWaylandSeat::testPointerSubSurfaceTree()
732{
733 // this test verifies that pointer motion on a surface with sub-surfaces sends motion enter/leave to the sub-surface
734 using namespace KWin;
735
736 // first create the pointer
737 QSignalSpy hasPointerChangedSpy(m_seat, &KWayland::Client::Seat::hasPointerChanged);
738 m_seatInterface->setHasPointer(true);
739 QVERIFY(hasPointerChangedSpy.wait());
740 std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer());
741
742 // create a sub surface tree
743 // parent surface (100, 100) with one sub surface taking the half of it's size (50, 100)
744 // which has two further children (50, 50) which are overlapping
745 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
746 std::unique_ptr<KWayland::Client::Surface> parentSurface(m_compositor->createSurface());
747 std::unique_ptr<KWayland::Client::Surface> childSurface(m_compositor->createSurface());
748 std::unique_ptr<KWayland::Client::Surface> grandChild1Surface(m_compositor->createSurface());
749 std::unique_ptr<KWayland::Client::Surface> grandChild2Surface(m_compositor->createSurface());
750 std::unique_ptr<KWayland::Client::SubSurface> childSubSurface(m_subCompositor->createSubSurface(childSurface.get(), parentSurface.get()));
751 std::unique_ptr<KWayland::Client::SubSurface> grandChild1SubSurface(m_subCompositor->createSubSurface(grandChild1Surface.get(), childSurface.get()));
752 std::unique_ptr<KWayland::Client::SubSurface> grandChild2SubSurface(m_subCompositor->createSubSurface(grandChild2Surface.get(), childSurface.get()));
753 grandChild2SubSurface->setPosition(QPoint(0, 25));
754
755 // let's map the surfaces
756 auto render = [this](KWayland::Client::Surface *s, const QSize &size) {
757 QImage image(size, QImage::Format_ARGB32_Premultiplied);
758 image.fill(Qt::black);
759 s->attachBuffer(m_shm->createBuffer(image));
760 s->damage(QRect(QPoint(0, 0), size));
761 s->commit(KWayland::Client::Surface::CommitFlag::None);
762 };
763 render(grandChild2Surface.get(), QSize(50, 50));
764 render(grandChild1Surface.get(), QSize(50, 50));
765 render(childSurface.get(), QSize(50, 100));
766 render(parentSurface.get(), QSize(100, 100));
767
768 QVERIFY(surfaceCreatedSpy.wait());
769 auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
770 QVERIFY(serverSurface->isMapped());
771
772 // send in pointer events
773 QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered);
774 QSignalSpy leftSpy(pointer.get(), &KWayland::Client::Pointer::left);
775 QSignalSpy motionSpy(pointer.get(), &KWayland::Client::Pointer::motion);
776 // first to the grandChild2 in the overlapped area
777 std::chrono::milliseconds timestamp(1);
778 m_seatInterface->setTimestamp(timestamp++);
779 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(25, 50));
780 QVERIFY(enteredSpy.wait());
781 QCOMPARE(enteredSpy.count(), 1);
782 QCOMPARE(leftSpy.count(), 0);
783 QCOMPARE(motionSpy.count(), 0);
784 QCOMPARE(enteredSpy.last().last().toPointF(), QPointF(25, 25));
785 QCOMPARE(pointer->enteredSurface(), grandChild2Surface.get());
786 // a motion on grandchild2
787 m_seatInterface->setTimestamp(timestamp++);
788 m_seatInterface->notifyPointerMotion(QPointF(25, 60));
789 m_seatInterface->notifyPointerFrame();
790 QVERIFY(motionSpy.wait());
791 QCOMPARE(enteredSpy.count(), 1);
792 QCOMPARE(leftSpy.count(), 0);
793 QCOMPARE(motionSpy.count(), 1);
794 QCOMPARE(motionSpy.last().first().toPointF(), QPointF(25, 35));
795 // motion which changes to childSurface
796 m_seatInterface->setTimestamp(timestamp++);
797 m_seatInterface->notifyPointerMotion(QPointF(25, 80));
798 m_seatInterface->notifyPointerFrame();
799 QVERIFY(enteredSpy.wait());
800 QCOMPARE(enteredSpy.count(), 2);
801 QCOMPARE(leftSpy.count(), 1);
802 QCOMPARE(motionSpy.count(), 2);
803 QCOMPARE(enteredSpy.last().last().toPointF(), QPointF(25, 80));
804 QCOMPARE(pointer->enteredSurface(), childSurface.get());
805 // a leave for the whole surface
806 m_seatInterface->setTimestamp(timestamp++);
807 m_seatInterface->notifyPointerLeave();
808 QVERIFY(leftSpy.wait());
809 QCOMPARE(enteredSpy.count(), 2);
810 QCOMPARE(leftSpy.count(), 2);
811 QCOMPARE(motionSpy.count(), 2);
812 // a new enter on the main surface
813 m_seatInterface->setTimestamp(timestamp++);
814 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(75, 50));
815 QVERIFY(enteredSpy.wait());
816 QCOMPARE(enteredSpy.count(), 3);
817 QCOMPARE(leftSpy.count(), 2);
818 QCOMPARE(motionSpy.count(), 2);
819 QCOMPARE(enteredSpy.last().last().toPointF(), QPointF(75, 50));
820 QCOMPARE(pointer->enteredSurface(), parentSurface.get());
821}
822
823void TestWaylandSeat::testPointerSwipeGesture_data()
824{
825 QTest::addColumn<bool>("cancel");
826 QTest::addColumn<int>("expectedEndCount");
827 QTest::addColumn<int>("expectedCancelCount");
828
829 QTest::newRow("end") << false << 1 << 0;
830 QTest::newRow("cancel") << true << 0 << 1;
831}
832
833void TestWaylandSeat::testPointerSwipeGesture()
834{
835 using namespace KWin;
836
837 // first create the pointer and pointer swipe gesture
838 QSignalSpy hasPointerChangedSpy(m_seat, &KWayland::Client::Seat::hasPointerChanged);
839 m_seatInterface->setHasPointer(true);
840 QVERIFY(hasPointerChangedSpy.wait());
841 std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer());
842 std::unique_ptr<KWayland::Client::PointerSwipeGesture> gesture(m_pointerGestures->createSwipeGesture(pointer.get()));
843 QVERIFY(gesture);
844 QVERIFY(gesture->isValid());
845 QVERIFY(gesture->surface().isNull());
846 QCOMPARE(gesture->fingerCount(), 0u);
847
848 QSignalSpy startSpy(gesture.get(), &KWayland::Client::PointerSwipeGesture::started);
849 QSignalSpy updateSpy(gesture.get(), &KWayland::Client::PointerSwipeGesture::updated);
850 QSignalSpy endSpy(gesture.get(), &KWayland::Client::PointerSwipeGesture::ended);
851 QSignalSpy cancelledSpy(gesture.get(), &KWayland::Client::PointerSwipeGesture::cancelled);
852
853 // now create a surface
854 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
855 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
856 QVERIFY(surfaceCreatedSpy.wait());
857 auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
858 QVERIFY(serverSurface);
859
860 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
861 image.fill(Qt::black);
862 surface->attachBuffer(m_shm->createBuffer(image));
863 surface->damage(image.rect());
864 surface->commit(KWayland::Client::Surface::CommitFlag::None);
865 QSignalSpy committedSpy(serverSurface, &KWin::SurfaceInterface::committed);
866 QVERIFY(committedSpy.wait());
867
868 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0));
869 QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface);
870 QVERIFY(m_seatInterface->pointer());
871
872 // send in the start
873 std::chrono::milliseconds timestamp(1);
874 m_seatInterface->setTimestamp(timestamp++);
875 m_seatInterface->startPointerSwipeGesture(2);
876 QVERIFY(startSpy.wait());
877 QCOMPARE(startSpy.count(), 1);
878 QCOMPARE(startSpy.first().at(0).value<quint32>(), m_display->serial());
879 QCOMPARE(startSpy.first().at(1).value<quint32>(), 1u);
880 QCOMPARE(gesture->fingerCount(), 2u);
881 QCOMPARE(gesture->surface().data(), surface.get());
882
883 // another start should not be possible
884 m_seatInterface->startPointerSwipeGesture(2);
885 QVERIFY(sync());
886 QCOMPARE(startSpy.count(), 1);
887
888 // send in some updates
889 m_seatInterface->setTimestamp(timestamp++);
890 m_seatInterface->updatePointerSwipeGesture(QPointF(2, 3));
891 QVERIFY(updateSpy.wait());
892 m_seatInterface->setTimestamp(timestamp++);
893 m_seatInterface->updatePointerSwipeGesture(QPointF(4, 5));
894 QVERIFY(updateSpy.wait());
895 QCOMPARE(updateSpy.count(), 2);
896 QCOMPARE(updateSpy.at(0).at(0).toSizeF(), QSizeF(2, 3));
897 QCOMPARE(updateSpy.at(0).at(1).value<quint32>(), 2u);
898 QCOMPARE(updateSpy.at(1).at(0).toSizeF(), QSizeF(4, 5));
899 QCOMPARE(updateSpy.at(1).at(1).value<quint32>(), 3u);
900
901 // now end or cancel
902 QFETCH(bool, cancel);
903 QSignalSpy *spy;
904 m_seatInterface->setTimestamp(timestamp++);
905 if (cancel) {
906 m_seatInterface->cancelPointerSwipeGesture();
907 spy = &cancelledSpy;
908 } else {
909 m_seatInterface->endPointerSwipeGesture();
910 spy = &endSpy;
911 }
912 QVERIFY(spy->wait());
913 QFETCH(int, expectedEndCount);
914 QCOMPARE(endSpy.count(), expectedEndCount);
915 QFETCH(int, expectedCancelCount);
916 QCOMPARE(cancelledSpy.count(), expectedCancelCount);
917 QCOMPARE(spy->count(), 1);
918 QCOMPARE(spy->first().at(0).value<quint32>(), m_display->serial());
919 QCOMPARE(spy->first().at(1).value<quint32>(), 4u);
920
921 QCOMPARE(gesture->fingerCount(), 0u);
922 QVERIFY(gesture->surface().isNull());
923
924 // now a start should be possible again
925 m_seatInterface->setTimestamp(timestamp++);
926 m_seatInterface->startPointerSwipeGesture(2);
927 QVERIFY(startSpy.wait());
928
929 // unsetting the focused pointer surface should not change anything
930 m_seatInterface->notifyPointerLeave();
931 m_seatInterface->setTimestamp(timestamp++);
932 m_seatInterface->updatePointerSwipeGesture(QPointF(6, 7));
933 QVERIFY(updateSpy.wait());
934 // and end
935 m_seatInterface->setTimestamp(timestamp++);
936 if (cancel) {
937 m_seatInterface->cancelPointerSwipeGesture();
938 } else {
939 m_seatInterface->endPointerSwipeGesture();
940 }
941 QVERIFY(spy->wait());
942}
943
944void TestWaylandSeat::testPointerPinchGesture_data()
945{
946 QTest::addColumn<bool>("cancel");
947 QTest::addColumn<int>("expectedEndCount");
948 QTest::addColumn<int>("expectedCancelCount");
949
950 QTest::newRow("end") << false << 1 << 0;
951 QTest::newRow("cancel") << true << 0 << 1;
952}
953
954void TestWaylandSeat::testPointerPinchGesture()
955{
956 using namespace KWin;
957
958 // first create the pointer and pointer swipe gesture
959 QSignalSpy hasPointerChangedSpy(m_seat, &KWayland::Client::Seat::hasPointerChanged);
960 m_seatInterface->setHasPointer(true);
961 QVERIFY(hasPointerChangedSpy.wait());
962 std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer());
963 std::unique_ptr<KWayland::Client::PointerPinchGesture> gesture(m_pointerGestures->createPinchGesture(pointer.get()));
964 QVERIFY(gesture);
965 QVERIFY(gesture->isValid());
966 QVERIFY(gesture->surface().isNull());
967 QCOMPARE(gesture->fingerCount(), 0u);
968
969 QSignalSpy startSpy(gesture.get(), &KWayland::Client::PointerPinchGesture::started);
970 QSignalSpy updateSpy(gesture.get(), &KWayland::Client::PointerPinchGesture::updated);
971 QSignalSpy endSpy(gesture.get(), &KWayland::Client::PointerPinchGesture::ended);
972 QSignalSpy cancelledSpy(gesture.get(), &KWayland::Client::PointerPinchGesture::cancelled);
973
974 // now create a surface
975 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
976 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
977 QVERIFY(surfaceCreatedSpy.wait());
978 auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
979 QVERIFY(serverSurface);
980
981 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
982 image.fill(Qt::black);
983 surface->attachBuffer(m_shm->createBuffer(image));
984 surface->damage(image.rect());
985 surface->commit(KWayland::Client::Surface::CommitFlag::None);
986 QSignalSpy committedSpy(serverSurface, &KWin::SurfaceInterface::committed);
987 QVERIFY(committedSpy.wait());
988
989 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0));
990 QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface);
991 QVERIFY(m_seatInterface->pointer());
992
993 // send in the start
994 std::chrono::milliseconds timestamp(1);
995 m_seatInterface->setTimestamp(timestamp++);
996 m_seatInterface->startPointerPinchGesture(3);
997 QVERIFY(startSpy.wait());
998 QCOMPARE(startSpy.count(), 1);
999 QCOMPARE(startSpy.first().at(0).value<quint32>(), m_display->serial());
1000 QCOMPARE(startSpy.first().at(1).value<quint32>(), 1u);
1001 QCOMPARE(gesture->fingerCount(), 3u);
1002 QCOMPARE(gesture->surface().data(), surface.get());
1003
1004 // another start should not be possible
1005 m_seatInterface->startPointerPinchGesture(3);
1006 QVERIFY(sync());
1007 QCOMPARE(startSpy.count(), 1);
1008
1009 // send in some updates
1010 m_seatInterface->setTimestamp(timestamp++);
1011 m_seatInterface->updatePointerPinchGesture(QPointF(2, 3), 2, 45);
1012 QVERIFY(updateSpy.wait());
1013 m_seatInterface->setTimestamp(timestamp++);
1014 m_seatInterface->updatePointerPinchGesture(QPointF(4, 5), 1, 90);
1015 QVERIFY(updateSpy.wait());
1016 QCOMPARE(updateSpy.count(), 2);
1017 QCOMPARE(updateSpy.at(0).at(0).toSizeF(), QSizeF(2, 3));
1018 QCOMPARE(updateSpy.at(0).at(1).value<quint32>(), 2u);
1019 QCOMPARE(updateSpy.at(0).at(2).value<quint32>(), 45u);
1020 QCOMPARE(updateSpy.at(0).at(3).value<quint32>(), 2u);
1021 QCOMPARE(updateSpy.at(1).at(0).toSizeF(), QSizeF(4, 5));
1022 QCOMPARE(updateSpy.at(1).at(1).value<quint32>(), 1u);
1023 QCOMPARE(updateSpy.at(1).at(2).value<quint32>(), 90u);
1024 QCOMPARE(updateSpy.at(1).at(3).value<quint32>(), 3u);
1025
1026 // now end or cancel
1027 QFETCH(bool, cancel);
1028 QSignalSpy *spy;
1029 m_seatInterface->setTimestamp(timestamp++);
1030 if (cancel) {
1031 m_seatInterface->cancelPointerPinchGesture();
1032 spy = &cancelledSpy;
1033 } else {
1034 m_seatInterface->endPointerPinchGesture();
1035 spy = &endSpy;
1036 }
1037 QVERIFY(spy->wait());
1038 QFETCH(int, expectedEndCount);
1039 QCOMPARE(endSpy.count(), expectedEndCount);
1040 QFETCH(int, expectedCancelCount);
1041 QCOMPARE(cancelledSpy.count(), expectedCancelCount);
1042 QCOMPARE(spy->count(), 1);
1043 QCOMPARE(spy->first().at(0).value<quint32>(), m_display->serial());
1044 QCOMPARE(spy->first().at(1).value<quint32>(), 4u);
1045
1046 QCOMPARE(gesture->fingerCount(), 0u);
1047 QVERIFY(gesture->surface().isNull());
1048
1049 // now a start should be possible again
1050 m_seatInterface->setTimestamp(timestamp++);
1051 m_seatInterface->startPointerPinchGesture(3);
1052 QVERIFY(startSpy.wait());
1053
1054 // unsetting the focused pointer surface should not change anything
1055 m_seatInterface->notifyPointerLeave();
1056 m_seatInterface->setTimestamp(timestamp++);
1057 m_seatInterface->updatePointerPinchGesture(QPointF(6, 7), 2, -45);
1058 QVERIFY(updateSpy.wait());
1059 // and end
1060 m_seatInterface->setTimestamp(timestamp++);
1061 if (cancel) {
1062 m_seatInterface->cancelPointerPinchGesture();
1063 } else {
1064 m_seatInterface->endPointerPinchGesture();
1065 }
1066 QVERIFY(spy->wait());
1067}
1068
1069void TestWaylandSeat::testPointerHoldGesture_data()
1070{
1071 QTest::addColumn<bool>("cancel");
1072 QTest::addColumn<int>("expectedEndCount");
1073 QTest::addColumn<int>("expectedCancelCount");
1074
1075 QTest::newRow("end") << false << 1 << 0;
1076 QTest::newRow("cancel") << true << 0 << 1;
1077}
1078
1079class PointerHoldGesture : public QObject, public QtWayland::zwp_pointer_gesture_hold_v1
1080{
1081 using zwp_pointer_gesture_hold_v1::zwp_pointer_gesture_hold_v1;
1082 Q_OBJECT
1083 void zwp_pointer_gesture_hold_v1_begin(uint32_t serial, uint32_t time, wl_surface *surface, uint32_t fingers) override
1084 {
1085 Q_EMIT started(serial, time, surface, fingers);
1086 }
1087
1088 void zwp_pointer_gesture_hold_v1_end(uint32_t serial, uint32_t time, int32_t cancelled) override
1089 {
1090 cancelled ? Q_EMIT this->cancelled(serial, time) : Q_EMIT ended(serial, time);
1091 }
1092Q_SIGNALS:
1093 void started(quint32 serial, quint32 time, void *surface, quint32 fingers);
1094 void ended(quint32 serial, quint32 time);
1095 void cancelled(quint32 serial, quint32 time);
1096};
1097
1098void TestWaylandSeat::testPointerHoldGesture()
1099{
1100 using namespace KWin;
1101
1102 // first create the pointer and pointer swipe gesture
1103 QSignalSpy hasPointerChangedSpy(m_seat, &KWayland::Client::Seat::hasPointerChanged);
1104 m_seatInterface->setHasPointer(true);
1105 QVERIFY(hasPointerChangedSpy.wait());
1106 std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer());
1107 KWayland::Client::Registry registry;
1108 QSignalSpy gesturesAnnoucedSpy(&registry, &KWayland::Client::Registry::pointerGesturesUnstableV1Announced);
1109 registry.create(m_connection);
1110 registry.setup();
1111 QVERIFY(gesturesAnnoucedSpy.wait());
1112 QtWayland::zwp_pointer_gestures_v1 gestures(registry, gesturesAnnoucedSpy.first().at(0).value<int>(), gesturesAnnoucedSpy.first().at(1).value<int>());
1113 PointerHoldGesture gesture(gestures.get_hold_gesture(*pointer));
1114 QVERIFY(gesture.isInitialized());
1115
1116 QSignalSpy startSpy(&gesture, &PointerHoldGesture::started);
1117 QSignalSpy endSpy(&gesture, &PointerHoldGesture::ended);
1118 QSignalSpy cancelledSpy(&gesture, &PointerHoldGesture::cancelled);
1119
1120 // now create a surface
1121 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
1122 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
1123 QVERIFY(surfaceCreatedSpy.wait());
1124 auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
1125 QVERIFY(serverSurface);
1126
1127 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
1128 image.fill(Qt::black);
1129 surface->attachBuffer(m_shm->createBuffer(image));
1130 surface->damage(image.rect());
1131 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1132 QSignalSpy committedSpy(serverSurface, &KWin::SurfaceInterface::committed);
1133 QVERIFY(committedSpy.wait());
1134
1135 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0));
1136 QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface);
1137 QVERIFY(m_seatInterface->pointer());
1138
1139 // send in the start
1140 std::chrono::milliseconds timestamp(1);
1141 m_seatInterface->setTimestamp(timestamp++);
1142 m_seatInterface->startPointerHoldGesture(3);
1143 QVERIFY(startSpy.wait());
1144 QCOMPARE(startSpy.count(), 1);
1145 QCOMPARE(startSpy.first().at(0).value<quint32>(), m_display->serial());
1146 QCOMPARE(startSpy.first().at(1).value<quint32>(), 1u);
1147 QCOMPARE(startSpy.first().at(2).value<void *>(), *surface.get());
1148 QCOMPARE(startSpy.first().at(3).value<quint32>(), 3);
1149
1150 // another start should not be possible
1151 m_seatInterface->startPointerPinchGesture(3);
1152 QVERIFY(sync());
1153 QCOMPARE(startSpy.count(), 1);
1154
1155 // now end or cancel
1156 QFETCH(bool, cancel);
1157 QSignalSpy *spy;
1158 m_seatInterface->setTimestamp(timestamp++);
1159 if (cancel) {
1160 m_seatInterface->cancelPointerHoldGesture();
1161 spy = &cancelledSpy;
1162 } else {
1163 m_seatInterface->endPointerHoldGesture();
1164 spy = &endSpy;
1165 }
1166 QVERIFY(spy->wait());
1167 QFETCH(int, expectedEndCount);
1168 QCOMPARE(endSpy.count(), expectedEndCount);
1169 QFETCH(int, expectedCancelCount);
1170 QCOMPARE(cancelledSpy.count(), expectedCancelCount);
1171 QCOMPARE(spy->count(), 1);
1172 QCOMPARE(spy->first().at(0).value<quint32>(), m_display->serial());
1173 QCOMPARE(spy->first().at(1).value<quint32>(), 2);
1174
1175 // now a start should be possible again
1176 m_seatInterface->setTimestamp(timestamp++);
1177 m_seatInterface->startPointerHoldGesture(3);
1178 QVERIFY(startSpy.wait());
1179
1180 // and end
1181 m_seatInterface->setTimestamp(timestamp++);
1182 if (cancel) {
1183 m_seatInterface->cancelPointerHoldGesture();
1184 } else {
1185 m_seatInterface->endPointerHoldGesture();
1186 }
1187 QVERIFY(spy->wait());
1188}
1189
1190void TestWaylandSeat::testPointerAxis()
1191{
1192 using namespace KWin;
1193
1194 // first create the pointer
1195 QSignalSpy hasPointerChangedSpy(m_seat, &KWayland::Client::Seat::hasPointerChanged);
1196 m_seatInterface->setHasPointer(true);
1197 QVERIFY(hasPointerChangedSpy.wait());
1198 std::unique_ptr<KWayland::Client::Pointer> pointer(m_seat->createPointer());
1199 QVERIFY(pointer);
1200
1201 // now create a surface
1202 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
1203 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
1204 QVERIFY(surfaceCreatedSpy.wait());
1205 auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
1206 QVERIFY(serverSurface);
1207
1208 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
1209 image.fill(Qt::black);
1210 surface->attachBuffer(m_shm->createBuffer(image));
1211 surface->damage(image.rect());
1212 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1213 QSignalSpy committedSpy(serverSurface, &KWin::SurfaceInterface::committed);
1214 QVERIFY(committedSpy.wait());
1215
1216 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0));
1217 QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface);
1218 QSignalSpy frameSpy(pointer.get(), &KWayland::Client::Pointer::frame);
1219 QVERIFY(frameSpy.wait());
1220 QCOMPARE(frameSpy.count(), 1);
1221
1222 // let's scroll vertically
1223 QSignalSpy axisSourceSpy(pointer.get(), &KWayland::Client::Pointer::axisSourceChanged);
1224 QSignalSpy axisSpy(pointer.get(), &KWayland::Client::Pointer::axisChanged);
1225 QSignalSpy axisDiscreteSpy(pointer.get(), &KWayland::Client::Pointer::axisDiscreteChanged);
1226 QSignalSpy axisStoppedSpy(pointer.get(), &KWayland::Client::Pointer::axisStopped);
1227
1228 std::chrono::milliseconds timestamp(1);
1229 m_seatInterface->setTimestamp(timestamp++);
1230 m_seatInterface->notifyPointerAxis(Qt::Vertical, 10, 120, PointerAxisSource::Wheel);
1231 m_seatInterface->notifyPointerFrame();
1232 QVERIFY(frameSpy.wait());
1233 QCOMPARE(frameSpy.count(), 2);
1234 QCOMPARE(axisSourceSpy.count(), 1);
1235 QCOMPARE(axisSourceSpy.last().at(0).value<KWayland::Client::Pointer::AxisSource>(), KWayland::Client::Pointer::AxisSource::Wheel);
1236 QCOMPARE(axisDiscreteSpy.count(), 1);
1237 QCOMPARE(axisDiscreteSpy.last().at(0).value<KWayland::Client::Pointer::Axis>(), KWayland::Client::Pointer::Axis::Vertical);
1238 QCOMPARE(axisDiscreteSpy.last().at(1).value<qint32>(), 1);
1239 QCOMPARE(axisSpy.count(), 1);
1240 QCOMPARE(axisSpy.last().at(0).value<quint32>(), quint32(1));
1241 QCOMPARE(axisSpy.last().at(1).value<KWayland::Client::Pointer::Axis>(), KWayland::Client::Pointer::Axis::Vertical);
1242 QCOMPARE(axisSpy.last().at(2).value<qreal>(), 10.0);
1243 QCOMPARE(axisStoppedSpy.count(), 0);
1244
1245 // let's scroll using fingers
1246 m_seatInterface->setTimestamp(timestamp++);
1247 m_seatInterface->notifyPointerAxis(Qt::Horizontal, 42, 0, PointerAxisSource::Finger);
1248 m_seatInterface->notifyPointerFrame();
1249 QVERIFY(frameSpy.wait());
1250 QCOMPARE(frameSpy.count(), 3);
1251 QCOMPARE(axisSourceSpy.count(), 2);
1252 QCOMPARE(axisSourceSpy.last().at(0).value<KWayland::Client::Pointer::AxisSource>(), KWayland::Client::Pointer::AxisSource::Finger);
1253 QCOMPARE(axisDiscreteSpy.count(), 1);
1254 QCOMPARE(axisSpy.count(), 2);
1255 QCOMPARE(axisSpy.last().at(0).value<quint32>(), quint32(2));
1256 QCOMPARE(axisSpy.last().at(1).value<KWayland::Client::Pointer::Axis>(), KWayland::Client::Pointer::Axis::Horizontal);
1257 QCOMPARE(axisSpy.last().at(2).value<qreal>(), 42.0);
1258 QCOMPARE(axisStoppedSpy.count(), 0);
1259
1260 // lift the fingers off the device
1261 m_seatInterface->setTimestamp(timestamp++);
1262 m_seatInterface->notifyPointerAxis(Qt::Horizontal, 0, 0, PointerAxisSource::Finger);
1263 m_seatInterface->notifyPointerFrame();
1264 QVERIFY(frameSpy.wait());
1265 QCOMPARE(frameSpy.count(), 4);
1266 QCOMPARE(axisSourceSpy.count(), 3);
1267 QCOMPARE(axisSourceSpy.last().at(0).value<KWayland::Client::Pointer::AxisSource>(), KWayland::Client::Pointer::AxisSource::Finger);
1268 QCOMPARE(axisDiscreteSpy.count(), 1);
1269 QCOMPARE(axisSpy.count(), 2);
1270 QCOMPARE(axisStoppedSpy.count(), 1);
1271 QCOMPARE(axisStoppedSpy.last().at(0).value<quint32>(), 3);
1272 QCOMPARE(axisStoppedSpy.last().at(1).value<KWayland::Client::Pointer::Axis>(), KWayland::Client::Pointer::Axis::Horizontal);
1273
1274 // if the device is unknown, no axis_source event should be sent
1275 m_seatInterface->setTimestamp(timestamp++);
1276 m_seatInterface->notifyPointerAxis(Qt::Horizontal, 42, 120, PointerAxisSource::Unknown);
1277 m_seatInterface->notifyPointerFrame();
1278 QVERIFY(frameSpy.wait());
1279 QCOMPARE(frameSpy.count(), 5);
1280 QCOMPARE(axisSourceSpy.count(), 3);
1281 QCOMPARE(axisDiscreteSpy.count(), 2);
1282 QCOMPARE(axisDiscreteSpy.last().at(0).value<KWayland::Client::Pointer::Axis>(), KWayland::Client::Pointer::Axis::Horizontal);
1283 QCOMPARE(axisDiscreteSpy.last().at(1).value<qint32>(), 1);
1284 QCOMPARE(axisSpy.count(), 3);
1285 QCOMPARE(axisSpy.last().at(0).value<quint32>(), quint32(4));
1286 QCOMPARE(axisSpy.last().at(1).value<KWayland::Client::Pointer::Axis>(), KWayland::Client::Pointer::Axis::Horizontal);
1287 QCOMPARE(axisSpy.last().at(2).value<qreal>(), 42.0);
1288 QCOMPARE(axisStoppedSpy.count(), 1);
1289}
1290
1291void TestWaylandSeat::testCursor()
1292{
1293 using namespace KWin;
1294
1295 QSignalSpy pointerSpy(m_seat, &KWayland::Client::Seat::hasPointerChanged);
1296 m_seatInterface->setHasPointer(true);
1297 QVERIFY(pointerSpy.wait());
1298
1299 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
1300 KWayland::Client::Surface *surface = m_compositor->createSurface(m_compositor);
1301 QVERIFY(surfaceCreatedSpy.wait());
1302 SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value<KWin::SurfaceInterface *>();
1303 QVERIFY(serverSurface);
1304
1305 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
1306 image.fill(Qt::black);
1307 surface->attachBuffer(m_shm->createBuffer(image));
1308 surface->damage(image.rect());
1309 surface->commit(KWayland::Client::Surface::CommitFlag::None);
1310 QSignalSpy committedSpy(serverSurface, &KWin::SurfaceInterface::committed);
1311 QVERIFY(committedSpy.wait());
1312
1313 std::unique_ptr<KWayland::Client::Pointer> p(m_seat->createPointer());
1314 QVERIFY(p->isValid());
1315 wl_display_flush(m_connection->display());
1316 QCoreApplication::processEvents();
1317
1318 QSignalSpy enteredSpy(p.get(), &KWayland::Client::Pointer::entered);
1319
1320 uint32_t serial = m_seatInterface->display()->serial();
1321 m_seatInterface->notifyPointerEnter(serverSurface, QPointF(20, 18), QPointF(10, 15));
1322 QVERIFY(enteredSpy.wait());
1323 QCOMPARE_GT(enteredSpy.first().first().value<quint32>(), serial);
1324 QVERIFY(m_seatInterface->focusedPointerSurface());
1325
1326 QSignalSpy cursorChangedSpy(m_seatInterface->pointer(), &KWin::PointerInterface::cursorChanged);
1327 // just remove the pointer
1328 p->setCursor(nullptr);
1329 QVERIFY(cursorChangedSpy.wait());
1330 QCOMPARE(cursorChangedSpy.count(), 1);
1331 auto cursor = std::get<KWin::PointerSurfaceCursor *>(cursorChangedSpy.last().first().value<KWin::PointerCursor>());
1332 QVERIFY(cursor);
1333 QVERIFY(!cursor->surface());
1334 QCOMPARE(cursor->hotspot(), QPoint());
1335
1336 // test changing hotspot
1337 p->setCursor(nullptr, QPoint(1, 2));
1338 QVERIFY(cursorChangedSpy.wait());
1339 QCOMPARE(cursorChangedSpy.count(), 2);
1340 QCOMPARE(cursor->surface(), nullptr);
1341 QCOMPARE(cursor->hotspot(), QPoint(1, 2));
1342
1343 // set surface
1344 QImage img(QSize(10, 20), QImage::Format_RGB32);
1345 img.fill(Qt::red);
1346 auto cursorSurface = m_compositor->createSurface(m_compositor);
1347 cursorSurface->attachBuffer(m_shm->createBuffer(img));
1348 cursorSurface->damage(QRect(0, 0, 10, 20));
1349 cursorSurface->commit(KWayland::Client::Surface::CommitFlag::None);
1350 p->setCursor(cursorSurface, QPoint(1, 2));
1351 QVERIFY(cursorChangedSpy.wait());
1352 QCOMPARE(cursorChangedSpy.count(), 3);
1353 QCOMPARE(cursor->hotspot(), QPoint(1, 2));
1354 QVERIFY(cursor->surface());
1355
1356 p->hideCursor();
1357 QVERIFY(cursorChangedSpy.wait());
1358 QCOMPARE(cursorChangedSpy.count(), 4);
1359 QVERIFY(!cursor->surface());
1360}
1361
1362void TestWaylandSeat::testKeyboard()
1363{
1364 using namespace KWin;
1365
1366 QSignalSpy keyboardSpy(m_seat, &KWayland::Client::Seat::hasKeyboardChanged);
1367 m_seatInterface->setHasKeyboard(true);
1368 QVERIFY(keyboardSpy.wait());
1369
1370 // update modifiers before any surface focused
1371 m_seatInterface->notifyKeyboardModifiers(4, 3, 2, 1);
1372
1373 // create the surface
1374 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
1375 KWayland::Client::Surface *s = m_compositor->createSurface(m_compositor);
1376 QVERIFY(surfaceCreatedSpy.wait());
1377 SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value<KWin::SurfaceInterface *>();
1378 QVERIFY(serverSurface);
1379
1380 KWayland::Client::Keyboard *keyboard = m_seat->createKeyboard(m_seat);
1381 QSignalSpy repeatInfoSpy(keyboard, &KWayland::Client::Keyboard::keyRepeatChanged);
1382 const KWayland::Client::Keyboard &ckeyboard = *keyboard;
1383 QVERIFY(keyboard->isValid());
1384 QCOMPARE(keyboard->isKeyRepeatEnabled(), false);
1385 QCOMPARE(keyboard->keyRepeatDelay(), 0);
1386 QCOMPARE(keyboard->keyRepeatRate(), 0);
1387 QVERIFY(repeatInfoSpy.wait());
1388
1389 auto serverKeyboard = m_seatInterface->keyboard();
1390 QVERIFY(serverKeyboard);
1391
1392 // we should get the repeat info announced
1393 QCOMPARE(repeatInfoSpy.count(), 1);
1394 QCOMPARE(keyboard->isKeyRepeatEnabled(), false);
1395 QCOMPARE(keyboard->keyRepeatDelay(), 0);
1396 QCOMPARE(keyboard->keyRepeatRate(), 0);
1397
1398 // let's change repeat in server
1399 m_seatInterface->keyboard()->setRepeatInfo(25, 660);
1400 QVERIFY(repeatInfoSpy.wait());
1401 QCOMPARE(repeatInfoSpy.count(), 2);
1402 QCOMPARE(keyboard->isKeyRepeatEnabled(), true);
1403 QCOMPARE(keyboard->keyRepeatRate(), 25);
1404 QCOMPARE(keyboard->keyRepeatDelay(), 660);
1405
1406 std::chrono::milliseconds time(1);
1407
1408 m_seatInterface->setTimestamp(time++);
1409 m_seatInterface->notifyKeyboardKey(KEY_K, KeyboardKeyState::Pressed);
1410 m_seatInterface->setTimestamp(time++);
1411 m_seatInterface->notifyKeyboardKey(KEY_D, KeyboardKeyState::Pressed);
1412 m_seatInterface->setTimestamp(time++);
1413 m_seatInterface->notifyKeyboardKey(KEY_E, KeyboardKeyState::Pressed);
1414
1415 QSignalSpy modifierSpy(keyboard, &KWayland::Client::Keyboard::modifiersChanged);
1416
1417 QSignalSpy enteredSpy(keyboard, &KWayland::Client::Keyboard::entered);
1418 m_seatInterface->setFocusedKeyboardSurface(serverSurface);
1419 QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
1420 QCOMPARE(m_seatInterface->keyboard()->focusedSurface(), serverSurface);
1421
1422 // we get the modifiers sent after the enter
1423 QVERIFY(modifierSpy.wait());
1424 QCOMPARE(modifierSpy.count(), 1);
1425 QCOMPARE(modifierSpy.first().at(0).value<quint32>(), quint32(4));
1426 QCOMPARE(modifierSpy.first().at(1).value<quint32>(), quint32(3));
1427 QCOMPARE(modifierSpy.first().at(2).value<quint32>(), quint32(2));
1428 QCOMPARE(modifierSpy.first().at(3).value<quint32>(), quint32(1));
1429 QCOMPARE(enteredSpy.count(), 1);
1430 // TODO: get through API
1431 QCOMPARE(enteredSpy.first().first().value<quint32>(), m_display->serial() - 1);
1432
1433 QSignalSpy keyChangedSpy(keyboard, &KWayland::Client::Keyboard::keyChanged);
1434
1435 m_seatInterface->setTimestamp(time++);
1436 m_seatInterface->notifyKeyboardKey(KEY_E, KeyboardKeyState::Released);
1437 QVERIFY(keyChangedSpy.wait());
1438 m_seatInterface->setTimestamp(time++);
1439 m_seatInterface->notifyKeyboardKey(KEY_D, KeyboardKeyState::Released);
1440 QVERIFY(keyChangedSpy.wait());
1441 m_seatInterface->setTimestamp(time++);
1442 m_seatInterface->notifyKeyboardKey(KEY_K, KeyboardKeyState::Released);
1443 QVERIFY(keyChangedSpy.wait());
1444 m_seatInterface->setTimestamp(time++);
1445 m_seatInterface->notifyKeyboardKey(KEY_F1, KeyboardKeyState::Pressed);
1446 QVERIFY(keyChangedSpy.wait());
1447 m_seatInterface->setTimestamp(time++);
1448 m_seatInterface->notifyKeyboardKey(KEY_F1, KeyboardKeyState::Released);
1449 QVERIFY(keyChangedSpy.wait());
1450
1451 QCOMPARE(keyChangedSpy.count(), 5);
1452 QCOMPARE(keyChangedSpy.at(0).at(0).value<quint32>(), quint32(KEY_E));
1453 QCOMPARE(keyChangedSpy.at(0).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Released);
1454 QCOMPARE(keyChangedSpy.at(0).at(2).value<quint32>(), quint32(4));
1455 QCOMPARE(keyChangedSpy.at(1).at(0).value<quint32>(), quint32(KEY_D));
1456 QCOMPARE(keyChangedSpy.at(1).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Released);
1457 QCOMPARE(keyChangedSpy.at(1).at(2).value<quint32>(), quint32(5));
1458 QCOMPARE(keyChangedSpy.at(2).at(0).value<quint32>(), quint32(KEY_K));
1459 QCOMPARE(keyChangedSpy.at(2).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Released);
1460 QCOMPARE(keyChangedSpy.at(2).at(2).value<quint32>(), quint32(6));
1461 QCOMPARE(keyChangedSpy.at(3).at(0).value<quint32>(), quint32(KEY_F1));
1462 QCOMPARE(keyChangedSpy.at(3).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Pressed);
1463 QCOMPARE(keyChangedSpy.at(3).at(2).value<quint32>(), quint32(7));
1464 QCOMPARE(keyChangedSpy.at(4).at(0).value<quint32>(), quint32(KEY_F1));
1465 QCOMPARE(keyChangedSpy.at(4).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Released);
1466 QCOMPARE(keyChangedSpy.at(4).at(2).value<quint32>(), quint32(8));
1467
1468 // releasing a key which is already released should not set a key changed
1469 m_seatInterface->notifyKeyboardKey(KEY_F1, KeyboardKeyState::Released);
1470 QVERIFY(sync());
1471 QCOMPARE(keyChangedSpy.count(), 5);
1472 // let's press it again
1473 m_seatInterface->notifyKeyboardKey(KEY_F1, KeyboardKeyState::Pressed);
1474 QVERIFY(keyChangedSpy.wait());
1475 QCOMPARE(keyChangedSpy.count(), 6);
1476 // press again should be ignored
1477 m_seatInterface->notifyKeyboardKey(KEY_F1, KeyboardKeyState::Pressed);
1478 QVERIFY(sync());
1479 QCOMPARE(keyChangedSpy.count(), 6);
1480 // and release
1481 m_seatInterface->notifyKeyboardKey(KEY_F1, KeyboardKeyState::Released);
1482 QVERIFY(keyChangedSpy.wait());
1483 QCOMPARE(keyChangedSpy.count(), 7);
1484
1485 m_seatInterface->notifyKeyboardModifiers(1, 2, 3, 4);
1486 QVERIFY(modifierSpy.wait());
1487 QCOMPARE(modifierSpy.count(), 2);
1488 QCOMPARE(modifierSpy.last().at(0).value<quint32>(), quint32(1));
1489 QCOMPARE(modifierSpy.last().at(1).value<quint32>(), quint32(2));
1490 QCOMPARE(modifierSpy.last().at(2).value<quint32>(), quint32(3));
1491 QCOMPARE(modifierSpy.last().at(3).value<quint32>(), quint32(4));
1492
1493 QSignalSpy leftSpy(keyboard, &KWayland::Client::Keyboard::left);
1494 m_seatInterface->setFocusedKeyboardSurface(nullptr);
1495 QVERIFY(!m_seatInterface->focusedKeyboardSurface());
1496 QVERIFY(leftSpy.wait());
1497 QCOMPARE(leftSpy.count(), 1);
1498 // TODO: get through API
1499 QCOMPARE(leftSpy.first().first().value<quint32>(), m_display->serial() - 1);
1500
1501 QVERIFY(!keyboard->enteredSurface());
1502 QVERIFY(!ckeyboard.enteredSurface());
1503
1504 // enter it again
1505 m_seatInterface->setFocusedKeyboardSurface(serverSurface);
1506 QVERIFY(modifierSpy.wait());
1507 QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
1508 QCOMPARE(m_seatInterface->keyboard()->focusedSurface(), serverSurface);
1509 QCOMPARE(enteredSpy.count(), 2);
1510
1511 QCOMPARE(keyboard->enteredSurface(), s);
1512 QCOMPARE(ckeyboard.enteredSurface(), s);
1513
1514 QSignalSpy serverSurfaceDestroyedSpy(serverSurface, &QObject::destroyed);
1515 QCOMPARE(keyboard->enteredSurface(), s);
1516 delete s;
1517 QVERIFY(!keyboard->enteredSurface());
1518 QVERIFY(leftSpy.wait());
1519 QCOMPARE(serverSurfaceDestroyedSpy.count(), 1);
1520 QVERIFY(!m_seatInterface->focusedKeyboardSurface());
1521 QVERIFY(!serverKeyboard->focusedSurface());
1522
1523 // let's create a Surface again
1524 std::unique_ptr<KWayland::Client::Surface> s2(m_compositor->createSurface());
1525 QVERIFY(surfaceCreatedSpy.wait());
1526 QCOMPARE(surfaceCreatedSpy.count(), 2);
1527 serverSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
1528 QVERIFY(serverSurface);
1529 m_seatInterface->setFocusedKeyboardSurface(serverSurface);
1530 QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
1531 QCOMPARE(m_seatInterface->keyboard(), serverKeyboard);
1532}
1533
1534void TestWaylandSeat::testSelection()
1535{
1536 using namespace KWin;
1537 std::unique_ptr<DataDeviceManagerInterface> ddmi(new DataDeviceManagerInterface(m_display));
1538 KWayland::Client::Registry registry;
1539 QSignalSpy dataDeviceManagerSpy(&registry, &KWayland::Client::Registry::dataDeviceManagerAnnounced);
1540 m_seatInterface->setHasKeyboard(true);
1541 registry.setEventQueue(m_queue);
1542 registry.create(m_connection->display());
1543 QVERIFY(registry.isValid());
1544 registry.setup();
1545
1546 QVERIFY(dataDeviceManagerSpy.wait());
1547 std::unique_ptr<KWayland::Client::DataDeviceManager> ddm(
1548 registry.createDataDeviceManager(dataDeviceManagerSpy.first().first().value<quint32>(), dataDeviceManagerSpy.first().last().value<quint32>()));
1549 QVERIFY(ddm->isValid());
1550
1551 std::unique_ptr<KWayland::Client::DataDevice> dd1(ddm->getDataDevice(m_seat));
1552 QVERIFY(dd1->isValid());
1553 QSignalSpy selectionSpy(dd1.get(), &KWayland::Client::DataDevice::selectionOffered);
1554 QSignalSpy selectionClearedSpy(dd1.get(), &KWayland::Client::DataDevice::selectionCleared);
1555
1556 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
1557 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
1558 QVERIFY(surface->isValid());
1559 QVERIFY(surfaceCreatedSpy.wait());
1560 auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
1561 QVERIFY(!m_seatInterface->selection());
1562 m_seatInterface->setFocusedKeyboardSurface(serverSurface);
1563 QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
1564 QVERIFY(selectionClearedSpy.wait());
1565 QVERIFY(selectionSpy.isEmpty());
1566 QVERIFY(!selectionClearedSpy.isEmpty());
1567 selectionClearedSpy.clear();
1568 QVERIFY(!m_seatInterface->selection());
1569
1570 // now let's try to set a selection - we have keyboard focus, so it should be sent to us
1571 std::unique_ptr<KWayland::Client::DataSource> ds(ddm->createDataSource());
1572 QVERIFY(ds->isValid());
1573 ds->offer(QStringLiteral("text/plain"));
1574 dd1->setSelection(0, ds.get());
1575 QVERIFY(selectionSpy.wait());
1576 QCOMPARE(selectionSpy.count(), 1);
1577 auto ddi = m_seatInterface->selection();
1578 QVERIFY(ddi);
1579 auto df = selectionSpy.first().first().value<KWayland::Client::DataOffer *>();
1580 QCOMPARE(df->offeredMimeTypes().count(), 1);
1581 QCOMPARE(df->offeredMimeTypes().first().name(), QStringLiteral("text/plain"));
1582
1583 // try to clear
1584 dd1->setSelection(0);
1585 QVERIFY(selectionClearedSpy.wait());
1586 QCOMPARE(selectionClearedSpy.count(), 1);
1587 QCOMPARE(selectionSpy.count(), 1);
1588
1589 // unset the keyboard focus
1590 m_seatInterface->setFocusedKeyboardSurface(nullptr);
1591 QVERIFY(!m_seatInterface->focusedKeyboardSurface());
1592 serverSurface->client()->flush();
1593 QCoreApplication::processEvents();
1594 QCoreApplication::processEvents();
1595
1596 // try to set Selection
1597 dd1->setSelection(0, ds.get());
1598 wl_display_flush(m_connection->display());
1599 QCoreApplication::processEvents();
1600 QCoreApplication::processEvents();
1601 QCOMPARE(selectionSpy.count(), 1);
1602
1603 // let's unset the selection on the seat
1604 m_seatInterface->setSelection(nullptr);
1605 // and pass focus back on our surface
1606 m_seatInterface->setFocusedKeyboardSurface(serverSurface);
1607 // we don't have a selection, so it should not send a selection
1608 QVERIFY(sync());
1609 QCOMPARE(selectionSpy.count(), 1);
1610 // now let's set it manually
1611 m_seatInterface->setSelection(ddi);
1612 QCOMPARE(m_seatInterface->selection(), ddi);
1613 QVERIFY(selectionSpy.wait());
1614 QCOMPARE(selectionSpy.count(), 2);
1615 // setting the same again should not change
1616 m_seatInterface->setSelection(ddi);
1617 QVERIFY(sync());
1618 QCOMPARE(selectionSpy.count(), 2);
1619 // now clear it manually
1620 m_seatInterface->setSelection(nullptr);
1621 QVERIFY(selectionClearedSpy.wait());
1622 QCOMPARE(selectionSpy.count(), 2);
1623
1624 // create a second ddi and a data source
1625 std::unique_ptr<KWayland::Client::DataDevice> dd2(ddm->getDataDevice(m_seat));
1626 QVERIFY(dd2->isValid());
1627 std::unique_ptr<KWayland::Client::DataSource> ds2(ddm->createDataSource());
1628 QVERIFY(ds2->isValid());
1629 ds2->offer(QStringLiteral("text/plain"));
1630 dd2->setSelection(0, ds2.get());
1631 QVERIFY(selectionSpy.wait());
1632 QSignalSpy cancelledSpy(ds2.get(), &KWayland::Client::DataSource::cancelled);
1633 m_seatInterface->setSelection(ddi);
1634 QVERIFY(cancelledSpy.wait());
1635}
1636
1637void TestWaylandSeat::testDataDeviceForKeyboardSurface()
1638{
1639 // this test verifies that the server does not crash when creating a datadevice for the focused keyboard surface
1640 // and the currentSelection does not have a DataSource.
1641 // to properly test the functionality this test requires a second client
1642 using namespace KWin;
1643 // create the DataDeviceManager
1644 std::unique_ptr<DataDeviceManagerInterface> ddmi(new DataDeviceManagerInterface(m_display));
1645 QSignalSpy ddiCreatedSpy(ddmi.get(), &DataDeviceManagerInterface::dataDeviceCreated);
1646 m_seatInterface->setHasKeyboard(true);
1647
1648 // create a second Wayland client connection to use it for setSelection
1649 auto c = new KWayland::Client::ConnectionThread;
1650 QSignalSpy connectedSpy(c, &KWayland::Client::ConnectionThread::connected);
1651 c->setSocketName(s_socketName);
1652
1653 auto thread = new QThread(this);
1654 c->moveToThread(thread);
1655 thread->start();
1656
1657 c->initConnection();
1658 QVERIFY(connectedSpy.wait());
1659
1660 std::unique_ptr<KWayland::Client::EventQueue> queue(new KWayland::Client::EventQueue);
1661 queue->setup(c);
1662
1663 std::unique_ptr<KWayland::Client::Registry> registry(new KWayland::Client::Registry);
1664 QSignalSpy interfacesAnnouncedSpy(registry.get(), &KWayland::Client::Registry::interfacesAnnounced);
1665 registry->setEventQueue(queue.get());
1666 registry->create(c);
1667 QVERIFY(registry->isValid());
1668 registry->setup();
1669
1670 QVERIFY(interfacesAnnouncedSpy.wait());
1671 std::unique_ptr<KWayland::Client::Seat> seat(
1672 registry->createSeat(registry->interface(KWayland::Client::Registry::Interface::Seat).name, registry->interface(KWayland::Client::Registry::Interface::Seat).version));
1673 QVERIFY(seat->isValid());
1674 std::unique_ptr<KWayland::Client::DataDeviceManager> ddm1(registry->createDataDeviceManager(registry->interface(KWayland::Client::Registry::Interface::DataDeviceManager).name,
1675 registry->interface(KWayland::Client::Registry::Interface::DataDeviceManager).version));
1676 QVERIFY(ddm1->isValid());
1677
1678 // now create our first datadevice
1679 std::unique_ptr<KWayland::Client::DataDevice> dd1(ddm1->getDataDevice(seat.get()));
1680 QVERIFY(ddiCreatedSpy.wait());
1681 auto ddi = ddiCreatedSpy.first().first().value<DataDeviceInterface *>();
1682 QVERIFY(ddi);
1683 m_seatInterface->setSelection(ddi->selection());
1684
1685 // switch to other client
1686 // create a surface and pass it keyboard focus
1687 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
1688 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
1689 QVERIFY(surface->isValid());
1690 QVERIFY(surfaceCreatedSpy.wait());
1691 auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
1692 m_seatInterface->setFocusedKeyboardSurface(serverSurface);
1693 QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
1694
1695 // now create a DataDevice
1696 KWayland::Client::Registry registry2;
1697 QSignalSpy dataDeviceManagerSpy(&registry2, &KWayland::Client::Registry::dataDeviceManagerAnnounced);
1698 registry2.setEventQueue(m_queue);
1699 registry2.create(m_connection->display());
1700 QVERIFY(registry2.isValid());
1701 registry2.setup();
1702
1703 QVERIFY(dataDeviceManagerSpy.wait());
1704 std::unique_ptr<KWayland::Client::DataDeviceManager> ddm(
1705 registry2.createDataDeviceManager(dataDeviceManagerSpy.first().first().value<quint32>(), dataDeviceManagerSpy.first().last().value<quint32>()));
1706 QVERIFY(ddm->isValid());
1707
1708 std::unique_ptr<KWayland::Client::DataDevice> dd(ddm->getDataDevice(m_seat));
1709 QVERIFY(dd->isValid());
1710 QVERIFY(ddiCreatedSpy.wait());
1711
1712 // unset surface and set again
1713 m_seatInterface->setFocusedKeyboardSurface(nullptr);
1714 m_seatInterface->setFocusedKeyboardSurface(serverSurface);
1715
1716 // and delete the connection thread again
1717 dd1.reset();
1718 ddm1.reset();
1719 seat.reset();
1720 registry.reset();
1721 queue.reset();
1722 c->deleteLater();
1723 thread->quit();
1724 thread->wait();
1725 delete thread;
1726}
1727
1728void TestWaylandSeat::testTouch()
1729{
1730 using namespace KWin;
1731
1732 QSignalSpy touchSpy(m_seat, &KWayland::Client::Seat::hasTouchChanged);
1733 m_seatInterface->setHasTouch(true);
1734 QVERIFY(touchSpy.wait());
1735
1736 // create the surface
1737 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
1738 KWayland::Client::Surface *s = m_compositor->createSurface(m_compositor);
1739 QVERIFY(surfaceCreatedSpy.wait());
1740 SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value<KWin::SurfaceInterface *>();
1741 QVERIFY(serverSurface);
1742
1743 m_seatInterface->setFocusedTouchSurface(serverSurface);
1744 // no keyboard yet
1745 QCOMPARE(m_seatInterface->focusedTouchSurface(), serverSurface);
1746
1747 KWayland::Client::Touch *touch = m_seat->createTouch(m_seat);
1748 QVERIFY(touch->isValid());
1749
1750 // Process wl_touch bind request.
1751 wl_display_flush(m_connection->display());
1752 QCoreApplication::processEvents();
1753
1754 QSignalSpy sequenceStartedSpy(touch, &KWayland::Client::Touch::sequenceStarted);
1755 QSignalSpy sequenceEndedSpy(touch, &KWayland::Client::Touch::sequenceEnded);
1756 QSignalSpy sequenceCanceledSpy(touch, &KWayland::Client::Touch::sequenceCanceled);
1757 QSignalSpy frameEndedSpy(touch, &KWayland::Client::Touch::frameEnded);
1758 QSignalSpy pointAddedSpy(touch, &KWayland::Client::Touch::pointAdded);
1759 QSignalSpy pointMovedSpy(touch, &KWayland::Client::Touch::pointMoved);
1760 QSignalSpy pointRemovedSpy(touch, &KWayland::Client::Touch::pointRemoved);
1761
1762 std::chrono::milliseconds timestamp(1);
1763
1764 // try a few things
1765 m_seatInterface->setFocusedTouchSurfacePosition(QPointF(10, 20));
1766 QCOMPARE(m_seatInterface->focusedTouchSurfacePosition(), QPointF(10, 20));
1767 m_seatInterface->setTimestamp(timestamp++);
1768 m_seatInterface->notifyTouchDown(0, QPointF(15, 26));
1769 QVERIFY(sequenceStartedSpy.wait());
1770 QCOMPARE(sequenceStartedSpy.count(), 1);
1771 QCOMPARE(sequenceEndedSpy.count(), 0);
1772 QCOMPARE(sequenceCanceledSpy.count(), 0);
1773 QCOMPARE(frameEndedSpy.count(), 0);
1774 QCOMPARE(pointAddedSpy.count(), 0);
1775 QCOMPARE(pointMovedSpy.count(), 0);
1776 QCOMPARE(pointRemovedSpy.count(), 0);
1777 KWayland::Client::TouchPoint *tp = sequenceStartedSpy.first().first().value<KWayland::Client::TouchPoint *>();
1778 QVERIFY(tp);
1779 QCOMPARE(tp->downSerial(), m_seatInterface->display()->serial());
1780 QCOMPARE(tp->id(), 0);
1781 QVERIFY(tp->isDown());
1782 QCOMPARE(tp->position(), QPointF(5, 6));
1783 QCOMPARE(tp->positions().size(), 1);
1784 QCOMPARE(tp->time(), 1u);
1785 QCOMPARE(tp->timestamps().count(), 1);
1786 QCOMPARE(tp->upSerial(), 0u);
1787 QCOMPARE(tp->surface().data(), s);
1788 QCOMPARE(touch->sequence().count(), 1);
1789 QCOMPARE(touch->sequence().first(), tp);
1790
1791 // let's end the frame
1792 m_seatInterface->notifyTouchFrame();
1793 QVERIFY(frameEndedSpy.wait());
1794 QCOMPARE(frameEndedSpy.count(), 1);
1795
1796 // move the one point
1797 m_seatInterface->setTimestamp(timestamp++);
1798 m_seatInterface->notifyTouchMotion(0, QPointF(10, 20));
1799 m_seatInterface->notifyTouchFrame();
1800 QVERIFY(frameEndedSpy.wait());
1801 QCOMPARE(sequenceStartedSpy.count(), 1);
1802 QCOMPARE(sequenceEndedSpy.count(), 0);
1803 QCOMPARE(sequenceCanceledSpy.count(), 0);
1804 QCOMPARE(frameEndedSpy.count(), 2);
1805 QCOMPARE(pointAddedSpy.count(), 0);
1806 QCOMPARE(pointMovedSpy.count(), 1);
1807 QCOMPARE(pointRemovedSpy.count(), 0);
1808 QCOMPARE(pointMovedSpy.first().first().value<KWayland::Client::TouchPoint *>(), tp);
1809
1810 QCOMPARE(tp->id(), 0);
1811 QVERIFY(tp->isDown());
1812 QCOMPARE(tp->position(), QPointF(0, 0));
1813 QCOMPARE(tp->positions().size(), 2);
1814 QCOMPARE(tp->time(), 2u);
1815 QCOMPARE(tp->timestamps().count(), 2);
1816 QCOMPARE(tp->upSerial(), 0u);
1817 QCOMPARE(tp->surface().data(), s);
1818
1819 // add onther point
1820 m_seatInterface->setTimestamp(timestamp++);
1821 m_seatInterface->notifyTouchDown(1, QPointF(15, 26));
1822 m_seatInterface->notifyTouchFrame();
1823 QVERIFY(frameEndedSpy.wait());
1824 QCOMPARE(sequenceStartedSpy.count(), 1);
1825 QCOMPARE(sequenceEndedSpy.count(), 0);
1826 QCOMPARE(sequenceCanceledSpy.count(), 0);
1827 QCOMPARE(frameEndedSpy.count(), 3);
1828 QCOMPARE(pointAddedSpy.count(), 1);
1829 QCOMPARE(pointMovedSpy.count(), 1);
1830 QCOMPARE(pointRemovedSpy.count(), 0);
1831 QCOMPARE(touch->sequence().count(), 2);
1832 QCOMPARE(touch->sequence().first(), tp);
1833 KWayland::Client::TouchPoint *tp2 = pointAddedSpy.first().first().value<KWayland::Client::TouchPoint *>();
1834 QVERIFY(tp2);
1835 QCOMPARE(touch->sequence().last(), tp2);
1836 QCOMPARE(tp2->id(), 1);
1837 QVERIFY(tp2->isDown());
1838 QCOMPARE(tp2->position(), QPointF(5, 6));
1839 QCOMPARE(tp2->positions().size(), 1);
1840 QCOMPARE(tp2->time(), 3u);
1841 QCOMPARE(tp2->timestamps().count(), 1);
1842 QCOMPARE(tp2->upSerial(), 0u);
1843 QCOMPARE(tp2->surface().data(), s);
1844
1845 // send it an up
1846 m_seatInterface->setTimestamp(timestamp++);
1847 m_seatInterface->notifyTouchUp(1);
1848 m_seatInterface->notifyTouchFrame();
1849 QVERIFY(frameEndedSpy.wait());
1850 QCOMPARE(sequenceStartedSpy.count(), 1);
1851 QCOMPARE(sequenceEndedSpy.count(), 0);
1852 QCOMPARE(sequenceCanceledSpy.count(), 0);
1853 QCOMPARE(frameEndedSpy.count(), 4);
1854 QCOMPARE(pointAddedSpy.count(), 1);
1855 QCOMPARE(pointMovedSpy.count(), 1);
1856 QCOMPARE(pointRemovedSpy.count(), 1);
1857 QCOMPARE(pointRemovedSpy.first().first().value<KWayland::Client::TouchPoint *>(), tp2);
1858 QCOMPARE(tp2->id(), 1);
1859 QVERIFY(!tp2->isDown());
1860 QCOMPARE(tp2->position(), QPointF(5, 6));
1861 QCOMPARE(tp2->positions().size(), 1);
1862 QCOMPARE(tp2->time(), 4u);
1863 QCOMPARE(tp2->timestamps().count(), 2);
1864 QCOMPARE(tp2->upSerial(), m_seatInterface->display()->serial());
1865 QCOMPARE(tp2->surface().data(), s);
1866
1867 // send another down and up
1868 m_seatInterface->setTimestamp(timestamp++);
1869 m_seatInterface->notifyTouchDown(1, QPointF(15, 26));
1870 m_seatInterface->notifyTouchFrame();
1871 m_seatInterface->setTimestamp(timestamp++);
1872 m_seatInterface->notifyTouchUp(1);
1873 // and send an up for the first point
1874 m_seatInterface->notifyTouchUp(0);
1875 m_seatInterface->notifyTouchFrame();
1876 QVERIFY(frameEndedSpy.wait());
1877 QCOMPARE(sequenceStartedSpy.count(), 1);
1878 QCOMPARE(sequenceEndedSpy.count(), 1);
1879 QCOMPARE(sequenceCanceledSpy.count(), 0);
1880 QCOMPARE(frameEndedSpy.count(), 6);
1881 QCOMPARE(pointAddedSpy.count(), 2);
1882 QCOMPARE(pointMovedSpy.count(), 1);
1883 QCOMPARE(pointRemovedSpy.count(), 3);
1884 QCOMPARE(touch->sequence().count(), 3);
1885 QVERIFY(!touch->sequence().at(0)->isDown());
1886 QVERIFY(!touch->sequence().at(1)->isDown());
1887 QVERIFY(!touch->sequence().at(2)->isDown());
1888 QVERIFY(!m_seatInterface->isTouchSequence());
1889
1890 // try cancel
1891 m_seatInterface->setFocusedTouchSurface(serverSurface, QPointF(15, 26));
1892 m_seatInterface->setTimestamp(timestamp++);
1893 m_seatInterface->notifyTouchDown(0, QPointF(15, 26));
1894 m_seatInterface->notifyTouchFrame();
1895 m_seatInterface->notifyTouchCancel();
1896 QVERIFY(sequenceCanceledSpy.wait());
1897 QCOMPARE(sequenceStartedSpy.count(), 2);
1898 QCOMPARE(sequenceEndedSpy.count(), 1);
1899 QCOMPARE(sequenceCanceledSpy.count(), 1);
1900 QCOMPARE(frameEndedSpy.count(), 7);
1901 QCOMPARE(pointAddedSpy.count(), 2);
1902 QCOMPARE(pointMovedSpy.count(), 1);
1903 QCOMPARE(pointRemovedSpy.count(), 3);
1904 QCOMPARE(touch->sequence().first()->position(), QPointF(0, 0));
1905}
1906
1907void TestWaylandSeat::testKeymap()
1908{
1909 using namespace KWin;
1910
1911 m_seatInterface->setHasKeyboard(true);
1912 QSignalSpy keyboardChangedSpy(m_seat, &KWayland::Client::Seat::hasKeyboardChanged);
1913 QVERIFY(keyboardChangedSpy.wait());
1914
1915 std::unique_ptr<KWayland::Client::Keyboard> keyboard(m_seat->createKeyboard());
1916
1917 // create surface
1918 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
1919 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
1920 QVERIFY(surface->isValid());
1921 QVERIFY(surfaceCreatedSpy.wait());
1922 auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
1923 QVERIFY(!m_seatInterface->selection());
1924 m_seatInterface->setFocusedKeyboardSurface(serverSurface);
1925
1926 QSignalSpy keymapChangedSpy(keyboard.get(), &KWayland::Client::Keyboard::keymapChanged);
1927
1928 m_seatInterface->keyboard()->setKeymap(QByteArrayLiteral("foo"));
1929 QVERIFY(keymapChangedSpy.wait());
1930 int fd = keymapChangedSpy.first().first().toInt();
1931 QVERIFY(fd != -1);
1932 // Account for null terminator.
1933 QCOMPARE(keymapChangedSpy.first().last().value<quint32>(), 4u);
1934 QFile file;
1935 QVERIFY(file.open(fd, QIODevice::ReadOnly));
1936 const char *address = reinterpret_cast<char *>(file.map(0, keymapChangedSpy.first().last().value<quint32>()));
1937 QVERIFY(address);
1938 QCOMPARE(qstrcmp(address, "foo"), 0);
1939 file.close();
1940
1941 // change the keymap
1942 keymapChangedSpy.clear();
1943 m_seatInterface->keyboard()->setKeymap(QByteArrayLiteral("bar"));
1944 QVERIFY(keymapChangedSpy.wait());
1945 fd = keymapChangedSpy.first().first().toInt();
1946 QVERIFY(fd != -1);
1947 // Account for null terminator.
1948 QCOMPARE(keymapChangedSpy.first().last().value<quint32>(), 4u);
1949 QVERIFY(file.open(fd, QIODevice::ReadWrite));
1950 address = reinterpret_cast<char *>(file.map(0, keymapChangedSpy.first().last().value<quint32>()));
1951 QVERIFY(address);
1952 QCOMPARE(qstrcmp(address, "bar"), 0);
1953}
1954
1955QTEST_GUILESS_MAIN(TestWaylandSeat)
1956#include "test_wayland_seat.moc"
void surfaceCreated(KWin::SurfaceInterface *surface)
DataDeviceInterface allows clients to share data by copy-and-paste and drag-and-drop.
Definition datadevice.h:80
Represents the Global for wl_data_device_manager interface.
Class holding the Wayland server display loop.
Definition display.h:34
void createShm()
Definition display.cpp:128
quint32 serial()
Definition display.cpp:139
bool addSocketName(const QString &name=QString())
Definition display.cpp:68
bool isRunning() const
Definition display.cpp:144
bool start()
Definition display.cpp:92
SurfaceInterface * focusedSurface() const
Definition keyboard.cpp:252
void setRepeatInfo(qint32 charactersPerSecond, qint32 delay)
Definition keyboard.cpp:240
void setKeymap(const QByteArray &content)
Definition keyboard.cpp:88
void cursorChanged(const PointerCursor &cursor)
Represents a Seat on the Wayland Display.
Definition seat.h:134
void endPointerHoldGesture()
Definition seat.cpp:886
void setFocusedTouchSurface(SurfaceInterface *surface, const QPointF &surfacePosition=QPointF())
Definition seat.cpp:1023
quint32 pointerButtonSerial(quint32 button) const
Definition seat.cpp:757
void setHasTouch(bool has)
Definition seat.cpp:372
void cancelPointerHoldGesture()
Definition seat.cpp:898
Display * display() const
Definition seat.cpp:424
void updatePointerSwipeGesture(const QPointF &delta)
Definition seat.cpp:790
SurfaceInterface * focusedTouchSurface() const
Definition seat.cpp:998
void endPointerPinchGesture()
Definition seat.cpp:850
void setHasKeyboard(bool has)
Definition seat.cpp:342
void setTimestamp(std::chrono::microseconds time)
Definition seat.cpp:488
void setSelection(AbstractDataSource *selection)
Definition seat.cpp:1283
void notifyTouchCancel()
Definition seat.cpp:984
bool isTouchSequence() const
Definition seat.cpp:1008
void notifyKeyboardKey(quint32 keyCode, KeyboardKeyState state)
Definition seat.cpp:968
void notifyPointerMotion(const QPointF &pos)
Definition seat.cpp:442
void cancelPointerSwipeGesture()
Definition seat.cpp:814
void setName(const QString &name)
Definition seat.cpp:387
void startPointerHoldGesture(quint32 fingerCount)
Definition seat.cpp:874
void setHasPointer(bool has)
Definition seat.cpp:357
void notifyTouchMotion(qint32 id, const QPointF &globalPosition)
Definition seat.cpp:1094
SurfaceInterface * focusedPointerSurface() const
Definition seat.cpp:550
SurfaceInterface * focusedKeyboardSurface() const
Definition seat.cpp:910
void updatePointerPinchGesture(const QPointF &delta, qreal scale, qreal rotation)
Definition seat.cpp:838
PointerInterface * pointer() const
Definition seat.cpp:648
void notifyPointerEnter(SurfaceInterface *surface, const QPointF &position, const QPointF &surfacePosition=QPointF())
Definition seat.cpp:555
void notifyTouchFrame()
Definition seat.cpp:1165
void notifyPointerLeave()
Definition seat.cpp:604
bool isPointerButtonPressed(quint32 button) const
Definition seat.cpp:682
void startPointerPinchGesture(quint32 fingerCount)
Definition seat.cpp:826
void endPointerSwipeGesture()
Definition seat.cpp:802
void notifyPointerAxis(Qt::Orientation orientation, qreal delta, qint32 deltaV120, PointerAxisSource source, PointerAxisRelativeDirection direction=PointerAxisRelativeDirection::Normal)
Definition seat.cpp:691
KeyboardInterface * keyboard() const
Definition seat.cpp:963
void notifyKeyboardModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group)
Definition seat.cpp:976
QPointF focusedTouchSurfacePosition() const
Definition seat.cpp:1003
void notifyPointerFrame()
Definition seat.cpp:744
void startPointerSwipeGesture(quint32 fingerCount)
Definition seat.cpp:778
void notifyTouchUp(qint32 id)
Definition seat.cpp:1133
void relativePointerMotion(const QPointF &delta, const QPointF &deltaNonAccelerated, std::chrono::microseconds timestamp)
Definition seat.cpp:766
AbstractDataSource * selection() const
Definition seat.cpp:1278
void setFocusedTouchSurfacePosition(const QPointF &surfacePosition)
Definition seat.cpp:1053
void notifyPointerButton(quint32 button, PointerButtonState state)
Definition seat.cpp:712
void setFocusedKeyboardSurface(SurfaceInterface *surface)
Definition seat.cpp:915
void cancelPointerPinchGesture()
Definition seat.cpp:862
void notifyTouchDown(qint32 id, const QPointF &globalPosition)
Definition seat.cpp:1060
Resource representing a wl_surface.
Definition surface.h:80
ClientConnection * client() const
Definition surface.cpp:444
bool isMapped() const
Definition surface.cpp:891
void ended(quint32 serial, quint32 time)
void cancelled(quint32 serial, quint32 time)
void started(quint32 serial, quint32 time, void *surface, quint32 fingers)
TestWaylandSeat(QObject *parent=nullptr)
WaylandSyncPoint(KWayland::Client::ConnectionThread *connection, KWayland::Client::EventQueue *eventQueue)
Q_DECLARE_METATYPE(KWin::SwitchEvent::State)
KWayland::Client::Seat * seat
KWayland::Client::EventQueue * queue
void render(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32_Premultiplied)
KWayland::Client::Registry * registry
QThread * thread
std::variant< PointerSurfaceCursor *, QByteArray > PointerCursor
Definition pointer.h:29