KWayland

tablet_interface.cpp
1 /********************************************************************
2 Copyright 2019 Aleix Pol Gonzalez <[email protected]>
3 
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11 
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16 
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
20 #include "tablet_interface.h"
21 #include "display.h"
22 #include "resource_p.h"
23 #include "seat_interface.h"
24 #include "surface_interface.h"
25 
26 #include "qwayland-server-tablet-unstable-v2.h"
27 #include <QHash>
28 
29 using namespace KWayland;
30 using namespace Server;
31 
32 static int s_version = 1;
33 
34 class TabletInterface::Private : public QtWaylandServer::zwp_tablet_v2
35 {
36 public:
37  Private(TabletInterface* q, uint32_t vendorId, uint32_t productId, const QString name, const QStringList &paths)
38  : zwp_tablet_v2()
39  , q(q)
40  , m_vendorId(vendorId)
41  , m_productId(productId)
42  , m_name(name)
43  , m_paths(paths)
44  {
45  }
46 
47  wl_resource *resourceForSurface(SurfaceInterface *surface) const
48  {
49  ClientConnection *client = surface->client();
50  QtWaylandServer::zwp_tablet_v2::Resource *r = resourceMap().value(*client);
51  return r ? r->handle : nullptr;
52  }
53 
54  void zwp_tablet_v2_destroy_resource(QtWaylandServer::zwp_tablet_v2::Resource * resource) override
55  {
56  Q_UNUSED(resource);
57  if (removed && resourceMap().isEmpty()) {
58  delete q;
59  }
60  }
61 
62  TabletInterface *const q;
63  const uint32_t m_vendorId;
64  const uint32_t m_productId;
65  const QString m_name;
66  const QStringList m_paths;
67  bool removed = false;
68 };
69 
70 TabletInterface::TabletInterface(uint32_t vendorId, uint32_t productId,
71  const QString &name, const QStringList &paths,
72  QObject *parent)
73  : QObject(parent)
74  , d(new Private(this, vendorId, productId, name, paths))
75 {
76 }
77 
78 TabletInterface::~TabletInterface() = default;
79 
80 bool TabletInterface::isSurfaceSupported(SurfaceInterface *surface) const
81 {
82  return d->resourceForSurface(surface);
83 }
84 
85 void TabletInterface::sendRemoved()
86 {
87  d->removed = true;
88  for (QtWaylandServer::zwp_tablet_v2::Resource *resource : d->resourceMap()) {
89  d->send_removed(resource->handle);
90  }
91 }
92 
93 class TabletCursor::Private
94 {
95 public:
96  Private(TabletCursor* q) : q(q) {}
97 
98  void update(quint32 serial, SurfaceInterface *surface, const QPoint &hotspot)
99  {
100  const bool diff = m_serial != serial && m_surface != surface && m_hotspot != hotspot;
101  m_serial = serial;
102  m_surface = surface;
103  m_hotspot = hotspot;
104  if (diff)
105  Q_EMIT q->changed();
106  }
107 
108  TabletCursor* const q;
109 
110  quint32 m_serial = 0;
111  SurfaceInterface* m_surface = nullptr;
112  QPoint m_hotspot;
113 };
114 
115 TabletCursor::TabletCursor()
116  : QObject()
117  , d(new Private(this))
118 {
119 }
120 
121 TabletCursor::~TabletCursor() = default;
122 
123 QPoint TabletCursor::hotspot() const
124 {
125  return d->m_hotspot;
126 }
127 
128 quint32 TabletCursor::enteredSerial() const
129 {
130  return d->m_serial;
131 }
132 
133 SurfaceInterface* TabletCursor::surface() const
134 {
135  return d->m_surface;
136 }
137 
138 class TabletToolInterface::Private : public QtWaylandServer::zwp_tablet_tool_v2
139 {
140 public:
141  Private(TabletToolInterface* q, Display *display, Type type, uint32_t hsh, uint32_t hsl, uint32_t hih,
142  uint32_t hil, const QVector<Capability>& capabilities)
143  : zwp_tablet_tool_v2()
144  , m_display(display)
145  , m_type(type)
146  , m_hardwareSerialHigh(hsh)
147  , m_hardwareSerialLow(hsl)
148  , m_hardwareIdHigh(hih)
149  , m_hardwareIdLow(hil)
150  , m_capabilities(capabilities)
151  , q(q)
152  {
153  }
154 
155 
156  wl_resource *targetResource()
157  {
158  if (!m_surface)
159  return nullptr;
160 
161  ClientConnection *client = m_surface->client();
162  const Resource *r = resourceMap().value(*client);
163  return r ? r->handle : nullptr;
164  }
165 
166  quint64 hardwareId() const
167  {
168  return quint64(quint64(m_hardwareIdHigh) << 32) + m_hardwareIdLow;
169  }
170  quint64 hardwareSerial() const
171  {
172  return quint64(quint64(m_hardwareSerialHigh) << 32) + m_hardwareSerialLow;
173  }
174 
175  void zwp_tablet_tool_v2_bind_resource(QtWaylandServer::zwp_tablet_tool_v2::Resource * resource) override
176  {
177  TabletCursor *&c = m_cursors[resource->handle];
178  if (!c)
179  c = new TabletCursor;
180  }
181 
182  void zwp_tablet_tool_v2_set_cursor(Resource * resource, uint32_t serial, struct ::wl_resource * _surface, int32_t hotspot_x, int32_t hotspot_y) override
183  {
184  TabletCursor *c = m_cursors[resource->handle];
185  c->d->update(serial, SurfaceInterface::get(_surface), {hotspot_x, hotspot_y});
186  if (resource->handle == targetResource())
187  q->cursorChanged(c);
188  }
189 
190  void zwp_tablet_tool_v2_destroy_resource(Resource * resource) override {
191  delete m_cursors.take(resource->handle);
192  }
193 
194  Display *const m_display;
195  bool m_cleanup = false;
196  QPointer<SurfaceInterface> m_surface;
197  QPointer<TabletInterface> m_lastTablet;
198  const uint32_t m_type;
199  const uint32_t m_hardwareSerialHigh, m_hardwareSerialLow;
200  const uint32_t m_hardwareIdHigh, m_hardwareIdLow;
201  const QVector<Capability> m_capabilities;
203  TabletToolInterface *const q;
204 };
205 
206 TabletToolInterface::TabletToolInterface(Display *display, Type type, uint32_t hsh,
207  uint32_t hsl, uint32_t hih, uint32_t hil,
208  const QVector<Capability>& capabilities,
209  QObject *parent)
210  : QObject(parent)
211  , d(new Private(this, display, type, hsh, hsl, hih, hil, capabilities))
212 {
213 }
214 
215 TabletToolInterface::~TabletToolInterface() = default;
216 
217 void TabletToolInterface::setCurrentSurface(SurfaceInterface *surface)
218 {
219  if (d->m_surface == surface)
220  return;
221 
222  TabletInterface *const lastTablet = d->m_lastTablet;
223  if (d->m_surface && d->resourceMap().contains(*d->m_surface->client())) {
224  sendProximityOut();
225  sendFrame(0);
226  }
227 
228  d->m_surface = surface;
229 
230  if (lastTablet && lastTablet->d->resourceForSurface(surface)) {
231  sendProximityIn(lastTablet);
232  } else {
233  d->m_lastTablet = lastTablet;
234  }
235 
236  Q_EMIT cursorChanged(d->m_cursors.value(d->targetResource()));
237 }
238 
239 bool TabletToolInterface::isClientSupported() const
240 {
241  return d->m_surface && d->targetResource();
242 }
243 
244 void TabletToolInterface::sendButton(uint32_t button, bool pressed)
245 {
246  d->send_button(d->targetResource(), d->m_display->nextSerial(), button,
247  pressed ? QtWaylandServer::zwp_tablet_tool_v2::button_state_pressed
248  : QtWaylandServer::zwp_tablet_tool_v2::button_state_released);
249 }
250 
251 void TabletToolInterface::sendMotion(const QPointF &pos)
252 {
253  d->send_motion(d->targetResource(), wl_fixed_from_double(pos.x()),
254  wl_fixed_from_double(pos.y()));
255 }
256 
257 void TabletToolInterface::sendDistance(uint32_t distance)
258 {
259  d->send_distance(d->targetResource(), distance);
260 }
261 
262 void TabletToolInterface::sendFrame(uint32_t time)
263 {
264  d->send_frame(d->targetResource(), time);
265 
266  if (d->m_cleanup) {
267  d->m_surface = nullptr;
268  d->m_lastTablet = nullptr;
269  d->m_cleanup = false;
270  }
271 }
272 
273 void TabletToolInterface::sendPressure(uint32_t pressure)
274 {
275  d->send_pressure(d->targetResource(), pressure);
276 }
277 
278 void TabletToolInterface::sendRotation(qreal rotation)
279 {
280  d->send_rotation(d->targetResource(), wl_fixed_from_double(rotation));
281 }
282 
283 void TabletToolInterface::sendSlider(int32_t position)
284 {
285  d->send_slider(d->targetResource(), position);
286 }
287 
288 void TabletToolInterface::sendTilt(qreal degreesX, qreal degreesY)
289 {
290  d->send_tilt(d->targetResource(), wl_fixed_from_double(degreesX),
291  wl_fixed_from_double(degreesY));
292 }
293 
294 void TabletToolInterface::sendWheel(int32_t degrees, int32_t clicks)
295 {
296  d->send_wheel(d->targetResource(), degrees, clicks);
297 }
298 
299 void TabletToolInterface::sendProximityIn(TabletInterface *tablet)
300 {
301  wl_resource* tabletResource = tablet->d->resourceForSurface(d->m_surface);
302  d->send_proximity_in(d->targetResource(), d->m_display->nextSerial(),
303  tabletResource, d->m_surface->resource());
304  d->m_lastTablet = tablet;
305 }
306 
307 void TabletToolInterface::sendProximityOut()
308 {
309  d->send_proximity_out(d->targetResource());
310  d->m_cleanup = true;
311 }
312 
313 void TabletToolInterface::sendDown()
314 {
315  d->send_down(d->targetResource(), d->m_display->nextSerial());
316 }
317 
318 void TabletToolInterface::sendUp()
319 {
320  d->send_up(d->targetResource());
321 }
322 
323 void TabletToolInterface::sendRemoved()
324 {
325  for (QtWaylandServer::zwp_tablet_tool_v2::Resource *resource : d->resourceMap()) {
326  d->send_removed(resource->handle);
327  }
328 }
329 
330 class TabletSeatInterface::Private : public QtWaylandServer::zwp_tablet_seat_v2
331 {
332 public:
333  Private(Display *display, TabletSeatInterface *q)
334  : zwp_tablet_seat_v2()
335  , q(q)
336  , m_display(display)
337  {
338  }
339 
340  void zwp_tablet_seat_v2_bind_resource(Resource *resource) override
341  {
342  for (auto iface : qAsConst(m_tablets)) {
343  sendTabletAdded(resource, iface);
344  }
345 
346  for (auto *tool : qAsConst(m_tools)) {
347  sendToolAdded(resource, tool);
348  }
349  }
350 
351  void sendToolAdded(Resource *resource, TabletToolInterface *tool)
352  {
353  wl_resource *toolResource = tool->d->add(resource->client(), resource->version())->handle;
354  send_tool_added(resource->handle, toolResource);
355 
356  tool->d->send_type(toolResource, tool->d->m_type);
357  tool->d->send_hardware_serial(toolResource, tool->d->m_hardwareSerialHigh,
358  tool->d->m_hardwareSerialLow);
359  tool->d->send_hardware_id_wacom(toolResource, tool->d->m_hardwareIdHigh,
360  tool->d->m_hardwareIdLow);
361  for (uint32_t cap : qAsConst(tool->d->m_capabilities)) {
362  tool->d->send_capability(toolResource, cap);
363  }
364  tool->d->send_done(toolResource);
365  }
366  void sendTabletAdded(Resource *resource, TabletInterface *tablet)
367  {
368  wl_resource *tabletResource = tablet->d->add(resource->client(), resource->version())->handle;
369  send_tablet_added(resource->handle, tabletResource);
370 
371  tablet->d->send_name(tabletResource, tablet->d->m_name);
372  if (tablet->d->m_vendorId && tablet->d->m_productId) {
373  tablet->d->send_id(tabletResource, tablet->d->m_vendorId, tablet->d->m_productId);
374  }
375  for (const QString &path : qAsConst(tablet->d->m_paths)) {
376  tablet->d->send_path(tabletResource, path);
377  }
378  tablet->d->send_done(tabletResource);
379  }
380 
381  TabletSeatInterface *const q;
384  Display *const m_display;
385 };
386 
387 TabletSeatInterface::TabletSeatInterface(Display *display, QObject *parent)
388  : QObject(parent)
389  , d(new Private(display, this))
390 {
391 }
392 
393 TabletSeatInterface::~TabletSeatInterface() = default;
394 
395 TabletToolInterface *TabletSeatInterface::addTool(TabletToolInterface::Type type,
396  quint64 hardwareSerial,
397  quint64 hardwareId,
398  const QVector<TabletToolInterface::Capability> &capabilities)
399 {
400  constexpr auto MAX_UINT_32 = std::numeric_limits<quint32>::max();
401  auto tool = new TabletToolInterface(d->m_display,
402  type, hardwareSerial >> 32, hardwareSerial & MAX_UINT_32,
403  hardwareId >> 32, hardwareId & MAX_UINT_32, capabilities, this);
404  for (QtWaylandServer::zwp_tablet_seat_v2::Resource *resource : d->resourceMap()) {
405  d->sendToolAdded(resource, tool);
406  }
407 
408  d->m_tools.append(tool);
409  QObject::connect(tool, &QObject::destroyed, this, [this](QObject *object) {
410  auto tti = static_cast<TabletToolInterface *>(object);
411  tti->d->send_removed();
412  d->m_tools.removeAll(tti);
413  });
414  return tool;
415 }
416 
417 TabletInterface *TabletSeatInterface::addTablet(uint32_t vendorId, uint32_t productId,
418  const QString &sysname,
419  const QString &name,
420  const QStringList &paths)
421 {
422  auto iface = new TabletInterface(vendorId, productId, name, paths, this);
423 
424  for (QtWaylandServer::zwp_tablet_seat_v2::Resource *r : d->resourceMap()) {
425  d->sendTabletAdded(r, iface);
426  }
427 
428  d->m_tablets[sysname] = iface;
429  return iface;
430 }
431 
432 void TabletSeatInterface::removeTablet(const QString &sysname)
433 {
434  auto tablet = d->m_tablets.take(sysname);
435  if (tablet) {
436  tablet->sendRemoved();
437  }
438 }
439 
440 TabletToolInterface *TabletSeatInterface::toolByHardwareId(quint64 hardwareId) const
441 {
442  for (TabletToolInterface *tool : d->m_tools) {
443  if (tool->d->hardwareId() == hardwareId)
444  return tool;
445  }
446  return nullptr;
447 }
448 
449 TabletToolInterface *TabletSeatInterface::toolByHardwareSerial(quint64 hardwareSerial) const
450 {
451  for (TabletToolInterface *tool : d->m_tools) {
452  if (tool->d->hardwareSerial() == hardwareSerial)
453  return tool;
454  }
455  return nullptr;
456 }
457 
458 TabletInterface *TabletSeatInterface::tabletByName(const QString &name) const
459 {
460  return d->m_tablets.value(name);
461 }
462 
463 class TabletManagerInterface::Private : public QtWaylandServer::zwp_tablet_manager_v2
464 {
465 public:
466  Private(Display *display, TabletManagerInterface *q)
467  : zwp_tablet_manager_v2(*display, s_version)
468  , q(q)
469  , m_display(display)
470  {
471  }
472 
473  void zwp_tablet_manager_v2_get_tablet_seat(Resource *resource, uint32_t tablet_seat,
474  struct ::wl_resource *seat_resource) override {
475  SeatInterface* seat = SeatInterface::get(seat_resource);
476  TabletSeatInterface *tsi = get(seat);
477  tsi->d->add(resource->client(), tablet_seat, s_version);
478  }
479 
481  {
482  TabletSeatInterface *&tabletSeat = m_seats[seat];
483  if (!tabletSeat) {
484  tabletSeat = new TabletSeatInterface(m_display, q);
485  }
486  return tabletSeat;
487  }
488 
489  TabletManagerInterface *const q;
490  Display *const m_display;
492 };
493 
494 TabletManagerInterface::TabletManagerInterface(Display *display, QObject *parent)
495  : QObject(parent)
496  , d(new Private(display, this))
497 {
498 }
499 
500 TabletSeatInterface *TabletManagerInterface::seat(SeatInterface *seat) const
501 {
502  return d->get(seat);
503 }
504 
505 TabletManagerInterface::~TabletManagerInterface() = default;
T * get() const const
This is an implementation of wayland-protocols/unstable/tablet/tablet-unstable-v2.xml.
qreal x() const const
qreal y() const const
Represents a Seat on the Wayland Display.
static SurfaceInterface * get(wl_resource *native)
Resource representing a wl_surface.
Class holding the Wayland server display loop.
Definition: display.h:89
Represents a bound Resource.
Definition: resource.h:32
Convenient Class which represents a wl_client.
void update(Part *part, const QByteArray &data, qint64 dataSize)
ClientConnection * client()
Definition: resource.cpp:78
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
void destroyed(QObject *obj)
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Aug 7 2020 22:48:20 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.