KWaylandServer

pointer_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2014 Martin Gräßlin <[email protected]>
3  SPDX-FileCopyrightText: 2020 Adrien Faveraux <[email protected]>
4  SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8 
9 #include "pointer_interface.h"
10 #include "clientconnection.h"
11 #include "display.h"
12 #include "logging.h"
13 #include "pointer_interface_p.h"
14 #include "pointergestures_v1_interface_p.h"
15 #include "relativepointer_v1_interface_p.h"
16 #include "seat_interface.h"
17 #include "surface_interface.h"
18 #include "surfacerole_p.h"
19 #include "utils.h"
20 
21 namespace KWaylandServer
22 {
23 
24 class CursorPrivate
25 {
26 public:
27  CursorPrivate(Cursor *q, PointerInterface *pointer);
28 
29  Cursor *q;
30  PointerInterface *pointer;
31  quint32 enteredSerial = 0;
32  QPoint hotspot;
34 
35  void update(SurfaceInterface *surface, quint32 serial, const QPoint &hotspot);
36 };
37 
38 PointerInterfacePrivate *PointerInterfacePrivate::get(PointerInterface *pointer)
39 {
40  return pointer->d.data();
41 }
42 
43 PointerInterfacePrivate::PointerInterfacePrivate(PointerInterface *q, SeatInterface *seat)
44  : q(q)
45  , seat(seat)
46  , relativePointersV1(new RelativePointerV1Interface(q))
47  , swipeGesturesV1(new PointerSwipeGestureV1Interface(q))
48  , pinchGesturesV1(new PointerPinchGestureV1Interface(q))
49 {
50 }
51 
52 PointerInterfacePrivate::~PointerInterfacePrivate()
53 {
54 }
55 
56 QList<PointerInterfacePrivate::Resource *> PointerInterfacePrivate::pointersForClient(ClientConnection *client) const
57 {
58  return resourceMap().values(client->client());
59 }
60 
61 void PointerInterfacePrivate::pointer_set_cursor(Resource *resource, uint32_t serial,
62  ::wl_resource *surface_resource,
63  int32_t hotspot_x, int32_t hotspot_y)
64 {
65  SurfaceInterface *surface = nullptr;
66 
67  if (!focusedSurface) {
68  return;
69  }
70  if (focusedSurface->client()->client() != resource->client()) {
71  qCDebug(KWAYLAND_SERVER, "Denied set_cursor request from unfocused client");
72  return;
73  }
74 
75  if (surface_resource) {
76  surface = SurfaceInterface::get(surface_resource);
77  if (!surface) {
78  wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT,
79  "invalid surface");
80  return;
81  }
82 
83  const SurfaceRole *surfaceRole = SurfaceRole::get(surface);
84  if (surfaceRole) {
85  wl_resource_post_error(resource->handle, error_role,
86  "the wl_surface already has a role assigned %s",
87  surfaceRole->name().constData());
88  return;
89  }
90  }
91 
92  if (!cursor) { // TODO: Assign the cursor surface role.
93  cursor = new Cursor(q);
94  cursor->d->update(surface, serial, QPoint(hotspot_x, hotspot_y));
95  QObject::connect(cursor, &Cursor::changed, q, &PointerInterface::cursorChanged);
96  Q_EMIT q->cursorChanged();
97  } else {
98  cursor->d->update(surface, serial, QPoint(hotspot_x, hotspot_y));
99  }
100 }
101 
102 void PointerInterfacePrivate::pointer_release(Resource *resource)
103 {
104  wl_resource_destroy(resource->handle);
105 }
106 
107 void PointerInterfacePrivate::pointer_bind_resource(Resource *resource)
108 {
109  const ClientConnection *focusedClient = focusedSurface ? focusedSurface->client() : nullptr;
110 
111  if (focusedClient && focusedClient->client() == resource->client()) {
112  const quint32 serial = seat->display()->nextSerial();
113  send_enter(resource->handle, serial, focusedSurface->resource(),
114  wl_fixed_from_double(lastPosition.x()), wl_fixed_from_double(lastPosition.y()));
115  if (resource->version() >= WL_POINTER_FRAME_SINCE_VERSION) {
116  send_frame(resource->handle);
117  }
118  }
119 }
120 
121 void PointerInterfacePrivate::sendLeave(quint32 serial)
122 {
123  const QList<Resource *> pointerResources = pointersForClient(focusedSurface->client());
124  for (Resource *resource : pointerResources) {
125  send_leave(resource->handle, serial, focusedSurface->resource());
126  }
127 }
128 
129 void PointerInterfacePrivate::sendEnter(const QPointF &position, quint32 serial)
130 {
131  const QList<Resource *> pointerResources = pointersForClient(focusedSurface->client());
132  for (Resource *resource : pointerResources) {
133  send_enter(resource->handle, serial, focusedSurface->resource(),
134  wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y()));
135  }
136 }
137 
138 void PointerInterfacePrivate::sendFrame()
139 {
140  const QList<Resource *> pointerResources = pointersForClient(focusedSurface->client());
141  for (Resource *resource : pointerResources) {
142  if (resource->version() >= WL_POINTER_FRAME_SINCE_VERSION) {
143  send_frame(resource->handle);
144  }
145  }
146 }
147 
148 PointerInterface::PointerInterface(SeatInterface *seat)
149  : d(new PointerInterfacePrivate(this, seat))
150 {
151 }
152 
153 PointerInterface::~PointerInterface()
154 {
155 }
156 
158 {
159  return d->focusedSurface;
160 }
161 
162 void PointerInterface::setFocusedSurface(SurfaceInterface *surface, const QPointF &position, quint32 serial)
163 {
164  if (d->focusedSurface == surface) {
165  return;
166  }
167 
168  if (d->focusedSurface) {
169  d->sendLeave(serial);
170  if (!surface || d->focusedSurface->client() != surface->client()) {
171  d->sendFrame();
172  }
173  disconnect(d->destroyConnection);
174  }
175 
176  d->focusedSurface = surface;
177 
178  if (d->focusedSurface) {
179  d->destroyConnection = connect(d->focusedSurface, &SurfaceInterface::aboutToBeDestroyed, this, [this]() {
180  d->sendLeave(d->seat->display()->nextSerial());
181  d->sendFrame();
182  d->focusedSurface = nullptr;
183  Q_EMIT focusedSurfaceChanged();
184  });
185  d->sendEnter(position, serial);
186  d->sendFrame();
187  d->lastPosition = position;
188  }
189 
190  Q_EMIT focusedSurfaceChanged();
191 }
192 
193 void PointerInterface::sendButton(quint32 button, PointerButtonState state, quint32 serial)
194 {
195  if (!d->focusedSurface) {
196  return;
197  }
198 
199  const auto pointerResources = d->pointersForClient(d->focusedSurface->client());
200  for (PointerInterfacePrivate::Resource *resource : pointerResources) {
201  d->send_button(resource->handle, serial, d->seat->timestamp(), button, quint32(state));
202  }
203 }
204 
205 void PointerInterface::sendAxis(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source)
206 {
207  if (!d->focusedSurface) {
208  return;
209  }
210 
211  const auto pointerResources = d->pointersForClient(d->focusedSurface->client());
212  for (PointerInterfacePrivate::Resource *resource : pointerResources) {
213  const quint32 version = resource->version();
214 
215  const auto wlOrientation = (orientation == Qt::Vertical)
216  ? PointerInterfacePrivate::axis_vertical_scroll
217  : PointerInterfacePrivate::axis_horizontal_scroll;
218 
219  if (source != PointerAxisSource::Unknown && version >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION) {
220  PointerInterfacePrivate::axis_source wlSource;
221  switch (source) {
222  case PointerAxisSource::Wheel:
223  wlSource = PointerInterfacePrivate::axis_source_wheel;
224  break;
225  case PointerAxisSource::Finger:
226  wlSource = PointerInterfacePrivate::axis_source_finger;
227  break;
228  case PointerAxisSource::Continuous:
229  wlSource = PointerInterfacePrivate::axis_source_continuous;
230  break;
231  case PointerAxisSource::WheelTilt:
232  wlSource = PointerInterfacePrivate::axis_source_wheel_tilt;
233  break;
234  default:
235  Q_UNREACHABLE();
236  break;
237  }
238  d->send_axis_source(resource->handle, wlSource);
239  }
240 
241  if (delta != 0.0) {
242  if (discreteDelta && version >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) {
243  d->send_axis_discrete(resource->handle, wlOrientation, discreteDelta);
244  }
245  d->send_axis(resource->handle, d->seat->timestamp(), wlOrientation, wl_fixed_from_double(delta));
246  } else if (version >= WL_POINTER_AXIS_STOP_SINCE_VERSION) {
247  d->send_axis_stop(resource->handle, d->seat->timestamp(), wlOrientation);
248  }
249  }
250 }
251 
252 void PointerInterface::sendMotion(const QPointF &position)
253 {
254  d->lastPosition = position;
255 
256  if (!d->focusedSurface) {
257  return;
258  }
259 
260  const auto pointerResources = d->pointersForClient(d->focusedSurface->client());
261  for (PointerInterfacePrivate::Resource *resource : pointerResources) {
262  d->send_motion(resource->handle, d->seat->timestamp(),
263  wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y()));
264  }
265 }
266 
267 void PointerInterface::sendFrame()
268 {
269  if (d->focusedSurface) {
270  d->sendFrame();
271  }
272 }
273 
274 Cursor *PointerInterface::cursor() const
275 {
276  return d->cursor;
277 }
278 
280 {
281  return d->seat;
282 }
283 
285 {
286  if (PointerInterfacePrivate *pointerPrivate = resource_cast<PointerInterfacePrivate *>(native)) {
287  return pointerPrivate->q;
288  }
289  return nullptr;
290 }
291 
292 CursorPrivate::CursorPrivate(Cursor *q, PointerInterface *pointer)
293  : q(q)
294  , pointer(pointer)
295 {
296 }
297 
298 void CursorPrivate::update(SurfaceInterface *s, quint32 serial, const QPoint &p)
299 {
300  bool emitChanged = false;
301  if (enteredSerial != serial) {
302  enteredSerial = serial;
303  emitChanged = true;
304  Q_EMIT q->enteredSerialChanged();
305  }
306  if (hotspot != p) {
307  hotspot = p;
308  emitChanged = true;
309  Q_EMIT q->hotspotChanged();
310  }
311  if (surface != s) {
312  if (!surface.isNull()) {
313  QObject::disconnect(surface.data(), &SurfaceInterface::damaged, q, &Cursor::changed);
314  }
315  surface = s;
316  if (!surface.isNull()) {
317  QObject::connect(surface.data(), &SurfaceInterface::damaged, q, &Cursor::changed);
318  }
319  emitChanged = true;
320  Q_EMIT q->surfaceChanged();
321  }
322  if (emitChanged) {
323  Q_EMIT q->changed();
324  }
325 }
326 
327 Cursor::Cursor(PointerInterface *parent)
328  : QObject(parent)
329  , d(new CursorPrivate(this, parent))
330 {
331 }
332 
333 Cursor::~Cursor()
334 {
335 }
336 
337 quint32 Cursor::enteredSerial() const
338 {
339  return d->enteredSerial;
340 }
341 
343 {
344  return d->hotspot;
345 }
346 
348 {
349  return d->pointer;
350 }
351 
353 {
354  return d->surface;
355 }
356 
357 } // namespace KWaylandServer
Represents a Seat on the Wayland Display.
quint32 enteredSerial() const
The entered serial when the Cursor got set.
ClientConnection * client() const
Returns the Wayland client that owns this SurfaceInterface.
void cursorChanged()
This signal is emitted whenever the cursor surface changes.
Class encapsulating a Cursor image.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
static PointerInterface * get(wl_resource *native)
The PointerInterface class represents one or more input devices such as mice, which control the point...
qreal x() const const
qreal y() const const
static SurfaceInterface * get(wl_resource *native)
void setFocusedSurface(SurfaceInterface *surface, const QPointF &position, quint32 serial)
Sets the effective focused pointer surface to surface.
QObject(QObject *parent)
QPoint hotspot() const
The hotspot of the cursor image in surface-relative coordinates.
SurfaceInterface * focusedSurface() const
Returns the focused pointer surface.
PointerInterface * pointer() const
The PointerInterface this Cursor belongs to.
void update(Part *part, const QByteArray &data, qint64 dataSize)
Resource representing a wl_surface.
Orientation
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void aboutToBeDestroyed()
This signal is emitted when the underlying wl_surface resource is about to be freed.
QObject * parent() const const
Q_EMITQ_EMIT
SeatInterface * seat() const
Returns the seat to which this pointer belongs to.
void damaged(const QRegion &)
Emitted whenever the SurfaceInterface got damaged.
SurfaceInterface * surface() const
The SurfaceInterface for the image content of the Cursor.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Jul 31 2021 23:10:11 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.