aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSanthosh Kumar <santhosh.kumar.selvaraj@qt.io>2022-11-01 13:28:30 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-11-07 13:10:16 +0000
commitd194d32fc99a71d499c2ed5db25a67a75b8822db (patch)
treec88be7d2ad57167b5c9d2170b5ae8f6a31d5b144
parent6911a4b2c2cac0953bf256f1e2642c0fdcad3b1b (diff)
Fix performance issue with drag retrigger events for qtquick items
The items that reject drag events (specifically onEntered in DropArea) should not be retriggered with DragEnter event until entered once again. Fixes: QTBUG-74496 Change-Id: I241a6004da6382685be89fe8a001b98dfde5c8a2 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> (cherry picked from commit 0b7374fefa1abf08e956bc5d34008352144bd9ae) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/quick/items/qquickdrag_p.h3
-rw-r--r--src/quick/util/qquickdeliveryagent.cpp36
-rw-r--r--tests/auto/quick/qquickdroparea/data/ignoreRetriggerEvent.qml15
-rw-r--r--tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp29
4 files changed, 72 insertions, 11 deletions
diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index e17a28d07e..26191c6545 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -108,9 +108,12 @@ public:
void grab(QQuickItem *item) { m_items.insert(new Item(item)); }
iterator release(iterator at) { Item *item = *at; at = at.erase(); delete item; return at; }
+ auto& ignoreList() { return m_ignoreDragItems; }
+
private:
ItemList m_items;
+ QVarLengthArray<QQuickItem *, 4> m_ignoreDragItems;
QObject *m_target;
};
diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp
index 855f608149..e027ef8fdf 100644
--- a/src/quick/util/qquickdeliveryagent.cpp
+++ b/src/quick/util/qquickdeliveryagent.cpp
@@ -2184,6 +2184,7 @@ void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QE
QDragLeaveEvent leaveEvent;
for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
QCoreApplication::sendEvent(**grabItem, &leaveEvent);
+ grabber->ignoreList().clear();
return;
} else {
QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
@@ -2241,6 +2242,8 @@ void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QE
e->modifiers());
QQuickDropEventEx::copyActions(&enterEvent, *e);
event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
+ } else {
+ grabber->ignoreList().clear();
}
}
@@ -2254,8 +2257,13 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(
QPointF p = item->mapFromScene(event->position().toPoint());
bool itemContained = item->contains(p);
- if (!itemContained && itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- return false;
+ const int itemIndex = grabber->ignoreList().indexOf(item);
+ if (!itemContained) {
+ if (itemIndex >= 0)
+ grabber->ignoreList().remove(itemIndex);
+
+ if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape)
+ return false;
}
QDragEnterEvent enterEvent(
@@ -2285,15 +2293,19 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(
}
if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
- if (event->type() == QEvent::DragEnter && formerTarget) {
- QQuickItem *formerTargetItem = qobject_cast<QQuickItem *>(formerTarget);
- if (formerTargetItem && currentGrabItems) {
- QDragLeaveEvent leaveEvent;
- QCoreApplication::sendEvent(formerTarget, &leaveEvent);
-
- // Remove the item from the currentGrabItems so a leave event won't be generated
- // later on
- currentGrabItems->removeAll(formerTarget);
+ if (event->type() == QEvent::DragEnter) {
+ if (formerTarget) {
+ QQuickItem *formerTargetItem = qobject_cast<QQuickItem *>(formerTarget);
+ if (formerTargetItem && currentGrabItems) {
+ QDragLeaveEvent leaveEvent;
+ QCoreApplication::sendEvent(formerTarget, &leaveEvent);
+
+ // Remove the item from the currentGrabItems so a leave event won't be generated
+ // later on
+ currentGrabItems->removeAll(formerTarget);
+ }
+ } else if (itemIndex >= 0) {
+ return false;
}
}
@@ -2309,6 +2321,8 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(
grabber->grab(item);
grabber->setTarget(item);
return true;
+ } else if (itemIndex < 0) {
+ grabber->ignoreList().append(item);
}
} else {
return true;
diff --git a/tests/auto/quick/qquickdroparea/data/ignoreRetriggerEvent.qml b/tests/auto/quick/qquickdroparea/data/ignoreRetriggerEvent.qml
new file mode 100644
index 0000000000..af25a04ee7
--- /dev/null
+++ b/tests/auto/quick/qquickdroparea/data/ignoreRetriggerEvent.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+
+DropArea {
+ property int enterEvents: 0
+ property int exitEvents: 0
+ width: 100; height: 100
+ objectName: "dropArea"
+ onEntered: function (drag) { ++enterEvents; drag.accepted = false }
+ onExited: {++exitEvents}
+ Item {
+ objectName: "dragItem"
+ x: 50; y: 50
+ width: 10; height: 10
+ }
+}
diff --git a/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp b/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp
index de7e3f1629..dcc05f548b 100644
--- a/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp
+++ b/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp
@@ -67,6 +67,9 @@ public:
private slots:
void containsDrag_internal();
void containsDrag_external();
+
+ void ignoreRetriggerEvent();
+
void keys_internal();
void keys_external();
void source_internal();
@@ -829,6 +832,32 @@ void tst_QQuickDropArea::competingDrags()
QCOMPARE(evaluate<QString>(dropArea1, "statuslol"), QStringLiteral("parent"));
}
+void tst_QQuickDropArea::ignoreRetriggerEvent()
+{
+ QQuickView window;
+ QByteArray errorMessage;
+ QVERIFY2(QQuickTest::initView(window, testFileUrl("ignoreRetriggerEvent.qml"), true, &errorMessage), errorMessage.constData());
+
+ QQuickItem *dropArea = window.rootObject();
+ QVERIFY(dropArea);
+ QQuickItem *dragItem = dropArea->findChild<QQuickItem *>("dragItem");
+ QVERIFY(dragItem);
+
+ evaluate<void>(dragItem, "Drag.active = true");
+ // Drag the item within the drop area
+ dragItem->setPosition(QPointF(25, 25));
+ QCoreApplication::processEvents();
+ dragItem->setPosition(QPointF(50, 50));
+ QCoreApplication::processEvents();
+ dragItem->setPosition(QPointF(75, 75));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false);
+ QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1);
+ QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 0);
+}
+
+
void tst_QQuickDropArea::simultaneousDrags()
{
QQuickWindow window;