aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Gräßlin <[email protected]>2017-03-31 07:41:21 +0200
committerMartin Gräßlin <[email protected]>2017-04-07 16:16:34 +0200
commite6aabf5b9f7a653f2f624866ed2a53d60f754e82 (patch)
treef328102342b85d1376c2816a25e9087992b2a78e
parent64ce6259a92e63e610db459e7eddf9aeb6b6a159 (diff)
Add callback functionality for touch screen swipe gestures
Summary: This is implemented through QActions following the general approach inside KWin and not the older approach used by ScreenEdges for pointer callback activation. Test Plan: Extended auto test Reviewers: #kwin, #plasma Subscribers: plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D5263
-rw-r--r--autotests/mock_effectshandler.h2
-rw-r--r--autotests/test_screen_edges.cpp94
-rw-r--r--effects.cpp10
-rw-r--r--effects.h3
-rw-r--r--libkwineffects/kwineffects.h22
-rw-r--r--screenedge.cpp58
-rw-r--r--screenedge.h27
7 files changed, 216 insertions, 0 deletions
diff --git a/autotests/mock_effectshandler.h b/autotests/mock_effectshandler.h
index 1f6bb5b..8b96f18 100644
--- a/autotests/mock_effectshandler.h
+++ b/autotests/mock_effectshandler.h
@@ -181,6 +181,8 @@ public:
void reloadEffect(KWin::Effect *) override {}
void removeSupportProperty(const QByteArray &, KWin::Effect *) override {}
void reserveElectricBorder(KWin::ElectricBorder, KWin::Effect *) override {}
+ void registerTouchBorder(KWin::ElectricBorder, QAction *) override {}
+ void unregisterTouchBorder(KWin::ElectricBorder, QAction *) override {}
QPainter *scenePainter() override {
return nullptr;
}
diff --git a/autotests/test_screen_edges.cpp b/autotests/test_screen_edges.cpp
index 1e91df8..d68fa71 100644
--- a/autotests/test_screen_edges.cpp
+++ b/autotests/test_screen_edges.cpp
@@ -130,6 +130,8 @@ private Q_SLOTS:
void testFullScreenBlocking();
void testClientEdge();
void testTouchEdge();
+ void testTouchCallback_data();
+ void testTouchCallback();
};
void TestScreenEdges::initTestCase()
@@ -940,6 +942,98 @@ void TestScreenEdges::testTouchEdge()
}
+void TestScreenEdges::testTouchCallback_data()
+{
+ QTest::addColumn<KWin::ElectricBorder>("border");
+ QTest::addColumn<QPoint>("startPos");
+ QTest::addColumn<QSizeF>("delta");
+
+ QTest::newRow("left") << KWin::ElectricLeft << QPoint(0, 50) << QSizeF(250, 20);
+ QTest::newRow("top") << KWin::ElectricTop << QPoint(50, 0) << QSizeF(20, 250);
+ QTest::newRow("right") << KWin::ElectricRight << QPoint(99, 50) << QSizeF(-200, 0);
+ QTest::newRow("bottom") << KWin::ElectricBottom << QPoint(50, 99) << QSizeF(0, -200);
+}
+
+void TestScreenEdges::testTouchCallback()
+{
+ qRegisterMetaType<KWin::ElectricBorder>("ElectricBorder");
+ using namespace KWin;
+ auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
+ auto group = config->group("TouchEdges");
+ group.writeEntry("Top", "none");
+ group.writeEntry("Left", "none");
+ group.writeEntry("Bottom", "none");
+ group.writeEntry("Right", "none");
+ config->sync();
+
+ auto s = ScreenEdges::self();
+ s->setConfig(config);
+ s->init();
+
+ // none of our actions should be reserved
+ const QList<Edge*> edges = s->findChildren<Edge*>(QString(), Qt::FindDirectChildrenOnly);
+ QCOMPARE(edges.size(), 8);
+ for (auto e : edges) {
+ QCOMPARE(e->isReserved(), false);
+ QCOMPARE(e->activatesForPointer(), false);
+ QCOMPARE(e->activatesForTouchGesture(), false);
+ }
+
+ // let's reserve an action
+ QAction action;
+ QSignalSpy actionTriggeredSpy(&action, &QAction::triggered);
+ QVERIFY(actionTriggeredSpy.isValid());
+ QSignalSpy approachingSpy(s, &ScreenEdges::approaching);
+ QVERIFY(approachingSpy.isValid());
+
+ // reserve on edge
+ QFETCH(KWin::ElectricBorder, border);
+ s->reserveTouch(border, &action);
+ for (auto e : edges) {
+ QCOMPARE(e->isReserved(), e->border() == border);
+ QCOMPARE(e->activatesForPointer(), false);
+ QCOMPARE(e->activatesForTouchGesture(), e->border() == border);
+ }
+
+ QVERIFY(approachingSpy.isEmpty());
+ QFETCH(QPoint, startPos);
+ QCOMPARE(s->gestureRecognizer()->startSwipeGesture(startPos), 1);
+ QVERIFY(actionTriggeredSpy.isEmpty());
+ QCOMPARE(approachingSpy.count(), 1);
+ QFETCH(QSizeF, delta);
+ s->gestureRecognizer()->updateSwipeGesture(delta);
+ QCOMPARE(approachingSpy.count(), 2);
+ QVERIFY(actionTriggeredSpy.isEmpty());
+ s->gestureRecognizer()->endSwipeGesture();
+ QVERIFY(actionTriggeredSpy.wait());
+ QCOMPARE(actionTriggeredSpy.count(), 1);
+ QCOMPARE(approachingSpy.count(), 3);
+
+ // unreserve again
+ s->unreserveTouch(border, &action);
+ for (auto e : edges) {
+ QCOMPARE(e->isReserved(), false);
+ QCOMPARE(e->activatesForPointer(), false);
+ QCOMPARE(e->activatesForTouchGesture(), false);
+ }
+
+ // reserve another action
+ QScopedPointer<QAction> action2(new QAction);
+ s->reserveTouch(border, action2.data());
+ for (auto e : edges) {
+ QCOMPARE(e->isReserved(), e->border() == border);
+ QCOMPARE(e->activatesForPointer(), false);
+ QCOMPARE(e->activatesForTouchGesture(), e->border() == border);
+ }
+ // and unreserve by destroying
+ action2.reset();
+ for (auto e : edges) {
+ QCOMPARE(e->isReserved(), false);
+ QCOMPARE(e->activatesForPointer(), false);
+ QCOMPARE(e->activatesForTouchGesture(), false);
+ }
+}
+
Q_CONSTRUCTOR_FUNCTION(forceXcb)
QTEST_MAIN(TestScreenEdges)
#include "test_screen_edges.moc"
diff --git a/effects.cpp b/effects.cpp
index 1323f4d..3343cf1 100644
--- a/effects.cpp
+++ b/effects.cpp
@@ -1306,6 +1306,16 @@ void EffectsHandlerImpl::unreserveElectricBorder(ElectricBorder border, Effect *
ScreenEdges::self()->unreserve(border, effect);
}
+void EffectsHandlerImpl::registerTouchBorder(ElectricBorder border, QAction *action)
+{
+ ScreenEdges::self()->reserveTouch(border, action);
+}
+
+void EffectsHandlerImpl::unregisterTouchBorder(ElectricBorder border, QAction *action)
+{
+ ScreenEdges::self()->unreserveTouch(border, action);
+}
+
unsigned long EffectsHandlerImpl::xrenderBufferPicture()
{
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
diff --git a/effects.h b/effects.h
index 0720313..24fc9c9 100644
--- a/effects.h
+++ b/effects.h
@@ -172,6 +172,9 @@ public:
void reserveElectricBorder(ElectricBorder border, Effect *effect) override;
void unreserveElectricBorder(ElectricBorder border, Effect *effect) override;
+ void registerTouchBorder(ElectricBorder border, QAction *action) override;
+ void unregisterTouchBorder(ElectricBorder border, QAction *action) override;
+
unsigned long xrenderBufferPicture() override;
QPainter* scenePainter() override;
void reconfigure() override;
diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h
index 6ddff5a..d27fccc 100644
--- a/libkwineffects/kwineffects.h
+++ b/libkwineffects/kwineffects.h
@@ -897,6 +897,28 @@ public:
virtual void reserveElectricBorder(ElectricBorder border, Effect *effect) = 0;
virtual void unreserveElectricBorder(ElectricBorder border, Effect *effect) = 0;
+ /**
+ * Registers the given @p action for the given @p border to be activated through
+ * a touch swipe gesture.
+ *
+ * If the @p border gets triggered through a touch swipe gesture the @link{QAction::triggered}
+ * signal gets invoked.
+ *
+ * To unregister the touch screen action either delete the @p action or
+ * invoke @link{unregisterTouchBorder}.
+ *
+ * @see unregisterTouchBorder
+ * @since 5.10
+ **/
+ virtual void registerTouchBorder(ElectricBorder border, QAction *action) = 0;
+ /**
+ * Unregisters the given @p action for the given touch @p border.
+ *
+ * @see registerTouchBorder
+ * @since 5.10
+ **/
+ virtual void unregisterTouchBorder(ElectricBorder border, QAction *action) = 0;
+
// functions that allow controlling windows/desktop
virtual void activateWindow(KWin::EffectWindow* c) = 0;
virtual KWin::EffectWindow* activeWindow() const = 0 ;
diff --git a/screenedge.cpp b/screenedge.cpp
index c30b5e7..2a85a8b 100644
--- a/screenedge.cpp
+++ b/screenedge.cpp
@@ -48,6 +48,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// frameworks
#include <KConfigGroup>
// Qt
+#include <QAction>
#include <QMouseEvent>
#include <QSharedPointer>
#include <QTimer>
@@ -86,6 +87,7 @@ Edge::Edge(ScreenEdges *parent)
return;
}
handleTouchAction();
+ handleTouchCallback();
}, Qt::QueuedConnection
);
connect(m_gesture, &SwipeGesture::started, this, &Edge::startApproaching);
@@ -132,6 +134,29 @@ void Edge::reserve(QObject *object, const char *slot)
reserve();
}
+void Edge::reserveTouchCallBack(QAction *action)
+{
+ if (m_touchActions.contains(action)) {
+ return;
+ }
+ connect(action, &QAction::destroyed, this,
+ [this, action] {
+ unreserveTouchCallBack(action);
+ }
+ );
+ m_touchActions << action;
+ reserve();
+}
+
+void Edge::unreserveTouchCallBack(QAction *action)
+{
+ auto it = std::find_if(m_touchActions.begin(), m_touchActions.end(), [action] (QAction *a) { return a == action; });
+ if (it != m_touchActions.end()) {
+ m_touchActions.erase(it);
+ unreserve();
+ }
+}
+
void Edge::unreserve()
{
m_reserved--;
@@ -178,6 +203,9 @@ bool Edge::activatesForTouchGesture() const
if (m_touchAction != ElectricActionNone) {
return true;
}
+ if (!m_touchActions.isEmpty()) {
+ return true;
+ }
return false;
}
@@ -365,6 +393,14 @@ bool Edge::handleByCallback()
return false;
}
+void Edge::handleTouchCallback()
+{
+ if (m_touchActions.isEmpty()) {
+ return;
+ }
+ m_touchActions.first()->trigger();
+}
+
void Edge::switchDesktop(const QPoint &cursorPos)
{
QPoint pos(cursorPos);
@@ -1002,6 +1038,10 @@ void ScreenEdges::recreateEdges()
++callback) {
edge->reserve(callback.key(), callback.value().constData());
}
+ const auto touchCallBacks = oldEdge->touchCallBacks();
+ for (auto a : touchCallBacks) {
+ edge->reserveTouchCallBack(a);
+ }
}
}
qDeleteAll(oldEdges);
@@ -1188,6 +1228,24 @@ void ScreenEdges::reserve(AbstractClient *client, ElectricBorder border)
}
}
+void ScreenEdges::reserveTouch(ElectricBorder border, QAction *action)
+{
+ for (auto it = m_edges.begin(); it != m_edges.end(); ++it) {
+ if ((*it)->border() == border) {
+ (*it)->reserveTouchCallBack(action);
+ }
+ }
+}
+
+void ScreenEdges::unreserveTouch(ElectricBorder border, QAction *action)
+{
+ for (auto it = m_edges.begin(); it != m_edges.end(); ++it) {
+ if ((*it)->border() == border) {
+ (*it)->unreserveTouchCallBack(action);
+ }
+ }
+}
+
void ScreenEdges::createEdgeForClient(AbstractClient *client, ElectricBorder border)
{
int y = 0;
diff --git a/screenedge.h b/screenedge.h
index 6d398c3..779764c 100644
--- a/screenedge.h
+++ b/screenedge.h
@@ -39,6 +39,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QDateTime>
#include <QRect>
+class QAction;
class QMouseEvent;
namespace KWin {
@@ -69,6 +70,11 @@ public:
ElectricBorder border() const;
void reserve(QObject *object, const char *slot);
const QHash<QObject *, QByteArray> &callBacks() const;
+ void reserveTouchCallBack(QAction *action);
+ void unreserveTouchCallBack(QAction *action);
+ QVector<QAction *> touchCallBacks() const {
+ return m_touchActions;
+ }
void startApproaching();
void stopApproaching();
bool isApproaching() const;
@@ -128,6 +134,7 @@ private:
return handleAction(m_touchAction);
}
bool handleByCallback();
+ void handleTouchCallback();
void switchDesktop(const QPoint &cursorPos);
void pushCursorBack(const QPoint &cursorPos);
ScreenEdges *m_edges;
@@ -147,6 +154,7 @@ private:
bool m_pushBackBlocked;
AbstractClient *m_client;
SwipeGesture *m_gesture;
+ QVector<QAction *> m_touchActions;
};
/**
@@ -275,6 +283,25 @@ public:
* @param border The border which the client wants to use, only proper borders are supported (no corners)
**/
void reserve(KWin::AbstractClient *client, ElectricBorder border);
+
+ /**
+ * Mark the specified screen edge as reserved for touch gestures. This method is provided for
+ * external activation like effects and scripts.
+ * When the effect/script does no longer need the edge it is supposed
+ * to call @link unreserveTouch.
+ * @param border the screen edge to mark as reserved
+ * @param action The action which gets triggered
+ * @see unreserveTouch
+ * @since 5.10
+ **/
+ void reserveTouch(ElectricBorder border, QAction *action);
+ /**
+ * Unreserves the specified @p border from activating the @p action for touch gestures.
+ * @see reserveTouch
+ * @since 5.10
+ **/
+ void unreserveTouch(ElectricBorder border, QAction *action);
+
/**
* Reserve desktop switching for screen edges, if @p isToReserve is @c true. Unreserve otherwise.
* @param reserve indicated weather desktop switching should be reserved or unreseved