1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qwaylandtouch.h"
5#include "qwaylandtouch_p.h"
6
7#include <QtWaylandCompositor/QWaylandCompositor>
8#include <QtWaylandCompositor/QWaylandSeat>
9#include <QtWaylandCompositor/QWaylandView>
10#include <QtWaylandCompositor/QWaylandClient>
11
12#include <QtWaylandCompositor/private/qwlqttouch_p.h>
13
14QT_BEGIN_NAMESPACE
15
16QWaylandTouchPrivate::QWaylandTouchPrivate(QWaylandTouch *touch, QWaylandSeat *seat)
17 : seat(seat)
18{
19 Q_UNUSED(touch);
20}
21
22void QWaylandTouchPrivate::touch_release(Resource *resource)
23{
24 wl_resource_destroy(resource->handle);
25}
26
27uint QWaylandTouchPrivate::sendDown(QWaylandSurface *surface, uint32_t time, int touch_id, const QPointF &position)
28{
29 Q_Q(QWaylandTouch);
30 auto focusResource = resourceMap().value(surface->client()->client());
31 if (!focusResource)
32 return 0;
33
34 uint32_t serial = q->compositor()->nextSerial();
35
36 wl_touch_send_down(focusResource->handle, serial, time, surface->resource(), touch_id,
37 wl_fixed_from_double(d: position.x()), wl_fixed_from_double(d: position.y()));
38 return serial;
39}
40
41uint QWaylandTouchPrivate::sendUp(QWaylandClient *client, uint32_t time, int touch_id)
42{
43 auto focusResource = resourceMap().value(client->client());
44
45 if (!focusResource)
46 return 0;
47
48 uint32_t serial = compositor()->nextSerial();
49
50 wl_touch_send_up(focusResource->handle, serial, time, touch_id);
51 return serial;
52}
53
54void QWaylandTouchPrivate::sendMotion(QWaylandClient *client, uint32_t time, int touch_id, const QPointF &position)
55{
56 auto focusResource = resourceMap().value(client->client());
57
58 if (!focusResource)
59 return;
60
61 wl_touch_send_motion(focusResource->handle, time, touch_id,
62 wl_fixed_from_double(d: position.x()), wl_fixed_from_double(d: position.y()));
63}
64
65int QWaylandTouchPrivate::toSequentialWaylandId(int touchId)
66{
67 const int waylandId = ids.indexOf(touchId);
68 if (waylandId != -1)
69 return waylandId;
70 const int availableId = ids.indexOf(-1);
71 if (availableId != -1) {
72 ids[availableId] = touchId;
73 return availableId;
74 }
75 ids.append(touchId);
76 return ids.size() - 1;
77}
78
79/*!
80 * \class QWaylandTouch
81 * \inmodule QtWaylandCompositor
82 * \since 5.8
83 * \brief The QWaylandTouch class provides access to a touch device.
84 *
85 * This class provides access to the touch device in a QWaylandSeat. It corresponds to
86 * the Wayland interface wl_touch.
87 */
88
89/*!
90 * Constructs a QWaylandTouch for the \a seat and with the given \a parent.
91 */
92QWaylandTouch::QWaylandTouch(QWaylandSeat *seat, QObject *parent)
93 : QWaylandObject(*new QWaylandTouchPrivate(this, seat), parent)
94{
95}
96
97/*!
98 * Returns the input device for this QWaylandTouch.
99 */
100QWaylandSeat *QWaylandTouch::seat() const
101{
102 Q_D(const QWaylandTouch);
103 return d->seat;
104}
105
106/*!
107 * Returns the compositor for this QWaylandTouch.
108 */
109QWaylandCompositor *QWaylandTouch::compositor() const
110{
111 Q_D(const QWaylandTouch);
112 return d->compositor();
113}
114
115/*!
116 * Sends a touch point event to the touch device of \a surface with the given \a id,
117 * \a position, and \a state.
118 *
119 * Returns the serial of the down or up event if sent, otherwise 0.
120 */
121uint QWaylandTouch::sendTouchPointEvent(QWaylandSurface *surface, int id, const QPointF &position, Qt::TouchPointState state)
122{
123 Q_D(QWaylandTouch);
124 uint32_t time = compositor()->currentTimeMsecs();
125 uint serial = 0;
126 switch (state) {
127 case Qt::TouchPointPressed:
128 serial = d->sendDown(surface, time, touch_id: id, position);
129 break;
130 case Qt::TouchPointMoved:
131 d->sendMotion(client: surface->client(), time, touch_id: id, position);
132 break;
133 case Qt::TouchPointReleased:
134 serial = d->sendUp(client: surface->client(), time, touch_id: id);
135 break;
136 case Qt::TouchPointStationary:
137 // stationary points are not sent through wayland, the client must cache them
138 break;
139 case Qt::TouchPointUnknownState:
140 // Ignored
141 break;
142 }
143
144 return serial;
145}
146
147/*!
148 * Sends a touch frame event to the touch device of a \a client. This indicates the end of a
149 * contact point list.
150 */
151void QWaylandTouch::sendFrameEvent(QWaylandClient *client)
152{
153 Q_D(QWaylandTouch);
154 auto focusResource = d->resourceMap().value(client->client());
155 if (focusResource)
156 d->send_frame(focusResource->handle);
157}
158
159/*!
160 * Sends a touch cancel event to the touch device of a \a client.
161 */
162void QWaylandTouch::sendCancelEvent(QWaylandClient *client)
163{
164 Q_D(QWaylandTouch);
165 auto focusResource = d->resourceMap().value(client->client());
166 if (focusResource)
167 d->send_cancel(focusResource->handle);
168}
169
170/*!
171 * Sends all touch points in \a event to the specified \a surface,
172 * followed by a touch frame event.
173 *
174 * \sa sendTouchPointEvent(), sendFrameEvent()
175 */
176void QWaylandTouch::sendFullTouchEvent(QWaylandSurface *surface, QTouchEvent *event)
177{
178 Q_D(QWaylandTouch);
179 if (event->type() == QEvent::TouchCancel) {
180 sendCancelEvent(client: surface->client());
181 return;
182 }
183
184 QtWayland::TouchExtensionGlobal *ext = QtWayland::TouchExtensionGlobal::findIn(container: d->compositor());
185 if (ext && ext->postTouchEvent(event, surface))
186 return;
187
188 const QList<QTouchEvent::TouchPoint> points = event->points();
189 if (points.isEmpty())
190 return;
191
192 const int pointCount = points.size();
193 for (int i = 0; i < pointCount; ++i) {
194 const QTouchEvent::TouchPoint &tp(points.at(i));
195 // Convert the local pos in the compositor window to surface-relative.
196 const int id = d->toSequentialWaylandId(touchId: tp.id());
197 sendTouchPointEvent(surface, id, position: tp.position(), state: Qt::TouchPointState(tp.state()));
198 if (tp.state() == QEventPoint::Released)
199 d->ids[id] = -1;
200 }
201 sendFrameEvent(client: surface->client());
202}
203
204/*!
205 * \internal
206 */
207void QWaylandTouch::addClient(QWaylandClient *client, uint32_t id, uint32_t version)
208{
209 Q_D(QWaylandTouch);
210 d->add(client->client(), id, qMin<uint32_t>(QtWaylandServer::wl_touch::interfaceVersion(), version));
211}
212
213QT_END_NAMESPACE
214
215#include "moc_qwaylandtouch.cpp"
216

source code of qtwayland/src/compositor/compositor_api/qwaylandtouch.cpp