1/*
2 SPDX-FileCopyrightText: 2014, 2015 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#include "touchclienttest.h"
7// KWin::Wayland
8#include <../src/client/buffer.h>
9#include <../src/client/compositor.h>
10#include <../src/client/connection_thread.h>
11#include <../src/client/event_queue.h>
12#include <../src/client/keyboard.h>
13#include <../src/client/output.h>
14#include <../src/client/pointer.h>
15#include <../src/client/registry.h>
16#include <../src/client/seat.h>
17#include <../src/client/shell.h>
18#include <../src/client/shm_pool.h>
19#include <../src/client/surface.h>
20#include <../src/client/touch.h>
21// Qt
22#include <QAbstractEventDispatcher>
23#include <QCoreApplication>
24#include <QDebug>
25#include <QImage>
26#include <QPainter>
27#include <QThread>
28#include <QTimer>
29
30#include <linux/input.h>
31
32using namespace KWayland::Client;
33
34static Qt::GlobalColor s_colors[] = {Qt::white, Qt::red, Qt::green, Qt::blue, Qt::black};
35static int s_colorIndex = 0;
36
37WaylandClientTest::WaylandClientTest(QObject *parent)
38 : QObject(parent)
39 , m_connectionThread(new QThread(this))
40 , m_connectionThreadObject(new ConnectionThread(nullptr))
41 , m_eventQueue(nullptr)
42 , m_compositor(nullptr)
43 , m_output(nullptr)
44 , m_surface(nullptr)
45 , m_shm(nullptr)
46 , m_timer(new QTimer(this))
47{
48 init();
49}
50
51WaylandClientTest::~WaylandClientTest()
52{
53 m_connectionThread->quit();
54 m_connectionThread->wait();
55 m_connectionThreadObject->deleteLater();
56}
57
58void WaylandClientTest::init()
59{
60 connect(
61 sender: m_connectionThreadObject,
62 signal: &ConnectionThread::connected,
63 context: this,
64 slot: [this]() {
65 // create the event queue for the main gui thread
66 m_eventQueue = new EventQueue(this);
67 m_eventQueue->setup(m_connectionThreadObject);
68 // setup registry
69 Registry *registry = new Registry(this);
70 setupRegistry(registry);
71 },
72 type: Qt::QueuedConnection);
73
74 m_connectionThreadObject->moveToThread(thread: m_connectionThread);
75 m_connectionThread->start();
76
77 m_connectionThreadObject->initConnection();
78
79 connect(sender: m_timer, signal: &QTimer::timeout, context: this, slot: [this]() {
80 s_colorIndex = (s_colorIndex + 1) % 5;
81 render();
82 });
83 m_timer->setInterval(1000);
84 m_timer->start();
85}
86
87void WaylandClientTest::setupRegistry(Registry *registry)
88{
89 connect(sender: registry, signal: &Registry::compositorAnnounced, context: this, slot: [this, registry](quint32 name) {
90 m_compositor = registry->createCompositor(name, version: 1, parent: this);
91 m_surface = m_compositor->createSurface(parent: this);
92 });
93 connect(sender: registry, signal: &Registry::shellAnnounced, context: this, slot: [this, registry](quint32 name) {
94 Shell *shell = registry->createShell(name, version: 1, parent: this);
95 ShellSurface *shellSurface = shell->createSurface(surface: m_surface, parent: m_surface);
96 shellSurface->setToplevel();
97 render(size: QSize(400, 200));
98 });
99 connect(sender: registry, signal: &Registry::outputAnnounced, context: this, slot: [this, registry](quint32 name) {
100 if (m_output) {
101 return;
102 }
103 m_output = registry->createOutput(name, version: 2, parent: this);
104 });
105 connect(sender: registry, signal: &Registry::shmAnnounced, context: this, slot: [this, registry](quint32 name) {
106 m_shm = registry->createShmPool(name, version: 1, parent: this);
107 });
108 connect(sender: registry, signal: &Registry::seatAnnounced, context: this, slot: [this, registry](quint32 name) {
109 Seat *s = registry->createSeat(name, version: 2, parent: this);
110 connect(sender: s, signal: &Seat::hasKeyboardChanged, context: this, slot: [this, s](bool has) {
111 if (!has) {
112 return;
113 }
114 Keyboard *k = s->createKeyboard(parent: this);
115 connect(sender: k, signal: &Keyboard::keyChanged, context: this, slot: [](quint32 key, Keyboard::KeyState state) {
116 if (key == KEY_Q && state == Keyboard::KeyState::Released) {
117 QCoreApplication::instance()->quit();
118 }
119 });
120 });
121 connect(sender: s, signal: &Seat::hasPointerChanged, context: this, slot: [this, s](bool has) {
122 if (!has) {
123 return;
124 }
125 Pointer *p = s->createPointer(parent: this);
126 connect(sender: p, signal: &Pointer::buttonStateChanged, context: this, slot: [this](quint32 serial, quint32 time, quint32 button, Pointer::ButtonState state) {
127 Q_UNUSED(serial)
128 Q_UNUSED(time)
129 if (state == Pointer::ButtonState::Released) {
130 if (button == BTN_LEFT) {
131 if (m_timer->isActive()) {
132 m_timer->stop();
133 } else {
134 m_timer->start();
135 }
136 }
137 if (button == BTN_RIGHT) {
138 QCoreApplication::instance()->quit();
139 }
140 }
141 });
142 });
143 connect(sender: s, signal: &Seat::hasTouchChanged, context: this, slot: [this, s](bool has) {
144 if (!has) {
145 return;
146 }
147 Touch *t = s->createTouch(parent: this);
148 connect(sender: t, signal: &Touch::sequenceStarted, context: this, slot: [](KWayland::Client::TouchPoint *startPoint) {
149 qDebug() << "Touch sequence started at" << startPoint->position() << "with id" << startPoint->id();
150 });
151 connect(sender: t, signal: &Touch::sequenceCanceled, context: this, slot: []() {
152 qDebug() << "Touch sequence canceled";
153 });
154 connect(sender: t, signal: &Touch::sequenceEnded, context: this, slot: []() {
155 qDebug() << "Touch sequence finished";
156 });
157 connect(sender: t, signal: &Touch::frameEnded, context: this, slot: []() {
158 qDebug() << "End of touch contact point list";
159 });
160 connect(sender: t, signal: &Touch::pointAdded, context: this, slot: [](KWayland::Client::TouchPoint *point) {
161 qDebug() << "Touch point added at" << point->position() << "with id" << point->id();
162 });
163 connect(sender: t, signal: &Touch::pointRemoved, context: this, slot: [](KWayland::Client::TouchPoint *point) {
164 qDebug() << "Touch point " << point->id() << " removed at" << point->position();
165 });
166 connect(sender: t, signal: &Touch::pointMoved, context: this, slot: [](KWayland::Client::TouchPoint *point) {
167 qDebug() << "Touch point " << point->id() << " moved to" << point->position();
168 });
169 });
170 });
171 registry->create(display: m_connectionThreadObject->display());
172 registry->setEventQueue(m_eventQueue);
173 registry->setup();
174}
175
176void WaylandClientTest::render(const QSize &size)
177{
178 m_currentSize = size;
179 render();
180}
181
182void WaylandClientTest::render()
183{
184 if (!m_shm || !m_surface || !m_surface->isValid() || !m_currentSize.isValid()) {
185 return;
186 }
187 auto buffer = m_shm->getBuffer(size: m_currentSize, stride: m_currentSize.width() * 4).toStrongRef();
188 buffer->setUsed(true);
189 QImage image(buffer->address(), m_currentSize.width(), m_currentSize.height(), QImage::Format_ARGB32_Premultiplied);
190 image.fill(color: s_colors[s_colorIndex]);
191
192 m_surface->attachBuffer(buffer: *buffer);
193 m_surface->damage(rect: QRect(QPoint(0, 0), m_currentSize));
194 m_surface->commit(flag: Surface::CommitFlag::None);
195 buffer->setUsed(false);
196}
197
198int main(int argc, char **argv)
199{
200 QCoreApplication app(argc, argv);
201
202 new WaylandClientTest(&app);
203
204 return app.exec();
205}
206
207#include "moc_touchclienttest.cpp"
208

source code of kwayland/tests/touchclienttest.cpp