Add support for activating screenedges through touch swipe gestures
Summary: Each Edge creates a SwipeGesture for touch activation. The swipe needs to be a single finger starting from the edge into the screen for at least 20 %. The SwipeGesture and GestureRecognizer is extended to support the use cases of the touch screen edge swipe. New features supported by the gesture system are: * minimum and maximum position * a minimum delta for the swipe * progress signal based on the minimum delta * starting a swipe with a start point The Edge has the progress signal connected to its approach signal, thus visual feedback is provided through the screen edge effect. The screen edge system supports touch only for the edges (corners are too difficult to activate on touch screens). At the moment the following features are supported: * screen edge show/raise of windows (e.g. auto hidden panels) * trigger the configured action * trigger the configured callback function (e.g. script) In future it might make sense to add a touch specific configuration action to support different actions for screen edges activated by mouse and touch. BUG: 370323 Test Plan: configured a screen edge and triggered through touch, added an auto-hiding panel and triggered through touch Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel Tags: #plasma_on_wayland Differential Revision: https://phabricator.kde.org/D5106
This commit is contained in:
parent
22c91df2ec
commit
aa6c8f8116
9 changed files with 513 additions and 16 deletions
|
@ -281,6 +281,7 @@ set( testScreenEdges_SRCS
|
|||
mock_screens.cpp
|
||||
mock_workspace.cpp
|
||||
../atoms.cpp
|
||||
../gestures.cpp
|
||||
../screens.cpp
|
||||
../screenedge.cpp
|
||||
../virtualdesktops.cpp
|
||||
|
|
|
@ -34,6 +34,18 @@ private Q_SLOTS:
|
|||
void testSwipeMaxFinger();
|
||||
void testDirection_data();
|
||||
void testDirection();
|
||||
void testMinimumX_data();
|
||||
void testMinimumX();
|
||||
void testMinimumY_data();
|
||||
void testMinimumY();
|
||||
void testMaximumX_data();
|
||||
void testMaximumX();
|
||||
void testMaximumY_data();
|
||||
void testMaximumY();
|
||||
void testStartGeometry();
|
||||
void testSetMinimumDelta();
|
||||
void testMinimumDeltaReached_data();
|
||||
void testMinimumDeltaReached();
|
||||
void testUnregisterSwipeCancels();
|
||||
void testDeleteSwipeCancels();
|
||||
void testSwipeCancel_data();
|
||||
|
@ -45,6 +57,8 @@ private Q_SLOTS:
|
|||
void testSwipeMinFingerStart();
|
||||
void testSwipeMaxFingerStart_data();
|
||||
void testSwipeMaxFingerStart();
|
||||
void testSwipeGeometryStart_data();
|
||||
void testSwipeGeometryStart();
|
||||
void testSwipeDiagonalCancels_data();
|
||||
void testSwipeDiagonalCancels();
|
||||
};
|
||||
|
@ -119,6 +133,178 @@ void GestureTest::testDirection()
|
|||
QCOMPARE(gesture.direction(), SwipeGesture::Direction::Down);
|
||||
}
|
||||
|
||||
void GestureTest::testMinimumX_data()
|
||||
{
|
||||
QTest::addColumn<int>("min");
|
||||
|
||||
QTest::newRow("0") << 0;
|
||||
QTest::newRow("-1") << -1;
|
||||
QTest::newRow("1") << 1;
|
||||
}
|
||||
|
||||
void GestureTest::testMinimumX()
|
||||
{
|
||||
SwipeGesture gesture;
|
||||
QCOMPARE(gesture.minimumX(), 0);
|
||||
QCOMPARE(gesture.minimumXIsRelevant(), false);
|
||||
QFETCH(int, min);
|
||||
gesture.setMinimumX(min);
|
||||
QCOMPARE(gesture.minimumX(), min);
|
||||
QCOMPARE(gesture.minimumXIsRelevant(), true);
|
||||
}
|
||||
|
||||
void GestureTest::testMinimumY_data()
|
||||
{
|
||||
QTest::addColumn<int>("min");
|
||||
|
||||
QTest::newRow("0") << 0;
|
||||
QTest::newRow("-1") << -1;
|
||||
QTest::newRow("1") << 1;
|
||||
}
|
||||
|
||||
void GestureTest::testMinimumY()
|
||||
{
|
||||
SwipeGesture gesture;
|
||||
QCOMPARE(gesture.minimumY(), 0);
|
||||
QCOMPARE(gesture.minimumYIsRelevant(), false);
|
||||
QFETCH(int, min);
|
||||
gesture.setMinimumY(min);
|
||||
QCOMPARE(gesture.minimumY(), min);
|
||||
QCOMPARE(gesture.minimumYIsRelevant(), true);
|
||||
}
|
||||
|
||||
void GestureTest::testMaximumX_data()
|
||||
{
|
||||
QTest::addColumn<int>("max");
|
||||
|
||||
QTest::newRow("0") << 0;
|
||||
QTest::newRow("-1") << -1;
|
||||
QTest::newRow("1") << 1;
|
||||
}
|
||||
|
||||
void GestureTest::testMaximumX()
|
||||
{
|
||||
SwipeGesture gesture;
|
||||
QCOMPARE(gesture.maximumX(), 0);
|
||||
QCOMPARE(gesture.maximumXIsRelevant(), false);
|
||||
QFETCH(int, max);
|
||||
gesture.setMaximumX(max);
|
||||
QCOMPARE(gesture.maximumX(), max);
|
||||
QCOMPARE(gesture.maximumXIsRelevant(), true);
|
||||
}
|
||||
|
||||
void GestureTest::testMaximumY_data()
|
||||
{
|
||||
QTest::addColumn<int>("max");
|
||||
|
||||
QTest::newRow("0") << 0;
|
||||
QTest::newRow("-1") << -1;
|
||||
QTest::newRow("1") << 1;
|
||||
}
|
||||
|
||||
void GestureTest::testMaximumY()
|
||||
{
|
||||
SwipeGesture gesture;
|
||||
QCOMPARE(gesture.maximumY(), 0);
|
||||
QCOMPARE(gesture.maximumYIsRelevant(), false);
|
||||
QFETCH(int, max);
|
||||
gesture.setMaximumY(max);
|
||||
QCOMPARE(gesture.maximumY(), max);
|
||||
QCOMPARE(gesture.maximumYIsRelevant(), true);
|
||||
}
|
||||
|
||||
void GestureTest::testStartGeometry()
|
||||
{
|
||||
SwipeGesture gesture;
|
||||
gesture.setStartGeometry(QRect(1, 2, 20, 30));
|
||||
QCOMPARE(gesture.minimumXIsRelevant(), true);
|
||||
QCOMPARE(gesture.minimumYIsRelevant(), true);
|
||||
QCOMPARE(gesture.maximumXIsRelevant(), true);
|
||||
QCOMPARE(gesture.maximumYIsRelevant(), true);
|
||||
QCOMPARE(gesture.minimumX(), 1);
|
||||
QCOMPARE(gesture.minimumY(), 2);
|
||||
QCOMPARE(gesture.maximumX(), 21);
|
||||
QCOMPARE(gesture.maximumY(), 32);
|
||||
}
|
||||
|
||||
void GestureTest::testSetMinimumDelta()
|
||||
{
|
||||
SwipeGesture gesture;
|
||||
QCOMPARE(gesture.isMinimumDeltaRelevant(), false);
|
||||
QCOMPARE(gesture.minimumDelta(), QSizeF());
|
||||
QCOMPARE(gesture.minimumDeltaReached(QSizeF()), true);
|
||||
gesture.setMinimumDelta(QSizeF(2, 3));
|
||||
QCOMPARE(gesture.isMinimumDeltaRelevant(), true);
|
||||
QCOMPARE(gesture.minimumDelta(), QSizeF(2, 3));
|
||||
QCOMPARE(gesture.minimumDeltaReached(QSizeF()), false);
|
||||
QCOMPARE(gesture.minimumDeltaReached(QSizeF(2, 3)), true);
|
||||
}
|
||||
|
||||
void GestureTest::testMinimumDeltaReached_data()
|
||||
{
|
||||
QTest::addColumn<KWin::SwipeGesture::Direction>("direction");
|
||||
QTest::addColumn<QSizeF>("minimumDelta");
|
||||
QTest::addColumn<QSizeF>("delta");
|
||||
QTest::addColumn<bool>("reached");
|
||||
QTest::addColumn<qreal>("progress");
|
||||
|
||||
QTest::newRow("Up (more)") << KWin::SwipeGesture::Direction::Up << QSizeF(0, -30) << QSizeF(0, -40) << true << 1.0;
|
||||
QTest::newRow("Up (exact)") << KWin::SwipeGesture::Direction::Up << QSizeF(0, -30) << QSizeF(0, -30) << true << 1.0;
|
||||
QTest::newRow("Up (less)") << KWin::SwipeGesture::Direction::Up << QSizeF(0, -30) << QSizeF(0, -29) << false << 29.0/30.0;
|
||||
QTest::newRow("Left (more)") << KWin::SwipeGesture::Direction::Left << QSizeF(-30, -30) << QSizeF(-40, 20) << true << 1.0;
|
||||
QTest::newRow("Left (exact)") << KWin::SwipeGesture::Direction::Left << QSizeF(-30, -40) << QSizeF(-30, 0) << true << 1.0;
|
||||
QTest::newRow("Left (less)") << KWin::SwipeGesture::Direction::Left << QSizeF(-30, -30) << QSizeF(-29, 0) << false << 29.0/30.0;
|
||||
QTest::newRow("Right (more)") << KWin::SwipeGesture::Direction::Right << QSizeF(30, -30) << QSizeF(40, 20) << true << 1.0;
|
||||
QTest::newRow("Right (exact)") << KWin::SwipeGesture::Direction::Right << QSizeF(30, -40) << QSizeF(30, 0) << true << 1.0;
|
||||
QTest::newRow("Right (less)") << KWin::SwipeGesture::Direction::Right << QSizeF(30, -30) << QSizeF(29, 0) << false << 29.0/30.0;
|
||||
QTest::newRow("Down (more)") << KWin::SwipeGesture::Direction::Down << QSizeF(0, 30) << QSizeF(0, 40) << true << 1.0;
|
||||
QTest::newRow("Down (exact)") << KWin::SwipeGesture::Direction::Down << QSizeF(0, 30) << QSizeF(0, 30) << true << 1.0;
|
||||
QTest::newRow("Down (less)") << KWin::SwipeGesture::Direction::Down << QSizeF(0, 30) << QSizeF(0, 29) << false << 29.0/30.0;
|
||||
}
|
||||
|
||||
void GestureTest::testMinimumDeltaReached()
|
||||
{
|
||||
SwipeGesture gesture;
|
||||
QFETCH(SwipeGesture::Direction, direction);
|
||||
gesture.setDirection(direction);
|
||||
QFETCH(QSizeF, minimumDelta);
|
||||
gesture.setMinimumDelta(minimumDelta);
|
||||
QFETCH(QSizeF, delta);
|
||||
QFETCH(bool, reached);
|
||||
QCOMPARE(gesture.minimumDeltaReached(delta), reached);
|
||||
|
||||
GestureRecognizer recognizer;
|
||||
recognizer.registerGesture(&gesture);
|
||||
|
||||
QSignalSpy startedSpy(&gesture, &SwipeGesture::started);
|
||||
QVERIFY(startedSpy.isValid());
|
||||
QSignalSpy triggeredSpy(&gesture, &SwipeGesture::triggered);
|
||||
QVERIFY(triggeredSpy.isValid());
|
||||
QSignalSpy cancelledSpy(&gesture, &SwipeGesture::cancelled);
|
||||
QVERIFY(cancelledSpy.isValid());
|
||||
QSignalSpy progressSpy(&gesture, &SwipeGesture::progress);
|
||||
QVERIFY(progressSpy.isValid());
|
||||
|
||||
recognizer.startSwipeGesture(1);
|
||||
QCOMPARE(startedSpy.count(), 1);
|
||||
QCOMPARE(triggeredSpy.count(), 0);
|
||||
QCOMPARE(cancelledSpy.count(), 0);
|
||||
QCOMPARE(progressSpy.count(), 0);
|
||||
|
||||
recognizer.updateSwipeGesture(delta);
|
||||
QCOMPARE(startedSpy.count(), 1);
|
||||
QCOMPARE(triggeredSpy.count(), 0);
|
||||
QCOMPARE(cancelledSpy.count(), 0);
|
||||
QCOMPARE(progressSpy.count(), 1);
|
||||
QTEST(progressSpy.first().first().value<qreal>(), "progress");
|
||||
|
||||
recognizer.endSwipeGesture();
|
||||
QCOMPARE(startedSpy.count(), 1);
|
||||
QCOMPARE(progressSpy.count(), 1);
|
||||
QCOMPARE(triggeredSpy.isEmpty(), !reached);
|
||||
QCOMPARE(cancelledSpy.isEmpty(), reached);
|
||||
}
|
||||
|
||||
void GestureTest::testUnregisterSwipeCancels()
|
||||
{
|
||||
GestureRecognizer recognizer;
|
||||
|
@ -219,12 +405,21 @@ void GestureTest::testSwipeUpdateCancel()
|
|||
QSignalSpy leftTriggeredSpy(&leftGesture, &SwipeGesture::triggered);
|
||||
QVERIFY(leftTriggeredSpy.isValid());
|
||||
|
||||
QSignalSpy upProgressSpy(&upGesture, &SwipeGesture::progress);
|
||||
QVERIFY(upProgressSpy.isValid());
|
||||
QSignalSpy downProgressSpy(&downGesture, &SwipeGesture::progress);
|
||||
QVERIFY(downProgressSpy.isValid());
|
||||
QSignalSpy leftProgressSpy(&leftGesture, &SwipeGesture::progress);
|
||||
QVERIFY(leftProgressSpy.isValid());
|
||||
QSignalSpy rightProgressSpy(&rightGesture, &SwipeGesture::progress);
|
||||
QVERIFY(rightProgressSpy.isValid());
|
||||
|
||||
recognizer.registerGesture(&upGesture);
|
||||
recognizer.registerGesture(&downGesture);
|
||||
recognizer.registerGesture(&rightGesture);
|
||||
recognizer.registerGesture(&leftGesture);
|
||||
|
||||
recognizer.startSwipeGesture(4);
|
||||
QCOMPARE(recognizer.startSwipeGesture(4), 4);
|
||||
|
||||
// first a down gesture
|
||||
recognizer.updateSwipeGesture(QSizeF(1, 20));
|
||||
|
@ -251,6 +446,11 @@ void GestureTest::testSwipeUpdateCancel()
|
|||
QCOMPARE(downTriggeredSpy.count(), 0);
|
||||
QCOMPARE(leftTriggeredSpy.count(), 0);
|
||||
QCOMPARE(rightTriggeredSpy.count(), 0);
|
||||
|
||||
QCOMPARE(upProgressSpy.count(), 0);
|
||||
QCOMPARE(downProgressSpy.count(), 0);
|
||||
QCOMPARE(leftProgressSpy.count(), 0);
|
||||
QCOMPARE(rightProgressSpy.count(), 0);
|
||||
}
|
||||
|
||||
void GestureTest::testSwipeUpdateTrigger_data()
|
||||
|
@ -343,6 +543,39 @@ void GestureTest::testSwipeMaxFingerStart()
|
|||
QTEST(!startedSpy.isEmpty(), "started");
|
||||
}
|
||||
|
||||
void GestureTest::testSwipeGeometryStart_data()
|
||||
{
|
||||
QTest::addColumn<QRect>("geometry");
|
||||
QTest::addColumn<QPointF>("startPos");
|
||||
QTest::addColumn<bool>("started");
|
||||
|
||||
QTest::newRow("top left") << QRect(0, 0, 10, 20) << QPointF(0, 0) << true;
|
||||
QTest::newRow("top right") << QRect(0, 0, 10, 20) << QPointF(10, 0) << true;
|
||||
QTest::newRow("bottom left") << QRect(0, 0, 10, 20) << QPointF(0, 20) << true;
|
||||
QTest::newRow("bottom right") << QRect(0, 0, 10, 20) << QPointF(10, 20) << true;
|
||||
QTest::newRow("x too small") << QRect(10, 20, 30, 40) << QPointF(9, 25) << false;
|
||||
QTest::newRow("y too small") << QRect(10, 20, 30, 40) << QPointF(25, 19) << false;
|
||||
QTest::newRow("x too large") << QRect(10, 20, 30, 40) << QPointF(41, 25) << false;
|
||||
QTest::newRow("y too large") << QRect(10, 20, 30, 40) << QPointF(25, 61) << false;
|
||||
QTest::newRow("inside") << QRect(10, 20, 30, 40) << QPointF(25, 25) << true;
|
||||
}
|
||||
|
||||
void GestureTest::testSwipeGeometryStart()
|
||||
{
|
||||
GestureRecognizer recognizer;
|
||||
SwipeGesture gesture;
|
||||
QFETCH(QRect, geometry);
|
||||
gesture.setStartGeometry(geometry);
|
||||
|
||||
QSignalSpy startedSpy(&gesture, &SwipeGesture::started);
|
||||
QVERIFY(startedSpy.isValid());
|
||||
|
||||
recognizer.registerGesture(&gesture);
|
||||
QFETCH(QPointF, startPos);
|
||||
recognizer.startSwipeGesture(startPos);
|
||||
QTEST(!startedSpy.isEmpty(), "started");
|
||||
}
|
||||
|
||||
void GestureTest::testSwipeDiagonalCancels_data()
|
||||
{
|
||||
QTest::addColumn<KWin::SwipeGesture::Direction>("direction");
|
||||
|
|
70
gestures.cpp
70
gestures.cpp
|
@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
*********************************************************************/
|
||||
#include "gestures.h"
|
||||
|
||||
#include <QSizeF>
|
||||
#include <QRect>
|
||||
#include <functional>
|
||||
|
||||
namespace KWin
|
||||
|
@ -39,6 +39,36 @@ SwipeGesture::SwipeGesture(QObject *parent)
|
|||
|
||||
SwipeGesture::~SwipeGesture() = default;
|
||||
|
||||
void SwipeGesture::setStartGeometry(const QRect &geometry)
|
||||
{
|
||||
setMinimumX(geometry.x());
|
||||
setMinimumY(geometry.y());
|
||||
setMaximumX(geometry.x() + geometry.width());
|
||||
setMaximumY(geometry.y() + geometry.height());
|
||||
}
|
||||
|
||||
qreal SwipeGesture::minimumDeltaReachedProgress(const QSizeF &delta) const
|
||||
{
|
||||
if (!m_minimumDeltaRelevant || m_minimumDelta.isNull()) {
|
||||
return 1.0;
|
||||
}
|
||||
switch (m_direction) {
|
||||
case Direction::Up:
|
||||
case Direction::Down:
|
||||
return std::min(std::abs(delta.height()) / std::abs(m_minimumDelta.height()), 1.0);
|
||||
case Direction::Left:
|
||||
case Direction::Right:
|
||||
return std::min(std::abs(delta.width()) / std::abs(m_minimumDelta.width()), 1.0);
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
bool SwipeGesture::minimumDeltaReached(const QSizeF &delta) const
|
||||
{
|
||||
return minimumDeltaReachedProgress(delta) >= 1.0;
|
||||
}
|
||||
|
||||
GestureRecognizer::GestureRecognizer(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
|
@ -67,8 +97,9 @@ void GestureRecognizer::unregisterGesture(KWin::Gesture* gesture)
|
|||
}
|
||||
}
|
||||
|
||||
void GestureRecognizer::startSwipeGesture(uint fingerCount)
|
||||
int GestureRecognizer::startSwipeGesture(uint fingerCount, const QPointF &startPos, StartPositionBehavior startPosBehavior)
|
||||
{
|
||||
int count = 0;
|
||||
// TODO: verify that no gesture is running
|
||||
for (Gesture *gesture : qAsConst(m_gestures)) {
|
||||
SwipeGesture *swipeGesture = qobject_cast<SwipeGesture*>(gesture);
|
||||
|
@ -85,10 +116,34 @@ void GestureRecognizer::startSwipeGesture(uint fingerCount)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if (startPosBehavior == StartPositionBehavior::Relevant) {
|
||||
if (swipeGesture->minimumXIsRelevant()) {
|
||||
if (swipeGesture->minimumX() > startPos.x()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (swipeGesture->maximumXIsRelevant()) {
|
||||
if (swipeGesture->maximumX() < startPos.x()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (swipeGesture->minimumYIsRelevant()) {
|
||||
if (swipeGesture->minimumY() > startPos.y()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (swipeGesture->maximumYIsRelevant()) {
|
||||
if (swipeGesture->maximumY() < startPos.y()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// direction doesn't matter yet
|
||||
m_activeSwipeGestures << swipeGesture;
|
||||
count++;
|
||||
emit swipeGesture->started();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void GestureRecognizer::updateSwipeGesture(const QSizeF &delta)
|
||||
|
@ -108,9 +163,13 @@ void GestureRecognizer::updateSwipeGesture(const QSizeF &delta)
|
|||
// vertical
|
||||
direction = delta.height() < 0 ? SwipeGesture::Direction::Up : SwipeGesture::Direction::Down;
|
||||
}
|
||||
const QSizeF combinedDelta = std::accumulate(m_swipeUpdates.constBegin(), m_swipeUpdates.constEnd(), QSizeF(0, 0));
|
||||
for (auto it = m_activeSwipeGestures.begin(); it != m_activeSwipeGestures.end();) {
|
||||
auto g = qobject_cast<SwipeGesture*>(*it);
|
||||
if (g->direction() == direction) {
|
||||
if (g->isMinimumDeltaRelevant()) {
|
||||
emit g->progress(g->minimumDeltaReachedProgress(combinedDelta));
|
||||
}
|
||||
it++;
|
||||
} else {
|
||||
emit g->cancelled();
|
||||
|
@ -135,8 +194,13 @@ void GestureRecognizer::cancelSwipeGesture()
|
|||
|
||||
void GestureRecognizer::endSwipeGesture()
|
||||
{
|
||||
const QSizeF delta = std::accumulate(m_swipeUpdates.constBegin(), m_swipeUpdates.constEnd(), QSizeF(0, 0));
|
||||
for (auto g : qAsConst(m_activeSwipeGestures)) {
|
||||
emit g->triggered();
|
||||
if (static_cast<SwipeGesture*>(g)->minimumDeltaReached(delta)) {
|
||||
emit g->triggered();
|
||||
} else {
|
||||
emit g->cancelled();
|
||||
}
|
||||
}
|
||||
m_activeSwipeGestures.clear();
|
||||
m_swipeUpdates.clear();
|
||||
|
|
88
gestures.h
88
gestures.h
|
@ -21,6 +21,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#define KWIN_GESTURES_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointF>
|
||||
#include <QSizeF>
|
||||
#include <QMap>
|
||||
#include <QVector>
|
||||
|
||||
|
@ -95,12 +97,86 @@ public:
|
|||
m_direction = direction;
|
||||
}
|
||||
|
||||
void setMinimumX(int x) {
|
||||
m_minimumX = x;
|
||||
m_minimumXRelevant = true;
|
||||
}
|
||||
int minimumX() const {
|
||||
return m_minimumX;
|
||||
}
|
||||
bool minimumXIsRelevant() const {
|
||||
return m_minimumXRelevant;
|
||||
}
|
||||
void setMinimumY(int y) {
|
||||
m_minimumY = y;
|
||||
m_minimumYRelevant = true;
|
||||
}
|
||||
int minimumY() const {
|
||||
return m_minimumY;
|
||||
}
|
||||
bool minimumYIsRelevant() const {
|
||||
return m_minimumYRelevant;
|
||||
}
|
||||
|
||||
void setMaximumX(int x) {
|
||||
m_maximumX = x;
|
||||
m_maximumXRelevant = true;
|
||||
}
|
||||
int maximumX() const {
|
||||
return m_maximumX;
|
||||
}
|
||||
bool maximumXIsRelevant() const {
|
||||
return m_maximumXRelevant;
|
||||
}
|
||||
void setMaximumY(int y) {
|
||||
m_maximumY = y;
|
||||
m_maximumYRelevant = true;
|
||||
}
|
||||
int maximumY() const {
|
||||
return m_maximumY;
|
||||
}
|
||||
bool maximumYIsRelevant() const {
|
||||
return m_maximumYRelevant;
|
||||
}
|
||||
void setStartGeometry(const QRect &geometry);
|
||||
|
||||
QSizeF minimumDelta() const {
|
||||
return m_minimumDelta;
|
||||
}
|
||||
void setMinimumDelta(const QSizeF &delta) {
|
||||
m_minimumDelta = delta;
|
||||
m_minimumDeltaRelevant = true;
|
||||
}
|
||||
bool isMinimumDeltaRelevant() const {
|
||||
return m_minimumDeltaRelevant;
|
||||
}
|
||||
|
||||
qreal minimumDeltaReachedProgress(const QSizeF &delta) const;
|
||||
bool minimumDeltaReached(const QSizeF &delta) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The progress of the gesture if a @link{minimumDelta} is set.
|
||||
* The progress is reported in [0.0,1.0]
|
||||
**/
|
||||
void progress(qreal);
|
||||
|
||||
private:
|
||||
bool m_minimumFingerCountRelevant = false;
|
||||
uint m_minimumFingerCount = 0;
|
||||
bool m_maximumFingerCountRelevant = false;
|
||||
uint m_maximumFingerCount = 0;
|
||||
Direction m_direction = Direction::Down;
|
||||
bool m_minimumXRelevant = false;
|
||||
int m_minimumX = 0;
|
||||
bool m_minimumYRelevant = false;
|
||||
int m_minimumY = 0;
|
||||
bool m_maximumXRelevant = false;
|
||||
int m_maximumX = 0;
|
||||
bool m_maximumYRelevant = false;
|
||||
int m_maximumY = 0;
|
||||
bool m_minimumDeltaRelevant = false;
|
||||
QSizeF m_minimumDelta;
|
||||
};
|
||||
|
||||
class GestureRecognizer : public QObject
|
||||
|
@ -113,13 +189,23 @@ public:
|
|||
void registerGesture(Gesture *gesture);
|
||||
void unregisterGesture(Gesture *gesture);
|
||||
|
||||
void startSwipeGesture(uint fingerCount);
|
||||
int startSwipeGesture(uint fingerCount) {
|
||||
return startSwipeGesture(fingerCount, QPointF(), StartPositionBehavior::Irrelevant);
|
||||
}
|
||||
int startSwipeGesture(const QPointF &startPos) {
|
||||
return startSwipeGesture(1, startPos, StartPositionBehavior::Relevant);
|
||||
}
|
||||
void updateSwipeGesture(const QSizeF &delta);
|
||||
void cancelSwipeGesture();
|
||||
void endSwipeGesture();
|
||||
|
||||
private:
|
||||
void cancelActiveSwipeGestures();
|
||||
enum class StartPositionBehavior {
|
||||
Relevant,
|
||||
Irrelevant
|
||||
};
|
||||
int startSwipeGesture(uint fingerCount, const QPointF &startPos, StartPositionBehavior startPosBehavior);
|
||||
QVector<Gesture*> m_gestures;
|
||||
QVector<Gesture*> m_activeSwipeGestures;
|
||||
QMap<Gesture*, QMetaObject::Connection> m_destroyConnections;
|
||||
|
|
41
input.cpp
41
input.cpp
|
@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "touch_input.h"
|
||||
#include "client.h"
|
||||
#include "effects.h"
|
||||
#include "gestures.h"
|
||||
#include "globalshortcuts.h"
|
||||
#include "logind.h"
|
||||
#include "main.h"
|
||||
|
@ -1047,6 +1048,46 @@ public:
|
|||
// always forward
|
||||
return false;
|
||||
}
|
||||
bool touchDown(quint32 id, const QPointF &pos, quint32 time) override {
|
||||
Q_UNUSED(time)
|
||||
// TODO: better check whether a touch sequence is in progess
|
||||
if (m_touchInProgress || waylandServer()->seat()->isTouchSequence()) {
|
||||
// cancel existing touch
|
||||
ScreenEdges::self()->gestureRecognizer()->cancelSwipeGesture();
|
||||
m_touchInProgress = false;
|
||||
m_id = 0;
|
||||
return false;
|
||||
}
|
||||
if (ScreenEdges::self()->gestureRecognizer()->startSwipeGesture(pos) > 0) {
|
||||
m_touchInProgress = true;
|
||||
m_id = id;
|
||||
m_lastPos = pos;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override {
|
||||
Q_UNUSED(time)
|
||||
if (m_touchInProgress && m_id == id) {
|
||||
ScreenEdges::self()->gestureRecognizer()->updateSwipeGesture(QSizeF(pos.x() - m_lastPos.x(), pos.y() - m_lastPos.y()));
|
||||
m_lastPos = pos;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool touchUp(quint32 id, quint32 time) override {
|
||||
Q_UNUSED(time)
|
||||
if (m_touchInProgress && m_id == id) {
|
||||
ScreenEdges::self()->gestureRecognizer()->endSwipeGesture();
|
||||
m_touchInProgress = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
bool m_touchInProgress = false;
|
||||
quint32 m_id = 0;
|
||||
QPointF m_lastPos;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,14 +44,14 @@ WindowBasedEdge::~WindowBasedEdge()
|
|||
{
|
||||
}
|
||||
|
||||
void WindowBasedEdge::activate()
|
||||
void WindowBasedEdge::doActivate()
|
||||
{
|
||||
createWindow();
|
||||
createApproachWindow();
|
||||
doUpdateBlocking();
|
||||
}
|
||||
|
||||
void WindowBasedEdge::deactivate()
|
||||
void WindowBasedEdge::doDeactivate()
|
||||
{
|
||||
m_window.reset();
|
||||
m_approachWindow.reset();
|
||||
|
|
|
@ -50,8 +50,8 @@ public:
|
|||
|
||||
protected:
|
||||
virtual void doGeometryUpdate();
|
||||
virtual void activate();
|
||||
virtual void deactivate();
|
||||
virtual void doActivate() override;
|
||||
virtual void doDeactivate() override;
|
||||
virtual void doStartApproaching();
|
||||
virtual void doStopApproaching();
|
||||
virtual void doUpdateBlocking();
|
||||
|
|
|
@ -31,6 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
// KWin
|
||||
#include "atoms.h"
|
||||
#include "gestures.h"
|
||||
#include <client.h>
|
||||
#include "cursor.h"
|
||||
#include "main.h"
|
||||
|
@ -72,7 +73,33 @@ Edge::Edge(ScreenEdges *parent)
|
|||
, m_blocked(false)
|
||||
, m_pushBackBlocked(false)
|
||||
, m_client(nullptr)
|
||||
, m_gesture(new SwipeGesture(this))
|
||||
{
|
||||
m_gesture->setMinimumFingerCount(1);
|
||||
m_gesture->setMaximumFingerCount(1);
|
||||
connect(m_gesture, &Gesture::triggered, this,
|
||||
[this] {
|
||||
stopApproaching();
|
||||
if (m_client) {
|
||||
m_client->showOnScreenEdge();
|
||||
unreserve();
|
||||
return;
|
||||
}
|
||||
handleAction();
|
||||
handleByCallback();
|
||||
}, Qt::QueuedConnection
|
||||
);
|
||||
connect(m_gesture, &SwipeGesture::started, this, &Edge::startApproaching);
|
||||
connect(m_gesture, &SwipeGesture::cancelled, this, &Edge::stopApproaching);
|
||||
connect(m_gesture, &SwipeGesture::progress, this,
|
||||
[this] (qreal progress) {
|
||||
int factor = progress * 256.0f;
|
||||
if (m_lastApproachingFactor != factor) {
|
||||
m_lastApproachingFactor = factor;
|
||||
emit approaching(border(), m_lastApproachingFactor/256.0f, m_approachGeometry);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Edge::~Edge()
|
||||
|
@ -436,13 +463,31 @@ void Edge::doUpdateBlocking()
|
|||
|
||||
void Edge::doGeometryUpdate()
|
||||
{
|
||||
if (isScreenEdge()) {
|
||||
m_gesture->setStartGeometry(m_geometry);
|
||||
m_gesture->setMinimumDelta(screens()->size(screens()->number(m_geometry.center())) * 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
void Edge::activate()
|
||||
{
|
||||
if (isScreenEdge() && !m_edges->isDesktopSwitching()) {
|
||||
m_edges->gestureRecognizer()->registerGesture(m_gesture);
|
||||
}
|
||||
doActivate();
|
||||
}
|
||||
|
||||
void Edge::doActivate()
|
||||
{
|
||||
}
|
||||
|
||||
void Edge::deactivate()
|
||||
{
|
||||
m_edges->gestureRecognizer()->unregisterGesture(m_gesture);
|
||||
doDeactivate();
|
||||
}
|
||||
|
||||
void Edge::doDeactivate()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -531,6 +576,27 @@ quint32 Edge::approachWindow() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Edge::setBorder(ElectricBorder border)
|
||||
{
|
||||
m_border = border;
|
||||
switch (m_border) {
|
||||
case ElectricTop:
|
||||
m_gesture->setDirection(SwipeGesture::Direction::Down);
|
||||
break;
|
||||
case ElectricRight:
|
||||
m_gesture->setDirection(SwipeGesture::Direction::Left);
|
||||
break;
|
||||
case ElectricBottom:
|
||||
m_gesture->setDirection(SwipeGesture::Direction::Up);
|
||||
break;
|
||||
case ElectricLeft:
|
||||
m_gesture->setDirection(SwipeGesture::Direction::Right);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
* ScreenEdges
|
||||
*********************************************************/
|
||||
|
@ -551,6 +617,7 @@ ScreenEdges::ScreenEdges(QObject *parent)
|
|||
, m_actionBottom(ElectricActionNone)
|
||||
, m_actionBottomLeft(ElectricActionNone)
|
||||
, m_actionLeft(ElectricActionNone)
|
||||
, m_gestureRecognizer(new GestureRecognizer(this))
|
||||
{
|
||||
QWidget w;
|
||||
m_cornerOffset = (w.physicalDpiX() + w.physicalDpiY() + 5) / 6;
|
||||
|
|
19
screenedge.h
19
screenedge.h
|
@ -44,7 +44,9 @@ class QMouseEvent;
|
|||
namespace KWin {
|
||||
|
||||
class AbstractClient;
|
||||
class GestureRecognizer;
|
||||
class ScreenEdges;
|
||||
class SwipeGesture;
|
||||
|
||||
class KWIN_EXPORT Edge : public QObject
|
||||
{
|
||||
|
@ -103,12 +105,14 @@ protected:
|
|||
const ScreenEdges *edges() const;
|
||||
bool isBlocked() const;
|
||||
virtual void doGeometryUpdate();
|
||||
virtual void activate();
|
||||
virtual void deactivate();
|
||||
virtual void doActivate();
|
||||
virtual void doDeactivate();
|
||||
virtual void doStartApproaching();
|
||||
virtual void doStopApproaching();
|
||||
virtual void doUpdateBlocking();
|
||||
private:
|
||||
void activate();
|
||||
void deactivate();
|
||||
bool canActivate(const QPoint &cursorPos, const QDateTime &triggerTime);
|
||||
void handle(const QPoint &cursorPos);
|
||||
bool handleAction();
|
||||
|
@ -130,6 +134,7 @@ private:
|
|||
bool m_blocked;
|
||||
bool m_pushBackBlocked;
|
||||
AbstractClient *m_client;
|
||||
SwipeGesture *m_gesture;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -304,6 +309,10 @@ public:
|
|||
ElectricBorderAction actionBottomLeft() const;
|
||||
ElectricBorderAction actionLeft() const;
|
||||
|
||||
GestureRecognizer *gestureRecognizer() const {
|
||||
return m_gestureRecognizer;
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
void reconfigure();
|
||||
/**
|
||||
|
@ -358,6 +367,7 @@ private:
|
|||
ElectricBorderAction m_actionBottomLeft;
|
||||
ElectricBorderAction m_actionLeft;
|
||||
int m_cornerOffset;
|
||||
GestureRecognizer *m_gestureRecognizer;
|
||||
|
||||
KWIN_SINGLETON(ScreenEdges)
|
||||
};
|
||||
|
@ -412,11 +422,6 @@ inline void Edge::setAction(ElectricBorderAction action)
|
|||
m_action = action;
|
||||
}
|
||||
|
||||
inline void Edge::setBorder(ElectricBorder border)
|
||||
{
|
||||
m_border = border;
|
||||
}
|
||||
|
||||
inline ScreenEdges *Edge::edges()
|
||||
{
|
||||
return m_edges;
|
||||
|
|
Loading…
Reference in a new issue