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 class CursorPrivate
24 {
25 public:
26  CursorPrivate(Cursor *q, PointerInterface *pointer);
27 
28  Cursor *q;
29  PointerInterface *pointer;
30  quint32 enteredSerial = 0;
31  QPoint hotspot;
33 
34  void update(SurfaceInterface *surface, quint32 serial, const QPoint &hotspot);
35 };
36 
37 PointerInterfacePrivate *PointerInterfacePrivate::get(PointerInterface *pointer)
38 {
39  return pointer->d.data();
40 }
41 
42 PointerInterfacePrivate::PointerInterfacePrivate(PointerInterface *q, SeatInterface *seat)
43  : q(q)
44  , seat(seat)
45  , relativePointersV1(new RelativePointerV1Interface(q))
46  , swipeGesturesV1(new PointerSwipeGestureV1Interface(q))
47  , pinchGesturesV1(new PointerPinchGestureV1Interface(q))
48 {
49 }
50 
51 PointerInterfacePrivate::~PointerInterfacePrivate()
52 {
53 }
54 
55 QList<PointerInterfacePrivate::Resource *> PointerInterfacePrivate::pointersForClient(ClientConnection *client) const
56 {
57  return resourceMap().values(client->client());
58 }
59 
60 void PointerInterfacePrivate::pointer_set_cursor(Resource *resource, uint32_t serial, ::wl_resource *surface_resource, int32_t hotspot_x, int32_t hotspot_y)
61 {
62  SurfaceInterface *surface = nullptr;
63 
64  if (!focusedSurface) {
65  return;
66  }
67  if (focusedSurface->client()->client() != resource->client()) {
68  qCDebug(KWAYLAND_SERVER, "Denied set_cursor request from unfocused client");
69  return;
70  }
71 
72  if (surface_resource) {
73  surface = SurfaceInterface::get(surface_resource);
74  if (!surface) {
75  wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid surface");
76  return;
77  }
78 
79  const SurfaceRole *surfaceRole = SurfaceRole::get(surface);
80  if (surfaceRole) {
81  wl_resource_post_error(resource->handle, error_role, "the wl_surface already has a role assigned %s", surfaceRole->name().constData());
82  return;
83  }
84  }
85 
86  if (!cursor) { // TODO: Assign the cursor surface role.
87  cursor = new Cursor(q);
88  cursor->d->update(surface, serial, QPoint(hotspot_x, hotspot_y));
89  QObject::connect(cursor, &Cursor::changed, q, &PointerInterface::cursorChanged);
90  Q_EMIT q->cursorChanged();
91  } else {
92  cursor->d->update(surface, serial, QPoint(hotspot_x, hotspot_y));
93  }
94 }
95 
96 void PointerInterfacePrivate::pointer_release(Resource *resource)
97 {
98  wl_resource_destroy(resource->handle);
99 }
100 
101 void PointerInterfacePrivate::pointer_bind_resource(Resource *resource)
102 {
103  const ClientConnection *focusedClient = focusedSurface ? focusedSurface->client() : nullptr;
104 
105  if (focusedClient && focusedClient->client() == resource->client()) {
106  const quint32 serial = seat->display()->nextSerial();
107  send_enter(resource->handle, serial, focusedSurface->resource(), wl_fixed_from_double(lastPosition.x()), wl_fixed_from_double(lastPosition.y()));
108  if (resource->version() >= WL_POINTER_FRAME_SINCE_VERSION) {
109  send_frame(resource->handle);
110  }
111  }
112 }
113 
114 void PointerInterfacePrivate::sendLeave(quint32 serial)
115 {
116  const QList<Resource *> pointerResources = pointersForClient(focusedSurface->client());
117  for (Resource *resource : pointerResources) {
118  send_leave(resource->handle, serial, focusedSurface->resource());
119  }
120 }
121 
122 void PointerInterfacePrivate::sendEnter(const QPointF &position, quint32 serial)
123 {
124  const QList<Resource *> pointerResources = pointersForClient(focusedSurface->client());
125  for (Resource *resource : pointerResources) {
126  send_enter(resource->handle, serial, focusedSurface->resource(), wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y()));
127  }
128 }
129 
130 void PointerInterfacePrivate::sendFrame()
131 {
132  const QList<Resource *> pointerResources = pointersForClient(focusedSurface->client());
133  for (Resource *resource : pointerResources) {
134  if (resource->version() >= WL_POINTER_FRAME_SINCE_VERSION) {
135  send_frame(resource->handle);
136  }
137  }
138 }
139 
140 PointerInterface::PointerInterface(SeatInterface *seat)
141  : d(new PointerInterfacePrivate(this, seat))
142 {
143 }
144 
145 PointerInterface::~PointerInterface()
146 {
147 }
148 
150 {
151  return d->focusedSurface;
152 }
153 
154 void PointerInterface::setFocusedSurface(SurfaceInterface *surface, const QPointF &position, quint32 serial)
155 {
156  if (d->focusedSurface == surface) {
157  return;
158  }
159 
160  if (d->focusedSurface) {
161  d->sendLeave(serial);
162  if (!surface || d->focusedSurface->client() != surface->client()) {
163  d->sendFrame();
164  }
165  disconnect(d->destroyConnection);
166  }
167 
168  d->focusedSurface = surface;
169 
170  if (d->focusedSurface) {
171  d->destroyConnection = connect(d->focusedSurface, &SurfaceInterface::aboutToBeDestroyed, this, [this]() {
172  d->sendLeave(d->seat->display()->nextSerial());
173  d->sendFrame();
174  d->focusedSurface = nullptr;
175  Q_EMIT focusedSurfaceChanged();
176  });
177  d->sendEnter(position, serial);
178  d->sendFrame();
179  d->lastPosition = position;
180  }
181 
182  Q_EMIT focusedSurfaceChanged();
183 }
184 
185 void PointerInterface::sendButton(quint32 button, PointerButtonState state, quint32 serial)
186 {
187  if (!d->focusedSurface) {
188  return;
189  }
190 
191  const auto pointerResources = d->pointersForClient(d->focusedSurface->client());
192  for (PointerInterfacePrivate::Resource *resource : pointerResources) {
193  d->send_button(resource->handle, serial, d->seat->timestamp(), button, quint32(state));
194  }
195 }
196 
197 void PointerInterface::sendAxis(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source)
198 {
199  if (!d->focusedSurface) {
200  return;
201  }
202 
203  const auto pointerResources = d->pointersForClient(d->focusedSurface->client());
204  for (PointerInterfacePrivate::Resource *resource : pointerResources) {
205  const quint32 version = resource->version();
206 
207  const auto wlOrientation =
208  (orientation == Qt::Vertical) ? PointerInterfacePrivate::axis_vertical_scroll : PointerInterfacePrivate::axis_horizontal_scroll;
209 
210  if (source != PointerAxisSource::Unknown && version >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION) {
211  PointerInterfacePrivate::axis_source wlSource;
212  switch (source) {
213  case PointerAxisSource::Wheel:
214  wlSource = PointerInterfacePrivate::axis_source_wheel;
215  break;
216  case PointerAxisSource::Finger:
217  wlSource = PointerInterfacePrivate::axis_source_finger;
218  break;
219  case PointerAxisSource::Continuous:
220  wlSource = PointerInterfacePrivate::axis_source_continuous;
221  break;
222  case PointerAxisSource::WheelTilt:
223  wlSource = PointerInterfacePrivate::axis_source_wheel_tilt;
224  break;
225  default:
226  Q_UNREACHABLE();
227  break;
228  }
229  d->send_axis_source(resource->handle, wlSource);
230  }
231 
232  if (delta != 0.0) {
233  if (discreteDelta && version >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) {
234  d->send_axis_discrete(resource->handle, wlOrientation, discreteDelta);
235  }
236  d->send_axis(resource->handle, d->seat->timestamp(), wlOrientation, wl_fixed_from_double(delta));
237  } else if (version >= WL_POINTER_AXIS_STOP_SINCE_VERSION) {
238  d->send_axis_stop(resource->handle, d->seat->timestamp(), wlOrientation);
239  }
240  }
241 }
242 
243 void PointerInterface::sendMotion(const QPointF &position)
244 {
245  d->lastPosition = position;
246 
247  if (!d->focusedSurface) {
248  return;
249  }
250 
251  const auto pointerResources = d->pointersForClient(d->focusedSurface->client());
252  for (PointerInterfacePrivate::Resource *resource : pointerResources) {
253  d->send_motion(resource->handle, d->seat->timestamp(), wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y()));
254  }
255 }
256 
257 void PointerInterface::sendFrame()
258 {
259  if (d->focusedSurface) {
260  d->sendFrame();
261  }
262 }
263 
264 Cursor *PointerInterface::cursor() const
265 {
266  return d->cursor;
267 }
268 
270 {
271  return d->seat;
272 }
273 
275 {
276  if (PointerInterfacePrivate *pointerPrivate = resource_cast<PointerInterfacePrivate *>(native)) {
277  return pointerPrivate->q;
278  }
279  return nullptr;
280 }
281 
282 CursorPrivate::CursorPrivate(Cursor *q, PointerInterface *pointer)
283  : q(q)
284  , pointer(pointer)
285 {
286 }
287 
288 void CursorPrivate::update(SurfaceInterface *s, quint32 serial, const QPoint &p)
289 {
290  bool emitChanged = false;
291  if (enteredSerial != serial) {
292  enteredSerial = serial;
293  emitChanged = true;
294  Q_EMIT q->enteredSerialChanged();
295  }
296  if (hotspot != p) {
297  hotspot = p;
298  emitChanged = true;
299  Q_EMIT q->hotspotChanged();
300  }
301  if (surface != s) {
302  if (!surface.isNull()) {
303  QObject::disconnect(surface.data(), &SurfaceInterface::damaged, q, &Cursor::changed);
304  }
305  surface = s;
306  if (!surface.isNull()) {
307  QObject::connect(surface.data(), &SurfaceInterface::damaged, q, &Cursor::changed);
308  }
309  emitChanged = true;
310  Q_EMIT q->surfaceChanged();
311  }
312  if (emitChanged) {
313  Q_EMIT q->changed();
314  }
315 }
316 
317 Cursor::Cursor(PointerInterface *parent)
318  : QObject(parent)
319  , d(new CursorPrivate(this, parent))
320 {
321 }
322 
323 Cursor::~Cursor()
324 {
325 }
326 
327 quint32 Cursor::enteredSerial() const
328 {
329  return d->enteredSerial;
330 }
331 
333 {
334  return d->hotspot;
335 }
336 
338 {
339  return d->pointer;
340 }
341 
343 {
344  return d->surface;
345 }
346 
347 } // 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 Fri Oct 22 2021 23:08:36 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.