diff --git a/input.cpp b/input.cpp index 3bad55b14b..93a7c445ce 100644 --- a/input.cpp +++ b/input.cpp @@ -326,6 +326,53 @@ public: } return true; } + bool pinchGestureBegin(int fingerCount, quint32 time) override { + Q_UNUSED(fingerCount) + Q_UNUSED(time) + // no touchpad multi-finger gestures on lock screen + return waylandServer()->isScreenLocked(); + } + bool pinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time) override { + Q_UNUSED(scale) + Q_UNUSED(angleDelta) + Q_UNUSED(delta) + Q_UNUSED(time) + // no touchpad multi-finger gestures on lock screen + return waylandServer()->isScreenLocked(); + } + bool pinchGestureEnd(quint32 time) override { + Q_UNUSED(time) + // no touchpad multi-finger gestures on lock screen + return waylandServer()->isScreenLocked(); + } + bool pinchGestureCancelled(quint32 time) override { + Q_UNUSED(time) + // no touchpad multi-finger gestures on lock screen + return waylandServer()->isScreenLocked(); + } + + bool swipeGestureBegin(int fingerCount, quint32 time) override { + Q_UNUSED(fingerCount) + Q_UNUSED(time) + // no touchpad multi-finger gestures on lock screen + return waylandServer()->isScreenLocked(); + } + bool swipeGestureUpdate(const QSizeF &delta, quint32 time) override { + Q_UNUSED(delta) + Q_UNUSED(time) + // no touchpad multi-finger gestures on lock screen + return waylandServer()->isScreenLocked(); + } + bool swipeGestureEnd(quint32 time) override { + Q_UNUSED(time) + // no touchpad multi-finger gestures on lock screen + return waylandServer()->isScreenLocked(); + } + bool swipeGestureCancelled(quint32 time) override { + Q_UNUSED(time) + // no touchpad multi-finger gestures on lock screen + return waylandServer()->isScreenLocked(); + } private: bool surfaceAllowed(KWayland::Server::SurfaceInterface *(KWayland::Server::SeatInterface::*method)() const) const { if (KWayland::Server::SurfaceInterface *s = (waylandServer()->seat()->*method)()) { @@ -978,6 +1025,79 @@ public: } return true; } + bool pinchGestureBegin(int fingerCount, quint32 time) override { + if (!workspace()) { + return false; + } + auto seat = waylandServer()->seat(); + seat->setTimestamp(time); + seat->startPointerPinchGesture(fingerCount); + return true; + } + bool pinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time) override { + if (!workspace()) { + return false; + } + auto seat = waylandServer()->seat(); + seat->setTimestamp(time); + seat->updatePointerPinchGesture(delta, scale, angleDelta); + return true; + } + bool pinchGestureEnd(quint32 time) override { + if (!workspace()) { + return false; + } + auto seat = waylandServer()->seat(); + seat->setTimestamp(time); + seat->endPointerPinchGesture(); + return true; + } + bool pinchGestureCancelled(quint32 time) override { + if (!workspace()) { + return false; + } + auto seat = waylandServer()->seat(); + seat->setTimestamp(time); + seat->cancelPointerPinchGesture(); + return true; + } + + bool swipeGestureBegin(int fingerCount, quint32 time) override { + if (!workspace()) { + return false; + } + auto seat = waylandServer()->seat(); + seat->setTimestamp(time); + seat->startPointerSwipeGesture(fingerCount); + return true; + } + bool swipeGestureUpdate(const QSizeF &delta, quint32 time) override { + if (!workspace()) { + return false; + } + auto seat = waylandServer()->seat(); + seat->setTimestamp(time); + seat->updatePointerSwipeGesture(delta); + return true; + } + bool swipeGestureEnd(quint32 time) override { + if (!workspace()) { + return false; + } + auto seat = waylandServer()->seat(); + seat->setTimestamp(time); + seat->endPointerSwipeGesture(); + return true; + } + bool swipeGestureCancelled(quint32 time) override { + if (!workspace()) { + return false; + } + auto seat = waylandServer()->seat(); + seat->setTimestamp(time); + seat->cancelPointerSwipeGesture(); + return true; + } }; class DragAndDropInputFilter : public InputEventFilter diff --git a/pointer_input.cpp b/pointer_input.cpp index 566ccc4494..5659631240 100644 --- a/pointer_input.cpp +++ b/pointer_input.cpp @@ -127,7 +127,13 @@ void PointerInputRedirection::init() connect(workspace(), &Workspace::stackingOrderChanged, this, &PointerInputRedirection::update); connect(screens(), &Screens::changed, this, &PointerInputRedirection::updateAfterScreenChange); if (waylandServer()->hasScreenLockerIntegration()) { - connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &PointerInputRedirection::update); + connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, + [this] { + waylandServer()->seat()->cancelPointerPinchGesture(); + waylandServer()->seat()->cancelPointerSwipeGesture(); + update(); + } + ); } connect(workspace(), &QObject::destroyed, this, [this] { m_inited = false; }); connect(waylandServer(), &QObject::destroyed, this, [this] { m_inited = false; }); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 357d0bbb4f..55f6c51ce5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -36,3 +36,7 @@ endif() add_executable(x11shadowreader x11shadowreader.cpp) target_link_libraries(x11shadowreader XCB::XCB Qt5::Widgets Qt5::X11Extras KF5::ConfigCore KF5::WindowSystem) + +add_executable(pointergestures pointergesturestest.cpp) +add_definitions(-DDIR="${CMAKE_CURRENT_SOURCE_DIR}") +target_link_libraries(pointergestures Qt5::Gui Qt5::Quick KF5::WaylandClient) diff --git a/tests/pointergesturestest.cpp b/tests/pointergesturestest.cpp new file mode 100644 index 0000000000..f096de7298 --- /dev/null +++ b/tests/pointergesturestest.cpp @@ -0,0 +1,168 @@ +/* + * Copyright 2016 Martin Gräßlin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace KWayland::Client; + +class PinchGesture : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(qreal scale READ scale NOTIFY scaleChanged) + Q_PROPERTY(qreal progressScale READ progressScale NOTIFY progressScaleChanged) + +public: + explicit PinchGesture(QQuickItem *parent = nullptr); + virtual ~PinchGesture(); + + qreal scale() const { + return m_scale; + } + + qreal progressScale() const { + return m_progressScale; + } + +protected: + void componentComplete() override; + +Q_SIGNALS: + void scaleChanged(); + void progressScaleChanged(); + +private: + void initWayland(); + void setupGesture(); + + Pointer *m_pointer = nullptr; + PointerGestures *m_pointerGestures = nullptr; + PointerPinchGesture *m_gesture = nullptr; + + qreal m_scale = 1.0; + qreal m_progressScale = 1.0; +}; + +PinchGesture::PinchGesture(QQuickItem* parent) + : QQuickItem(parent) +{ +} + +PinchGesture::~PinchGesture() = default; + +void PinchGesture::componentComplete() +{ + QQuickItem::componentComplete(); + initWayland(); +} + +void PinchGesture::initWayland() +{ + auto c = ConnectionThread::fromApplication(this); + Registry *r = new Registry(c); + r->create(c); + + connect(r, &Registry::interfacesAnnounced, this, + [this, r] { + const auto gi = r->interface(Registry::Interface::PointerGesturesUnstableV1); + if (gi.name == 0) { + return; + } + m_pointerGestures = r->createPointerGestures(gi.name, gi.version, this); + + // now create seat + const auto si = r->interface(Registry::Interface::Seat); + if (si.name == 0) { + return; + } + auto seat = r->createSeat(si.name, si.version, this); + connect(seat, &Seat::hasKeyboardChanged, this, + [this, seat] (bool hasPointer) { + if (hasPointer) { + m_pointer = seat->createPointer(this); + setupGesture(); + } else { + delete m_pointer; + delete m_gesture; + m_pointer = nullptr; + m_gesture = nullptr; + } + } + ); + } + ); + + r->setup(); + c->roundtrip(); +} + +void PinchGesture::setupGesture() +{ + if (m_gesture || !m_pointerGestures || !m_pointer) { + return; + } + m_gesture = m_pointerGestures->createPinchGesture(m_pointer, this); + connect(m_gesture, &PointerPinchGesture::updated, this, + [this] (const QSizeF &delta, qreal scale) { + Q_UNUSED(delta) + m_progressScale = scale; + emit progressScaleChanged(); + } + ); + connect(m_gesture, &PointerPinchGesture::ended, this, + [this] { + m_scale = m_scale * m_progressScale; + m_progressScale = 1.0; + emit scaleChanged(); + emit progressScaleChanged(); + } + ); + connect(m_gesture, &PointerPinchGesture::cancelled, this, + [this] { + m_progressScale = 1.0; + emit progressScaleChanged(); + } + ); +} + + +int main(int argc, char *argv[]) +{ + qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("wayland")); + QGuiApplication app(argc, argv); + + qmlRegisterType("org.kde.kwin.tests", 1, 0, "PinchGesture"); + + QQuickView view; + view.setSource(QUrl::fromLocalFile(QStringLiteral(DIR) +QStringLiteral("/pointergesturestest.qml"))); + + view.show(); + + return app.exec(); +} + +#include "pointergesturestest.moc" diff --git a/tests/pointergesturestest.qml b/tests/pointergesturestest.qml new file mode 100644 index 0000000000..96614c6f1d --- /dev/null +++ b/tests/pointergesturestest.qml @@ -0,0 +1,30 @@ +/* + * Copyright 2016 Martin Gräßlin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ +import QtQuick 2.0 +import org.kde.kwin.tests 1.0 + +Image { + source: "../48-apps-kwin.png" + scale: gesture.scale * gesture.progressScale + + PinchGesture { + id: gesture + } +} diff --git a/wayland_server.cpp b/wayland_server.cpp index bd40ddbe19..53771ee438 100644 --- a/wayland_server.cpp +++ b/wayland_server.cpp @@ -40,6 +40,7 @@ along with this program. If not, see . #include #include #include +#include #include #include #include @@ -184,6 +185,7 @@ bool WaylandServer::init(const QByteArray &socketName, InitalizationFlags flags) m_display->createShm(); m_seat = m_display->createSeat(m_display); m_seat->create(); + m_display->createPointerGestures(PointerGesturesInterfaceVersion::UnstableV1, m_display)->create(); auto ddm = m_display->createDataDeviceManager(m_display); ddm->create(); connect(ddm, &DataDeviceManagerInterface::dataDeviceCreated, this,