QQuickWidget: accept touchpoint even if it has a passive grab

In the test case from QTBUG-113558, a QQuickWidget's only event-handling
object is a TapHandler with its default gesturePolicy, so that on touch
press, it gets pressed; but it was missing the touch release and getting
stuck in pressed state.

As explained in dc8f44b145, widgets don't
care about (exclusive or passive) grabbers, and rely on points being
accepted to make the widget that received the TouchBegin an implicit
grabber. If the only thing that happened in the Qt Quick scene in the
QQuickWidget is that the touchpoint got a passive grab, it's still a
kind of interaction, and we want to ensure that the TapHandler will see
the release too, to avoid getting stuck. (This means that passive grabs
are not passive from the perspective of widget event delivery: the
TapHandler ends up excluding delivery of the touchpoint to other
widgets, even though it didn't mean to. But hopefully nobody expects
cooperation with touch-handling widgets underneath the Quick scene.)

Fixes: QTBUG-113558
Pick-to: 6.6 6.5
Change-Id: Ided6247b43a2405dbfdf9d195bb45ceae4cf58fd
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit 59b0b59090)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Shawn Rutledge 2024-01-04 00:07:05 -07:00 committed by Qt Cherry-pick Bot
parent 341e40077a
commit 9f85654f7d
3 changed files with 53 additions and 1 deletions

View File

@ -1665,7 +1665,7 @@ bool QQuickWidget::event(QEvent *e)
QPointerEvent *pointerEvent = static_cast<QPointerEvent *>(e);
auto deliveredPoints = pointerEvent->points();
for (auto &point : deliveredPoints) {
if (pointerEvent->exclusiveGrabber(point))
if (pointerEvent->exclusiveGrabber(point) || !pointerEvent->passiveGrabbers(point).isEmpty())
point.setAccepted(true);
}
}

View File

@ -0,0 +1,11 @@
import QtQuick
Rectangle {
width: 100
height: 100
color: th.pressed ? "steelblue" : "beige"
TapHandler {
id: th
}
}

View File

@ -11,6 +11,7 @@
#include <QtQuick/qquickitem.h>
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
#include <QtQuick/private/qquicktaphandler_p.h>
#include <QtQuickTemplates2/private/qquickbutton_p.h>
#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtGui/QWindow>
@ -128,6 +129,8 @@ private slots:
void synthMouseFromTouch();
void touchTapMouseArea();
void touchTapButton();
void touchTapHandler_data();
void touchTapHandler();
void touchMultipleWidgets();
void tabKey();
void resizeOverlay();
@ -682,6 +685,44 @@ void tst_qquickwidget::touchTapButton()
QTRY_VERIFY(rootItem->property("wasClicked").toBool());
}
void tst_qquickwidget::touchTapHandler_data()
{
QTest::addColumn<bool>("guiSynthMouse"); // AA_SynthesizeMouseForUnhandledTouchEvents
QTest::addColumn<QQuickTapHandler::GesturePolicy>("gesturePolicy");
// QTest::newRow("nosynth: passive grab") << false << QQuickTapHandler::DragThreshold; // still failing
QTest::newRow("nosynth: exclusive grab") << false << QQuickTapHandler::ReleaseWithinBounds;
QTest::newRow("allowsynth: passive grab") << true << QQuickTapHandler::DragThreshold; // QTBUG-113558
QTest::newRow("allowsynth: exclusive grab") << true << QQuickTapHandler::ReleaseWithinBounds;
}
void tst_qquickwidget::touchTapHandler()
{
QFETCH(bool, guiSynthMouse);
QFETCH(QQuickTapHandler::GesturePolicy, gesturePolicy);
QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, guiSynthMouse);
QQuickWidget quick;
QVERIFY(quick.testAttribute(Qt::WA_AcceptTouchEvents));
quick.setSource(testFileUrl("tapHandler.qml"));
quick.show();
QVERIFY(QTest::qWaitForWindowExposed(&quick));
QQuickItem *rootItem = quick.rootObject();
QVERIFY(rootItem);
QQuickTapHandler *th = rootItem->findChild<QQuickTapHandler *>();
QVERIFY(th);
th->setGesturePolicy(gesturePolicy);
QSignalSpy tappedSpy(th, &QQuickTapHandler::tapped);
const QPoint p(50, 50);
QTest::touchEvent(&quick, device).press(0, p, &quick);
QTRY_COMPARE(th->isPressed(), true);
QTest::touchEvent(&quick, device).release(0, p, &quick);
QTRY_COMPARE(tappedSpy.size(), 1);
QCOMPARE(th->isPressed(), false);
}
void tst_qquickwidget::touchMultipleWidgets()
{
QWidget window;