diff --git a/autotests/test_screen_edges.cpp b/autotests/test_screen_edges.cpp
index e60856f8da..1e91df8534 100644
--- a/autotests/test_screen_edges.cpp
+++ b/autotests/test_screen_edges.cpp
@@ -21,6 +21,7 @@ along with this program. If not, see .
#include "../atoms.h"
#include "../cursor.h"
#include "../input.h"
+#include "../gestures.h"
#include "../main.h"
#include "../screenedge.h"
#include "../screens.h"
@@ -128,6 +129,7 @@ private Q_SLOTS:
void testPushBack();
void testFullScreenBlocking();
void testClientEdge();
+ void testTouchEdge();
};
void TestScreenEdges::initTestCase()
@@ -334,6 +336,8 @@ void TestScreenEdges::testCreatingInitialEdges()
QCOMPARE(edges.size(), 8);
for (auto e : edges) {
QVERIFY(e->isReserved());
+ QCOMPARE(e->activatesForPointer(), true);
+ QCOMPARE(e->activatesForTouchGesture(), false);
}
static_cast(screens())->setGeometries(QList{QRect{0, 0, 1024, 768}});
@@ -382,6 +386,8 @@ void TestScreenEdges::testCreatingInitialEdges()
for (int i = 0; i < 8; ++i) {
auto e = edges.at(i);
QVERIFY(!e->isReserved());
+ QCOMPARE(e->activatesForPointer(), false);
+ QCOMPARE(e->activatesForTouchGesture(), false);
QCOMPARE(e->approachGeometry(), expectedGeometries.at(i*2+1));
}
}
@@ -415,6 +421,8 @@ void TestScreenEdges::testCallback()
QCOMPARE(edges.size(), 10);
for (auto e: edges) {
QVERIFY(e->isReserved());
+ QCOMPARE(e->activatesForPointer(), true);
+ QCOMPARE(e->activatesForTouchGesture(), false);
}
auto it = std::find_if(edges.constBegin(), edges.constEnd(), [](Edge *e) {
return e->isScreenEdge() && e->isLeft() && e->approachGeometry().bottom() < 768;
@@ -523,6 +531,8 @@ void TestScreenEdges::testCallback()
s->unreserve(ElectricLeft, &callback);
for (auto e: s->findChildren(QString(), Qt::FindDirectChildrenOnly)) {
QVERIFY(!e->isReserved());
+ QCOMPARE(e->activatesForPointer(), false);
+ QCOMPARE(e->activatesForTouchGesture(), false);
}
}
@@ -739,6 +749,8 @@ void TestScreenEdges::testClientEdge()
QPointer edge = s->findChildren().last();
QCOMPARE(edge->isReserved(), true);
+ QCOMPARE(edge->activatesForPointer(), true);
+ QCOMPARE(edge->activatesForTouchGesture(), true);
//remove old reserves and resize to be in the middle of the screen
s->reserve(&client, KWin::ElectricNone);
@@ -844,6 +856,90 @@ void TestScreenEdges::testClientEdge()
QCOMPARE(Cursor::pos(), QPoint(1, 50));
}
+void TestScreenEdges::testTouchEdge()
+{
+ qRegisterMetaType("ElectricBorder");
+ using namespace KWin;
+ auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
+ auto group = config->group("TouchEdges");
+ group.writeEntry("Top", "krunner");
+ group.writeEntry("Left", "krunner");
+ group.writeEntry("Bottom", "krunner");
+ group.writeEntry("Right", "krunner");
+ config->sync();
+
+ auto s = ScreenEdges::self();
+ s->setConfig(config);
+ s->init();
+ // we don't have multiple desktops, so it's returning false
+ QCOMPARE(s->isDesktopSwitching(), false);
+ QCOMPARE(s->isDesktopSwitchingMovingClients(), false);
+ QCOMPARE(s->actionTopLeft(), ElectricBorderAction::ElectricActionNone);
+ QCOMPARE(s->actionTop(), ElectricBorderAction::ElectricActionNone);
+ QCOMPARE(s->actionTopRight(), ElectricBorderAction::ElectricActionNone);
+ QCOMPARE(s->actionRight(), ElectricBorderAction::ElectricActionNone);
+ QCOMPARE(s->actionBottomRight(), ElectricBorderAction::ElectricActionNone);
+ QCOMPARE(s->actionBottom(), ElectricBorderAction::ElectricActionNone);
+ QCOMPARE(s->actionBottomLeft(), ElectricBorderAction::ElectricActionNone);
+ QCOMPARE(s->actionLeft(), ElectricBorderAction::ElectricActionNone);
+
+ QList edges = s->findChildren(QString(), Qt::FindDirectChildrenOnly);
+ QCOMPARE(edges.size(), 8);
+ for (auto e : edges) {
+ QCOMPARE(e->isReserved(), e->isScreenEdge());
+ QCOMPARE(e->activatesForPointer(), false);
+ QCOMPARE(e->activatesForTouchGesture(), e->isScreenEdge());
+ }
+
+ // try to activate the edge through pointer, should not be possible
+ auto it = std::find_if(edges.constBegin(), edges.constEnd(), [](Edge *e) {
+ return e->isScreenEdge() && e->isLeft();
+ });
+ QVERIFY(it != edges.constEnd());
+
+ QSignalSpy approachingSpy(s, &ScreenEdges::approaching);
+ QVERIFY(approachingSpy.isValid());
+
+ xcb_enter_notify_event_t event;
+ auto setPos = [&event] (const QPoint &pos) {
+ Cursor::setPos(pos);
+ event.root_x = pos.x();
+ event.root_y = pos.y();
+ event.event_x = pos.x();
+ event.event_y = pos.y();
+ };
+ event.root = XCB_WINDOW_NONE;
+ event.child = XCB_WINDOW_NONE;
+ event.event = (*it)->window();
+ event.same_screen_focus = 1;
+ event.time = QDateTime::currentMSecsSinceEpoch();
+ setPos(QPoint(0, 50));
+ QCOMPARE(s->isEntered(&event), false);
+ QVERIFY(approachingSpy.isEmpty());
+
+ s->gestureRecognizer()->startSwipeGesture(QPoint(0, 50));
+ QCOMPARE(approachingSpy.count(), 1);
+ s->gestureRecognizer()->cancelSwipeGesture();
+ QCOMPARE(approachingSpy.count(), 2);
+
+ // let's reconfigure
+ group.writeEntry("Top", "none");
+ group.writeEntry("Left", "none");
+ group.writeEntry("Bottom", "none");
+ group.writeEntry("Right", "none");
+ config->sync();
+ s->reconfigure();
+
+ edges = s->findChildren(QString(), Qt::FindDirectChildrenOnly);
+ QCOMPARE(edges.size(), 8);
+ 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/screenedge.cpp b/screenedge.cpp
index 9eecbe6034..c30b5e7329 100644
--- a/screenedge.cpp
+++ b/screenedge.cpp
@@ -85,8 +85,7 @@ Edge::Edge(ScreenEdges *parent)
unreserve();
return;
}
- handleAction();
- handleByCallback();
+ handleTouchAction();
}, Qt::QueuedConnection
);
connect(m_gesture, &SwipeGesture::started, this, &Edge::startApproaching);
@@ -100,6 +99,17 @@ Edge::Edge(ScreenEdges *parent)
}
}
);
+ connect(this, &Edge::activatesForTouchGestureChanged, this,
+ [this] {
+ if (isReserved()) {
+ if (activatesForTouchGesture()) {
+ m_edges->gestureRecognizer()->registerGesture(m_gesture);
+ } else {
+ m_edges->gestureRecognizer()->unregisterGesture(m_gesture);
+ }
+ }
+ }
+ );
}
Edge::~Edge()
@@ -140,11 +150,45 @@ void Edge::unreserve(QObject *object)
}
}
+bool Edge::activatesForPointer() const
+{
+ if (m_client) {
+ return true;
+ }
+ if (m_edges->isDesktopSwitching()) {
+ return true;
+ }
+ if (!m_callBacks.isEmpty()) {
+ return true;
+ }
+ if (m_action != ElectricActionNone) {
+ return true;
+ }
+ return false;
+}
+
+bool Edge::activatesForTouchGesture() const
+{
+ if (!isScreenEdge()) {
+ return false;
+ }
+ if (m_client) {
+ return true;
+ }
+ if (m_touchAction != ElectricActionNone) {
+ return true;
+ }
+ return false;
+}
+
bool Edge::triggersFor(const QPoint &cursorPos) const
{
if (isBlocked()) {
return false;
}
+ if (!activatesForPointer()) {
+ return false;
+ }
if (!m_geometry.contains(cursorPos)) {
return false;
}
@@ -243,7 +287,7 @@ void Edge::handle(const QPoint &cursorPos)
return;
}
- if (handleAction() || handleByCallback()) {
+ if (handlePointerAction() || handleByCallback()) {
pushCursorBack(cursorPos);
return;
}
@@ -253,9 +297,9 @@ void Edge::handle(const QPoint &cursorPos)
}
}
-bool Edge::handleAction()
+bool Edge::handleAction(ElectricBorderAction action)
{
- switch (m_action) {
+ switch (action) {
case ElectricActionShowDesktop: {
Workspace::self()->setShowingDesktop(!Workspace::self()->showingDesktop());
return true;
@@ -439,6 +483,11 @@ void Edge::setGeometry(const QRect &geometry)
}
m_approachGeometry = QRect(x, y, width, height);
doGeometryUpdate();
+
+ if (isScreenEdge()) {
+ m_gesture->setStartGeometry(m_geometry);
+ m_gesture->setMinimumDelta(screens()->size(screens()->number(m_geometry.center())) * 0.2);
+ }
}
void Edge::checkBlocking()
@@ -463,15 +512,11 @@ 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()) {
+ if (activatesForTouchGesture()) {
m_edges->gestureRecognizer()->registerGesture(m_gesture);
}
doActivate();
@@ -597,6 +642,23 @@ void Edge::setBorder(ElectricBorder border)
}
}
+void Edge::setTouchAction(ElectricBorderAction action) {
+ const bool wasTouch = activatesForTouchGesture();
+ m_touchAction = action;
+ if (wasTouch != activatesForTouchGesture()) {
+ emit activatesForTouchGestureChanged();
+ }
+}
+
+void Edge::setClient(AbstractClient *client)
+{
+ const bool wasTouch = activatesForTouchGesture();
+ m_client = client;
+ if (wasTouch != activatesForTouchGesture()) {
+ emit activatesForTouchGestureChanged();
+ }
+}
+
/**********************************************************
* ScreenEdges
*********************************************************/
@@ -693,6 +755,12 @@ void ScreenEdges::reconfigure()
electricBorderAction(borderConfig.readEntry("BottomLeft", "None")));
setActionForBorder(ElectricLeft, &m_actionLeft,
electricBorderAction(borderConfig.readEntry("Left", "None")));
+
+ borderConfig = m_config->group("TouchEdges");
+ setActionForTouchBorder(ElectricTop, electricBorderAction(borderConfig.readEntry("Top", "None")));
+ setActionForTouchBorder(ElectricRight, electricBorderAction(borderConfig.readEntry("Right", "None")));
+ setActionForTouchBorder(ElectricBottom, electricBorderAction(borderConfig.readEntry("Bottom", "None")));
+ setActionForTouchBorder(ElectricLeft, electricBorderAction(borderConfig.readEntry("Left", "None")));
}
void ScreenEdges::setActionForBorder(ElectricBorder border, ElectricBorderAction *oldValue, ElectricBorderAction newValue)
@@ -725,6 +793,44 @@ void ScreenEdges::setActionForBorder(ElectricBorder border, ElectricBorderAction
}
}
+void ScreenEdges::setActionForTouchBorder(ElectricBorder border, ElectricBorderAction newValue)
+{
+ auto it = m_touchActions.find(border);
+ ElectricBorderAction oldValue = ElectricActionNone;
+ if (it != m_touchActions.constEnd()) {
+ oldValue = it.value();
+ }
+ if (oldValue == newValue) {
+ return;
+ }
+ if (oldValue == ElectricActionNone) {
+ // have to reserve
+ for (auto it = m_edges.begin(); it != m_edges.end(); ++it) {
+ if ((*it)->border() == border) {
+ (*it)->reserve();
+ }
+ }
+ }
+ if (newValue == ElectricActionNone) {
+ // have to unreserve
+ for (auto it = m_edges.begin(); it != m_edges.end(); ++it) {
+ if ((*it)->border() == border) {
+ (*it)->unreserve();
+ }
+ }
+
+ m_touchActions.erase(it);
+ } else {
+ m_touchActions.insert(border, newValue);
+ }
+ // update action on all Edges for given border
+ for (auto it = m_edges.begin(); it != m_edges.end(); ++it) {
+ if ((*it)->border() == border) {
+ (*it)->setTouchAction(newValue);
+ }
+ }
+}
+
void ScreenEdges::updateLayout()
{
const QSize desktopMatrix = VirtualDesktopManager::self()->grid().size();
@@ -963,6 +1069,11 @@ Edge *ScreenEdges::createEdge(ElectricBorder border, int x, int y, int width, in
edge->reserve();
edge->setAction(action);
}
+ const ElectricBorderAction touchAction = actionForTouchEdge(edge);
+ if (touchAction != KWin::ElectricActionNone) {
+ edge->reserve();
+ edge->setTouchAction(touchAction);
+ }
}
if (isDesktopSwitching()) {
if (edge->isCorner()) {
@@ -1009,6 +1120,15 @@ ElectricBorderAction ScreenEdges::actionForEdge(Edge *edge) const
return ElectricActionNone;
}
+ElectricBorderAction ScreenEdges::actionForTouchEdge(Edge *edge) const
+{
+ auto it = m_touchActions.find(edge->border());
+ if (it != m_touchActions.end()) {
+ return it.value();
+ }
+ return ElectricActionNone;
+}
+
void ScreenEdges::reserveDesktopSwitching(bool isToReserve, Qt::Orientations o)
{
if (!o)
@@ -1204,6 +1324,9 @@ bool ScreenEdges::isEntered(QMouseEvent *event)
if (!edge->isReserved()) {
continue;
}
+ if (!edge->activatesForPointer()) {
+ continue;
+ }
if (edge->approachGeometry().contains(event->globalPos())) {
if (!edge->isApproaching()) {
edge->startApproaching();
@@ -1245,6 +1368,9 @@ bool ScreenEdges::handleEnterNotifiy(xcb_window_t window, const QPoint &point, c
if (!edge->isReserved()) {
continue;
}
+ if (!edge->activatesForPointer()) {
+ continue;
+ }
if (edge->window() == window) {
if (edge->check(point, timestamp)) {
if ((*it)->client()) {
diff --git a/screenedge.h b/screenedge.h
index a65183b79b..6d398c35a0 100644
--- a/screenedge.h
+++ b/screenedge.h
@@ -75,6 +75,10 @@ public:
void setClient(AbstractClient *client);
AbstractClient *client() const;
const QRect &geometry() const;
+ void setTouchAction(ElectricBorderAction action);
+
+ bool activatesForPointer() const;
+ bool activatesForTouchGesture() const;
/**
* The window id of the native window representing the edge.
@@ -100,6 +104,7 @@ public Q_SLOTS:
void checkBlocking();
Q_SIGNALS:
void approaching(ElectricBorder border, qreal factor, const QRect &geometry);
+ void activatesForTouchGestureChanged();
protected:
ScreenEdges *edges();
const ScreenEdges *edges() const;
@@ -115,13 +120,20 @@ private:
void deactivate();
bool canActivate(const QPoint &cursorPos, const QDateTime &triggerTime);
void handle(const QPoint &cursorPos);
- bool handleAction();
+ bool handleAction(ElectricBorderAction action);
+ bool handlePointerAction() {
+ return handleAction(m_action);
+ }
+ bool handleTouchAction() {
+ return handleAction(m_touchAction);
+ }
bool handleByCallback();
void switchDesktop(const QPoint &cursorPos);
void pushCursorBack(const QPoint &cursorPos);
ScreenEdges *m_edges;
ElectricBorder m_border;
ElectricBorderAction m_action;
+ ElectricBorderAction m_touchAction = ElectricActionNone;
int m_reserved;
QRect m_geometry;
QRect m_approachGeometry;
@@ -345,7 +357,9 @@ private:
void createVerticalEdge(ElectricBorder border, const QRect &screen, const QRect &fullArea);
Edge *createEdge(ElectricBorder border, int x, int y, int width, int height, bool createAction = true);
void setActionForBorder(ElectricBorder border, ElectricBorderAction *oldValue, ElectricBorderAction newValue);
+ void setActionForTouchBorder(ElectricBorder border, ElectricBorderAction newValue);
ElectricBorderAction actionForEdge(Edge *edge) const;
+ ElectricBorderAction actionForTouchEdge(Edge *edge) const;
bool handleEnterNotifiy(xcb_window_t window, const QPoint &point, const QDateTime ×tamp);
bool handleDndNotify(xcb_window_t window, const QPoint &point);
void createEdgeForClient(AbstractClient *client, ElectricBorder border);
@@ -366,6 +380,7 @@ private:
ElectricBorderAction m_actionBottom;
ElectricBorderAction m_actionBottomLeft;
ElectricBorderAction m_actionLeft;
+ QMap m_touchActions;
int m_cornerOffset;
GestureRecognizer *m_gestureRecognizer;
@@ -457,11 +472,6 @@ inline bool Edge::isBlocked() const
return m_blocked;
}
-inline void Edge::setClient(AbstractClient *client)
-{
- m_client = client;
-}
-
inline AbstractClient *Edge::client() const
{
return m_client;