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
This commit is contained in:
parent
64ce6259a9
commit
e6aabf5b9f
7 changed files with 216 additions and 0 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
10
effects.cpp
10
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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ;
|
||||
|
|
|
@ -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;
|
||||
|
|
27
screenedge.h
27
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
|
||||
|
|
Loading…
Reference in a new issue