summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/client/CMakeLists.txt1
-rw-r--r--src/client/qwaylanddisplay.cpp3
-rw-r--r--src/client/qwaylanddisplay_p.h3
-rw-r--r--src/client/qwaylandinputdevice.cpp38
-rw-r--r--src/client/qwaylandinputdevice_p.h71
-rw-r--r--src/client/qwaylandpointergestures.cpp222
-rw-r--r--src/client/qwaylandpointergestures_p.h150
-rw-r--r--src/client/qwaylandwindow.cpp127
-rw-r--r--src/client/qwaylandwindow_p.h25
9 files changed, 638 insertions, 2 deletions
diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt
index f317d5316..1e1b83893 100644
--- a/src/client/CMakeLists.txt
+++ b/src/client/CMakeLists.txt
@@ -33,6 +33,7 @@ qt_internal_add_module(WaylandClient
qwaylandinputmethodcontext.cpp qwaylandinputmethodcontext_p.h
qwaylandintegration.cpp qwaylandintegration_p.h
qwaylandnativeinterface.cpp qwaylandnativeinterface_p.h
+ qwaylandpointergestures.cpp qwaylandpointergestures_p.h
qwaylandqtkey.cpp qwaylandqtkey_p.h
qwaylandscreen.cpp qwaylandscreen_p.h
qwaylandshellsurface.cpp qwaylandshellsurface_p.h
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index 94381992c..8806773d5 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -68,6 +68,7 @@
#include "qwaylandclientbufferintegration_p.h"
#include "qwaylandextendedsurface_p.h"
+#include "qwaylandpointergestures_p.h"
#include "qwaylandsubsurface_p.h"
#include "qwaylandtouch_p.h"
#include "qwaylandtabletv2_p.h"
@@ -355,6 +356,8 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id));
} else if (interface == QStringLiteral("zwp_tablet_manager_v2")) {
mTabletManager.reset(new QWaylandTabletManagerV2(this, id, qMin(1, int(version))));
+ } else if (interface == QStringLiteral("zwp_pointer_gestures_v1")) {
+ mPointerGestures.reset(new QWaylandPointerGestures(this, id, 1));
#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 91715a144..ae80cd33c 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -101,6 +101,7 @@ class QWaylandDataDeviceManager;
class QWaylandPrimarySelectionDeviceManagerV1;
#endif
class QWaylandTabletManagerV2;
+class QWaylandPointerGestures;
class QWaylandTouchExtension;
class QWaylandQtKeyExtension;
class QWaylandWindow;
@@ -172,6 +173,7 @@ public:
#endif
QtWayland::qt_surface_extension *windowExtension() const { return mWindowExtension.data(); }
QWaylandTabletManagerV2 *tabletManager() const { return mTabletManager.data(); }
+ QWaylandPointerGestures *pointerGestures() const { return mPointerGestures.data(); }
QWaylandTouchExtension *touchExtension() const { return mTouchExtension.data(); }
QtWayland::qt_text_input_method_manager_v1 *textInputMethodManager() const { return mTextInputMethodManager.data(); }
QtWayland::zwp_text_input_manager_v2 *textInputManager() const { return mTextInputManager.data(); }
@@ -275,6 +277,7 @@ private:
QScopedPointer<QWaylandQtKeyExtension> mQtKeyExtension;
QScopedPointer<QWaylandWindowManagerIntegration> mWindowManagerIntegration;
QScopedPointer<QWaylandTabletManagerV2> mTabletManager;
+ QScopedPointer<QWaylandPointerGestures> mPointerGestures;
#if QT_CONFIG(wayland_client_primary_selection)
QScopedPointer<QWaylandPrimarySelectionDeviceManagerV1> mPrimarySelectionManager;
#endif
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
index 3304b9118..6fe89cfcc 100644
--- a/src/client/qwaylandinputdevice.cpp
+++ b/src/client/qwaylandinputdevice.cpp
@@ -51,6 +51,7 @@
#include "qwaylandprimaryselectionv1_p.h"
#endif
#include "qwaylandtabletv2_p.h"
+#include "qwaylandpointergestures_p.h"
#include "qwaylandtouch_p.h"
#include "qwaylandscreen_p.h"
#include "qwaylandcursor_p.h"
@@ -82,6 +83,10 @@ namespace QtWaylandClient {
Q_LOGGING_CATEGORY(lcQpaWaylandInput, "qt.qpa.wayland.input");
+// The maximum number of concurrent touchpoints is not exposed in wayland, so we assume a
+// reasonable number of them. As of 2021 most touchscreen panels support 10 concurrent touchpoints.
+static const int MaxTouchPoints = 10;
+
QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p)
: mParent(p)
{
@@ -446,9 +451,28 @@ void QWaylandInputDevice::seat_capabilities(uint32_t caps)
if (caps & WL_SEAT_CAPABILITY_POINTER && !mPointer) {
mPointer = createPointer(this);
mPointer->init(get_pointer());
+
+ auto *pointerGestures = mQDisplay->pointerGestures();
+ if (pointerGestures) {
+ // NOTE: The name of the device and its system ID are not exposed on Wayland.
+ mTouchPadDevice = new QPointingDevice(QLatin1String("touchpad"), 0,
+ QInputDevice::DeviceType::TouchPad,
+ QPointingDevice::PointerType::Finger,
+ QInputDevice::Capability::Position,
+ MaxTouchPoints, 0);
+ QWindowSystemInterface::registerInputDevice(mTouchPadDevice);
+ mPointerGesturePinch = pointerGestures->createPointerGesturePinch(this);
+ mPointerGesturePinch->init(pointerGestures->get_pinch_gesture(get_pointer()));
+ mPointerGestureSwipe = pointerGestures->createPointerGestureSwipe(this);
+ mPointerGestureSwipe->init(pointerGestures->get_swipe_gesture(get_pointer()));
+ }
} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && mPointer) {
delete mPointer;
mPointer = nullptr;
+ delete mPointerGesturePinch;
+ mPointerGesturePinch = nullptr;
+ delete mPointerGestureSwipe;
+ mPointerGestureSwipe = nullptr;
}
if (caps & WL_SEAT_CAPABILITY_TOUCH && !mTouch) {
@@ -458,8 +482,8 @@ void QWaylandInputDevice::seat_capabilities(uint32_t caps)
if (!mTouchDevice) {
// TODO number of touchpoints, actual name and ID
mTouchDevice = new QPointingDevice(QLatin1String("some touchscreen"), 0,
- QInputDevice::DeviceType::TouchScreen, QPointingDevice::PointerType::Finger,
- QInputDevice::Capability::Position, 10, 0);
+ QInputDevice::DeviceType::TouchScreen, QPointingDevice::PointerType::Finger,
+ QInputDevice::Capability::Position, MaxTouchPoints, 0);
QWindowSystemInterface::registerInputDevice(mTouchDevice);
}
} else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && mTouch) {
@@ -493,6 +517,16 @@ QWaylandInputDevice::Pointer *QWaylandInputDevice::pointer() const
return mPointer;
}
+QWaylandPointerGestureSwipe *QWaylandInputDevice::pointerGestureSwipe() const
+{
+ return mPointerGestureSwipe;
+}
+
+QWaylandPointerGesturePinch *QWaylandInputDevice::pointerGesturePinch() const
+{
+ return mPointerGesturePinch;
+}
+
QWaylandInputDevice::Touch *QWaylandInputDevice::touch() const
{
return mTouch;
diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h
index 4a216bc43..0d408d36b 100644
--- a/src/client/qwaylandinputdevice_p.h
+++ b/src/client/qwaylandinputdevice_p.h
@@ -63,6 +63,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtWaylandClient/private/qwayland-wayland.h>
+#include <QtWaylandClient/private/qwayland-pointer-gestures-unstable-v1.h>
#if QT_CONFIG(xkbcommon)
#include <QtGui/private/qxkbcommon_p.h>
@@ -90,6 +91,9 @@ class QWaylandDisplay;
class QWaylandPrimarySelectionDeviceV1;
#endif
class QWaylandTabletSeatV2;
+class QWaylandPointerGestures;
+class QWaylandPointerGestureSwipe;
+class QWaylandPointerGesturePinch;
class QWaylandTextInput;
class QWaylandTextInputMethod;
#if QT_CONFIG(cursor)
@@ -97,6 +101,8 @@ class QWaylandCursorTheme;
class CursorSurface;
#endif
+Q_DECLARE_LOGGING_CATEGORY(lcQpaWaylandInput);
+
class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice
: public QObject
, public QtWayland::wl_seat
@@ -158,6 +164,8 @@ public:
Keyboard *keyboard() const;
Pointer *pointer() const;
+ QWaylandPointerGestureSwipe *pointerGestureSwipe() const;
+ QWaylandPointerGesturePinch *pointerGesturePinch() const;
Touch *touch() const;
protected:
@@ -187,6 +195,8 @@ protected:
Keyboard *mKeyboard = nullptr;
Pointer *mPointer = nullptr;
+ QWaylandPointerGestureSwipe *mPointerGestureSwipe = nullptr;
+ QWaylandPointerGesturePinch *mPointerGesturePinch = nullptr;
Touch *mTouch = nullptr;
QScopedPointer<QWaylandTextInput> mTextInput;
@@ -200,9 +210,13 @@ protected:
void handleTouchPoint(int id, Qt::TouchPointState state, const QPointF &surfacePosition = QPoint());
QPointingDevice *mTouchDevice = nullptr;
+ QPointingDevice *mTouchPadDevice = nullptr;
friend class QWaylandTouchExtension;
friend class QWaylandQtKeyExtension;
+ friend class QWaylandPointerGestureSwipe;
+ friend class QWaylandPointerGesturePinch;
+ friend class QWaylandWindow;
};
inline uint32_t QWaylandInputDevice::serial() const
@@ -461,6 +475,63 @@ public:
QPointer<QWaylandWindow> surface;
};
+#ifndef QT_NO_GESTURES
+class QWaylandPointerGestureSwipeEvent
+{
+ Q_GADGET
+public:
+ inline QWaylandPointerGestureSwipeEvent(QWaylandWindow *surface, Qt::GestureState state,
+ ulong timestamp, const QPointF &local,
+ const QPointF &global, uint fingers, const QPointF& delta)
+ : surface(surface)
+ , state(state)
+ , timestamp(timestamp)
+ , local(local)
+ , global(global)
+ , fingers(fingers)
+ , delta(delta)
+ {}
+
+ QPointer<QWaylandWindow> surface;
+ Qt::GestureState state = Qt::GestureState::NoGesture;
+ ulong timestamp = 0;
+ QPointF local;
+ QPointF global;
+ uint fingers = 0;
+ QPointF delta;
+};
+
+class QWaylandPointerGesturePinchEvent
+{
+ Q_GADGET
+public:
+ inline QWaylandPointerGesturePinchEvent(QWaylandWindow *surface, Qt::GestureState state,
+ ulong timestamp, const QPointF &local,
+ const QPointF &global, uint fingers, const QPointF& delta,
+ qreal scale_delta, qreal rotation_delta)
+ : surface(surface)
+ , state(state)
+ , timestamp(timestamp)
+ , local(local)
+ , global(global)
+ , fingers(fingers)
+ , delta(delta)
+ , scale_delta(scale_delta)
+ , rotation_delta(rotation_delta)
+ {}
+
+ QPointer<QWaylandWindow> surface;
+ Qt::GestureState state = Qt::GestureState::NoGesture;
+ ulong timestamp = 0;
+ QPointF local;
+ QPointF global;
+ uint fingers = 0;
+ QPointF delta;
+ qreal scale_delta = 0;
+ qreal rotation_delta = 0;
+};
+#endif // #ifndef QT_NO_GESTURES
+
}
QT_END_NAMESPACE
diff --git a/src/client/qwaylandpointergestures.cpp b/src/client/qwaylandpointergestures.cpp
new file mode 100644
index 000000000..c22ed2eb5
--- /dev/null
+++ b/src/client/qwaylandpointergestures.cpp
@@ -0,0 +1,222 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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 "qwaylandpointergestures_p.h"
+#include "qwaylanddisplay_p.h"
+#include "qwaylandinputdevice_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandPointerGestures::QWaylandPointerGestures(QWaylandDisplay *display, uint id, uint version)
+ : zwp_pointer_gestures_v1(display->wl_registry(), id, qMin(version, uint(1)))
+{
+}
+
+QWaylandPointerGestureSwipe *
+ QWaylandPointerGestures::createPointerGestureSwipe(QWaylandInputDevice *device)
+{
+ return new QWaylandPointerGestureSwipe(device);
+}
+
+QWaylandPointerGesturePinch *
+ QWaylandPointerGestures::createPointerGesturePinch(QWaylandInputDevice *device)
+{
+ return new QWaylandPointerGesturePinch(device);
+}
+
+QWaylandPointerGestureSwipe::QWaylandPointerGestureSwipe(QWaylandInputDevice *p)
+ : mParent(p)
+{
+}
+
+QWaylandPointerGestureSwipe::~QWaylandPointerGestureSwipe()
+{
+ destroy();
+}
+
+void QWaylandPointerGestureSwipe::zwp_pointer_gesture_swipe_v1_begin(uint32_t serial, uint32_t time,
+ struct ::wl_surface *surface,
+ uint32_t fingers)
+{
+#ifndef QT_NO_GESTURES
+ mParent->mSerial = serial;
+ mFocus = QWaylandWindow::fromWlSurface(surface);
+ mFingers = fingers;
+
+ const auto* pointer = mParent->pointer();
+
+ qCDebug(lcQpaWaylandInput) << "zwp_pointer_gesture_swipe_v1_begin @ "
+ << pointer->mSurfacePos << "fingers" << fingers;
+
+ auto e = QWaylandPointerGestureSwipeEvent(mFocus, Qt::GestureStarted, time,
+ pointer->mSurfacePos, pointer->mGlobalPos, mFingers,
+ QPointF());
+
+ mFocus->handleSwipeGesture(mParent, e);
+#endif
+}
+
+void QWaylandPointerGestureSwipe::zwp_pointer_gesture_swipe_v1_update(uint32_t time,
+ wl_fixed_t dx, wl_fixed_t dy)
+{
+#ifndef QT_NO_GESTURES
+ const auto* pointer = mParent->pointer();
+
+ const QPointF delta = QPointF(wl_fixed_to_double(dx), wl_fixed_to_double(dy));
+ qCDebug(lcQpaWaylandInput) << "zwp_pointer_gesture_swipe_v1_update @ "
+ << pointer->mSurfacePos << "delta" << delta;
+
+ auto e = QWaylandPointerGestureSwipeEvent(mFocus, Qt::GestureUpdated, time,
+ pointer->mSurfacePos, pointer->mGlobalPos, mFingers, delta);
+
+ mFocus->handleSwipeGesture(mParent, e);
+#endif
+}
+
+void QWaylandPointerGestureSwipe::zwp_pointer_gesture_swipe_v1_end(uint32_t serial, uint32_t time,
+ int32_t cancelled)
+{
+#ifndef QT_NO_GESTURES
+ mParent->mSerial = serial;
+ const auto* pointer = mParent->pointer();
+
+ qCDebug(lcQpaWaylandInput) << "zwp_pointer_gesture_swipe_v1_end @ "
+ << pointer->mSurfacePos << (cancelled ? "CANCELED" : "");
+
+ auto gestureType = cancelled ? Qt::GestureFinished : Qt::GestureCanceled;
+
+ auto e = QWaylandPointerGestureSwipeEvent(mFocus, gestureType, time,
+ pointer->mSurfacePos, pointer->mGlobalPos, mFingers,
+ QPointF());
+
+ mFocus->handleSwipeGesture(mParent, e);
+
+ mFocus.clear();
+ mFingers = 0;
+#endif
+}
+
+QWaylandPointerGesturePinch::QWaylandPointerGesturePinch(QWaylandInputDevice *p)
+ : mParent(p)
+{
+}
+
+QWaylandPointerGesturePinch::~QWaylandPointerGesturePinch()
+{
+ destroy();
+}
+
+void QWaylandPointerGesturePinch::zwp_pointer_gesture_pinch_v1_begin(uint32_t serial, uint32_t time,
+ struct ::wl_surface *surface,
+ uint32_t fingers)
+{
+#ifndef QT_NO_GESTURES
+ mParent->mSerial = serial;
+ mFocus = QWaylandWindow::fromWlSurface(surface);
+ mFingers = fingers;
+ mLastScale = 1;
+
+ const auto* pointer = mParent->pointer();
+
+ qCDebug(lcQpaWaylandInput) << "zwp_pointer_gesture_pinch_v1_begin @ "
+ << pointer->mSurfacePos << "fingers" << fingers;
+
+ auto e = QWaylandPointerGesturePinchEvent(mFocus, Qt::GestureStarted, time,
+ pointer->mSurfacePos, pointer->mGlobalPos, mFingers,
+ QPointF(), 0, 0);
+
+ mFocus->handlePinchGesture(mParent, e);
+#endif
+}
+
+void QWaylandPointerGesturePinch::zwp_pointer_gesture_pinch_v1_update(uint32_t time,
+ wl_fixed_t dx, wl_fixed_t dy,
+ wl_fixed_t scale,
+ wl_fixed_t rotation)
+{
+#ifndef QT_NO_GESTURES
+ const auto* pointer = mParent->pointer();
+
+ const qreal rscale = wl_fixed_to_double(scale);
+ const qreal rot = wl_fixed_to_double(rotation);
+ const QPointF delta = QPointF(wl_fixed_to_double(dx), wl_fixed_to_double(dy));
+ qCDebug(lcQpaWaylandInput) << "zwp_pointer_gesture_pinch_v1_update @ "
+ << pointer->mSurfacePos << "delta" << delta
+ << "scale" << mLastScale << "->" << rscale
+ << "delta" << rscale - mLastScale << "rot" << rot;
+
+ auto e = QWaylandPointerGesturePinchEvent(mFocus, Qt::GestureUpdated, time,
+ pointer->mSurfacePos, pointer->mGlobalPos, mFingers,
+ delta, rscale - mLastScale, rot);
+
+ mFocus->handlePinchGesture(mParent, e);
+
+ mLastScale = rscale;
+#endif
+}
+
+void QWaylandPointerGesturePinch::zwp_pointer_gesture_pinch_v1_end(uint32_t serial, uint32_t time,
+ int32_t cancelled)
+{
+#ifndef QT_NO_GESTURES
+ mParent->mSerial = serial;
+ const auto* pointer = mParent->pointer();
+
+ qCDebug(lcQpaWaylandInput) << "zwp_pointer_gesture_swipe_v1_end @ "
+ << pointer->mSurfacePos << (cancelled ? "CANCELED" : "");
+
+ auto gestureType = cancelled ? Qt::GestureFinished : Qt::GestureCanceled;
+
+ auto e = QWaylandPointerGesturePinchEvent(mFocus, gestureType, time,
+ pointer->mSurfacePos, pointer->mGlobalPos, mFingers,
+ QPointF(), 0, 0);
+
+ mFocus->handlePinchGesture(mParent, e);
+
+ mFocus.clear();
+ mFingers = 0;
+ mLastScale = 1;
+#endif
+}
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
diff --git a/src/client/qwaylandpointergestures_p.h b/src/client/qwaylandpointergestures_p.h
new file mode 100644
index 000000000..c9aa3ac35
--- /dev/null
+++ b/src/client/qwaylandpointergestures_p.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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 QWAYLANDPOINTERGESTURES_P_H
+#define QWAYLANDPOINTERGESTURES_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-pointer-gestures-unstable-v1.h>
+
+#include <QtWaylandClient/private/qtwaylandclientglobal_p.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandDisplay;
+class QWaylandWindow;
+class QWaylandInputDevice;
+class QWaylandPointerGestureSwipe;
+class QWaylandPointerGesturePinch;
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandPointerGestures : public QtWayland::zwp_pointer_gestures_v1
+{
+public:
+ explicit QWaylandPointerGestures(QWaylandDisplay *display, uint id, uint version);
+
+ QWaylandPointerGestureSwipe *createPointerGestureSwipe(QWaylandInputDevice *device);
+ QWaylandPointerGesturePinch *createPointerGesturePinch(QWaylandInputDevice *device);
+};
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandPointerGestureSwipe :
+ public QtWayland::zwp_pointer_gesture_swipe_v1
+{
+public:
+ QWaylandPointerGestureSwipe(QWaylandInputDevice *p);
+ ~QWaylandPointerGestureSwipe() override;
+
+ void zwp_pointer_gesture_swipe_v1_begin(uint32_t serial,
+ uint32_t time,
+ struct ::wl_surface *surface,
+ uint32_t fingers) override;
+
+ void zwp_pointer_gesture_swipe_v1_update(uint32_t time,
+ wl_fixed_t dx,
+ wl_fixed_t dy) override;
+
+ void zwp_pointer_gesture_swipe_v1_end(uint32_t serial,
+ uint32_t time,
+ int32_t cancelled) override;
+
+ struct ::zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1()
+ {
+ return QtWayland::zwp_pointer_gesture_swipe_v1::object();
+ }
+
+ QWaylandInputDevice *mParent = nullptr;
+ QPointer<QWaylandWindow> mFocus;
+ uint mFingers = 0;
+};
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandPointerGesturePinch :
+ public QtWayland::zwp_pointer_gesture_pinch_v1
+{
+public:
+ QWaylandPointerGesturePinch(QWaylandInputDevice *p);
+ ~QWaylandPointerGesturePinch() override;
+
+ void zwp_pointer_gesture_pinch_v1_begin(uint32_t serial,
+ uint32_t time,
+ struct ::wl_surface *surface,
+ uint32_t fingers) override;
+
+ void zwp_pointer_gesture_pinch_v1_update(uint32_t time,
+ wl_fixed_t dx,
+ wl_fixed_t dy,
+ wl_fixed_t scale,
+ wl_fixed_t rotation) override;
+
+ void zwp_pointer_gesture_pinch_v1_end(uint32_t serial,
+ uint32_t time,
+ int32_t cancelled) override;
+
+ struct ::zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1()
+ {
+ return QtWayland::zwp_pointer_gesture_pinch_v1::object();
+ }
+
+ QWaylandInputDevice *mParent = nullptr;
+ QPointer<QWaylandWindow> mFocus;
+ uint mFingers = 0;
+
+ // We need to convert between absolute scale provided by wayland/libinput and zoom deltas
+ // that Qt expects. This stores the scale of the last pinch event or 1.0 if there was none.
+ qreal mLastScale = 1;
+};
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDPOINTERGESTURES_P_H
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index 62690fc6f..5a5d18a93 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -978,6 +978,133 @@ void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylan
#endif
}
+#ifndef QT_NO_GESTURES
+void QWaylandWindow::handleSwipeGesture(QWaylandInputDevice *inputDevice,
+ const QWaylandPointerGestureSwipeEvent &e)
+{
+ switch (e.state) {
+ case Qt::GestureStarted:
+ if (mGestureState != GestureNotActive)
+ qCWarning(lcQpaWaylandInput) << "Unexpected gesture state. Gestures will act weird.";
+
+ if (mWindowDecoration && !mMouseEventsInContentArea) {
+ // whole gesture sequence will be ignored
+ mGestureState = GestureActiveInDecoration;
+ return;
+ }
+
+ mGestureState = GestureActiveInContentArea;
+ QWindowSystemInterface::handleGestureEvent(window(), e.timestamp,
+ inputDevice->mTouchPadDevice,
+ Qt::BeginNativeGesture,
+ e.local, e.global, e.fingers);
+ break;
+ case Qt::GestureUpdated:
+ if (mGestureState != GestureActiveInContentArea)
+ return;
+
+ if (!e.delta.isNull()) {
+ QWindowSystemInterface::handleGestureEventWithValueAndDeltas(
+ window(), e.timestamp, inputDevice->mTouchPadDevice,
+ Qt::PanNativeGesture,
+ 0, QVector2D(e.delta), e.local, e.global, e.fingers);
+ }
+ break;
+ case Qt::GestureFinished:
+ case Qt::GestureCanceled:
+ if (mGestureState == GestureActiveInDecoration) {
+ mGestureState = GestureNotActive;
+ return;
+ }
+
+ if (mGestureState != GestureActiveInContentArea)
+ qCWarning(lcQpaWaylandInput) << "Unexpected gesture state. Gestures will act weird.";
+
+ mGestureState = GestureNotActive;
+
+ // There's currently no way to expose cancelled gestures to the rest of Qt, so
+ // this part of information is lost.
+ QWindowSystemInterface::handleGestureEvent(window(), e.timestamp,
+ inputDevice->mTouchPadDevice,
+ Qt::EndNativeGesture,
+ e.local, e.global, e.fingers);
+ break;
+ default:
+ break;
+ }
+}
+
+void QWaylandWindow::handlePinchGesture(QWaylandInputDevice *inputDevice,
+ const QWaylandPointerGesturePinchEvent &e)
+{
+ switch (e.state) {
+ case Qt::GestureStarted:
+ if (mGestureState != GestureNotActive)
+ qCWarning(lcQpaWaylandInput) << "Unexpected gesture state. Gestures will act weird.";
+
+ if (mWindowDecoration && !mMouseEventsInContentArea) {
+ // whole gesture sequence will be ignored
+ mGestureState = GestureActiveInDecoration;
+ return;
+ }
+
+ mGestureState = GestureActiveInContentArea;
+ QWindowSystemInterface::handleGestureEvent(window(), e.timestamp,
+ inputDevice->mTouchPadDevice,
+ Qt::BeginNativeGesture,
+ e.local, e.global, e.fingers);
+ break;
+ case Qt::GestureUpdated:
+ if (mGestureState != GestureActiveInContentArea)
+ return;
+
+ if (!e.delta.isNull()) {
+ QWindowSystemInterface::handleGestureEventWithValueAndDeltas(
+ window(), e.timestamp, inputDevice->mTouchPadDevice,
+ Qt::PanNativeGesture,
+ 0, QVector2D(e.delta), e.local, e.global, e.fingers);
+ }
+ if (e.rotation_delta != 0) {
+ QWindowSystemInterface::handleGestureEventWithRealValue(window(), e.timestamp,
+ inputDevice->mTouchPadDevice,
+ Qt::RotateNativeGesture,
+ e.rotation_delta,
+ e.local, e.global, e.fingers);
+ }
+ if (e.scale_delta != 0) {
+ QWindowSystemInterface::handleGestureEventWithRealValue(window(), e.timestamp,
+ inputDevice->mTouchPadDevice,
+ Qt::ZoomNativeGesture,
+ e.scale_delta,
+ e.local, e.global, e.fingers);
+ }
+ break;
+ case Qt::GestureFinished:
+ case Qt::GestureCanceled:
+ if (mGestureState == GestureActiveInDecoration) {
+ mGestureState = GestureNotActive;
+ return;
+ }
+
+ if (mGestureState != GestureActiveInContentArea)
+ qCWarning(lcQpaWaylandInput) << "Unexpected gesture state. Gestures will act weird.";
+
+ mGestureState = GestureNotActive;
+
+ // There's currently no way to expose cancelled gestures to the rest of Qt, so
+ // this part of information is lost.
+ QWindowSystemInterface::handleGestureEvent(window(), e.timestamp,
+ inputDevice->mTouchPadDevice,
+ Qt::EndNativeGesture,
+ e.local, e.global, e.fingers);
+ break;
+ default:
+ break;
+ }
+}
+#endif // #ifndef QT_NO_GESTURES
+
+
bool QWaylandWindow::touchDragDecoration(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods)
{
if (!mWindowDecoration)
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index 314294fcf..09411792e 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -83,6 +83,8 @@ class QWaylandInputDevice;
class QWaylandScreen;
class QWaylandShmBackingStore;
class QWaylandPointerEvent;
+class QWaylandPointerGestureSwipeEvent;
+class QWaylandPointerGesturePinchEvent;
class QWaylandSurface;
class Q_WAYLAND_CLIENT_EXPORT QWaylandWindow : public QObject, public QPlatformWindow
@@ -177,6 +179,12 @@ public:
QWaylandAbstractDecoration *decoration() const;
void handleMouse(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e);
+#ifndef QT_NO_GESTURES
+ void handleSwipeGesture(QWaylandInputDevice *inputDevice,
+ const QWaylandPointerGestureSwipeEvent &e);
+ void handlePinchGesture(QWaylandInputDevice *inputDevice,
+ const QWaylandPointerGesturePinchEvent &e);
+#endif
bool touchDragDecoration(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global,
Qt::TouchPointState state, Qt::KeyboardModifiers mods);
@@ -241,6 +249,23 @@ protected:
bool mMouseEventsInContentArea = false;
Qt::MouseButtons mMousePressedInContentArea = Qt::NoButton;
+#ifndef QT_NO_GESTURES
+ enum GestureState {
+ GestureNotActive,
+ GestureActiveInContentArea,
+ GestureActiveInDecoration
+ };
+
+ // We want gestures started in the decoration area to be completely ignored even if the mouse
+ // pointer is later moved to content area. Likewise, gestures started in the content area should
+ // keep sending events even if the mouse pointer is moved over the decoration (consider that
+ // the events for that gesture will be sent to us even if it's moved outside the window).
+ // So we track the gesture state and accept or ignore events based on that. Note that
+ // concurrent gestures of different types are not allowed in the protocol, so single state is
+ // enough
+ GestureState mGestureState = GestureNotActive;
+#endif
+
WId mWindowId;
bool mWaitingForFrameCallback = false;
bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out