File indexing completed on 2024-12-22 05:09:25

0001 /*
0002     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 #include "touch.h"
0007 #include "surface.h"
0008 #include "wayland_pointer_p.h"
0009 // Qt
0010 #include <QList>
0011 #include <QPointF>
0012 #include <QPointer>
0013 // wayland
0014 #include <wayland-client-protocol.h>
0015 
0016 namespace KWayland
0017 {
0018 namespace Client
0019 {
0020 class Q_DECL_HIDDEN Touch::Private
0021 {
0022 public:
0023     Private(Touch *q);
0024     void setup(wl_touch *t);
0025     WaylandPointer<wl_touch, wl_touch_release> touch;
0026     bool active = false;
0027     QList<TouchPoint *> sequence;
0028     TouchPoint *getActivePoint(qint32 id) const;
0029 
0030 private:
0031     static void downCallback(void *data, wl_touch *touch, uint32_t serial, uint32_t time, wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y);
0032     static void upCallback(void *data, wl_touch *touch, uint32_t serial, uint32_t time, int32_t id);
0033     static void motionCallback(void *data, wl_touch *touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y);
0034     static void frameCallback(void *data, wl_touch *touch);
0035     static void cancelCallback(void *data, wl_touch *touch);
0036     void down(quint32 serial, quint32 time, qint32 id, const QPointF &position, const QPointer<Surface> &surface);
0037     void up(quint32 serial, quint32 time, qint32 id);
0038     void motion(quint32 time, qint32 id, const QPointF &position);
0039 
0040     Touch *q;
0041     static const wl_touch_listener s_listener;
0042 };
0043 
0044 class TouchPoint::Private
0045 {
0046 public:
0047     qint32 id = 0;
0048     quint32 downSerial = 0;
0049     quint32 upSerial = 0;
0050     QPointer<Surface> surface;
0051     QList<QPointF> positions;
0052     QList<quint32> timestamps;
0053     bool down = true;
0054 };
0055 
0056 TouchPoint::TouchPoint()
0057     : d(new Private)
0058 {
0059 }
0060 
0061 TouchPoint::~TouchPoint() = default;
0062 
0063 QPointF TouchPoint::position() const
0064 {
0065     if (d->positions.isEmpty()) {
0066         return QPointF();
0067     }
0068     return d->positions.last();
0069 }
0070 
0071 QList<QPointF> TouchPoint::positions() const
0072 {
0073     return d->positions;
0074 }
0075 
0076 quint32 TouchPoint::downSerial() const
0077 {
0078     return d->downSerial;
0079 }
0080 
0081 quint32 TouchPoint::upSerial() const
0082 {
0083     return d->upSerial;
0084 }
0085 
0086 QPointer<Surface> TouchPoint::surface() const
0087 {
0088     return d->surface;
0089 }
0090 
0091 quint32 TouchPoint::time() const
0092 {
0093     if (d->timestamps.isEmpty()) {
0094         return 0;
0095     }
0096     return d->timestamps.last();
0097 }
0098 
0099 QList<quint32> TouchPoint::timestamps() const
0100 {
0101     return d->timestamps;
0102 }
0103 
0104 bool TouchPoint::isDown() const
0105 {
0106     return d->down;
0107 }
0108 
0109 qint32 TouchPoint::id() const
0110 {
0111     return d->id;
0112 }
0113 
0114 Touch::Private::Private(Touch *q)
0115     : q(q)
0116 {
0117 }
0118 
0119 void Touch::Private::setup(wl_touch *t)
0120 {
0121     Q_ASSERT(t);
0122     Q_ASSERT(!touch);
0123     touch.setup(t);
0124     wl_touch_add_listener(touch, &s_listener, this);
0125 }
0126 
0127 const wl_touch_listener Touch::Private::s_listener = {downCallback, upCallback, motionCallback, frameCallback, cancelCallback};
0128 
0129 void Touch::Private::downCallback(void *data, wl_touch *touch, uint32_t serial, uint32_t time, wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y)
0130 {
0131     auto t = reinterpret_cast<Touch::Private *>(data);
0132     Q_ASSERT(t->touch == touch);
0133     t->down(serial, time, id, QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), QPointer<Surface>(Surface::get(surface)));
0134 }
0135 
0136 void Touch::Private::down(quint32 serial, quint32 time, qint32 id, const QPointF &position, const QPointer<Surface> &surface)
0137 {
0138     TouchPoint *p = new TouchPoint;
0139     p->d->downSerial = serial;
0140     p->d->surface = surface;
0141     p->d->id = id;
0142     p->d->positions << position;
0143     p->d->timestamps << time;
0144     if (active) {
0145         sequence << p;
0146         Q_EMIT q->pointAdded(p);
0147     } else {
0148         qDeleteAll(sequence);
0149         sequence.clear();
0150         sequence << p;
0151         active = true;
0152         Q_EMIT q->sequenceStarted(p);
0153     }
0154 }
0155 
0156 TouchPoint *Touch::Private::getActivePoint(qint32 id) const
0157 {
0158     auto it = std::find_if(sequence.constBegin(), sequence.constEnd(), [id](TouchPoint *p) {
0159         return p->id() == id && p->isDown();
0160     });
0161     if (it == sequence.constEnd()) {
0162         return nullptr;
0163     }
0164     return *it;
0165 }
0166 
0167 void Touch::Private::upCallback(void *data, wl_touch *touch, uint32_t serial, uint32_t time, int32_t id)
0168 {
0169     auto t = reinterpret_cast<Touch::Private *>(data);
0170     Q_ASSERT(t->touch == touch);
0171     t->up(serial, time, id);
0172 }
0173 
0174 void Touch::Private::up(quint32 serial, quint32 time, qint32 id)
0175 {
0176     TouchPoint *p = getActivePoint(id);
0177     if (!p) {
0178         return;
0179     }
0180     p->d->timestamps << time;
0181     p->d->upSerial = serial;
0182     p->d->down = false;
0183     Q_EMIT q->pointRemoved(p);
0184     // check whether the sequence ended
0185     for (auto it = sequence.constBegin(); it != sequence.constEnd(); ++it) {
0186         if ((*it)->isDown()) {
0187             return;
0188         }
0189     }
0190     // no touch point is down
0191     active = false;
0192     Q_EMIT q->sequenceEnded();
0193 }
0194 
0195 void Touch::Private::motionCallback(void *data, wl_touch *touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y)
0196 {
0197     auto t = reinterpret_cast<Touch::Private *>(data);
0198     Q_ASSERT(t->touch == touch);
0199     t->motion(time, id, QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)));
0200 }
0201 
0202 void Touch::Private::motion(quint32 time, qint32 id, const QPointF &position)
0203 {
0204     TouchPoint *p = getActivePoint(id);
0205     if (!p) {
0206         return;
0207     }
0208     p->d->positions << position;
0209     p->d->timestamps << time;
0210     Q_EMIT q->pointMoved(p);
0211 }
0212 
0213 void Touch::Private::frameCallback(void *data, wl_touch *touch)
0214 {
0215     auto t = reinterpret_cast<Touch::Private *>(data);
0216     Q_ASSERT(t->touch == touch);
0217     Q_EMIT t->q->frameEnded();
0218 }
0219 
0220 void Touch::Private::cancelCallback(void *data, wl_touch *touch)
0221 {
0222     auto t = reinterpret_cast<Touch::Private *>(data);
0223     Q_ASSERT(t->touch == touch);
0224     t->active = false;
0225     Q_EMIT t->q->sequenceCanceled();
0226 }
0227 
0228 Touch::Touch(QObject *parent)
0229     : QObject(parent)
0230     , d(new Private(this))
0231 {
0232 }
0233 
0234 Touch::~Touch()
0235 {
0236     release();
0237 }
0238 
0239 void Touch::destroy()
0240 {
0241     d->touch.destroy();
0242 }
0243 
0244 void Touch::release()
0245 {
0246     d->touch.release();
0247 }
0248 
0249 void Touch::setup(wl_touch *touch)
0250 {
0251     d->setup(touch);
0252 }
0253 
0254 bool Touch::isValid() const
0255 {
0256     return d->touch.isValid();
0257 }
0258 
0259 Touch::operator wl_touch *() const
0260 {
0261     return d->touch;
0262 }
0263 
0264 Touch::operator wl_touch *()
0265 {
0266     return d->touch;
0267 }
0268 
0269 QList<TouchPoint *> Touch::sequence() const
0270 {
0271     return d->sequence;
0272 }
0273 
0274 }
0275 }
0276 
0277 #include "moc_touch.cpp"