Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qwaylandtabletv2.cpp
Go to the documentation of this file.
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
6#include "qwaylanddisplay_p.h"
7#include "qwaylandsurface_p.h"
8#include <QtGui/private/qpointingdevice_p.h>
9
11
12namespace QtWaylandClient {
13
14using namespace Qt::StringLiterals;
15
16Q_LOGGING_CATEGORY(lcQpaInputDevices, "qt.qpa.input.devices")
17Q_DECLARE_LOGGING_CATEGORY(lcQpaWaylandInput)
18
20 : zwp_tablet_manager_v2(display->wl_registry(), id, qMin(version, uint(1)))
21{
22 // Create tabletSeats for all seats.
23 // This only works if we get the manager after all seats
24 const auto seats = display->inputDevices();
25 for (auto *seat : seats)
26 createTabletSeat(seat);
27}
28
30{
31 return new QWaylandTabletSeatV2(this, seat);
32}
33
35 : QtWayland::zwp_tablet_seat_v2(manager->get_tablet_seat(seat->wl_seat()))
36 , m_seat(seat)
37{
38}
39
41{
42 for (auto *tablet : m_tablets)
43 tablet->destroy();
44 for (auto *tool : m_tools)
45 tool->destroy();
46 for (auto *pad : m_pads)
47 pad->destroy();
48 qDeleteAll(m_tablets);
49 qDeleteAll(m_tools);
50 qDeleteAll(m_pads);
51 destroy();
52}
53
55{
56 auto *tablet = new QWaylandTabletV2(id, m_seat->seatName());
57 qCDebug(lcQpaInputDevices) << "seat" << this << id << "has tablet" << tablet;
58 tablet->setParent(this);
59 m_tablets.push_back(tablet);
60 connect(tablet, &QWaylandTabletV2::destroyed, this, [this, tablet] { m_tablets.removeOne(tablet); });
61}
62
64{
65 auto *tool = new QWaylandTabletToolV2(this, id);
66 if (m_tablets.size() == 1) {
67 tool->setParent(m_tablets.first());
69 d->name = m_tablets.first()->name() + u" stylus";
70 } else {
71 qCDebug(lcQpaInputDevices) << "seat" << this << "has tool" << tool << "for one of these tablets:" << m_tablets;
72 // TODO identify which tablet if there are several
73 }
74 m_tools.push_back(tool);
75 connect(tool, &QWaylandTabletToolV2::destroyed, this, [this, tool] { m_tools.removeOne(tool); });
76}
77
79{
80 auto *pad = new QWaylandTabletPadV2(id);
81 if (m_tablets.size() == 1) {
82 pad->setParent(m_tablets.first());
84 d->name = m_tablets.first()->name() + u" touchpad";
85 } else {
86 qCDebug(lcQpaInputDevices) << "seat" << this << "has touchpad" << pad << "for one of these tablets:" << m_tablets;
87 // TODO identify which tablet if there are several
88 }
89 m_pads.push_back(pad);
90 connect(pad, &QWaylandTabletPadV2::destroyed, this, [this, pad] { m_pads.removeOne(pad); });
91}
92
93QWaylandTabletV2::QWaylandTabletV2(::zwp_tablet_v2 *tablet, const QString &seatName)
94 : QPointingDevice(u"unknown"_s, -1, DeviceType::Stylus, PointerType::Pen,
95 Capability::Position | Capability::Hover,
96 1, 1)
97 , QtWayland::zwp_tablet_v2(tablet)
98{
100 d->seatName = seatName;
101}
102
104{
106 d->name = name;
107}
108
109void QWaylandTabletV2::zwp_tablet_v2_id(uint32_t vid, uint32_t pid)
110{
112 d->systemId = (quint64(vid) << 32) | pid;
113 qCDebug(lcQpaInputDevices) << "vid" << vid << "pid" << pid << "stored as systemId in" << this;
114}
115
117{
119 d->busId = path;
120}
121
123{
125}
126
128{
129 destroy();
130 delete this;
131}
132
134 : QPointingDevice(u"tool"_s, -1, DeviceType::Stylus, PointerType::Pen,
135 Capability::Position | Capability::Hover,
136 1, 1)
137 , QtWayland::zwp_tablet_tool_v2(tool)
138 , m_tabletSeat(tabletSeat)
139{
140 // TODO get the number of buttons somehow?
141}
142
144{
146
147 switch (tool_type) {
148 case type_airbrush:
149 case type_brush:
150 case type_pencil:
151 case type_pen:
153 break;
154 case type_eraser:
156 break;
157 case type_mouse:
158 case type_lens:
160 break;
161 case type_finger:
163 break;
164 }
165
166 switch (tool_type) {
167 case type::type_airbrush:
169 d->capabilities.setFlag(QInputDevice::Capability::TangentialPressure);
170 break;
171 case type::type_brush:
172 case type::type_pencil:
173 case type::type_pen:
174 case type::type_eraser:
176 break;
177 case type::type_lens:
178 d->deviceType = QInputDevice::DeviceType::Puck;
179 break;
180 case type::type_mouse:
181 case type::type_finger:
183 break;
184 }
185}
186
187void QWaylandTabletToolV2::zwp_tablet_tool_v2_hardware_serial(uint32_t hardware_serial_hi, uint32_t hardware_serial_lo)
188{
190 d->uniqueId = QPointingDeviceUniqueId::fromNumericId((quint64(hardware_serial_hi) << 32) + hardware_serial_lo);
191}
192
193void QWaylandTabletToolV2::zwp_tablet_tool_v2_hardware_id_wacom(uint32_t hardware_id_hi, uint32_t hardware_id_lo)
194{
196 d->systemId = (quint64(hardware_id_hi) << 32) + hardware_id_lo;
197}
198
200{
202 switch (capability) {
203 case capability_tilt:
204 // no distinction... we have to assume it has both axes
205 d->capabilities.setFlag(QInputDevice::Capability::XTilt);
206 d->capabilities.setFlag(QInputDevice::Capability::YTilt);
207 break;
208 case capability_pressure:
209 d->capabilities.setFlag(QInputDevice::Capability::Pressure);
210 break;
211 case capability_distance:
212 d->capabilities.setFlag(QInputDevice::Capability::ZPosition);
213 break;
214 case capability_rotation:
215 d->capabilities.setFlag(QInputDevice::Capability::Rotation);
216 break;
217 case capability_slider:
218 // nothing to represent that so far
219 break;
220 case capability_wheel:
221 d->capabilities.setFlag(QInputDevice::Capability::Scroll);
222 d->capabilities.setFlag(QInputDevice::Capability::PixelScroll);
223 break;
224 }
225 qCDebug(lcQpaInputDevices) << capability << "->" << this;
226}
227
229{
231}
232
234{
235 destroy();
236 delete this;
237}
238
239void QWaylandTabletToolV2::zwp_tablet_tool_v2_proximity_in(uint32_t serial, zwp_tablet_v2 *tablet, wl_surface *surface)
240{
241 Q_UNUSED(tablet);
242 Q_UNUSED(serial);
243 if (Q_UNLIKELY(!surface)) {
244 qCDebug(lcQpaWayland) << "Ignoring zwp_tablet_tool_v2_proximity_v2 with no surface";
245 return;
246 }
247 m_pending.enteredSurface = true;
248 m_pending.proximitySurface = QWaylandSurface::fromWlSurface(surface);
249}
250
252{
253 m_pending.enteredSurface = false;
254 m_pending.proximitySurface = nullptr;
255}
256
258{
259 m_pending.down = true;
260
261 if (m_pending.proximitySurface) {
262 if (QWaylandWindow *window = m_pending.proximitySurface->waylandWindow()) {
263 QWaylandInputDevice *seat = m_tabletSeat->seat();
264 seat->display()->setLastInputDevice(seat, serial, window);
265 }
266 }
267}
268
270{
271 m_pending.down = false;
272}
273
275{
276 m_pending.surfacePosition = QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y));
277}
278
280{
281 const int maxPressure = 65535;
282 m_pending.pressure = qreal(pressure)/maxPressure;
283}
284
286{
287 m_pending.distance = distance;
288}
289
290void QWaylandTabletToolV2::zwp_tablet_tool_v2_tilt(wl_fixed_t tilt_x, wl_fixed_t tilt_y)
291{
292 m_pending.xTilt = wl_fixed_to_double(tilt_x);
293 m_pending.yTilt = wl_fixed_to_double(tilt_y);
294}
295
297{
298 m_pending.rotation = wl_fixed_to_double(degrees);
299}
300
302{
303 m_pending.slider = qreal(position) / 65535;
304}
305
307{
308 switch (button) {
309 case 0x110: return Qt::MouseButton::LeftButton; // BTN_LEFT
310 case 0x14b: return Qt::MouseButton::MiddleButton; // BTN_STYLUS
311 case 0x14c: return Qt::MouseButton::RightButton; // BTN_STYLUS2
312 default:
313 return Qt::NoButton;
314 }
315}
316
317void QWaylandTabletToolV2::zwp_tablet_tool_v2_button(uint32_t serial, uint32_t button, uint32_t state)
318{
320 Q_UNUSED(serial);
322 if (state == button_state_pressed)
323 m_pending.buttons |= mouseButton;
324 else
325 m_pending.buttons &= ~mouseButton;
326 // ideally we'd get button count when the tool is discovered; seems to be a shortcoming in tablet-unstable-v2
327 // but if we get events from buttons we didn't know existed, increase it
328 if (mouseButton == Qt::RightButton)
329 d->buttonCount = qMax(d->buttonCount, 2);
330 else if (mouseButton == Qt::MiddleButton)
331 d->buttonCount = qMax(d->buttonCount, 3);
332}
333
335{
336 QWindow *window = nullptr;
337 QPointF localPosition;
338 QPointF globalPosition;
339 Qt::MouseButtons buttons = Qt::MouseButton::NoButton;
340 qreal pressure = 0;
341 int xTilt = 0;
342 int yTilt = 0;
343 qreal tangentialPressure = 0;
344 qreal rotation = 0;
345 int z = 0;
346 // TODO can we get keyboard modifiers here?
347
348 if (m_pending.proximitySurface) {
349 QWaylandWindow *waylandWindow = QWaylandWindow::fromWlSurface(m_pending.proximitySurface->object());
350 window = waylandWindow->window();
351 localPosition = waylandWindow->mapFromWlSurface(m_pending.surfacePosition);
352
353 const QPointF delta = localPosition - localPosition.toPoint();
354 globalPosition = window->mapToGlobal(localPosition.toPoint());
355 globalPosition += delta;
356
357 buttons = m_pending.down ? Qt::MouseButton::LeftButton : Qt::MouseButton::NoButton;
358 buttons |= m_pending.buttons;
359 pressure = m_pending.pressure;
360 xTilt = int(m_pending.xTilt);
361 yTilt = int(m_pending.yTilt);
362 tangentialPressure = m_pending.slider;
363 rotation = m_pending.rotation;
364 z = int(m_pending.distance);
365 if (m_applied.proximitySurface) {
366 QWindowSystemInterface::handleTabletEvent(window, time, this, localPosition, globalPosition,
367 buttons, pressure,
368 xTilt, yTilt, tangentialPressure, rotation, z);
369 } else {
371 localPosition, globalPosition, buttons,
372 xTilt, yTilt, tangentialPressure, rotation, z);
373 }
374 } else if (m_applied.enteredSurface) {
375 Q_ASSERT(m_applied.proximitySurface);
376 QWaylandWindow *waylandWindow = QWaylandWindow::fromWlSurface(m_applied.proximitySurface->object());
377 window = waylandWindow->window();
378 localPosition = waylandWindow->mapFromWlSurface(m_applied.surfacePosition);
379
380 const QPointF delta = localPosition - localPosition.toPoint();
381 globalPosition = window->mapToGlobal(localPosition.toPoint());
382 globalPosition += delta;
383
384 buttons = m_applied.down ? Qt::MouseButton::LeftButton : Qt::MouseButton::NoButton;
385 buttons |= m_applied.buttons;
386 pressure = m_applied.pressure;
387 xTilt = int(m_applied.xTilt);
388 yTilt = int(m_applied.yTilt);
389 tangentialPressure = m_applied.slider;
390 rotation = m_applied.rotation;
391 z = int(m_applied.distance);
393 localPosition, globalPosition, buttons,
394 xTilt, yTilt, tangentialPressure, rotation, z);
395 }
396
397 if (!m_pending.proximitySurface && m_applied.enteredSurface) {
398 m_pending = State(); // Don't leave pressure etc. lying around when we enter the next surface
399 }
400
401 m_applied = m_pending;
402}
403
404// TODO: delete when upgrading to c++20
405bool QWaylandTabletToolV2::State::operator==(const QWaylandTabletToolV2::State &o) const {
406 return
407 down == o.down &&
408 proximitySurface.data() == o.proximitySurface.data() &&
409 enteredSurface == o.enteredSurface &&
410 surfacePosition == o.surfacePosition &&
411 distance == o.distance &&
412 pressure == o.pressure &&
413 rotation == o.rotation &&
414 xTilt == o.xTilt &&
415 yTilt == o.yTilt &&
416 slider == o.slider &&
417 buttons == o.buttons;
418}
419
421 : QPointingDevice(u"tablet touchpad"_s, -1, DeviceType::TouchPad, PointerType::Finger,
422 Capability::Position,
423 1, 1)
424 , QtWayland::zwp_tablet_pad_v2(pad)
425{
426}
427
429{
431 d->busId = path;
432}
433
435{
437 d->buttonCount = buttons;
438}
439
441{
443}
444
446{
447 destroy();
448 delete this;
449}
450
451} // namespace QtWaylandClient
452
454
455#include "moc_qwaylandtabletv2_p.cpp"
DeviceType
This enum represents the type of device that generated a QPointerEvent.
Capability
Indicates what kind of information the input device or its driver can provide.
QString seatName
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
QWindow * window() const
Returns the window which belongs to the QPlatformWindow.
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition qpoint.h:394
static QPointingDevicePrivate * get(QPointingDevice *q)
static QPointingDeviceUniqueId fromNumericId(qint64 id)
Constructs a unique pointer ID from numeric ID id.
The QPointingDevice class describes a device from which mouse, touch or tablet events originate.
PointerType
This enum represents what is interacting with the pointing device.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static bool handleTabletEvent(QWindow *window, ulong timestamp, const QPointingDevice *device, const QPointF &local, const QPointF &global, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, int z, Qt::KeyboardModifiers modifiers=Qt::NoModifier)
static void registerInputDevice(const QInputDevice *device)
static bool handleTabletEnterLeaveProximityEvent(QWindow *window, ulong timestamp, const QPointingDevice *device, bool inProximity, const QPointF &local=QPointF(), const QPointF &global=QPointF(), Qt::MouseButtons buttons={}, int xTilt=0, int yTilt=0, qreal tangentialPressure=0, qreal rotation=0, int z=0, Qt::KeyboardModifiers modifiers=Qt::NoModifier)
\inmodule QtGui
Definition qwindow.h:63
void setLastInputDevice(QWaylandInputDevice *device, uint32_t serial, QWaylandWindow *window)
static QWaylandSurface * fromWlSurface(::wl_surface *surface)
QWaylandTabletSeatV2 * createTabletSeat(QWaylandInputDevice *seat)
void zwp_tablet_pad_v2_buttons(uint32_t buttons) override
void zwp_tablet_pad_v2_path(const QString &path) override
QWaylandTabletPadV2(::zwp_tablet_pad_v2 *pad)
QWaylandInputDevice * seat() const
void zwp_tablet_seat_v2_pad_added(struct ::zwp_tablet_pad_v2 *id) override
QWaylandTabletSeatV2(QWaylandTabletManagerV2 *manager, QWaylandInputDevice *seat)
void zwp_tablet_seat_v2_tool_added(struct ::zwp_tablet_tool_v2 *id) override
void zwp_tablet_seat_v2_tablet_added(struct ::zwp_tablet_v2 *id) override
void zwp_tablet_tool_v2_button(uint32_t serial, uint32_t button, uint32_t state) override
void zwp_tablet_tool_v2_motion(wl_fixed_t x, wl_fixed_t y) override
void zwp_tablet_tool_v2_tilt(wl_fixed_t tilt_x, wl_fixed_t tilt_y) override
QWaylandTabletToolV2(QWaylandTabletSeatV2 *tabletSeat, ::zwp_tablet_tool_v2 *tool)
void zwp_tablet_tool_v2_rotation(wl_fixed_t degrees) override
void zwp_tablet_tool_v2_distance(uint32_t distance) override
void zwp_tablet_tool_v2_hardware_serial(uint32_t hardware_serial_hi, uint32_t hardware_serial_lo) override
void zwp_tablet_tool_v2_down(uint32_t serial) override
void zwp_tablet_tool_v2_capability(uint32_t capability) override
void zwp_tablet_tool_v2_frame(uint32_t time) override
void zwp_tablet_tool_v2_pressure(uint32_t pressure) override
void zwp_tablet_tool_v2_type(uint32_t tool_type) override
void zwp_tablet_tool_v2_slider(int32_t position) override
void zwp_tablet_tool_v2_proximity_in(uint32_t serial, struct ::zwp_tablet_v2 *tablet, struct ::wl_surface *surface) override
void zwp_tablet_tool_v2_hardware_id_wacom(uint32_t hardware_id_hi, uint32_t hardware_id_lo) override
void zwp_tablet_v2_path(const QString &path) override
QWaylandTabletV2(::zwp_tablet_v2 *tablet, const QString &seatName)
void zwp_tablet_v2_id(uint32_t vid, uint32_t pid) override
void zwp_tablet_v2_name(const QString &name) override
QPointF mapFromWlSurface(const QPointF &surfacePosition) const
Converts from wl_surface coordinates to Qt window coordinates.
static QWaylandWindow * fromWlSurface(::wl_surface *surface)
QPushButton * button
[2]
qDeleteAll(list.begin(), list.end())
else opt state
[0]
struct wl_display * display
Definition linuxdmabuf.h:41
Combined button and popup list for selecting options.
static Qt::MouseButton mouseButtonFromTablet(uint button)
MouseButton
Definition qnamespace.h:55
@ LeftButton
Definition qnamespace.h:57
@ RightButton
Definition qnamespace.h:58
@ MiddleButton
Definition qnamespace.h:59
@ NoButton
Definition qnamespace.h:56
#define Q_UNLIKELY(x)
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLint GLint GLint GLint GLint x
[0]
GLsizei GLsizei GLfloat distance
GLuint name
GLint y
GLsizei const GLchar *const * path
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_UNUSED(x)
unsigned long long quint64
Definition qtypes.h:56
unsigned int uint
Definition qtypes.h:29
double qreal
Definition qtypes.h:92
aWidget window() -> setWindowTitle("New Window Title")
[2]
QNetworkAccessManager manager