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#include "pointer.h"
7#include "surface.h"
8#include "wayland_pointer_p.h"
9// Qt
10#include <QPointF>
11#include <QPointer>
12// wayland
13#include <wayland-client-protocol.h>
14
15namespace KWayland
16{
17namespace Client
18{
19static Pointer::Axis wlAxisToPointerAxis(uint32_t axis)
20{
21 switch (axis) {
22 case WL_POINTER_AXIS_VERTICAL_SCROLL:
23 return Pointer::Axis::Vertical;
24 case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
25 return Pointer::Axis::Horizontal;
26 }
27
28 Q_UNREACHABLE();
29}
30
31class Q_DECL_HIDDEN Pointer::Private
32{
33public:
34 Private(Pointer *q);
35 void setup(wl_pointer *p);
36
37 WaylandPointer<wl_pointer, wl_pointer_release> pointer;
38 QPointer<Surface> enteredSurface;
39 quint32 enteredSerial = 0;
40
41private:
42 void enter(uint32_t serial, wl_surface *surface, const QPointF &relativeToSurface);
43 void leave(uint32_t serial);
44 static void enterCallback(void *data, wl_pointer *pointer, uint32_t serial, wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy);
45 static void leaveCallback(void *data, wl_pointer *pointer, uint32_t serial, wl_surface *surface);
46 static void motionCallback(void *data, wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
47 static void buttonCallback(void *data, wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
48 static void axisCallback(void *data, wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value);
49 static void frameCallback(void *data, wl_pointer *pointer);
50 static void axisSourceCallback(void *data, wl_pointer *pointer, uint32_t axis_source);
51 static void axisStopCallback(void *data, wl_pointer *pointer, uint32_t time, uint32_t axis);
52 static void axisDiscreteCallback(void *data, wl_pointer *pointer, uint32_t axis, int32_t discrete);
53
54 Pointer *q;
55 static const wl_pointer_listener s_listener;
56};
57
58Pointer::Private::Private(Pointer *q)
59 : q(q)
60{
61}
62
63void Pointer::Private::setup(wl_pointer *p)
64{
65 Q_ASSERT(p);
66 Q_ASSERT(!pointer);
67 pointer.setup(pointer: p);
68 wl_pointer_add_listener(wl_pointer: pointer, listener: &s_listener, data: this);
69}
70
71const wl_pointer_listener Pointer::Private::s_listener =
72 {.enter: enterCallback, .leave: leaveCallback, .motion: motionCallback, .button: buttonCallback, .axis: axisCallback, .frame: frameCallback, .axis_source: axisSourceCallback, .axis_stop: axisStopCallback, .axis_discrete: axisDiscreteCallback};
73
74Pointer::Pointer(QObject *parent)
75 : QObject(parent)
76 , d(new Private(this))
77{
78}
79
80Pointer::~Pointer()
81{
82 release();
83}
84
85void Pointer::release()
86{
87 d->pointer.release();
88}
89
90void Pointer::destroy()
91{
92 d->pointer.destroy();
93}
94
95void Pointer::setup(wl_pointer *pointer)
96{
97 d->setup(pointer);
98}
99
100void Pointer::Private::enterCallback(void *data, wl_pointer *pointer, uint32_t serial, wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy)
101{
102 auto p = reinterpret_cast<Pointer::Private *>(data);
103 Q_ASSERT(p->pointer == pointer);
104 p->enter(serial, surface, relativeToSurface: QPointF(wl_fixed_to_double(f: sx), wl_fixed_to_double(f: sy)));
105}
106
107void Pointer::Private::enter(uint32_t serial, wl_surface *surface, const QPointF &relativeToSurface)
108{
109 enteredSurface = QPointer<Surface>(Surface::get(native: surface));
110 enteredSerial = serial;
111 Q_EMIT q->entered(serial, relativeToSurface);
112}
113
114void Pointer::Private::leaveCallback(void *data, wl_pointer *pointer, uint32_t serial, wl_surface *surface)
115{
116 auto p = reinterpret_cast<Pointer::Private *>(data);
117 Q_ASSERT(p->pointer == pointer);
118 Q_UNUSED(surface)
119 p->leave(serial);
120}
121
122void Pointer::Private::leave(uint32_t serial)
123{
124 enteredSurface.clear();
125 Q_EMIT q->left(serial);
126}
127
128void Pointer::Private::motionCallback(void *data, wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
129{
130 auto p = reinterpret_cast<Pointer::Private *>(data);
131 Q_ASSERT(p->pointer == pointer);
132 Q_EMIT p->q->motion(relativeToSurface: QPointF(wl_fixed_to_double(f: sx), wl_fixed_to_double(f: sy)), time);
133}
134
135void Pointer::Private::buttonCallback(void *data, wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
136{
137 auto p = reinterpret_cast<Pointer::Private *>(data);
138 Q_ASSERT(p->pointer == pointer);
139 auto toState = [state] {
140 if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
141 return ButtonState::Released;
142 } else {
143 return ButtonState::Pressed;
144 }
145 };
146 Q_EMIT p->q->buttonStateChanged(serial, time, button, state: toState());
147}
148
149void Pointer::Private::axisCallback(void *data, wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value)
150{
151 auto p = reinterpret_cast<Pointer::Private *>(data);
152 Q_ASSERT(p->pointer == pointer);
153 Q_EMIT p->q->axisChanged(time, axis: wlAxisToPointerAxis(axis), delta: wl_fixed_to_double(f: value));
154}
155
156void Pointer::Private::frameCallback(void *data, wl_pointer *pointer)
157{
158 auto p = reinterpret_cast<Pointer::Private *>(data);
159 Q_ASSERT(p->pointer == pointer);
160 Q_EMIT p->q->frame();
161}
162
163void Pointer::Private::axisSourceCallback(void *data, wl_pointer *pointer, uint32_t axis_source)
164{
165 auto p = reinterpret_cast<Pointer::Private *>(data);
166 Q_ASSERT(p->pointer == pointer);
167 AxisSource source;
168 switch (axis_source) {
169 case WL_POINTER_AXIS_SOURCE_WHEEL:
170 source = AxisSource::Wheel;
171 break;
172 case WL_POINTER_AXIS_SOURCE_FINGER:
173 source = AxisSource::Finger;
174 break;
175 case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
176 source = AxisSource::Continuous;
177 break;
178 case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
179 source = AxisSource::WheelTilt;
180 break;
181 default:
182 Q_UNREACHABLE();
183 break;
184 }
185 Q_EMIT p->q->axisSourceChanged(source);
186}
187
188void Pointer::Private::axisStopCallback(void *data, wl_pointer *pointer, uint32_t time, uint32_t axis)
189{
190 auto p = reinterpret_cast<Pointer::Private *>(data);
191 Q_ASSERT(p->pointer == pointer);
192 Q_EMIT p->q->axisStopped(time, axis: wlAxisToPointerAxis(axis));
193}
194
195void Pointer::Private::axisDiscreteCallback(void *data, wl_pointer *pointer, uint32_t axis, int32_t discrete)
196{
197 auto p = reinterpret_cast<Pointer::Private *>(data);
198 Q_ASSERT(p->pointer == pointer);
199 Q_EMIT p->q->axisDiscreteChanged(axis: wlAxisToPointerAxis(axis), discreteDelta: discrete);
200}
201
202void Pointer::setCursor(Surface *surface, const QPoint &hotspot)
203{
204 Q_ASSERT(isValid());
205 wl_surface *s = nullptr;
206 if (surface) {
207 s = *surface;
208 }
209 wl_pointer_set_cursor(wl_pointer: d->pointer, serial: d->enteredSerial, surface: s, hotspot_x: hotspot.x(), hotspot_y: hotspot.y());
210}
211
212void Pointer::hideCursor()
213{
214 setCursor(surface: nullptr);
215}
216
217Surface *Pointer::enteredSurface()
218{
219 return d->enteredSurface.data();
220}
221
222Surface *Pointer::enteredSurface() const
223{
224 return d->enteredSurface.data();
225}
226
227bool Pointer::isValid() const
228{
229 return d->pointer.isValid();
230}
231
232Pointer::operator wl_pointer *() const
233{
234 return d->pointer;
235}
236
237Pointer::operator wl_pointer *()
238{
239 return d->pointer;
240}
241
242}
243}
244
245#include "moc_pointer.cpp"
246

source code of kwayland/src/client/pointer.cpp