diff --git a/autotests/integration/decoration_input_test.cpp b/autotests/integration/decoration_input_test.cpp index 85d22e243e..e15c716e6a 100644 --- a/autotests/integration/decoration_input_test.cpp +++ b/autotests/integration/decoration_input_test.cpp @@ -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("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) diff --git a/autotests/integration/internal_window.cpp b/autotests/integration/internal_window.cpp index f67da3faaa..9a2407c8ba 100644 --- a/autotests/integration/internal_window.cpp +++ b/autotests/integration/internal_window.cpp @@ -211,6 +211,7 @@ void InternalWindowTest::testEnterLeave() QVERIFY(!workspace()->activeClient()); ShellClient *c = clientAddedSpy.first().first().value(); QVERIFY(c->isInternal()); + QCOMPARE(c->icon().name(), QStringLiteral("wayland")); QCOMPARE(workspace()->findToplevel(&win), c); QCOMPARE(c->geometry(), QRect(0, 0, 100, 100)); QVERIFY(c->isShown(false)); diff --git a/autotests/integration/quick_tiling_test.cpp b/autotests/integration/quick_tiling_test.cpp index d3c5ea9827..20a7ed9bc7 100644 --- a/autotests/integration/quick_tiling_test.cpp +++ b/autotests/integration/quick_tiling_test.cpp @@ -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()); } diff --git a/autotests/integration/shell_client_test.cpp b/autotests/integration/shell_client_test.cpp index 373a5b66e4..5edf5b4b7c 100644 --- a/autotests/integration/shell_client_test.cpp +++ b/autotests/integration/shell_client_test.cpp @@ -162,6 +162,7 @@ void TestShellClient::testMapUnmapMap() QCOMPARE(client->readyForPainting(), true); QCOMPARE(client->depth(), 32); QVERIFY(client->hasAlpha()); + QCOMPARE(client->icon().name(), QStringLiteral("wayland")); QCOMPARE(workspace()->activeClient(), client); QVERIFY(effectsWindowShownSpy.isEmpty()); QVERIFY(client->isMaximizable()); diff --git a/input.cpp b/input.cpp index 0385d1dda9..221fb6e944 100644 --- a/input.cpp +++ b/input.cpp @@ -1126,6 +1126,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(); diff --git a/shell_client.cpp b/shell_client.cpp index 646be6aff2..f2e1a2ab31 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -197,6 +197,7 @@ void ShellClient::init() findInternalWindow(); createWindowId(); setupCompositing(); + updateIcon(); SurfaceInterface *s = surface(); Q_ASSERT(s); if (s->buffer()) {