Send hoverLeave or hoverMotion after touch up on decoration

Summary:
On touch down a first hover motion is sent to the decoration. Thus e.g. a
button enters the hovered state. On touch release so far the decoration
did not get a leave event resulting in the button still being hovered.

This change ensures the leave event is sent or if the pointer is also on
the decoration a motion to the pointer position is sent.

BUG: 386231
FIXED-IN: 5.12.3

Test Plan:
New test case and manual testing to verify that the maximize
button is no longer hovered after touch down/up on it

Reviewers: #kwin, #plasma

Subscribers: plasma-devel, kwin

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D10308
icc-effect-5.14.5
Martin Flöser 2018-02-04 21:21:54 +01:00
parent 5795fc8cc0
commit 911176a887
3 changed files with 88 additions and 1 deletions

View File

@ -76,6 +76,8 @@ private Q_SLOTS:
void testModifierClickUnrestrictedMove();
void testModifierScrollOpacity_data();
void testModifierScrollOpacity();
void testTouchEvents_data();
void testTouchEvents();
private:
AbstractClient *showWindow(Test::ShellSurfaceType type);
@ -757,6 +759,81 @@ void DecorationInputTest::testModifierScrollOpacity()
}
}
void DecorationInputTest::testTouchEvents_data()
{
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell;
QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5;
QTest::newRow("xdgShellV6") << Test::ShellSurfaceType::XdgShellV6;
}
class EventHelper : public QObject
{
Q_OBJECT
public:
EventHelper() : QObject() {}
~EventHelper() override = default;
bool eventFilter(QObject *watched, QEvent *event) override
{
Q_UNUSED(watched)
if (event->type() == QEvent::HoverMove) {
emit hoverMove();
} else if (event->type() == QEvent::HoverLeave) {
emit hoverLeave();
}
return false;
}
Q_SIGNALS:
void hoverMove();
void hoverLeave();
};
void DecorationInputTest::testTouchEvents()
{
// this test verifies that the decoration gets a hover leave event on touch release
// see BUG 386231
QFETCH(Test::ShellSurfaceType, type);
AbstractClient *c = showWindow(type);
QVERIFY(c);
QVERIFY(c->isDecorated());
QVERIFY(!c->noBorder());
EventHelper helper;
c->decoration()->installEventFilter(&helper);
QSignalSpy hoverMoveSpy(&helper, &EventHelper::hoverMove);
QVERIFY(hoverMoveSpy.isValid());
QSignalSpy hoverLeaveSpy(&helper, &EventHelper::hoverLeave);
QVERIFY(hoverLeaveSpy.isValid());
quint32 timestamp = 1;
const QPoint tapPoint(c->geometry().center().x(), c->clientPos().y() / 2);
QVERIFY(!input()->touch()->decoration());
kwinApp()->platform()->touchDown(0, tapPoint, timestamp++);
QVERIFY(input()->touch()->decoration());
QCOMPARE(input()->touch()->decoration()->decoration(), c->decoration());
QCOMPARE(hoverMoveSpy.count(), 1);
QCOMPARE(hoverLeaveSpy.count(), 0);
kwinApp()->platform()->touchUp(0, timestamp++);
QCOMPARE(hoverMoveSpy.count(), 1);
QCOMPARE(hoverLeaveSpy.count(), 1);
QCOMPARE(c->isMove(), false);
// let's check that a hover motion is sent if the pointer is on deco, when touch release
Cursor::setPos(tapPoint);
QCOMPARE(hoverMoveSpy.count(), 2);
kwinApp()->platform()->touchDown(0, tapPoint, timestamp++);
QCOMPARE(hoverMoveSpy.count(), 3);
QCOMPARE(hoverLeaveSpy.count(), 1);
kwinApp()->platform()->touchUp(0, timestamp++);
QCOMPARE(hoverMoveSpy.count(), 4);
QCOMPARE(hoverLeaveSpy.count(), 1);
}
}
WAYLANDTEST_MAIN(KWin::DecorationInputTest)

View File

@ -560,7 +560,7 @@ void QuickTilingTest::testQuickTilingTouchMoveXdgShell()
QCOMPARE(quickTileChangedSpy.count(), 1);
QTEST(c->quickTileMode(), "expectedMode");
QVERIFY(configureRequestedSpy.wait());
QCOMPARE(configureRequestedSpy.count(), 5);
QTRY_COMPARE(configureRequestedSpy.count(), 5);
QCOMPARE(false, configureRequestedSpy.last().first().toSize().isEmpty());
}

View File

@ -1130,6 +1130,16 @@ public:
e.setAccepted(false);
QCoreApplication::sendEvent(decoration->decoration(), &e);
decoration->client()->processDecorationButtonRelease(&e);
if (input()->pointer()->decoration() == decoration) {
// send motion to current pointer position
const QPointF p = input()->pointer()->pos() - decoration->client()->pos();
QHoverEvent event(QEvent::HoverMove, p, p);
QCoreApplication::instance()->sendEvent(decoration->decoration(), &event);
} else {
// send leave
QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF());
QCoreApplication::instance()->sendEvent(decoration->decoration(), &event);
}
}
m_lastGlobalTouchPos = QPointF();