aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTarja Sundqvist <tarja.sundqvist@qt.io>2023-07-11 17:25:23 +0300
committerTarja Sundqvist <tarja.sundqvist@qt.io>2023-07-11 17:25:23 +0300
commita8caccc32cdb2aeb34b8029883f1b63bd342c863 (patch)
tree6f920fe51aa9abee0442ef7cb60a31854b48f309
parent2f1131c089cf18a88a07bfbd3652258bef9b5080 (diff)
parentcc1d21cfe56453b3f8d3aed30aea7baa8768ecb7 (diff)
Merge branch 'tqtc/lts-5.15' into tqtc/lts-5.15.15
-rw-r--r--src/qml/common/qqmljsmemorypool_p.h2
-rw-r--r--src/qml/qml/ftw/qintrusivelist_p.h5
-rw-r--r--src/qml/qml/ftw/qrecyclepool_p.h9
-rw-r--r--src/quick/doc/src/examples.qdoc1
-rw-r--r--src/quick/items/qquickitem.cpp10
-rw-r--r--src/quick/items/qquickwindow.cpp8
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointerhandler/data/grabberSceneChange.qml80
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp49
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"