summaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorJohan Klokkhammer Helsing <johan.helsing@qt.io>2019-12-17 12:08:54 +0100
committerJohan Klokkhammer Helsing <johan.helsing@qt.io>2020-01-08 15:33:50 +0100
commit222455cd643c128fa9730c9c527a7fdcadd0acfe (patch)
treec1a6c8f39cb9d1405ade2bc63d380a38ff4f36d3 /src/client
parent7542dc765002d0512ed56f23f9f5727c77ae7aff (diff)
downloadqtwayland-222455cd643c128fa9730c9c527a7fdcadd0acfe.tar.gz
Client: Add basic support for tablet-unstable-v2
[ChangeLog][QPA plugin] Added support for drawing tablets through the tablet-unstable-v2 protocol. Adds support for the basic one tablet, one tool, no pads scenario. Besides the auto tests, I tested with a Huion Kamvas Pro 16 with a simple pressure sensitive pen with two buttons. As far as I can tell, it works the same way as on xcb on Sway and Gnome Shell. Also tested on a Wacom PTZ-630 with a mouse, art pen, airbrush and a stylus. Mapped the distance event to QTabletEvent::Z and slider to QTabletEvent::tangentialPressure. For now we send QTabletEvents even when there's a mouse or finger on the tablet. Those should ideally be sent as QMouseEvents/QTouchEvents, but that's out of scope for this patch, but at least we will send synthesized mouse events if the tablet events are not accepted. Change-Id: I93291ffa5f00fa2bb8533eddd8d873b84a3386b8 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'src/client')
-rw-r--r--src/client/client.pro3
-rw-r--r--src/client/qwaylanddisplay.cpp3
-rw-r--r--src/client/qwaylanddisplay_p.h3
-rw-r--r--src/client/qwaylandinputdevice.cpp3
-rw-r--r--src/client/qwaylandinputdevice_p.h5
-rw-r--r--src/client/qwaylandintegration.cpp2
-rw-r--r--src/client/qwaylandtabletv2.cpp332
-rw-r--r--src/client/qwaylandtabletv2_p.h191
8 files changed, 542 insertions, 0 deletions
diff --git a/src/client/client.pro b/src/client/client.pro
index 1b514eee..793a4418 100644
--- a/src/client/client.pro
+++ b/src/client/client.pro
@@ -36,6 +36,7 @@ WAYLANDCLIENTSOURCES += \
../extensions/qt-key-unstable-v1.xml \
../extensions/qt-windowmanager.xml \
../3rdparty/protocol/wp-primary-selection-unstable-v1.xml \
+ ../3rdparty/protocol/tablet-unstable-v2.xml \
../3rdparty/protocol/text-input-unstable-v2.xml \
../3rdparty/protocol/xdg-output-unstable-v1.xml \
../3rdparty/protocol/wayland.xml
@@ -52,6 +53,7 @@ SOURCES += qwaylandintegration.cpp \
qwaylandextendedsurface.cpp \
qwaylandsubsurface.cpp \
qwaylandsurface.cpp \
+ qwaylandtabletv2.cpp \
qwaylandtouch.cpp \
qwaylandqtkey.cpp \
../shared/qwaylandmimehelper.cpp \
@@ -77,6 +79,7 @@ HEADERS += qwaylandintegration_p.h \
qwaylandextendedsurface_p.h \
qwaylandsubsurface_p.h \
qwaylandsurface_p.h \
+ qwaylandtabletv2_p.h \
qwaylandtouch_p.h \
qwaylandqtkey_p.h \
qwaylandabstractdecoration_p.h \
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index a8d19dc6..ffcc72ff 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -69,6 +69,7 @@
#include "qwaylandextendedsurface_p.h"
#include "qwaylandsubsurface_p.h"
#include "qwaylandtouch_p.h"
+#include "qwaylandtabletv2_p.h"
#include "qwaylandqtkey_p.h"
#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
@@ -330,6 +331,8 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
mTouchExtension.reset(new QWaylandTouchExtension(this, id));
} else if (interface == QStringLiteral("zqt_key_v1")) {
mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id));
+ } else if (interface == QStringLiteral("zwp_tablet_manager_v2")) {
+ mTabletManager.reset(new QWaylandTabletManagerV2(this, id, qMin(1, int(version))));
#if QT_CONFIG(wayland_client_primary_selection)
} else if (interface == QStringLiteral("zwp_primary_selection_device_manager_v1")) {
mPrimarySelectionManager.reset(new QWaylandPrimarySelectionDeviceManagerV1(this, id, 1));
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index cd845b44..e99ec198 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -97,6 +97,7 @@ class QWaylandDataDeviceManager;
#if QT_CONFIG(wayland_client_primary_selection)
class QWaylandPrimarySelectionDeviceManagerV1;
#endif
+class QWaylandTabletManagerV2;
class QWaylandTouchExtension;
class QWaylandQtKeyExtension;
class QWaylandWindow;
@@ -160,6 +161,7 @@ public:
QWaylandPrimarySelectionDeviceManagerV1 *primarySelectionManager() const { return mPrimarySelectionManager.data(); }
#endif
QtWayland::qt_surface_extension *windowExtension() const { return mWindowExtension.data(); }
+ QWaylandTabletManagerV2 *tabletManager() const { return mTabletManager.data(); }
QWaylandTouchExtension *touchExtension() const { return mTouchExtension.data(); }
QtWayland::zwp_text_input_manager_v2 *textInputManager() const { return mTextInputManager.data(); }
QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); }
@@ -247,6 +249,7 @@ private:
QScopedPointer<QWaylandTouchExtension> mTouchExtension;
QScopedPointer<QWaylandQtKeyExtension> mQtKeyExtension;
QScopedPointer<QWaylandWindowManagerIntegration> mWindowManagerIntegration;
+ QScopedPointer<QWaylandTabletManagerV2> mTabletManager;
#if QT_CONFIG(wayland_client_primary_selection)
QScopedPointer<QWaylandPrimarySelectionDeviceManagerV1> mPrimarySelectionManager;
#endif
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
index ce086ee4..e0f0c6c8 100644
--- a/src/client/qwaylandinputdevice.cpp
+++ b/src/client/qwaylandinputdevice.cpp
@@ -50,6 +50,7 @@
#if QT_CONFIG(wayland_client_primary_selection)
#include "qwaylandprimaryselectionv1_p.h"
#endif
+#include "qwaylandtabletv2_p.h"
#include "qwaylandtouch_p.h"
#include "qwaylandscreen_p.h"
#include "qwaylandcursor_p.h"
@@ -418,6 +419,8 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version,
if (mQDisplay->textInputManager())
mTextInput.reset(new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat())));
+ if (auto *tm = mQDisplay->tabletManager())
+ mTabletSeat.reset(new QWaylandTabletSeatV2(tm, this));
}
QWaylandInputDevice::~QWaylandInputDevice()
diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h
index 87f8559c..448d0fce 100644
--- a/src/client/qwaylandinputdevice_p.h
+++ b/src/client/qwaylandinputdevice_p.h
@@ -89,6 +89,7 @@ class QWaylandDisplay;
#if QT_CONFIG(wayland_client_primary_selection)
class QWaylandPrimarySelectionDeviceV1;
#endif
+class QWaylandTabletSeatV2;
class QWaylandTextInput;
#if QT_CONFIG(cursor)
class QWaylandCursorTheme;
@@ -127,6 +128,9 @@ public:
QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice() const;
#endif
+ void setTabletSeat(QWaylandTabletSeatV2 *tabletSeat);
+ QWaylandTabletSeatV2* tabletSeat() const;
+
void setTextInput(QWaylandTextInput *textInput);
QWaylandTextInput *textInput() const;
@@ -183,6 +187,7 @@ private:
Touch *mTouch = nullptr;
QScopedPointer<QWaylandTextInput> mTextInput;
+ QScopedPointer<QWaylandTabletSeatV2> mTabletSeat;
uint32_t mTime = 0;
uint32_t mSerial = 0;
diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
index 33e64c6e..85c1990b 100644
--- a/src/client/qwaylandintegration.cpp
+++ b/src/client/qwaylandintegration.cpp
@@ -425,6 +425,8 @@ void QWaylandIntegration::initializeShellIntegration()
qCWarning(lcQpaWayland) << "Loading shell integration failed.";
qCWarning(lcQpaWayland) << "Attempted to load the following shells" << preferredShells;
}
+
+ QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
}
QWaylandInputDevice *QWaylandIntegration::createInputDevice(QWaylandDisplay *display, int version, uint32_t id)
diff --git a/src/client/qwaylandtabletv2.cpp b/src/client/qwaylandtabletv2.cpp
new file mode 100644
index 00000000..eb2e865f
--- /dev/null
+++ b/src/client/qwaylandtabletv2.cpp
@@ -0,0 +1,332 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandtabletv2_p.h"
+#include "qwaylandinputdevice_p.h"
+#include "qwaylanddisplay_p.h"
+#include "qwaylandsurface_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandTabletManagerV2::QWaylandTabletManagerV2(QWaylandDisplay *display, uint id, uint version)
+ : zwp_tablet_manager_v2(display->wl_registry(), id, qMin(version, uint(1)))
+{
+ // Create tabletSeats for all seats.
+ // This only works if we get the manager after all seats
+ const auto seats = display->inputDevices();
+ for (auto *seat : seats)
+ createTabletSeat(seat);
+}
+
+QWaylandTabletSeatV2 *QWaylandTabletManagerV2::createTabletSeat(QWaylandInputDevice *seat)
+{
+ return new QWaylandTabletSeatV2(this, seat);
+}
+
+QWaylandTabletSeatV2::QWaylandTabletSeatV2(QWaylandTabletManagerV2 *manager, QWaylandInputDevice *seat)
+ : QtWayland::zwp_tablet_seat_v2(manager->get_tablet_seat(seat->wl_seat()))
+{
+}
+
+QWaylandTabletSeatV2::~QWaylandTabletSeatV2()
+{
+ for (auto *tablet : m_tablets)
+ tablet->destroy();
+ for (auto *tool : m_tools)
+ tool->destroy();
+ for (auto *pad : m_pads)
+ pad->destroy();
+ destroy();
+}
+
+void QWaylandTabletSeatV2::zwp_tablet_seat_v2_tablet_added(zwp_tablet_v2 *id)
+{
+ auto *tablet = new QWaylandTabletV2(id);
+ m_tablets.push_back(tablet);
+ connect(tablet, &QWaylandTabletV2::destroyed, this, [this, tablet] { m_tablets.removeOne(tablet); });
+}
+
+void QWaylandTabletSeatV2::zwp_tablet_seat_v2_tool_added(zwp_tablet_tool_v2 *id)
+{
+ auto *tool = new QWaylandTabletToolV2(id);
+ m_tools.push_back(tool);
+ connect(tool, &QWaylandTabletToolV2::destroyed, this, [this, tool] { m_tools.removeOne(tool); });
+}
+
+void QWaylandTabletSeatV2::zwp_tablet_seat_v2_pad_added(zwp_tablet_pad_v2 *id)
+{
+ auto *pad = new QWaylandTabletPadV2(id);
+ m_pads.push_back(pad);
+ connect(pad, &QWaylandTabletPadV2::destroyed, this, [this, pad] { m_pads.removeOne(pad); });
+}
+
+QWaylandTabletV2::QWaylandTabletV2(::zwp_tablet_v2 *tablet)
+ : QtWayland::zwp_tablet_v2(tablet)
+{
+}
+
+void QWaylandTabletV2::zwp_tablet_v2_removed()
+{
+ destroy();
+ delete this;
+}
+
+QWaylandTabletToolV2::QWaylandTabletToolV2(::zwp_tablet_tool_v2 *tool)
+ : QtWayland::zwp_tablet_tool_v2(tool)
+{
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_type(uint32_t tool_type)
+{
+ m_toolType = type(tool_type);
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_hardware_serial(uint32_t hardware_serial_hi, uint32_t hardware_serial_lo)
+{
+ m_uid = (quint64(hardware_serial_hi) << 32) + hardware_serial_lo;
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_capability(uint32_t capability)
+{
+ if (capability == capability_rotation)
+ m_hasRotation = true;
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_done()
+{
+ switch (m_toolType) {
+ case type::type_airbrush:
+ case type::type_brush:
+ case type::type_pencil:
+ case type::type_pen:
+ m_pointerType = QTabletEvent::PointerType::Pen;
+ break;
+ case type::type_eraser:
+ m_pointerType = QTabletEvent::PointerType::Eraser;
+ break;
+ case type::type_mouse:
+ case type::type_lens:
+ m_pointerType = QTabletEvent::PointerType::Cursor;
+ break;
+ case type::type_finger:
+ m_pointerType = QTabletEvent::PointerType::UnknownPointer;
+ break;
+ }
+ switch (m_toolType) {
+ case type::type_airbrush:
+ m_tabletDevice = QTabletEvent::TabletDevice::Airbrush;
+ break;
+ case type::type_brush:
+ case type::type_pencil:
+ case type::type_pen:
+ case type::type_eraser:
+ m_tabletDevice = m_hasRotation ? QTabletEvent::TabletDevice::RotationStylus : QTabletEvent::TabletDevice::Stylus;
+ break;
+ case type::type_lens:
+ m_tabletDevice = QTabletEvent::TabletDevice::Puck;
+ break;
+ case type::type_mouse:
+ case type::type_finger:
+ m_tabletDevice = QTabletEvent::TabletDevice::NoDevice;
+ break;
+ }
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_removed()
+{
+ destroy();
+ delete this;
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_proximity_in(uint32_t serial, zwp_tablet_v2 *tablet, wl_surface *surface)
+{
+ Q_UNUSED(tablet);
+ Q_UNUSED(serial);
+ if (Q_UNLIKELY(!surface)) {
+ qCDebug(lcQpaWayland) << "Ignoring zwp_tablet_tool_v2_proximity_v2 with no surface";
+ return;
+ }
+ m_pending.enteredSurface = true;
+ m_pending.proximitySurface = QWaylandSurface::fromWlSurface(surface);
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_proximity_out()
+{
+ m_pending.enteredSurface = false;
+ m_pending.proximitySurface = nullptr;
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_down(uint32_t serial)
+{
+ Q_UNUSED(serial);
+ m_pending.down = true;
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_up()
+{
+ m_pending.down = false;
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_motion(wl_fixed_t x, wl_fixed_t y)
+{
+ m_pending.surfacePosition = QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y));
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_pressure(uint32_t pressure)
+{
+ const int maxPressure = 65535;
+ m_pending.pressure = qreal(pressure)/maxPressure;
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_distance(uint32_t distance)
+{
+ m_pending.distance = distance;
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_tilt(wl_fixed_t tilt_x, wl_fixed_t tilt_y)
+{
+ m_pending.xTilt = wl_fixed_to_double(tilt_x);
+ m_pending.yTilt = wl_fixed_to_double(tilt_y);
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_rotation(wl_fixed_t degrees)
+{
+ m_pending.rotation = wl_fixed_to_double(degrees);
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_slider(int32_t position)
+{
+ m_pending.slider = qreal(position) / 65535;
+}
+
+static Qt::MouseButton mouseButtonFromTablet(uint button)
+{
+ switch (button) {
+ case 0x110: return Qt::MouseButton::LeftButton; // BTN_LEFT
+ case 0x14b: return Qt::MouseButton::MiddleButton; // BTN_STYLUS
+ case 0x14c: return Qt::MouseButton::RightButton; // BTN_STYLUS2
+ default:
+ return Qt::NoButton;
+ }
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_button(uint32_t serial, uint32_t button, uint32_t state)
+{
+ Q_UNUSED(serial);
+ Qt::MouseButton mouseButton = mouseButtonFromTablet(button);
+ if (state == button_state_pressed)
+ m_pending.buttons |= mouseButton;
+ else
+ m_pending.buttons &= ~mouseButton;
+}
+
+void QWaylandTabletToolV2::zwp_tablet_tool_v2_frame(uint32_t time)
+{
+ if (m_pending.proximitySurface && !m_applied.proximitySurface) {
+ QWindowSystemInterface::handleTabletEnterProximityEvent(m_tabletDevice, m_pointerType, m_uid);
+ m_applied.proximitySurface = m_pending.proximitySurface;
+ }
+
+ if (!(m_pending == m_applied) && m_pending.proximitySurface) {
+ if (!m_pending.proximitySurface) {
+ qCWarning(lcQpaWayland) << "Can't send tablet event with no proximity surface, ignoring";
+ return;
+ }
+ QWaylandWindow *waylandWindow = QWaylandWindow::fromWlSurface(m_pending.proximitySurface->object());
+ QWindow *window = waylandWindow->window();
+ ulong timestamp = time;
+ const QPointF localPosition = waylandWindow->mapFromWlSurface(m_pending.surfacePosition);
+
+ QPointF delta = localPosition - localPosition.toPoint();
+ QPointF globalPosition = window->mapToGlobal(localPosition.toPoint());
+ globalPosition += delta;
+
+ Qt::MouseButtons buttons = m_pending.down ? Qt::MouseButton::LeftButton : Qt::MouseButton::NoButton;
+ buttons |= m_pending.buttons;
+ qreal pressure = m_pending.pressure;
+ int xTilt = int(m_pending.xTilt);
+ int yTilt = int(m_pending.yTilt);
+ qreal tangentialPressure = m_pending.slider;
+ qreal rotation = m_pending.rotation;
+ int z = int(m_pending.distance);
+ QWindowSystemInterface::handleTabletEvent(window, timestamp, localPosition, globalPosition,
+ m_tabletDevice, m_pointerType, buttons, pressure,
+ xTilt, yTilt, tangentialPressure, rotation, z, m_uid);
+ }
+
+ if (!m_pending.proximitySurface && m_applied.enteredSurface) {
+ QWindowSystemInterface::handleTabletLeaveProximityEvent(m_tabletDevice, m_pointerType, m_uid);
+ m_pending = State(); // Don't leave pressure etc. lying around when we enter the next surface
+ }
+
+ m_applied = m_pending;
+}
+
+// TODO: delete when upgrading to c++20
+bool QWaylandTabletToolV2::State::operator==(const QWaylandTabletToolV2::State &o) const {
+ return
+ down == o.down &&
+ proximitySurface.data() == o.proximitySurface.data() &&
+ enteredSurface == o.enteredSurface &&
+ surfacePosition == o.surfacePosition &&
+ distance == o.distance &&
+ pressure == o.pressure &&
+ rotation == o.rotation &&
+ xTilt == o.xTilt &&
+ yTilt == o.yTilt &&
+ slider == o.slider &&
+ buttons == o.buttons;
+}
+
+QWaylandTabletPadV2::QWaylandTabletPadV2(::zwp_tablet_pad_v2 *pad)
+ : QtWayland::zwp_tablet_pad_v2(pad)
+{
+}
+
+void QWaylandTabletPadV2::zwp_tablet_pad_v2_removed()
+{
+ destroy();
+ delete this;
+}
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
diff --git a/src/client/qwaylandtabletv2_p.h b/src/client/qwaylandtabletv2_p.h
new file mode 100644
index 00000000..b4daaf5d
--- /dev/null
+++ b/src/client/qwaylandtabletv2_p.h
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDTABLETV2_P_H
+#define QWAYLANDTABLETV2_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtWaylandClient/private/qwayland-tablet-unstable-v2.h>
+
+#include <QtWaylandClient/private/qtwaylandclientglobal_p.h>
+
+#include <QtGui/QTabletEvent>
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+#include <QtCore/QPointF>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandDisplay;
+class QWaylandInputDevice;
+class QWaylandSurface;
+
+class QWaylandTabletSeatV2;
+class QWaylandTabletV2;
+class QWaylandTabletToolV2;
+class QWaylandTabletPadV2;
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandTabletManagerV2 : public QtWayland::zwp_tablet_manager_v2
+{
+public:
+ explicit QWaylandTabletManagerV2(QWaylandDisplay *display, uint id, uint version);
+ QWaylandTabletSeatV2 *createTabletSeat(QWaylandInputDevice *seat);
+};
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandTabletSeatV2 : public QObject, public QtWayland::zwp_tablet_seat_v2
+{
+ Q_OBJECT
+public:
+ explicit QWaylandTabletSeatV2(QWaylandTabletManagerV2 *manager, QWaylandInputDevice *seat);
+ ~QWaylandTabletSeatV2() override;
+
+protected:
+ void zwp_tablet_seat_v2_tablet_added(struct ::zwp_tablet_v2 *id) override;
+ void zwp_tablet_seat_v2_tool_added(struct ::zwp_tablet_tool_v2 *id) override;
+ void zwp_tablet_seat_v2_pad_added(struct ::zwp_tablet_pad_v2 *id) override;
+
+private:
+ QVector<QWaylandTabletV2 *> m_tablets;
+ QVector<QWaylandTabletToolV2 *> m_tools;
+ QVector<QWaylandTabletPadV2 *> m_pads;
+};
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandTabletV2 : public QObject, public QtWayland::zwp_tablet_v2
+{
+ Q_OBJECT
+public:
+ explicit QWaylandTabletV2(::zwp_tablet_v2 *tablet);
+
+protected:
+// void zwp_tablet_v2_name(const QString &name) override;
+// void zwp_tablet_v2_id(uint32_t vid, uint32_t pid) override;
+// void zwp_tablet_v2_path(const QString &path) override;
+// void zwp_tablet_v2_done() override;
+ void zwp_tablet_v2_removed() override;
+};
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandTabletToolV2 : public QObject, public QtWayland::zwp_tablet_tool_v2
+{
+ Q_OBJECT
+public:
+ explicit QWaylandTabletToolV2(::zwp_tablet_tool_v2 *tool);
+
+protected:
+ void zwp_tablet_tool_v2_type(uint32_t tool_type) override;
+ void zwp_tablet_tool_v2_hardware_serial(uint32_t hardware_serial_hi, uint32_t hardware_serial_lo) override;
+// void zwp_tablet_tool_v2_hardware_id_wacom(uint32_t hardware_id_hi, uint32_t hardware_id_lo) override;
+ void zwp_tablet_tool_v2_capability(uint32_t capability) override;
+ void zwp_tablet_tool_v2_done() override;
+ void zwp_tablet_tool_v2_removed() 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_proximity_out() override;
+ void zwp_tablet_tool_v2_down(uint32_t serial) override;
+ void zwp_tablet_tool_v2_up() override;
+ void zwp_tablet_tool_v2_motion(wl_fixed_t x, wl_fixed_t y) override;
+ void zwp_tablet_tool_v2_pressure(uint32_t pressure) override;
+ void zwp_tablet_tool_v2_distance(uint32_t distance) override;
+ void zwp_tablet_tool_v2_tilt(wl_fixed_t tilt_x, wl_fixed_t tilt_y) override;
+ void zwp_tablet_tool_v2_rotation(wl_fixed_t degrees) override;
+ void zwp_tablet_tool_v2_slider(int32_t position) override;
+// void zwp_tablet_tool_v2_wheel(wl_fixed_t degrees, int32_t clicks) override;
+ void zwp_tablet_tool_v2_button(uint32_t serial, uint32_t button, uint32_t state) override;
+ void zwp_tablet_tool_v2_frame(uint32_t time) override;
+
+private:
+
+ // Static state (sent before done event)
+ QTabletEvent::PointerType m_pointerType = QTabletEvent::PointerType::UnknownPointer;
+ QTabletEvent::TabletDevice m_tabletDevice = QTabletEvent::TabletDevice::NoDevice;
+ type m_toolType = type_pen;
+ bool m_hasRotation = false;
+ quint64 m_uid = 0;
+
+ // Accumulated state (applied on frame event)
+ struct State {
+ bool down = false;
+ QPointer<QWaylandSurface> proximitySurface;
+ bool enteredSurface = false; // Not enough with just proximitySurface, if the surface is deleted, we still want to send a leave event
+ QPointF surfacePosition;
+ uint distance = 0;
+ qreal pressure = 0;
+ qreal rotation = 0;
+ qreal xTilt = 0;
+ qreal yTilt = 0;
+ qreal slider = 0;
+ Qt::MouseButtons buttons = Qt::MouseButton::NoButton; // Actual buttons, down state -> left mouse is mapped inside the frame handler
+ //auto operator<=>(const Point&) const = default; // TODO: use this when upgrading to C++20
+ bool operator==(const State &o) const;
+ } m_pending, m_applied;
+};
+
+// We don't actually use this, but need to handle the "removed" event to comply with the protocol
+class Q_WAYLAND_CLIENT_EXPORT QWaylandTabletPadV2 : public QObject, public QtWayland::zwp_tablet_pad_v2
+{
+ Q_OBJECT
+public:
+ explicit QWaylandTabletPadV2(::zwp_tablet_pad_v2 *pad);
+
+protected:
+// void zwp_tablet_pad_v2_group(struct ::zwp_tablet_pad_group_v2 *pad_group) override;
+// void zwp_tablet_pad_v2_path(const QString &path) override;
+// void zwp_tablet_pad_v2_buttons(uint32_t buttons) override;
+// void zwp_tablet_pad_v2_done() override;
+// void zwp_tablet_pad_v2_button(uint32_t time, uint32_t button, uint32_t state) override;
+// void zwp_tablet_pad_v2_enter(uint32_t serial, struct ::zwp_tablet_v2 *tablet, struct ::wl_surface *surface) override;
+// void zwp_tablet_pad_v2_leave(uint32_t serial, struct ::wl_surface *surface) override;
+ void zwp_tablet_pad_v2_removed() override;
+};
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDTABLETV2_P_H