diff options
-rw-r--r-- | src/client/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/client/qwaylanddisplay.cpp | 3 | ||||
-rw-r--r-- | src/client/qwaylanddisplay_p.h | 3 | ||||
-rw-r--r-- | src/client/qwaylandinputdevice.cpp | 38 | ||||
-rw-r--r-- | src/client/qwaylandinputdevice_p.h | 71 | ||||
-rw-r--r-- | src/client/qwaylandpointergestures.cpp | 222 | ||||
-rw-r--r-- | src/client/qwaylandpointergestures_p.h | 150 | ||||
-rw-r--r-- | src/client/qwaylandwindow.cpp | 127 | ||||
-rw-r--r-- | src/client/qwaylandwindow_p.h | 25 |
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 |