KWayland

pointer_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2014 Martin Gräßlin <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 #include "pointer_interface.h"
7 #include "datadevice_interface.h"
8 #include "display.h"
9 #include "pointer_interface_p.h"
10 #include "pointerconstraints_interface.h"
11 #include "pointergestures_interface_p.h"
12 #include "relativepointer_interface_p.h"
13 #include "resource_p.h"
14 #include "seat_interface.h"
15 #include "subcompositor_interface.h"
16 #include "surface_interface.h"
17 // Wayland
18 #include <wayland-server.h>
19 
20 namespace KWayland
21 {
22 namespace Server
23 {
24 class Cursor::Private
25 {
26 public:
27  Private(Cursor *q, PointerInterface *pointer);
28  PointerInterface *pointer;
29  quint32 enteredSerial = 0;
32 
33  void update(const QPointer<SurfaceInterface> &surface, quint32 serial, const QPoint &hotspot);
34 
35 private:
36  Cursor *q;
37 };
38 
39 PointerInterface::Private::Private(SeatInterface *parent, wl_resource *parentResource, PointerInterface *q)
40  : Resource::Private(q, parent, parentResource, &wl_pointer_interface, &s_interface)
41  , seat(parent)
42 {
43 }
44 
45 void PointerInterface::Private::setCursor(quint32 serial, SurfaceInterface *surface, const QPoint &hotspot)
46 {
47  if (!cursor) {
48  Q_Q(PointerInterface);
49  cursor = new Cursor(q);
50  cursor->d->update(QPointer<SurfaceInterface>(surface), serial, hotspot);
51  QObject::connect(cursor, &Cursor::changed, q, &PointerInterface::cursorChanged);
52  Q_EMIT q->cursorChanged();
53  } else {
54  cursor->d->update(QPointer<SurfaceInterface>(surface), serial, hotspot);
55  }
56 }
57 
58 void PointerInterface::Private::sendLeave(SurfaceInterface *surface, quint32 serial)
59 {
60  if (!surface) {
61  return;
62  }
63  if (resource && surface->resource()) {
64  wl_pointer_send_leave(resource, serial, surface->resource());
65  }
66 }
67 
68 void PointerInterface::Private::registerRelativePointer(RelativePointerInterface *relativePointer)
69 {
70  relativePointers << relativePointer;
71  QObject::connect(relativePointer, &QObject::destroyed, q, [this, relativePointer] {
72  relativePointers.removeOne(relativePointer);
73  });
74 }
75 
76 void PointerInterface::Private::registerSwipeGesture(PointerSwipeGestureInterface *gesture)
77 {
78  swipeGestures << gesture;
79  QObject::connect(gesture, &QObject::destroyed, q, [this, gesture] {
80  swipeGestures.removeOne(gesture);
81  });
82 }
83 
84 void PointerInterface::Private::registerPinchGesture(PointerPinchGestureInterface *gesture)
85 {
86  pinchGestures << gesture;
87  QObject::connect(gesture, &QObject::destroyed, q, [this, gesture] {
88  pinchGestures.removeOne(gesture);
89  });
90 }
91 
92 namespace
93 {
94 static QPointF surfacePosition(SurfaceInterface *surface)
95 {
96  if (surface && surface->subSurface()) {
97  return surface->subSurface()->position() + surfacePosition(surface->subSurface()->parentSurface().data());
98  }
99  return QPointF();
100 }
101 }
102 
103 void PointerInterface::Private::sendEnter(SurfaceInterface *surface, const QPointF &parentSurfacePosition, quint32 serial)
104 {
105  if (!surface || !surface->resource()) {
106  return;
107  }
108  const QPointF adjustedPos = parentSurfacePosition - surfacePosition(surface);
109  wl_pointer_send_enter(resource, serial, surface->resource(), wl_fixed_from_double(adjustedPos.x()), wl_fixed_from_double(adjustedPos.y()));
110 }
111 
112 void PointerInterface::Private::startSwipeGesture(quint32 serial, quint32 fingerCount)
113 {
114  if (swipeGestures.isEmpty()) {
115  return;
116  }
117  for (auto it = swipeGestures.constBegin(), end = swipeGestures.constEnd(); it != end; it++) {
118  (*it)->start(serial, fingerCount);
119  }
120 }
121 
122 void PointerInterface::Private::updateSwipeGesture(const QSizeF &delta)
123 {
124  if (swipeGestures.isEmpty()) {
125  return;
126  }
127  for (auto it = swipeGestures.constBegin(), end = swipeGestures.constEnd(); it != end; it++) {
128  (*it)->update(delta);
129  }
130 }
131 
132 void PointerInterface::Private::endSwipeGesture(quint32 serial)
133 {
134  if (swipeGestures.isEmpty()) {
135  return;
136  }
137  for (auto it = swipeGestures.constBegin(), end = swipeGestures.constEnd(); it != end; it++) {
138  (*it)->end(serial);
139  }
140 }
141 
142 void PointerInterface::Private::cancelSwipeGesture(quint32 serial)
143 {
144  if (swipeGestures.isEmpty()) {
145  return;
146  }
147  for (auto it = swipeGestures.constBegin(), end = swipeGestures.constEnd(); it != end; it++) {
148  (*it)->cancel(serial);
149  }
150 }
151 
152 void PointerInterface::Private::startPinchGesture(quint32 serial, quint32 fingerCount)
153 {
154  if (pinchGestures.isEmpty()) {
155  return;
156  }
157  for (auto it = pinchGestures.constBegin(), end = pinchGestures.constEnd(); it != end; it++) {
158  (*it)->start(serial, fingerCount);
159  }
160 }
161 
162 void PointerInterface::Private::updatePinchGesture(const QSizeF &delta, qreal scale, qreal rotation)
163 {
164  if (pinchGestures.isEmpty()) {
165  return;
166  }
167  for (auto it = pinchGestures.constBegin(), end = pinchGestures.constEnd(); it != end; it++) {
168  (*it)->update(delta, scale, rotation);
169  }
170 }
171 
172 void PointerInterface::Private::endPinchGesture(quint32 serial)
173 {
174  if (pinchGestures.isEmpty()) {
175  return;
176  }
177  for (auto it = pinchGestures.constBegin(), end = pinchGestures.constEnd(); it != end; it++) {
178  (*it)->end(serial);
179  }
180 }
181 
182 void PointerInterface::Private::cancelPinchGesture(quint32 serial)
183 {
184  if (pinchGestures.isEmpty()) {
185  return;
186  }
187  for (auto it = pinchGestures.constBegin(), end = pinchGestures.constEnd(); it != end; it++) {
188  (*it)->cancel(serial);
189  }
190 }
191 
192 void PointerInterface::Private::sendFrame()
193 {
194  if (!resource || wl_resource_get_version(resource) < WL_POINTER_FRAME_SINCE_VERSION) {
195  return;
196  }
197  wl_pointer_send_frame(resource);
198 }
199 
200 #ifndef K_DOXYGEN
201 const struct wl_pointer_interface PointerInterface::Private::s_interface = {setCursorCallback, resourceDestroyedCallback};
202 #endif
203 
204 PointerInterface::PointerInterface(SeatInterface *parent, wl_resource *parentResource)
205  : Resource(new Private(parent, parentResource, this))
206 {
207  // TODO: handle touch
208  connect(parent, &SeatInterface::pointerPosChanged, this, [this] {
209  Q_D();
210  if (!d->focusedSurface || !d->resource) {
211  return;
212  }
213  if (d->seat->isDragPointer()) {
214  const auto *originSurface = d->seat->dragSource()->origin();
215  const bool proxyRemoteFocused = originSurface->dataProxy() && originSurface == d->focusedSurface;
216  if (!proxyRemoteFocused) {
217  // handled by DataDevice
218  return;
219  }
220  }
221  if (!d->focusedSurface->lockedPointer().isNull() && d->focusedSurface->lockedPointer()->isLocked()) {
222  return;
223  }
224  const QPointF pos = d->seat->focusedPointerSurfaceTransformation().map(d->seat->pointerPos());
225  auto targetSurface = d->focusedSurface->inputSurfaceAt(pos);
226  if (!targetSurface) {
227  targetSurface = d->focusedSurface;
228  }
229  if (targetSurface != d->focusedChildSurface.data()) {
230  const quint32 serial = d->seat->display()->nextSerial();
231  d->sendLeave(d->focusedChildSurface.data(), serial);
232  d->focusedChildSurface = QPointer<SurfaceInterface>(targetSurface);
233  d->sendEnter(targetSurface, pos, serial);
234  d->sendFrame();
235  d->client->flush();
236  } else {
237  const QPointF adjustedPos = pos - surfacePosition(d->focusedChildSurface);
238  wl_pointer_send_motion(d->resource, d->seat->timestamp(), wl_fixed_from_double(adjustedPos.x()), wl_fixed_from_double(adjustedPos.y()));
239  d->sendFrame();
240  }
241  });
242 }
243 
244 PointerInterface::~PointerInterface() = default;
245 
246 void PointerInterface::setFocusedSurface(SurfaceInterface *surface, quint32 serial)
247 {
248  Q_D();
249  d->sendLeave(d->focusedChildSurface.data(), serial);
250  disconnect(d->destroyConnection);
251  if (!surface) {
252  d->focusedSurface = nullptr;
253  d->focusedChildSurface.clear();
254  return;
255  }
256  d->focusedSurface = surface;
257  d->destroyConnection = connect(d->focusedSurface, &Resource::aboutToBeUnbound, this, [this] {
258  Q_D();
259  d->sendLeave(d->focusedChildSurface.data(), d->global->display()->nextSerial());
260  d->sendFrame();
261  d->focusedSurface = nullptr;
262  d->focusedChildSurface.clear();
263  });
264 
265  const QPointF pos = d->seat->focusedPointerSurfaceTransformation().map(d->seat->pointerPos());
266  d->focusedChildSurface = QPointer<SurfaceInterface>(d->focusedSurface->inputSurfaceAt(pos));
267  if (!d->focusedChildSurface) {
268  d->focusedChildSurface = QPointer<SurfaceInterface>(d->focusedSurface);
269  }
270  d->sendEnter(d->focusedChildSurface.data(), pos, serial);
271  d->client->flush();
272 }
273 
274 void PointerInterface::buttonPressed(quint32 button, quint32 serial)
275 {
276  Q_D();
277  Q_ASSERT(d->focusedSurface);
278  if (!d->resource) {
279  return;
280  }
281  wl_pointer_send_button(d->resource, serial, d->seat->timestamp(), button, WL_POINTER_BUTTON_STATE_PRESSED);
282  d->sendFrame();
283 }
284 
285 void PointerInterface::buttonReleased(quint32 button, quint32 serial)
286 {
287  Q_D();
288  Q_ASSERT(d->focusedSurface);
289  if (!d->resource) {
290  return;
291  }
292  wl_pointer_send_button(d->resource, serial, d->seat->timestamp(), button, WL_POINTER_BUTTON_STATE_RELEASED);
293  d->sendFrame();
294 }
295 
296 void PointerInterface::axis(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source)
297 {
298  Q_D();
299  Q_ASSERT(d->focusedSurface);
300  if (!d->resource) {
301  return;
302  }
303 
304  const quint32 version = wl_resource_get_version(d->resource);
305 
306  const auto wlOrientation = (orientation == Qt::Vertical) ? WL_POINTER_AXIS_VERTICAL_SCROLL : WL_POINTER_AXIS_HORIZONTAL_SCROLL;
307 
308  if (source != PointerAxisSource::Unknown && version >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION) {
309  wl_pointer_axis_source wlSource;
310  switch (source) {
311  case PointerAxisSource::Wheel:
312  wlSource = WL_POINTER_AXIS_SOURCE_WHEEL;
313  break;
314  case PointerAxisSource::Finger:
315  wlSource = WL_POINTER_AXIS_SOURCE_FINGER;
316  break;
317  case PointerAxisSource::Continuous:
318  wlSource = WL_POINTER_AXIS_SOURCE_CONTINUOUS;
319  break;
320  case PointerAxisSource::WheelTilt:
321  wlSource = WL_POINTER_AXIS_SOURCE_WHEEL_TILT;
322  break;
323  default:
324  Q_UNREACHABLE();
325  break;
326  }
327  wl_pointer_send_axis_source(d->resource, wlSource);
328  }
329 
330  if (delta != 0.0) {
331  if (discreteDelta && version >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) {
332  wl_pointer_send_axis_discrete(d->resource, wlOrientation, discreteDelta);
333  }
334  wl_pointer_send_axis(d->resource, d->seat->timestamp(), wlOrientation, wl_fixed_from_double(delta));
335  } else if (version >= WL_POINTER_AXIS_STOP_SINCE_VERSION) {
336  wl_pointer_send_axis_stop(d->resource, d->seat->timestamp(), wlOrientation);
337  }
338 
339  d->sendFrame();
340 }
341 
342 void PointerInterface::axis(Qt::Orientation orientation, quint32 delta)
343 {
344  Q_D();
345  Q_ASSERT(d->focusedSurface);
346  if (!d->resource) {
347  return;
348  }
349  wl_pointer_send_axis(d->resource,
350  d->seat->timestamp(),
351  (orientation == Qt::Vertical) ? WL_POINTER_AXIS_VERTICAL_SCROLL : WL_POINTER_AXIS_HORIZONTAL_SCROLL,
352  wl_fixed_from_int(delta));
353  d->sendFrame();
354 }
355 
356 void PointerInterface::Private::setCursorCallback(wl_client *client,
357  wl_resource *resource,
358  uint32_t serial,
359  wl_resource *surface,
360  int32_t hotspot_x,
361  int32_t hotspot_y)
362 {
363  auto p = cast<Private>(resource);
364  Q_ASSERT(p->client->client() == client);
365  p->setCursor(serial, SurfaceInterface::get(surface), QPoint(hotspot_x, hotspot_y));
366 }
367 
368 Cursor *PointerInterface::cursor() const
369 {
370  Q_D();
371  return d->cursor;
372 }
373 
374 void PointerInterface::relativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds)
375 {
376  Q_D();
377  if (d->relativePointers.isEmpty()) {
378  return;
379  }
380  for (auto it = d->relativePointers.constBegin(), end = d->relativePointers.constEnd(); it != end; it++) {
381  (*it)->relativeMotion(delta, deltaNonAccelerated, microseconds);
382  }
383  d->sendFrame();
384 }
385 
386 PointerInterface::Private *PointerInterface::d_func() const
387 {
388  return reinterpret_cast<Private *>(d.data());
389 }
390 
392 {
393  return Private::get<PointerInterface>(native);
394 }
395 
396 Cursor::Private::Private(Cursor *q, PointerInterface *pointer)
397  : pointer(pointer)
398  , q(q)
399 {
400 }
401 
402 void Cursor::Private::update(const QPointer<SurfaceInterface> &s, quint32 serial, const QPoint &p)
403 {
404  bool emitChanged = false;
405  if (enteredSerial != serial) {
406  enteredSerial = serial;
407  emitChanged = true;
408  Q_EMIT q->enteredSerialChanged();
409  }
410  if (hotspot != p) {
411  hotspot = p;
412  emitChanged = true;
413  Q_EMIT q->hotspotChanged();
414  }
415  if (surface != s) {
416  if (!surface.isNull()) {
417  QObject::disconnect(surface.data(), &SurfaceInterface::damaged, q, &Cursor::changed);
418  }
419  surface = s;
420  if (!surface.isNull()) {
421  QObject::connect(surface.data(), &SurfaceInterface::damaged, q, &Cursor::changed);
422  }
423  emitChanged = true;
424  Q_EMIT q->surfaceChanged();
425  }
426  if (emitChanged) {
427  Q_EMIT q->changed();
428  }
429 }
430 
431 Cursor::Cursor(PointerInterface *parent)
432  : QObject(parent)
433  , d(new Private(this, parent))
434 {
435 }
436 
437 Cursor::~Cursor() = default;
438 
439 quint32 Cursor::enteredSerial() const
440 {
441  return d->enteredSerial;
442 }
443 
445 {
446  return d->hotspot;
447 }
448 
450 {
451  return d->pointer;
452 }
453 
455 {
456  return d->surface;
457 }
458 
459 }
460 }
QPoint hotspot() const
The hotspot of the cursor image in surface-relative coordinates.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
Resource for the wl_pointer interface.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void destroyed(QObject *obj)
T * data() const const
void damaged(const QRegion &)
Emitted whenever the SurfaceInterface got damaged.
Orientation
bool isNull() const const
qreal x() const const
qreal y() const const
unsigned int version()
void update(Part *part, const QByteArray &data, qint64 dataSize)
PointerInterface * pointer() const
The PointerInterface this Cursor belongs to.
QPointer< SurfaceInterface > surface() const
The SurfaceInterface for the image content of the Cursor.
quint32 enteredSerial() const
The entered serial when the Cursor got set.
QObject * parent() const const
Q_D(Todo)
virtual QVariant get(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName)
Class encapsulating a Cursor image.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Jan 30 2023 03:56:24 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.