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

source code of qtwayland/src/client/qwaylandtabletv2.cpp