aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2021-11-02 12:09:47 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-11-09 17:43:08 +0000
commitc7b763e02a337dce5f7bb0ead594fbce57c21a36 (patch)
tree67e918061af4bd24c917e7cdc198712ed71f5817
parent43b248cb4bb15bf398ed602cc40a8ae0e1da44f7 (diff)
Start dispatching events to QQuickWindow virtual functions again
Users sometimes override those. Amends 68c103225f4e8bd6c1b18ef547108fd60f398c0f : we no longer bypass the "big switch" in QWindow::event() completely, but let it dispatch pointer events to any of the window virtual functions that may have been overridden, while using a guard to prevent them from calling back to QQuickWindow::event(). Fixes: QTBUG-97859 Change-Id: I2bb5258db9682a82a804fa5deca9eb8477cb38cc Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit 13a0da5bd2cf59aeb343fe9345b9bac2cfbb5e6f) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/quick/items/qquickwindow.cpp54
-rw-r--r--src/quick/items/qquickwindow_p.h1
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp108
3 files changed, 153 insertions, 10 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 9dbb61509c..fd65319f7b 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1338,6 +1338,38 @@ bool QQuickWindow::event(QEvent *e)
QQuickDeliveryAgent *da = d->deliveryAgent;
if (e->isPointerEvent()) {
/*
+ We can't bypass the virtual functions like mousePressEvent() tabletEvent() etc.,
+ for the sake of code that subclasses QQuickWindow and overrides them, even though
+ we no longer need them as entry points for Qt Quick event delivery.
+ So dispatch to them now, ahead of normal delivery, and stop them from calling
+ back into this function if they were called from here (avoid recursion).
+ It could also be that user code expects them to work as entry points, too;
+ in that case, windowEventDispatch _won't_ be set, so the event comes here and
+ we'll dispatch it further below.
+ */
+ if (d->windowEventDispatch)
+ return false;
+ {
+ const bool wasAccepted = e->isAccepted();
+ QBoolBlocker windowEventDispatchGuard(d->windowEventDispatch, true);
+ qCDebug(lcPtr) << "dispatching to window functions in case of override" << e;
+ QWindow::event(e);
+ if (e->isAccepted() && !wasAccepted)
+ return true;
+ }
+ /*
+ QQuickWindow does not override touchEvent(). If the application has a subclass
+ of QQuickWindow which allows the event to remain accepted, it means they want
+ to stop propagation here, so return early (below). But otherwise we will call
+ QWindow::touchEvent(), which will ignore(); in that case, we need to continue
+ with the usual delivery below, so we need to undo the ignore().
+ */
+ auto pe = static_cast<QPointerEvent *>(e);
+ if (QQuickDeliveryAgentPrivate::isTouchEvent(pe))
+ e->accept();
+ // end of dispatch to user-overridden virtual window functions
+
+ /*
When delivering update and release events to existing grabbers,
use the subscene delivery agent, if any. A possible scenario:
1) Two touchpoints pressed on the main window: QQuickWindowPrivate::deliveryAgent delivers to QQuick3DViewport,
@@ -1350,7 +1382,6 @@ bool QQuickWindow::event(QEvent *e)
With single-point events (mouse, or only one finger) it's simplified: there can only be one subscene of interest;
for (pt : pe->points()) would only iterate once, so we might as well skip that logic.
*/
- auto pe = static_cast<QPointerEvent *>(e);
if (pe->pointCount()) {
if (QQuickDeliveryAgentPrivate::subsceneAgentsExist) {
bool ret = false;
@@ -1521,13 +1552,18 @@ bool QQuickWindow::event(QEvent *e)
else if (e->type() == QEvent::Type(QQuickWindowPrivate::TriggerContextCreationFailure))
d->windowManager->handleContextCreationFailure(this);
- return QWindow::event(e);
+ if (e->isPointerEvent())
+ return true;
+ else
+ return QWindow::event(e);
}
/*! \reimp */
void QQuickWindow::keyPressEvent(QKeyEvent *e)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->deliverKeyEvent(e);
@@ -1537,6 +1573,8 @@ void QQuickWindow::keyPressEvent(QKeyEvent *e)
void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->deliverKeyEvent(e);
@@ -1547,6 +1585,8 @@ void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
void QQuickWindow::wheelEvent(QWheelEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->deliverSinglePointEventUntilAccepted(event);
@@ -1558,6 +1598,8 @@ void QQuickWindow::wheelEvent(QWheelEvent *event)
void QQuickWindow::tabletEvent(QTabletEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->deliverPointerEvent(event);
@@ -1568,6 +1610,8 @@ void QQuickWindow::tabletEvent(QTabletEvent *event)
void QQuickWindow::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->handleMouseEvent(event);
@@ -1576,6 +1620,8 @@ void QQuickWindow::mousePressEvent(QMouseEvent *event)
void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->handleMouseEvent(event);
@@ -1584,6 +1630,8 @@ void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->handleMouseEvent(event);
@@ -1592,6 +1640,8 @@ void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->handleMouseEvent(event);
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 1a3ff31539..04c33afc74 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -287,6 +287,7 @@ public:
uint hasActiveSwapchain : 1;
uint hasRenderableSwapchain : 1;
uint swapchainJustBecameRenderable : 1;
+ bool windowEventDispatch = false;
private:
static void cleanupNodesOnShutdown(QQuickItem *);
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index f88ce43c9b..6f08714fba 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -327,30 +327,68 @@ protected:
}
};
-class MouseRecordingWindow : public QQuickWindow
+class PointerRecordingWindow : public QQuickWindow
{
public:
- explicit MouseRecordingWindow(QWindow *parent = nullptr) : QQuickWindow(parent) { }
+ explicit PointerRecordingWindow(QWindow *parent = nullptr) : QQuickWindow(parent) { }
protected:
+ bool event(QEvent *event) override {
+ if (event->isPointerEvent()) {
+ qCDebug(lcTests) << event;
+ m_events << PointerEvent { event->type(), static_cast<QPointerEvent *>(event)->pointingDevice() };
+ }
+ return QQuickWindow::event(event);
+ }
+
void mousePressEvent(QMouseEvent *event) override {
qCDebug(lcTests) << event;
- m_mouseEvents << event->source();
+ m_mouseEvents << PointerEvent { event->type(), event->pointingDevice() };
QQuickWindow::mousePressEvent(event);
}
void mouseMoveEvent(QMouseEvent *event) override {
qCDebug(lcTests) << event;
- m_mouseEvents << event->source();
+ m_mouseEvents << PointerEvent { event->type(), event->pointingDevice() };
QQuickWindow::mouseMoveEvent(event);
}
void mouseReleaseEvent(QMouseEvent *event) override {
qCDebug(lcTests) << event;
- m_mouseEvents << event->source();
+ m_mouseEvents << PointerEvent { event->type(), event->pointingDevice() };
QQuickWindow::mouseReleaseEvent(event);
}
+ void touchEvent(QTouchEvent * event) override {
+ qCDebug(lcTests) << event;
+ m_touchEvents << PointerEvent { event->type(), event->pointingDevice() };
+ QQuickWindow::touchEvent(event);
+ }
+
+#if QT_CONFIG(tabletevent)
+ void tabletEvent(QTabletEvent * event) override {
+ qCDebug(lcTests) << event;
+ m_tabletEvents << PointerEvent { event->type(), event->pointingDevice() };
+ QQuickWindow::tabletEvent(event);
+ }
+#endif
+
+#if QT_CONFIG(wheelevent)
+ void wheelEvent(QWheelEvent * event) override {
+ qCDebug(lcTests) << event;
+ m_tabletEvents << PointerEvent { event->type(), event->pointingDevice() };
+ QQuickWindow::wheelEvent(event);
+ }
+#endif
+
public:
- QList<Qt::MouseEventSource> m_mouseEvents;
+ struct PointerEvent
+ {
+ QEvent::Type type;
+ const QPointingDevice *device;
+ };
+ QList<PointerEvent> m_events;
+ QList<PointerEvent> m_mouseEvents;
+ QList<PointerEvent> m_touchEvents;
+ QList<PointerEvent> m_tabletEvents;
};
class MouseRecordingItem : public QQuickItem
@@ -511,6 +549,9 @@ private slots:
void testChildMouseEventFilter_data();
void cleanupGrabsOnRelease();
+ void subclassWithPointerEventVirtualOverrides_data();
+ void subclassWithPointerEventVirtualOverrides();
+
#if QT_CONFIG(shortcut)
void testShortCut();
#endif
@@ -1250,7 +1291,7 @@ void tst_qquickwindow::synthMouseFromTouch()
QFETCH(bool, acceptTouch);
QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, synthMouse);
- QScopedPointer<MouseRecordingWindow> window(new MouseRecordingWindow);
+ QScopedPointer<PointerRecordingWindow> window(new PointerRecordingWindow);
QScopedPointer<MouseRecordingItem> item(new MouseRecordingItem(acceptTouch, nullptr));
item->setParentItem(window->contentItem());
window->resize(250, 250);
@@ -1295,7 +1336,7 @@ void tst_qquickwindow::synthMouseDoubleClickFromTouch()
QFETCH(bool, expectedSynthesizedDoubleClickEvent);
QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true);
- QScopedPointer<MouseRecordingWindow> window(new MouseRecordingWindow);
+ QScopedPointer<PointerRecordingWindow> window(new PointerRecordingWindow);
QScopedPointer<MouseRecordingItem> item(new MouseRecordingItem(false, nullptr));
item->setParentItem(window->contentItem());
window->resize(250, 250);
@@ -3578,6 +3619,57 @@ void tst_qquickwindow::cleanupGrabsOnRelease()
QCOMPARE(parent->mouseUngrabEventCount, 1);
}
+void tst_qquickwindow::subclassWithPointerEventVirtualOverrides_data()
+{
+ QTest::addColumn<QPointingDevice::DeviceType>("deviceType");
+
+ QTest::newRow("mouse click") << QPointingDevice::DeviceType::Mouse;
+ QTest::newRow("touch tap") << QPointingDevice::DeviceType::TouchScreen;
+ QTest::newRow("stylus tap") << QPointingDevice::DeviceType::Stylus;
+}
+
+void tst_qquickwindow::subclassWithPointerEventVirtualOverrides() // QTBUG-97859
+{
+ QFETCH(QPointingDevice::DeviceType, deviceType);
+
+ PointerRecordingWindow window;
+ window.resize(250, 250);
+ window.setPosition(100, 100);
+ window.setTitle(QTest::currentTestFunction());
+ window.show();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+ const qint64 stylusId = 1234567890;
+
+ const QPoint pos(120, 120);
+ switch (static_cast<QPointingDevice::DeviceType>(deviceType)) {
+ case QPointingDevice::DeviceType::Mouse:
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, pos);
+ QTRY_COMPARE(window.m_mouseEvents.count(), 3); // separate move before press
+ QCOMPARE(window.m_events.count(), 3);
+ break;
+ case QPointingDevice::DeviceType::TouchScreen:
+ QTest::touchEvent(&window, touchDevice).press(0, pos, &window);
+ QTest::touchEvent(&window, touchDevice).release(0, pos, &window);
+ QTRY_COMPARE(window.m_touchEvents.count(), 2);
+ QCOMPARE(window.m_events.count(), 2);
+ break;
+ case QPointingDevice::DeviceType::Stylus:
+ // press (pressure is 0.8)
+ QWindowSystemInterface::handleTabletEvent(&window, pos, window.mapToGlobal(pos),
+ int(QInputDevice::DeviceType::Stylus), int(QPointingDevice::PointerType::Pen),
+ Qt::LeftButton, 0.8, 0, 0, 0, 0, 0, stylusId, Qt::NoModifier);
+ // release (pressure is 0)
+ QWindowSystemInterface::handleTabletEvent(&window, pos, window.mapToGlobal(pos),
+ int(QInputDevice::DeviceType::Stylus), int(QPointingDevice::PointerType::Pen),
+ Qt::NoButton, 0, 0, 0, 0, 0, 0, stylusId, Qt::NoModifier);
+ QTRY_COMPARE(window.m_tabletEvents.count(), 2);
+ QVERIFY(window.m_events.count() >= window.m_tabletEvents.count()); // tablet + synth-mouse events
+ break;
+ default:
+ break;
+ }
+}
+
#if QT_CONFIG(shortcut)
void tst_qquickwindow::testShortCut()
{