1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qwaylandtabletv2_p.h"
5#include "qwaylandinputdevice_p.h"
6#include "qwaylanddisplay_p.h"
7#include "qwaylandsurface_p.h"
8#include "qwaylandscreen_p.h"
9#include "qwaylandbuffer_p.h"
10#include "qwaylandcursorsurface_p.h"
11#include "qwaylandcursor_p.h"
12
13#include <QtGui/private/qguiapplication_p.h>
14#include <QtGui/private/qpointingdevice_p.h>
15#include <QtGui/qpa/qplatformtheme.h>
16#include <QtGui/qpa/qwindowsysteminterface_p.h>
17
18#include <wayland-cursor.h>
19
20QT_BEGIN_NAMESPACE
21
22namespace QtWaylandClient {
23
24using namespace Qt::StringLiterals;
25
26#if QT_CONFIG(cursor)
27int QWaylandTabletToolV2::idealCursorScale() const
28{
29 if (m_tabletSeat->seat()->mQDisplay->compositor()->version() < 3) {
30 return 1;
31 }
32
33 if (auto *s = mCursor.surface.data()) {
34 if (s->outputScale() > 0)
35 return s->outputScale();
36 }
37
38 return m_tabletSeat->seat()->mCursor.fallbackOutputScale;
39}
40
41void QWaylandTabletToolV2::updateCursorTheme()
42{
43 QString cursorThemeName;
44 QSize cursorSize;
45
46 if (const QPlatformTheme *platformTheme = QGuiApplicationPrivate::platformTheme()) {
47 cursorThemeName = platformTheme->themeHint(hint: QPlatformTheme::MouseCursorTheme).toString();
48 cursorSize = platformTheme->themeHint(hint: QPlatformTheme::MouseCursorSize).toSize();
49 }
50
51 if (cursorThemeName.isEmpty())
52 cursorThemeName = QStringLiteral("default");
53 if (cursorSize.isEmpty())
54 cursorSize = QSize(24, 24);
55
56 int scale = idealCursorScale();
57 int pixelSize = cursorSize.width() * scale;
58 auto *display = m_tabletSeat->seat()->mQDisplay;
59 mCursor.theme = display->loadCursorTheme(name: cursorThemeName, pixelSize);
60
61 if (!mCursor.theme)
62 return; // A warning has already been printed in loadCursorTheme
63
64 if (auto *arrow = mCursor.theme->cursor(shape: Qt::ArrowCursor)) {
65 int arrowPixelSize = qMax(a: arrow->images[0]->width,
66 b: arrow->images[0]->height); // Not all cursor themes are square
67 while (scale > 1 && arrowPixelSize / scale < cursorSize.width())
68 --scale;
69 } else {
70 qCWarning(lcQpaWayland) << "Cursor theme does not support the arrow cursor";
71 }
72 mCursor.themeBufferScale = scale;
73}
74
75void QWaylandTabletToolV2::updateCursor()
76{
77 if (mEnterSerial == 0)
78 return;
79
80 auto shape = m_tabletSeat->seat()->mCursor.shape;
81
82 if (shape == Qt::BlankCursor) {
83 if (mCursor.surface)
84 mCursor.surface->reset();
85 set_cursor(mEnterSerial, nullptr, 0, 0);
86 return;
87 }
88
89 if (shape == Qt::BitmapCursor) {
90 auto buffer = m_tabletSeat->seat()->mCursor.bitmapBuffer;
91 if (!buffer) {
92 qCWarning(lcQpaWayland) << "No buffer for bitmap cursor, can't set cursor";
93 return;
94 }
95 auto hotspot = m_tabletSeat->seat()->mCursor.hotspot;
96 int bufferScale = m_tabletSeat->seat()->mCursor.bitmapScale;
97 getOrCreateCursorSurface()->update(buffer: buffer->buffer(), hotspot, size: buffer->size(), bufferScale);
98 return;
99 }
100
101 if (mCursor.shape) {
102 if (mCursor.surface) {
103 mCursor.surface->reset();
104 }
105 mCursor.shape->setShape(serial: mEnterSerial, shape);
106 return;
107 }
108
109 if (!mCursor.theme || idealCursorScale() != mCursor.themeBufferScale)
110 updateCursorTheme();
111
112 if (!mCursor.theme)
113 return;
114
115 // Set from shape using theme
116 QElapsedTimer &timer = m_tabletSeat->seat()->mCursor.animationTimer;
117 const uint time = timer.isValid() ? timer.elapsed() : 0;
118
119 if (struct ::wl_cursor *waylandCursor = mCursor.theme->cursor(shape)) {
120 uint duration = 0;
121 int frame = wl_cursor_frame_and_duration(cursor: waylandCursor, time, duration: &duration);
122 ::wl_cursor_image *image = waylandCursor->images[frame];
123
124 struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
125 if (!buffer) {
126 qCWarning(lcQpaWayland) << "Could not find buffer for cursor" << shape;
127 return;
128 }
129 int bufferScale = mCursor.themeBufferScale;
130 QPoint hotspot = QPoint(image->hotspot_x, image->hotspot_y) / bufferScale;
131 QSize size = QSize(image->width, image->height) / bufferScale;
132 bool animated = duration > 0;
133 if (animated) {
134 mCursor.gotFrameCallback = false;
135 mCursor.gotTimerCallback = false;
136 mCursor.frameTimer.start(msec: duration);
137 }
138 getOrCreateCursorSurface()->update(buffer, hotspot, size, bufferScale, animated);
139 return;
140 }
141
142 qCWarning(lcQpaWayland) << "Unable to change to cursor" << shape;
143}
144
145CursorSurface<QWaylandTabletToolV2> *QWaylandTabletToolV2::getOrCreateCursorSurface()
146{
147 if (!mCursor.surface)
148 mCursor.surface.reset(
149 other: new CursorSurface<QWaylandTabletToolV2>(this, m_tabletSeat->seat()->mQDisplay));
150 return mCursor.surface.get();
151}
152
153void QWaylandTabletToolV2::cursorTimerCallback()
154{
155 mCursor.gotTimerCallback = true;
156 if (mCursor.gotFrameCallback)
157 updateCursor();
158}
159
160void QWaylandTabletToolV2::cursorFrameCallback()
161{
162 mCursor.gotFrameCallback = true;
163 if (mCursor.gotTimerCallback)
164 updateCursor();
165}
166
167#endif // QT_CONFIG(cursor)
168
169QWaylandTabletManagerV2::QWaylandTabletManagerV2(QWaylandDisplay *display, uint id, uint version)
170 : zwp_tablet_manager_v2(display->wl_registry(), id, qMin(version, uint(1)))
171{
172 qCDebug(lcQpaInputDevices, "new tablet manager: ID %d version %d", id, version);
173}
174
175QWaylandTabletManagerV2::~QWaylandTabletManagerV2()
176{
177 destroy();
178}
179
180QWaylandTabletSeatV2::QWaylandTabletSeatV2(QWaylandTabletManagerV2 *manager, QWaylandInputDevice *seat)
181 : QtWayland::zwp_tablet_seat_v2(manager->get_tablet_seat(seat->wl_seat()))
182 , m_seat(seat)
183{
184 qCDebug(lcQpaInputDevices) << "new tablet seat" << seat->seatname() << "id" << seat->id();
185}
186
187QWaylandTabletSeatV2::~QWaylandTabletSeatV2()
188{
189 qDeleteAll(c: m_tablets);
190 qDeleteAll(c: m_tools);
191 qDeleteAll(c: m_deadTools);
192 qDeleteAll(c: m_pads);
193 destroy();
194}
195
196void QWaylandTabletSeatV2::zwp_tablet_seat_v2_tablet_added(zwp_tablet_v2 *id)
197{
198 auto *tablet = new QWaylandTabletV2(id, m_seat->seatname());
199 qCDebug(lcQpaInputDevices) << "seat" << this << id << "has tablet" << tablet;
200 tablet->setParent(this);
201 m_tablets.push_back(tablet);
202 connect(tablet, &QWaylandTabletV2::destroyed, this, [this, tablet] { m_tablets.removeOne(tablet); });
203}
204
205void QWaylandTabletSeatV2::zwp_tablet_seat_v2_tool_added(zwp_tablet_tool_v2 *id)
206{
207 qDeleteAll(c: m_deadTools);
208 auto *tool = new QWaylandTabletToolV2(this, id);
209 if (m_tablets.size() == 1) {
210 tool->setParent(m_tablets.first());
211 QPointingDevicePrivate *d = QPointingDevicePrivate::get(tool);
212 d->name = m_tablets.first()->name() + u" stylus";
213 } else {
214 qCDebug(lcQpaInputDevices) << "seat" << this << "has tool" << tool << "for one of these tablets:" << m_tablets;
215 // TODO identify which tablet if there are several; then tool->setParent(tablet)
216 }
217 m_tools.push_back(tool);
218 connect(tool, &QWaylandTabletToolV2::destroyed, this, [this, tool] {
219 m_tools.removeOne(tool);
220 m_deadTools.removeOne(tool);
221 });
222}
223
224void QWaylandTabletSeatV2::zwp_tablet_seat_v2_pad_added(zwp_tablet_pad_v2 *id)
225{
226 auto *pad = new QWaylandTabletPadV2(id);
227 if (m_tablets.size() == 1) {
228 pad->setParent(m_tablets.first());
229 QPointingDevicePrivate *d = QPointingDevicePrivate::get(pad);
230 d->name = m_tablets.first()->name() + u" touchpad";
231 } else {
232 qCDebug(lcQpaInputDevices) << "seat" << this << "has touchpad" << pad << "for one of these tablets:" << m_tablets;
233 // TODO identify which tablet if there are several
234 }
235 m_pads.push_back(pad);
236 connect(pad, &QWaylandTabletPadV2::destroyed, this, [this, pad] { m_pads.removeOne(pad); });
237}
238
239QWaylandTabletV2::QWaylandTabletV2(::zwp_tablet_v2 *tablet, const QString &seatName)
240 : QPointingDevice(u"unknown"_s, -1, DeviceType::Stylus, PointerType::Pen,
241 Capability::Position | Capability::Hover,
242 1, 1, seatName)
243 , QtWayland::zwp_tablet_v2(tablet)
244{
245 qCDebug(lcQpaInputDevices) << "new tablet on seat" << seatName;
246 QPointingDevicePrivate *d = QPointingDevicePrivate::get(q: this);
247 d->seatName = seatName;
248}
249
250QWaylandTabletV2::~QWaylandTabletV2()
251{
252 destroy();
253}
254
255void QWaylandTabletV2::zwp_tablet_v2_name(const QString &name)
256{
257 QPointingDevicePrivate *d = QPointingDevicePrivate::get(q: this);
258 d->name = name;
259}
260
261void QWaylandTabletV2::zwp_tablet_v2_id(uint32_t vid, uint32_t pid)
262{
263 QPointingDevicePrivate *d = QPointingDevicePrivate::get(q: this);
264 d->systemId = (quint64(vid) << 32) | pid;
265 qCDebug(lcQpaInputDevices) << "vid" << vid << "pid" << pid << "stored as systemId in" << this;
266}
267
268void QWaylandTabletV2::zwp_tablet_v2_path(const QString &path)
269{
270 QPointingDevicePrivate *d = QPointingDevicePrivate::get(q: this);
271 d->busId = path;
272}
273
274void QWaylandTabletV2::zwp_tablet_v2_done()
275{
276 QWindowSystemInterface::registerInputDevice(device: this);
277}
278
279void QWaylandTabletSeatV2::updateCursor()
280{
281 for (auto tool : m_tools)
282 tool->updateCursor();
283}
284
285void QWaylandTabletSeatV2::toolRemoved(QWaylandTabletToolV2 *tool)
286{
287 m_tools.removeOne(t: tool);
288 m_deadTools.append(t: tool);
289}
290
291void QWaylandTabletV2::zwp_tablet_v2_removed()
292{
293 deleteLater();
294}
295
296QWaylandTabletToolV2::QWaylandTabletToolV2(QWaylandTabletSeatV2 *tabletSeat, ::zwp_tablet_tool_v2 *tool)
297 : QPointingDevice(u"tool"_s, -1, DeviceType::Stylus, PointerType::Pen,
298 Capability::Position | Capability::Hover,
299 1, 1, tabletSeat->seat()->seatname())
300 , QtWayland::zwp_tablet_tool_v2(tool)
301 , m_tabletSeat(tabletSeat)
302{
303 // TODO get the number of buttons somehow?
304
305#if QT_CONFIG(cursor)
306 if (auto cursorShapeManager = m_tabletSeat->seat()->mQDisplay->cursorShapeManager()) {
307 mCursor.shape.reset(
308 other: new QWaylandCursorShape(cursorShapeManager->get_tablet_tool_v2(object())));
309 }
310
311 mCursor.frameTimer.setSingleShot(true);
312 mCursor.frameTimer.callOnTimeout(args: this, args: [&]() { cursorTimerCallback(); });
313#endif
314}
315
316QWaylandTabletToolV2::~QWaylandTabletToolV2()
317{
318 destroy();
319}
320
321void QWaylandTabletToolV2::zwp_tablet_tool_v2_type(uint32_t tool_type)
322{
323 QPointingDevicePrivate *d = QPointingDevicePrivate::get(this);
324
325 switch (tool_type) {
326 case type_airbrush:
327 case type_brush:
328 case type_pencil:
329 case type_pen:
330 d->pointerType = QPointingDevice::PointerType::Pen;
331 break;
332 case type_eraser:
333 d->pointerType = QPointingDevice::PointerType::Eraser;
334 break;
335 case type_mouse:
336 case type_lens:
337 d->pointerType = QPointingDevice::PointerType::Cursor;
338 break;
339 case type_finger:
340 d->pointerType = QPointingDevice::PointerType::Unknown;
341 break;
342 }
343
344 switch (tool_type) {
345 case type::type_airbrush:
346 d->deviceType = QInputDevice::DeviceType::Airbrush;
347 d->capabilities.setFlag(flag: QInputDevice::Capability::TangentialPressure);
348 break;
349 case type::type_brush:
350 case type::type_pencil:
351 case type::type_pen:
352 case type::type_eraser:
353 d->deviceType = QInputDevice::DeviceType::Stylus;
354 break;
355 case type::type_lens:
356 d->deviceType = QInputDevice::DeviceType::Puck;
357 break;
358 case type::type_mouse:
359 case type::type_finger:
360 d->deviceType = QInputDevice::DeviceType::Unknown;
361 break;
362 }
363}
364
365void QWaylandTabletToolV2::zwp_tablet_tool_v2_hardware_serial(uint32_t hardware_serial_hi, uint32_t hardware_serial_lo)
366{
367 QPointingDevicePrivate *d = QPointingDevicePrivate::get(this);
368 d->uniqueId = QPointingDeviceUniqueId::fromNumericId(id: (quint64(hardware_serial_hi) << 32) + hardware_serial_lo);
369}
370
371void QWaylandTabletToolV2::zwp_tablet_tool_v2_hardware_id_wacom(uint32_t hardware_id_hi, uint32_t hardware_id_lo)
372{
373 QPointingDevicePrivate *d = QPointingDevicePrivate::get(this);
374 d->systemId = (quint64(hardware_id_hi) << 32) + hardware_id_lo;
375}
376
377void QWaylandTabletToolV2::zwp_tablet_tool_v2_capability(uint32_t capability)
378{
379 QPointingDevicePrivate *d = QPointingDevicePrivate::get(this);
380 switch (capability) {
381 case capability_tilt:
382 // no distinction... we have to assume it has both axes
383 d->capabilities.setFlag(flag: QInputDevice::Capability::XTilt);
384 d->capabilities.setFlag(flag: QInputDevice::Capability::YTilt);
385 break;
386 case capability_pressure:
387 d->capabilities.setFlag(flag: QInputDevice::Capability::Pressure);
388 break;
389 case capability_distance:
390 d->capabilities.setFlag(flag: QInputDevice::Capability::ZPosition);
391 break;
392 case capability_rotation:
393 d->capabilities.setFlag(flag: QInputDevice::Capability::Rotation);
394 break;
395 case capability_slider:
396 // nothing to represent that so far
397 break;
398 case capability_wheel:
399 d->capabilities.setFlag(flag: QInputDevice::Capability::Scroll);
400 d->capabilities.setFlag(flag: QInputDevice::Capability::PixelScroll);
401 break;
402 }
403 qCDebug(lcQpaInputDevices) << capability << "->" << this;
404}
405
406void QWaylandTabletToolV2::zwp_tablet_tool_v2_done()
407{
408 QWindowSystemInterface::registerInputDevice(this);
409}
410
411void QWaylandTabletToolV2::zwp_tablet_tool_v2_removed()
412{
413 m_tabletSeat->toolRemoved(tool: this);
414}
415
416void QWaylandTabletToolV2::zwp_tablet_tool_v2_proximity_in(uint32_t serial, zwp_tablet_v2 *tablet, wl_surface *surface)
417{
418 Q_UNUSED(tablet);
419
420 m_tabletSeat->seat()->mSerial = serial;
421 mEnterSerial = serial;
422
423 if (Q_UNLIKELY(!surface)) {
424 qCDebug(lcQpaWayland) << "Ignoring zwp_tablet_tool_v2_proximity_v2 with no surface";
425 return;
426 }
427 m_pending.enteredSurface = true;
428 m_pending.proximitySurface = QWaylandSurface::fromWlSurface(surface);
429
430#if QT_CONFIG(cursor)
431 // Depends on mEnterSerial being updated
432 updateCursor();
433#endif
434}
435
436void QWaylandTabletToolV2::zwp_tablet_tool_v2_proximity_out()
437{
438 m_pending.enteredSurface = false;
439 m_pending.proximitySurface = nullptr;
440}
441
442void QWaylandTabletToolV2::zwp_tablet_tool_v2_down(uint32_t serial)
443{
444 m_pending.down = true;
445
446 m_tabletSeat->seat()->mSerial = serial;
447
448 if (m_pending.proximitySurface) {
449 if (QWaylandWindow *window = m_pending.proximitySurface->waylandWindow()) {
450 QWaylandInputDevice *seat = m_tabletSeat->seat();
451 seat->display()->setLastInputDevice(device: seat, serial, window);
452 }
453 }
454}
455
456void QWaylandTabletToolV2::zwp_tablet_tool_v2_up()
457{
458 m_pending.down = false;
459}
460
461void QWaylandTabletToolV2::zwp_tablet_tool_v2_motion(wl_fixed_t x, wl_fixed_t y)
462{
463 m_pending.surfacePosition = QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y));
464}
465
466void QWaylandTabletToolV2::zwp_tablet_tool_v2_pressure(uint32_t pressure)
467{
468 const int maxPressure = 65535;
469 m_pending.pressure = qreal(pressure)/maxPressure;
470}
471
472void QWaylandTabletToolV2::zwp_tablet_tool_v2_distance(uint32_t distance)
473{
474 m_pending.distance = distance;
475}
476
477void QWaylandTabletToolV2::zwp_tablet_tool_v2_tilt(wl_fixed_t tilt_x, wl_fixed_t tilt_y)
478{
479 m_pending.xTilt = wl_fixed_to_double(tilt_x);
480 m_pending.yTilt = wl_fixed_to_double(tilt_y);
481}
482
483void QWaylandTabletToolV2::zwp_tablet_tool_v2_rotation(wl_fixed_t degrees)
484{
485 m_pending.rotation = wl_fixed_to_double(degrees);
486}
487
488void QWaylandTabletToolV2::zwp_tablet_tool_v2_slider(int32_t position)
489{
490 m_pending.slider = qreal(position) / 65535;
491}
492
493static Qt::MouseButton mouseButtonFromTablet(uint button)
494{
495 switch (button) {
496 case 0x110: return Qt::MouseButton::LeftButton; // BTN_LEFT
497 case 0x14b: return Qt::MouseButton::MiddleButton; // BTN_STYLUS
498 case 0x14c: return Qt::MouseButton::RightButton; // BTN_STYLUS2
499 default:
500 return Qt::NoButton;
501 }
502}
503
504void QWaylandTabletToolV2::zwp_tablet_tool_v2_button(uint32_t serial, uint32_t button, uint32_t state)
505{
506 m_tabletSeat->seat()->mSerial = serial;
507
508 QPointingDevicePrivate *d = QPointingDevicePrivate::get(this);
509 Qt::MouseButton mouseButton = mouseButtonFromTablet(button);
510 if (state == button_state_pressed)
511 m_pending.buttons |= mouseButton;
512 else
513 m_pending.buttons &= ~mouseButton;
514 // ideally we'd get button count when the tool is discovered; seems to be a shortcoming in tablet-unstable-v2
515 // but if we get events from buttons we didn't know existed, increase it
516 if (mouseButton == Qt::RightButton)
517 d->buttonCount = qMax(a: d->buttonCount, b: 2);
518 else if (mouseButton == Qt::MiddleButton)
519 d->buttonCount = qMax(a: d->buttonCount, b: 3);
520}
521
522void QWaylandTabletToolV2::zwp_tablet_tool_v2_frame(uint32_t time)
523{
524 if (!m_pending.proximitySurface) {
525 if (m_applied.enteredSurface) {
526 // leaving proximity
527 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(nullptr, this, false);
528 m_pending = State(); // Don't leave pressure etc. lying around when we enter the next surface
529 m_applied = State();
530 } else {
531 qCWarning(lcQpaWayland) << "Can't send tablet event with no proximity surface, ignoring";
532 }
533 return;
534 }
535
536 QWaylandWindow *waylandWindow = QWaylandWindow::fromWlSurface(surface: m_pending.proximitySurface->object());
537 QWindow *window = waylandWindow->window();
538
539 if (!m_applied.proximitySurface) {
540 // TODO get position etc. as below
541 QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, this, true);
542 m_applied.proximitySurface = m_pending.proximitySurface;
543 }
544
545 if (!(m_pending == m_applied)) {
546 ulong timestamp = time;
547 const QPointF localPosition = waylandWindow->mapFromWlSurface(surfacePosition: m_pending.surfacePosition);
548
549 const QPointF globalPosition = waylandWindow->mapToGlobalF(localPosition);
550
551 Qt::MouseButtons buttons = m_pending.down ? Qt::MouseButton::LeftButton : Qt::MouseButton::NoButton;
552 buttons |= m_pending.buttons;
553 qreal pressure = m_pending.pressure;
554 qreal xTilt = m_pending.xTilt;
555 qreal yTilt = m_pending.yTilt;
556 qreal tangentialPressure = m_pending.slider;
557 qreal rotation = m_pending.rotation;
558 int z = int(m_pending.distance);
559
560 // do not use localPosition here since that is in Qt window coordinates
561 // but we need surface coordinates to include the decoration
562 bool decorationHandledEvent = waylandWindow->handleTabletEventDecoration(
563 inputDevice: m_tabletSeat->seat(), local: m_pending.surfacePosition,
564 global: window->mapToGlobal(pos: m_pending.surfacePosition), buttons,
565 modifiers: m_tabletSeat->seat()->modifiers());
566
567 if (!decorationHandledEvent) {
568 QWindowSystemInterface::handleTabletEvent(window, timestamp, this, localPosition, globalPosition,
569 buttons, pressure,
570 xTilt, yTilt, tangentialPressure, rotation, z,
571 m_tabletSeat->seat()->modifiers());
572 }
573 }
574
575 m_applied = m_pending;
576}
577
578// TODO: delete when upgrading to c++20
579bool QWaylandTabletToolV2::State::operator==(const QWaylandTabletToolV2::State &o) const {
580 return
581 down == o.down &&
582 proximitySurface.data() == o.proximitySurface.data() &&
583 enteredSurface == o.enteredSurface &&
584 surfacePosition == o.surfacePosition &&
585 distance == o.distance &&
586 pressure == o.pressure &&
587 rotation == o.rotation &&
588 xTilt == o.xTilt &&
589 yTilt == o.yTilt &&
590 slider == o.slider &&
591 buttons == o.buttons;
592}
593
594QWaylandTabletPadV2::QWaylandTabletPadV2(::zwp_tablet_pad_v2 *pad)
595 : QPointingDevice(u"tablet touchpad"_s, -1, DeviceType::TouchPad, PointerType::Finger,
596 Capability::Position,
597 1, 1)
598 , QtWayland::zwp_tablet_pad_v2(pad)
599{
600}
601
602QWaylandTabletPadV2::~QWaylandTabletPadV2()
603{
604 destroy();
605}
606
607void QWaylandTabletPadV2::zwp_tablet_pad_v2_path(const QString &path)
608{
609 QPointingDevicePrivate *d = QPointingDevicePrivate::get(q: this);
610 d->busId = path;
611}
612
613void QWaylandTabletPadV2::zwp_tablet_pad_v2_buttons(uint32_t buttons)
614{
615 QPointingDevicePrivate *d = QPointingDevicePrivate::get(q: this);
616 d->buttonCount = buttons;
617}
618
619void QWaylandTabletPadV2::zwp_tablet_pad_v2_group(zwp_tablet_pad_group_v2 *pad_group)
620{
621 // As of writing Qt does not handle tablet pads group and the controls on it
622 // This proxy is server created so it is just deleted here to not leak it
623 zwp_tablet_pad_group_v2_destroy(pad_group);
624}
625
626void QWaylandTabletPadV2::zwp_tablet_pad_v2_done()
627{
628 QWindowSystemInterface::registerInputDevice(device: this);
629}
630
631void QWaylandTabletPadV2::zwp_tablet_pad_v2_removed()
632{
633 delete this;
634}
635
636} // namespace QtWaylandClient
637
638QT_END_NAMESPACE
639
640#include "moc_qwaylandtabletv2_p.cpp"
641

source code of qtbase/src/plugins/platforms/wayland/qwaylandtabletv2.cpp