diff --git a/autotests/test_screen_edges.cpp b/autotests/test_screen_edges.cpp --- a/autotests/test_screen_edges.cpp +++ b/autotests/test_screen_edges.cpp @@ -21,6 +21,7 @@ #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 @@ void testPushBack(); void testFullScreenBlocking(); void testClientEdge(); + void testTouchEdge(); }; void TestScreenEdges::initTestCase() @@ -334,6 +336,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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.h b/screenedge.h --- a/screenedge.h +++ b/screenedge.h @@ -75,6 +75,10 @@ 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 @@ 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 @@ 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 @@ 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 @@ ElectricBorderAction m_actionBottom; ElectricBorderAction m_actionBottomLeft; ElectricBorderAction m_actionLeft; + QMap m_touchActions; int m_cornerOffset; GestureRecognizer *m_gestureRecognizer; @@ -457,11 +472,6 @@ return m_blocked; } -inline void Edge::setClient(AbstractClient *client) -{ - m_client = client; -} - inline AbstractClient *Edge::client() const { return m_client; diff --git a/screenedge.cpp b/screenedge.cpp --- a/screenedge.cpp +++ b/screenedge.cpp @@ -85,8 +85,7 @@ unreserve(); return; } - handleAction(); - handleByCallback(); + handleTouchAction(); }, Qt::QueuedConnection ); connect(m_gesture, &SwipeGesture::started, this, &Edge::startApproaching); @@ -100,6 +99,17 @@ } } ); + 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 @@ } } +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 @@ return; } - if (handleAction() || handleByCallback()) { + if (handlePointerAction() || handleByCallback()) { pushCursorBack(cursorPos); return; } @@ -253,9 +297,9 @@ } } -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 @@ } 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::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::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 @@ 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::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->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 @@ 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 @@ if (!edge->isReserved()) { continue; } + if (!edge->activatesForPointer()) { + continue; + } if (edge->approachGeometry().contains(event->globalPos())) { if (!edge->isApproaching()) { edge->startApproaching(); @@ -1245,6 +1368,9 @@ if (!edge->isReserved()) { continue; } + if (!edge->activatesForPointer()) { + continue; + } if (edge->window() == window) { if (edge->check(point, timestamp)) { if ((*it)->client()) {