QWaylandTablet: Implement cursor
Currently we don't set a cursor for tablet devices, so we get either a generic fallback cursor (KWin) or no cursor at all (GNOME). This makes sure we get the same cursor we get for mouse input. The code is mostly identical to the mouse cursor handling, so refactor things a bit to share Pick-to: 6.8 Fixes: QTBUG-105843 Fixes: QTBUG-123776 Change-Id: Ie626ff978d9b66ec422804a103699eebec85e267 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
parent
efd45d447e
commit
577d4e2244
31
src/plugins/platforms/wayland/qwaylandcallback_p.h
Normal file
31
src/plugins/platforms/wayland/qwaylandcallback_p.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#ifndef QWAYLANDCALLBACK_H
|
||||
#define QWAYLANDCALLBACK_H
|
||||
|
||||
#include "qwayland-wayland.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
|
||||
class WlCallback : public QtWayland::wl_callback
|
||||
{
|
||||
public:
|
||||
explicit WlCallback(::wl_callback *callback, std::function<void(uint32_t)> fn)
|
||||
: QtWayland::wl_callback(callback), m_fn(fn)
|
||||
{
|
||||
}
|
||||
~WlCallback() override { wl_callback_destroy(object()); }
|
||||
void callback_done(uint32_t callback_data) override { m_fn(callback_data); }
|
||||
|
||||
private:
|
||||
std::function<void(uint32_t)> m_fn;
|
||||
};
|
||||
|
||||
} // namespace QtWaylandClient
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QWAYLANDCALLBACK_H
|
81
src/plugins/platforms/wayland/qwaylandcursorsurface_p.h
Normal file
81
src/plugins/platforms/wayland/qwaylandcursorsurface_p.h
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#ifndef QWAYLANDCURSORSURFACE_H
|
||||
#define QWAYLANDCURSORSURFACE_H
|
||||
|
||||
#include "qwaylandsurface_p.h"
|
||||
#include "qwaylandcallback_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
|
||||
#if QT_CONFIG(cursor)
|
||||
template <typename InputDevice>
|
||||
class CursorSurface : public QWaylandSurface
|
||||
{
|
||||
public:
|
||||
explicit CursorSurface(InputDevice *pointer, QWaylandDisplay *display)
|
||||
: QWaylandSurface(display), m_pointer(pointer)
|
||||
{
|
||||
connect(this, &QWaylandSurface::screensChanged, m_pointer, &InputDevice::updateCursor);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_setSerial = 0;
|
||||
m_hotspot = QPoint();
|
||||
}
|
||||
|
||||
// Size and hotspot are in surface coordinates
|
||||
void update(wl_buffer *buffer, const QPoint &hotspot, const QSize &size, int bufferScale,
|
||||
bool animated = false)
|
||||
{
|
||||
// Calling code needs to ensure buffer scale is supported if != 1
|
||||
Q_ASSERT(bufferScale == 1 || version() >= 3);
|
||||
|
||||
auto enterSerial = m_pointer->mEnterSerial;
|
||||
if (m_setSerial < enterSerial || m_hotspot != hotspot) {
|
||||
m_pointer->set_cursor(m_pointer->mEnterSerial, object(), hotspot.x(), hotspot.y());
|
||||
m_setSerial = enterSerial;
|
||||
m_hotspot = hotspot;
|
||||
}
|
||||
|
||||
if (version() >= 3)
|
||||
set_buffer_scale(bufferScale);
|
||||
|
||||
attach(buffer, 0, 0);
|
||||
damage(0, 0, size.width(), size.height());
|
||||
m_frameCallback.reset();
|
||||
if (animated) {
|
||||
m_frameCallback.reset(new WlCallback(frame(), [this](uint32_t time) {
|
||||
Q_UNUSED(time);
|
||||
m_pointer->cursorFrameCallback();
|
||||
}));
|
||||
}
|
||||
commit();
|
||||
}
|
||||
|
||||
int outputScale() const
|
||||
{
|
||||
int scale = 0;
|
||||
for (auto *screen : m_screens)
|
||||
scale = qMax(scale, screen->scale());
|
||||
return scale;
|
||||
}
|
||||
|
||||
private:
|
||||
QScopedPointer<WlCallback> m_frameCallback;
|
||||
InputDevice *m_pointer = nullptr;
|
||||
uint m_setSerial = 0;
|
||||
QPoint m_hotspot;
|
||||
};
|
||||
|
||||
#endif // QT_CONFIG(cursor)
|
||||
|
||||
} // namespace QtWaylandClient
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QWAYLANDCURSORSURFACE_H
|
@ -29,6 +29,8 @@
|
||||
#include "qwaylandtextinputinterface_p.h"
|
||||
#include "qwaylandinputcontext_p.h"
|
||||
#include "qwaylandinputmethodcontext_p.h"
|
||||
#include "qwaylandcallback_p.h"
|
||||
#include "qwaylandcursorsurface_p.h"
|
||||
|
||||
#include <QtGui/private/qpixmap_raster_p.h>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
@ -152,80 +154,6 @@ QWaylandWindow *QWaylandInputDevice::Pointer::focusWindow() const
|
||||
|
||||
#if QT_CONFIG(cursor)
|
||||
|
||||
class WlCallback : public QtWayland::wl_callback {
|
||||
public:
|
||||
explicit WlCallback(::wl_callback *callback, std::function<void(uint32_t)> fn)
|
||||
: QtWayland::wl_callback(callback)
|
||||
, m_fn(fn)
|
||||
{}
|
||||
~WlCallback() override { wl_callback_destroy(object()); }
|
||||
void callback_done(uint32_t callback_data) override {
|
||||
m_fn(callback_data);
|
||||
}
|
||||
private:
|
||||
std::function<void(uint32_t)> m_fn;
|
||||
};
|
||||
|
||||
class CursorSurface : public QWaylandSurface
|
||||
{
|
||||
public:
|
||||
explicit CursorSurface(QWaylandInputDevice::Pointer *pointer, QWaylandDisplay *display)
|
||||
: QWaylandSurface(display)
|
||||
, m_pointer(pointer)
|
||||
{
|
||||
connect(this, &QWaylandSurface::screensChanged,
|
||||
m_pointer, &QWaylandInputDevice::Pointer::updateCursor);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_setSerial = 0;
|
||||
m_hotspot = QPoint();
|
||||
}
|
||||
|
||||
// Size and hotspot are in surface coordinates
|
||||
void update(wl_buffer *buffer, const QPoint &hotspot, const QSize &size, int bufferScale, bool animated = false)
|
||||
{
|
||||
// Calling code needs to ensure buffer scale is supported if != 1
|
||||
Q_ASSERT(bufferScale == 1 || version() >= 3);
|
||||
|
||||
auto enterSerial = m_pointer->mEnterSerial;
|
||||
if (m_setSerial < enterSerial || m_hotspot != hotspot) {
|
||||
m_pointer->set_cursor(m_pointer->mEnterSerial, object(), hotspot.x(), hotspot.y());
|
||||
m_setSerial = enterSerial;
|
||||
m_hotspot = hotspot;
|
||||
}
|
||||
|
||||
if (version() >= 3)
|
||||
set_buffer_scale(bufferScale);
|
||||
|
||||
attach(buffer, 0, 0);
|
||||
damage(0, 0, size.width(), size.height());
|
||||
m_frameCallback.reset();
|
||||
if (animated) {
|
||||
m_frameCallback.reset(new WlCallback(frame(), [this](uint32_t time){
|
||||
Q_UNUSED(time);
|
||||
m_pointer->cursorFrameCallback();
|
||||
}));
|
||||
}
|
||||
commit();
|
||||
}
|
||||
|
||||
int outputScale() const
|
||||
{
|
||||
int scale = 0;
|
||||
for (auto *screen : m_screens)
|
||||
scale = qMax(scale, screen->scale());
|
||||
return scale;
|
||||
}
|
||||
|
||||
private:
|
||||
QScopedPointer<WlCallback> m_frameCallback;
|
||||
QWaylandInputDevice::Pointer *m_pointer = nullptr;
|
||||
uint m_setSerial = 0;
|
||||
QPoint m_hotspot;
|
||||
};
|
||||
|
||||
int QWaylandInputDevice::Pointer::idealCursorScale() const
|
||||
{
|
||||
if (seat()->mQDisplay->compositor()->version() < 3) {
|
||||
@ -342,7 +270,8 @@ void QWaylandInputDevice::Pointer::updateCursor()
|
||||
qCWarning(lcQpaWayland) << "Unable to change to cursor" << shape;
|
||||
}
|
||||
|
||||
CursorSurface *QWaylandInputDevice::Pointer::getOrCreateCursorSurface()
|
||||
CursorSurface<QWaylandInputDevice::Pointer> *
|
||||
QWaylandInputDevice::Pointer::getOrCreateCursorSurface()
|
||||
{
|
||||
if (!mCursor.surface)
|
||||
mCursor.surface.reset(new CursorSurface(this, seat()->mQDisplay));
|
||||
@ -688,6 +617,9 @@ void QWaylandInputDevice::setCursor(const QCursor *cursor, const QSharedPointer<
|
||||
|
||||
if (mPointer)
|
||||
mPointer->updateCursor();
|
||||
|
||||
if (mTabletSeat)
|
||||
mTabletSeat->updateCursor();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -65,6 +65,7 @@ class QWaylandTextInputMethod;
|
||||
#if QT_CONFIG(cursor)
|
||||
class QWaylandCursorTheme;
|
||||
class QWaylandCursorShape;
|
||||
template <typename T>
|
||||
class CursorSurface;
|
||||
#endif
|
||||
|
||||
@ -294,7 +295,7 @@ public:
|
||||
void updateCursor();
|
||||
void cursorTimerCallback();
|
||||
void cursorFrameCallback();
|
||||
CursorSurface *getOrCreateCursorSurface();
|
||||
CursorSurface<QWaylandInputDevice::Pointer> *getOrCreateCursorSurface();
|
||||
#endif
|
||||
QWaylandInputDevice *seat() const { return mParent; }
|
||||
|
||||
@ -336,7 +337,7 @@ public:
|
||||
QScopedPointer<QWaylandCursorShape> shape;
|
||||
QWaylandCursorTheme *theme = nullptr;
|
||||
int themeBufferScale = 0;
|
||||
QScopedPointer<CursorSurface> surface;
|
||||
QScopedPointer<CursorSurface<QWaylandInputDevice::Pointer>> surface;
|
||||
QTimer frameTimer;
|
||||
bool gotFrameCallback = false;
|
||||
bool gotTimerCallback = false;
|
||||
|
@ -5,7 +5,16 @@
|
||||
#include "qwaylandinputdevice_p.h"
|
||||
#include "qwaylanddisplay_p.h"
|
||||
#include "qwaylandsurface_p.h"
|
||||
#include "qwaylandscreen_p.h"
|
||||
#include "qwaylandbuffer_p.h"
|
||||
#include "qwaylandcursorsurface_p.h"
|
||||
#include "qwaylandcursor_p.h"
|
||||
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
#include <QtGui/private/qpointingdevice_p.h>
|
||||
#include <qpa/qplatformtheme.h>
|
||||
|
||||
#include <wayland-cursor.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -16,6 +25,148 @@ using namespace Qt::StringLiterals;
|
||||
Q_LOGGING_CATEGORY(lcQpaInputDevices, "qt.qpa.input.devices")
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaWaylandInput)
|
||||
|
||||
#if QT_CONFIG(cursor)
|
||||
int QWaylandTabletToolV2::idealCursorScale() const
|
||||
{
|
||||
if (m_tabletSeat->seat()->mQDisplay->compositor()->version() < 3) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (auto *s = mCursor.surface.data()) {
|
||||
if (s->outputScale() > 0)
|
||||
return s->outputScale();
|
||||
}
|
||||
|
||||
return m_tabletSeat->seat()->mCursor.fallbackOutputScale;
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::updateCursorTheme()
|
||||
{
|
||||
QString cursorThemeName;
|
||||
QSize cursorSize;
|
||||
|
||||
if (const QPlatformTheme *platformTheme = QGuiApplicationPrivate::platformTheme()) {
|
||||
cursorThemeName = platformTheme->themeHint(QPlatformTheme::MouseCursorTheme).toString();
|
||||
cursorSize = platformTheme->themeHint(QPlatformTheme::MouseCursorSize).toSize();
|
||||
}
|
||||
|
||||
if (cursorThemeName.isEmpty())
|
||||
cursorThemeName = QStringLiteral("default");
|
||||
if (cursorSize.isEmpty())
|
||||
cursorSize = QSize(24, 24);
|
||||
|
||||
int scale = idealCursorScale();
|
||||
int pixelSize = cursorSize.width() * scale;
|
||||
auto *display = m_tabletSeat->seat()->mQDisplay;
|
||||
mCursor.theme = display->loadCursorTheme(cursorThemeName, pixelSize);
|
||||
|
||||
if (!mCursor.theme)
|
||||
return; // A warning has already been printed in loadCursorTheme
|
||||
|
||||
if (auto *arrow = mCursor.theme->cursor(Qt::ArrowCursor)) {
|
||||
int arrowPixelSize = qMax(arrow->images[0]->width,
|
||||
arrow->images[0]->height); // Not all cursor themes are square
|
||||
while (scale > 1 && arrowPixelSize / scale < cursorSize.width())
|
||||
--scale;
|
||||
} else {
|
||||
qCWarning(lcQpaWayland) << "Cursor theme does not support the arrow cursor";
|
||||
}
|
||||
mCursor.themeBufferScale = scale;
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::updateCursor()
|
||||
{
|
||||
if (mEnterSerial == 0)
|
||||
return;
|
||||
|
||||
auto shape = m_tabletSeat->seat()->mCursor.shape;
|
||||
|
||||
if (shape == Qt::BlankCursor) {
|
||||
if (mCursor.surface)
|
||||
mCursor.surface->reset();
|
||||
set_cursor(mEnterSerial, nullptr, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (shape == Qt::BitmapCursor) {
|
||||
auto buffer = m_tabletSeat->seat()->mCursor.bitmapBuffer;
|
||||
if (!buffer) {
|
||||
qCWarning(lcQpaWayland) << "No buffer for bitmap cursor, can't set cursor";
|
||||
return;
|
||||
}
|
||||
auto hotspot = m_tabletSeat->seat()->mCursor.hotspot;
|
||||
int bufferScale = m_tabletSeat->seat()->mCursor.bitmapScale;
|
||||
getOrCreateCursorSurface()->update(buffer->buffer(), hotspot, buffer->size(), bufferScale);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCursor.shape) {
|
||||
if (mCursor.surface) {
|
||||
mCursor.surface->reset();
|
||||
}
|
||||
mCursor.shape->setShape(mEnterSerial, shape);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mCursor.theme || idealCursorScale() != mCursor.themeBufferScale)
|
||||
updateCursorTheme();
|
||||
|
||||
if (!mCursor.theme)
|
||||
return;
|
||||
|
||||
// Set from shape using theme
|
||||
uint time = m_tabletSeat->seat()->mCursor.animationTimer.elapsed();
|
||||
|
||||
if (struct ::wl_cursor *waylandCursor = mCursor.theme->cursor(shape)) {
|
||||
uint duration = 0;
|
||||
int frame = wl_cursor_frame_and_duration(waylandCursor, time, &duration);
|
||||
::wl_cursor_image *image = waylandCursor->images[frame];
|
||||
|
||||
struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
|
||||
if (!buffer) {
|
||||
qCWarning(lcQpaWayland) << "Could not find buffer for cursor" << shape;
|
||||
return;
|
||||
}
|
||||
int bufferScale = mCursor.themeBufferScale;
|
||||
QPoint hotspot = QPoint(image->hotspot_x, image->hotspot_y) / bufferScale;
|
||||
QSize size = QSize(image->width, image->height) / bufferScale;
|
||||
bool animated = duration > 0;
|
||||
if (animated) {
|
||||
mCursor.gotFrameCallback = false;
|
||||
mCursor.gotTimerCallback = false;
|
||||
mCursor.frameTimer.start(duration);
|
||||
}
|
||||
getOrCreateCursorSurface()->update(buffer, hotspot, size, bufferScale, animated);
|
||||
return;
|
||||
}
|
||||
|
||||
qCWarning(lcQpaWayland) << "Unable to change to cursor" << shape;
|
||||
}
|
||||
|
||||
CursorSurface<QWaylandTabletToolV2> *QWaylandTabletToolV2::getOrCreateCursorSurface()
|
||||
{
|
||||
if (!mCursor.surface)
|
||||
mCursor.surface.reset(
|
||||
new CursorSurface<QWaylandTabletToolV2>(this, m_tabletSeat->seat()->mQDisplay));
|
||||
return mCursor.surface.get();
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::cursorTimerCallback()
|
||||
{
|
||||
mCursor.gotTimerCallback = true;
|
||||
if (mCursor.gotFrameCallback)
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::cursorFrameCallback()
|
||||
{
|
||||
mCursor.gotFrameCallback = true;
|
||||
if (mCursor.gotTimerCallback)
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
#endif // QT_CONFIG(cursor)
|
||||
|
||||
QWaylandTabletManagerV2::QWaylandTabletManagerV2(QWaylandDisplay *display, uint id, uint version)
|
||||
: zwp_tablet_manager_v2(display->wl_registry(), id, qMin(version, uint(1)))
|
||||
{
|
||||
@ -127,6 +278,12 @@ void QWaylandTabletV2::zwp_tablet_v2_done()
|
||||
QWindowSystemInterface::registerInputDevice(this);
|
||||
}
|
||||
|
||||
void QWaylandTabletSeatV2::updateCursor()
|
||||
{
|
||||
for (auto tool : m_tools)
|
||||
tool->updateCursor();
|
||||
}
|
||||
|
||||
void QWaylandTabletSeatV2::toolRemoved(QWaylandTabletToolV2 *tool)
|
||||
{
|
||||
m_tools.removeOne(tool);
|
||||
@ -147,8 +304,20 @@ QWaylandTabletToolV2::QWaylandTabletToolV2(QWaylandTabletSeatV2 *tabletSeat, ::z
|
||||
, m_tabletSeat(tabletSeat)
|
||||
{
|
||||
// TODO get the number of buttons somehow?
|
||||
|
||||
#if QT_CONFIG(cursor)
|
||||
if (auto cursorShapeManager = m_tabletSeat->seat()->mQDisplay->cursorShapeManager()) {
|
||||
mCursor.shape.reset(
|
||||
new QWaylandCursorShape(cursorShapeManager->get_tablet_tool_v2(object())));
|
||||
}
|
||||
|
||||
mCursor.frameTimer.setSingleShot(true);
|
||||
mCursor.frameTimer.callOnTimeout(this, [&]() { cursorTimerCallback(); });
|
||||
#endif
|
||||
}
|
||||
|
||||
QWaylandTabletToolV2::~QWaylandTabletToolV2() = default;
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_type(uint32_t tool_type)
|
||||
{
|
||||
QPointingDevicePrivate *d = QPointingDevicePrivate::get(this);
|
||||
@ -250,6 +419,7 @@ void QWaylandTabletToolV2::zwp_tablet_tool_v2_proximity_in(uint32_t serial, zwp_
|
||||
Q_UNUSED(tablet);
|
||||
|
||||
m_tabletSeat->seat()->mSerial = serial;
|
||||
mEnterSerial = serial;
|
||||
|
||||
if (Q_UNLIKELY(!surface)) {
|
||||
qCDebug(lcQpaWayland) << "Ignoring zwp_tablet_tool_v2_proximity_v2 with no surface";
|
||||
@ -257,6 +427,11 @@ void QWaylandTabletToolV2::zwp_tablet_tool_v2_proximity_in(uint32_t serial, zwp_
|
||||
}
|
||||
m_pending.enteredSurface = true;
|
||||
m_pending.proximitySurface = QWaylandSurface::fromWlSurface(surface);
|
||||
|
||||
#if QT_CONFIG(cursor)
|
||||
// Depends on mEnterSerial being updated
|
||||
updateCursor();
|
||||
#endif
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_proximity_out()
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtCore/QPointF>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtGui/QPointingDevice>
|
||||
#include <QtGui/QInputDevice>
|
||||
|
||||
@ -38,6 +39,13 @@ class QWaylandTabletV2;
|
||||
class QWaylandTabletToolV2;
|
||||
class QWaylandTabletPadV2;
|
||||
|
||||
#if QT_CONFIG(cursor)
|
||||
class QWaylandCursorTheme;
|
||||
class QWaylandCursorShape;
|
||||
template <typename T>
|
||||
class CursorSurface;
|
||||
#endif
|
||||
|
||||
class Q_WAYLANDCLIENT_EXPORT QWaylandTabletManagerV2 : public QtWayland::zwp_tablet_manager_v2
|
||||
{
|
||||
public:
|
||||
@ -54,6 +62,7 @@ public:
|
||||
|
||||
QWaylandInputDevice *seat() const { return m_seat; }
|
||||
|
||||
void updateCursor();
|
||||
void toolRemoved(QWaylandTabletToolV2 *tool);
|
||||
|
||||
protected:
|
||||
@ -89,6 +98,9 @@ class Q_WAYLANDCLIENT_EXPORT QWaylandTabletToolV2 : public QPointingDevice, publ
|
||||
Q_OBJECT
|
||||
public:
|
||||
QWaylandTabletToolV2(QWaylandTabletSeatV2 *tabletSeat, ::zwp_tablet_tool_v2 *tool);
|
||||
~QWaylandTabletToolV2() override;
|
||||
|
||||
void updateCursor();
|
||||
|
||||
protected:
|
||||
void zwp_tablet_tool_v2_type(uint32_t tool_type) override;
|
||||
@ -112,8 +124,37 @@ protected:
|
||||
void zwp_tablet_tool_v2_frame(uint32_t time) override;
|
||||
|
||||
private:
|
||||
#if QT_CONFIG(cursor)
|
||||
int idealCursorScale() const;
|
||||
void updateCursorTheme();
|
||||
void cursorTimerCallback();
|
||||
void cursorFrameCallback();
|
||||
CursorSurface<QWaylandTabletToolV2> *getOrCreateCursorSurface();
|
||||
#endif
|
||||
|
||||
QWaylandTabletSeatV2 *m_tabletSeat;
|
||||
|
||||
// Static state (sent before done event)
|
||||
QPointingDevice::PointerType m_pointerType = QPointingDevice::PointerType::Unknown;
|
||||
QInputDevice::DeviceType m_tabletDevice = QInputDevice::DeviceType::Unknown;
|
||||
zwp_tablet_tool_v2::type m_toolType = type_pen;
|
||||
bool m_hasRotation = false;
|
||||
quint64 m_uid = 0;
|
||||
|
||||
uint32_t mEnterSerial = 0;
|
||||
#if QT_CONFIG(cursor)
|
||||
struct
|
||||
{
|
||||
QScopedPointer<QWaylandCursorShape> shape;
|
||||
QWaylandCursorTheme *theme = nullptr;
|
||||
int themeBufferScale = 0;
|
||||
QScopedPointer<CursorSurface<QWaylandTabletToolV2>> surface;
|
||||
QTimer frameTimer;
|
||||
bool gotFrameCallback = false;
|
||||
bool gotTimerCallback = false;
|
||||
} mCursor;
|
||||
#endif
|
||||
|
||||
// Accumulated state (applied on frame event)
|
||||
struct State {
|
||||
bool down = false;
|
||||
@ -130,6 +171,9 @@ private:
|
||||
//auto operator<=>(const Point&) const = default; // TODO: use this when upgrading to C++20
|
||||
bool operator==(const State &o) const;
|
||||
} m_pending, m_applied;
|
||||
|
||||
template <typename T>
|
||||
friend class CursorSurface;
|
||||
};
|
||||
|
||||
class Q_WAYLANDCLIENT_EXPORT QWaylandTabletPadV2 : public QPointingDevice, public QtWayland::zwp_tablet_pad_v2
|
||||
|
Loading…
x
Reference in New Issue
Block a user