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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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