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:
Martin Gräßlin 2017-03-19 11:40:03 +01:00
parent 22c91df2ec
commit aa6c8f8116
9 changed files with 513 additions and 16 deletions

View file

@ -281,6 +281,7 @@ set( testScreenEdges_SRCS
mock_screens.cpp
mock_workspace.cpp
../atoms.cpp
../gestures.cpp
../screens.cpp
../screenedge.cpp
../virtualdesktops.cpp

View file

@ -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");

View file

@ -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();

View file

@ -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;

View file

@ -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;
};
/**

View file

@ -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();

View file

@ -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();

View file

@ -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;

View file

@ -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;