diff options
| author | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2023-07-11 17:25:23 +0300 |
|---|---|---|
| committer | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2023-07-11 17:25:23 +0300 |
| commit | a8caccc32cdb2aeb34b8029883f1b63bd342c863 (patch) | |
| tree | 6f920fe51aa9abee0442ef7cb60a31854b48f309 | |
| parent | 2f1131c089cf18a88a07bfbd3652258bef9b5080 (diff) | |
| parent | cc1d21cfe56453b3f8d3aed30aea7baa8768ecb7 (diff) | |
Merge branch 'tqtc/lts-5.15' into tqtc/lts-5.15.15
Change-Id: I057f0327e03783ef933b8d4b57bf1b5a1c0f233d
| -rw-r--r-- | src/qml/common/qqmljsmemorypool_p.h | 2 | ||||
| -rw-r--r-- | src/qml/qml/ftw/qintrusivelist_p.h | 5 | ||||
| -rw-r--r-- | src/qml/qml/ftw/qrecyclepool_p.h | 9 | ||||
| -rw-r--r-- | src/quick/doc/src/examples.qdoc | 1 | ||||
| -rw-r--r-- | src/quick/items/qquickitem.cpp | 10 | ||||
| -rw-r--r-- | src/quick/items/qquickwindow.cpp | 8 | ||||
| -rw-r--r-- | tests/auto/quick/pointerhandlers/qquickpointerhandler/data/grabberSceneChange.qml | 80 | ||||
| -rw-r--r-- | tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp | 49 |
8 files changed, 156 insertions, 8 deletions
diff --git a/src/qml/common/qqmljsmemorypool_p.h b/src/qml/common/qqmljsmemorypool_p.h index 79519221e9..832f4ce46b 100644 --- a/src/qml/common/qqmljsmemorypool_p.h +++ b/src/qml/common/qqmljsmemorypool_p.h @@ -87,7 +87,7 @@ public: inline void *allocate(size_t size) { size = (size + 7) & ~size_t(7); - if (Q_LIKELY(_ptr && (_ptr + size < _end))) { + if (Q_LIKELY(_ptr && size < size_t(_end - _ptr))) { void *addr = _ptr; _ptr += size; return addr; diff --git a/src/qml/qml/ftw/qintrusivelist_p.h b/src/qml/qml/ftw/qintrusivelist_p.h index 661bd2dc15..fbd29fcae8 100644 --- a/src/qml/qml/ftw/qintrusivelist_p.h +++ b/src/qml/qml/ftw/qintrusivelist_p.h @@ -241,7 +241,12 @@ typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::end() template<class N, QIntrusiveListNode N::*member> N *QIntrusiveList<N, member>::nodeToN(QIntrusiveListNode *node) { + QT_WARNING_PUSH +#if defined(Q_CC_CLANG) && ((__clang_major__ * 100) + __clang_minor__) >= 1300 + QT_WARNING_DISABLE_CLANG("-Wnull-pointer-subtraction") +#endif return (N *)((char *)node - ((char *)&(((N *)nullptr)->*member) - (char *)nullptr)); + QT_WARNING_POP } QIntrusiveListNode::QIntrusiveListNode() diff --git a/src/qml/qml/ftw/qrecyclepool_p.h b/src/qml/qml/ftw/qrecyclepool_p.h index 56fe177c0f..7e0357bbee 100644 --- a/src/qml/qml/ftw/qrecyclepool_p.h +++ b/src/qml/qml/ftw/qrecyclepool_p.h @@ -130,8 +130,7 @@ template<typename T, int Step> T *QRecyclePool<T, Step>::New() { T *rv = d->allocate(); - new (rv) T; - return rv; + return new (rv) T; } template<typename T, int Step> @@ -139,8 +138,7 @@ template<typename T1> T *QRecyclePool<T, Step>::New(const T1 &a) { T *rv = d->allocate(); - new (rv) T(a); - return rv; + return new (rv) T(a); } template<typename T, int Step> @@ -148,8 +146,7 @@ template<typename T1> T *QRecyclePool<T, Step>::New(T1 &a) { T *rv = d->allocate(); - new (rv) T(a); - return rv; + return new (rv) T(a); } template<typename T, int Step> diff --git a/src/quick/doc/src/examples.qdoc b/src/quick/doc/src/examples.qdoc index 9a1308440f..1675136817 100644 --- a/src/quick/doc/src/examples.qdoc +++ b/src/quick/doc/src/examples.qdoc @@ -124,7 +124,6 @@ Creator. \list \li \l{Qt Quick Controls - Gallery}{Controls Gallery} \li \l{Qt Quick System Dialog Examples}{Dialog Examples} - \li \l{Calendar Example} \li \l{tableview/gameoflife}{TableView} \li \l{Qt Quick Examples - Text}{Text and Fonts} \li \l{Qt Quick Examples - Toggle Switch}{Custom Toggle Switch} diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 86599e3b50..c615234629 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -70,6 +70,7 @@ #include <QtQuick/private/qquickaccessibleattached_p.h> #include <QtQuick/private/qquickhoverhandler_p.h> #include <QtQuick/private/qquickpointerhandler_p.h> +#include <QtQuick/private/qquickpointerhandler_p_p.h> #include <private/qv4engine_p.h> #include <private/qv4object_p.h> @@ -6341,6 +6342,15 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt } case QQuickItem::ItemSceneChange: q->itemChange(change, data); + if (hasPointerHandlers()) { + for (QQuickPointerHandler *handler : qAsConst(extra->pointerHandlers)) { + if (auto *currentEvent = handler->currentEvent()) { + for (int i = 0; i < currentEvent->pointCount(); ++i) + currentEvent->point(i)->cancelAllGrabs(handler); + } + } + } + break; case QQuickItem::ItemVisibleHasChanged: { q->itemChange(change, data); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index c6c7b6171e..8d631151f1 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2901,6 +2901,14 @@ void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo if (itemPrivate->wasDeleted) return; #endif + // QTBUG-114475 - handlers shouldn't get events if their item was taken out of the scene + // by a previous event-handling mechanism. + if (item->window() != q) { + qCDebug(DBG_TOUCH) << "Not delivering " << pointerEvent << " to " << item + << "- item has been parented away"; + return; + } + pointerEvent->localize(item); // Let the Item's handlers (if any) have the event first. diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/grabberSceneChange.qml b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/grabberSceneChange.qml new file mode 100644 index 0000000000..166f7d4618 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/grabberSceneChange.qml @@ -0,0 +1,80 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import Qt.test 1.0 + +Window { + id: root + visible: true + objectName: "root" + width: 320 + height: 480 + + property bool useTimer : false + property int grabChangedCounter : 0 + + Item { + id: back + anchors.fill: parent + + Rectangle { + id: background + anchors.fill: parent + color: "blue" + } + + Rectangle { + id: container + objectName: "container" + anchors.fill: parent + anchors.margins: 50 + z: 2 + + Rectangle { + id: likeButton + color: "gray" + anchors.centerIn: parent + width: 200 + height: 200 + + DragHandler { + id: handler + objectName: "dragHandler" + grabPermissions: PointerHandler.CanTakeOverFromItems + onGrabChanged: { + ++grabChangedCounter + } + } + } + } + + Timer { + id: reparentTimer + running: false + interval: 100 + repeat: false + onTriggered: { + container.parent = null + } + } + + Rectangle { + id: likeButton2 + color: "yellow" + anchors.centerIn: parent + width: 100 + height: 100 + z: 3 + + MultiPointTouchArea { + id: press + anchors.fill: parent + onPressed: { + if (useTimer) + reparentTimer.running = true + else + container.parent = null + } + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp index 2b6482465c..ed24cd82dd 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -244,6 +244,8 @@ private slots: void dynamicCreation(); void handlerInWindow(); void dynamicCreationInWindow(); + void grabberSceneChange_data(); + void grabberSceneChange(); protected: bool eventFilter(QObject *, QEvent *event) @@ -679,6 +681,53 @@ void tst_PointerHandlers::dynamicCreationInWindow() QTRY_COMPARE(handler->releaseEventCount, 1); } +/*! + Verify that removing an item that has a grabbing handler from the scene + does not result in crashes in our event dispatching code. The item's window() + pointer will be nullptr, so the handler must have released the grab, or never + gotten the grab, depending on when the item gets removed. + + See QTBUG-114475. +*/ +void tst_PointerHandlers::grabberSceneChange_data() +{ + QTest::addColumn<bool>("useTimer"); + QTest::addColumn<int>("grabChangedCount"); + + QTest::addRow("Immediately") << false << 0; + QTest::addRow("Delayed") << true << 2; +} + +void tst_PointerHandlers::grabberSceneChange() +{ + QFETCH(const bool, useTimer); + QFETCH(const int, grabChangedCount); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("grabberSceneChange.qml")); + QQuickWindow *window = qobject_cast<QQuickWindow*>(component.create()); + QScopedPointer<QQuickWindow> cleanup(window); + QVERIFY(window); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + window->setProperty("useTimer", useTimer); + + QQuickItem *container = window->findChild<QQuickItem *>("container"); + + QPoint p1 = QPoint(window->width() / 2, window->height() / 2); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + // The container gets removed from this window, either immediately on + // press, or through a timer. + QTRY_COMPARE(container->parentItem(), nullptr); + + QCOMPARE(window->property("grabChangedCounter").toInt(), grabChangedCount); + + // this should not crash + QTest::mouseMove(window, p1 + QPoint(5, 5)); +} + QTEST_MAIN(tst_PointerHandlers) #include "tst_qquickpointerhandler.moc" |
