aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2021-05-03 16:55:25 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-12-03 02:56:31 +0000
commit9e6274e180312e9e6c9d26322668f1427abfe4b9 (patch)
treea62078e581c6f809db31fae354924d7beaab16fd
parentdd806b30dc57e0c91dadf090cdd2d8f51a9f6f41 (diff)
qquickdeliveryagent: Fix drag events being sent in the wrong order
When a former drag event target is on a higher or the same z-level as the new target, send the QDragLeaveEvent before the QDragEnterEvent. [ChangeLog][Quick][Fix] Now sends DragArea leave events before enter events when appropriate (QTBUG-82263) Fixes: QTBUG-82263 Change-Id: Ibe76000cbe76748ee8928e4b98a92c38eff5b59c Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> (cherry picked from commit 4a5b0ad84fbc0f814c38b0abcccb7b5421f41a19) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/quick/util/qquickdeliveryagent.cpp33
-rw-r--r--src/quick/util/qquickdeliveryagent_p_p.h4
-rw-r--r--tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp59
3 files changed, 76 insertions, 20 deletions
diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp
index 0cea513b78..f613e74d53 100644
--- a/src/quick/util/qquickdeliveryagent.cpp
+++ b/src/quick/util/qquickdeliveryagent.cpp
@@ -2052,6 +2052,7 @@ void QQuickDeliveryAgentPrivate::deliverMatchingPointsToItem(QQuickItem *item, b
#if QT_CONFIG(quick_draganddrop)
void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
{
+ QObject *formerTarget = grabber->target();
grabber->resetTarget();
QQuickDragGrabber::iterator grabItem = grabber->begin();
if (grabItem != grabber->end()) {
@@ -2095,7 +2096,8 @@ void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QE
moveEvent->buttons(),
moveEvent->modifiers());
QQuickDropEventEx::copyActions(&enterEvent, *moveEvent);
- event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent, &currentGrabItems));
+ event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent, &currentGrabItems,
+ formerTarget));
for (grabItem = grabber->begin(); grabItem != grabber->end(); ++grabItem) {
int i = currentGrabItems.indexOf(**grabItem);
@@ -2136,7 +2138,9 @@ void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QE
}
}
-bool QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event, QVarLengthArray<QQuickItem*, 64> *currentGrabItems)
+bool QQuickDeliveryAgentPrivate::deliverDragEvent(
+ QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event,
+ QVarLengthArray<QQuickItem *, 64> *currentGrabItems, QObject *formerTarget)
{
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (!item->isVisible() || !item->isEnabled() || QQuickItemPrivate::get(item)->culled)
@@ -2161,7 +2165,7 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQ
for (int ii = children.count() - 1; ii >= 0; --ii) {
if (children.at(ii)->z() < 0)
continue;
- if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems))
+ if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
return true;
}
@@ -2175,13 +2179,20 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQ
}
if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
- QDragMoveEvent translatedEvent(
- p.toPoint(),
- event->possibleActions(),
- event->mimeData(),
- event->buttons(),
- event->modifiers(),
- event->type());
+ 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);
+ }
+ }
+
+ QDragMoveEvent translatedEvent(p.toPoint(), event->possibleActions(), event->mimeData(),
+ event->buttons(), event->modifiers(), event->type());
QQuickDropEventEx::copyActions(&translatedEvent, *event);
translatedEvent.setAccepted(event->isAccepted());
QCoreApplication::sendEvent(item, &translatedEvent);
@@ -2203,7 +2214,7 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQ
for (int ii = children.count() - 1; ii >= 0; --ii) {
if (children.at(ii)->z() >= 0)
continue;
- if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems))
+ if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
return true;
}
diff --git a/src/quick/util/qquickdeliveryagent_p_p.h b/src/quick/util/qquickdeliveryagent_p_p.h
index f9095158e8..4ea1ef0d36 100644
--- a/src/quick/util/qquickdeliveryagent_p_p.h
+++ b/src/quick/util/qquickdeliveryagent_p_p.h
@@ -199,7 +199,9 @@ public:
#if QT_CONFIG(quick_draganddrop)
void deliverDragEvent(QQuickDragGrabber *, QEvent *);
- bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *, QVarLengthArray<QQuickItem*, 64> *currentGrabItems = nullptr);
+ bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *,
+ QVarLengthArray<QQuickItem *, 64> *currentGrabItems = nullptr,
+ QObject *formerTarget = nullptr);
#endif
static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int startDragThreshold = -1);
diff --git a/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp b/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp
index dbf090bfed..6bbe0d522b 100644
--- a/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp
+++ b/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp
@@ -80,6 +80,7 @@ private slots:
void dropStuff();
void nestedDropAreas_data();
void nestedDropAreas();
+ void signalOrder();
private:
QQmlEngine engine;
@@ -958,8 +959,8 @@ void tst_QQuickDropArea::simultaneousDrags()
Qt::MouseButtons(), Qt::KeyboardModifiers());
//Same as in the first case, dropArea2 already contains a drag, dropArea1 will get the event
QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true);
- QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1);
- QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0);
+ QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2);
+ QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1);
QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true);
QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0);
QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0);
@@ -967,8 +968,8 @@ void tst_QQuickDropArea::simultaneousDrags()
QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction,
Qt::MouseButtons(), Qt::KeyboardModifiers());
QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false);
- QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1);
- QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1);
+ QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2);
+ QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 2);
QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true);
QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0);
QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0);
@@ -976,16 +977,16 @@ void tst_QQuickDropArea::simultaneousDrags()
QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction,
Qt::MouseButtons(), Qt::KeyboardModifiers());
QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true);
- QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2);
- QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1);
+ QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 4);
+ QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 3);
QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true);
QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0);
QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0);
evaluate<void>(dragItem1, "Drag.active = false");
QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true);
- QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2);
- QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1);
+ QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 4);
+ QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 3);
QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false);
QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0);
QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 1);
@@ -1290,6 +1291,48 @@ void tst_QQuickDropArea::nestedDropAreas()
QCOMPARE(window.rootObject()->property("innerExitEvents"), 2);
}
+void tst_QQuickDropArea::signalOrder()
+{
+ QQuickWindow window;
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick\n"
+ "Item {\n"
+ " id: root\n"
+ " property var eventOrder: []\n"
+ " DropArea {\n"
+ " width: 100; height: 100\n"
+ " x: 0; y: 0\n"
+ " onEntered: eventOrder.push('entered1');\n"
+ " onExited: eventOrder.push('exited1');\n"
+ " }\n"
+ " DropArea {\n"
+ " width: 100; height: 100\n"
+ " x: 0; y: 100\n"
+ " onEntered: eventOrder.push('entered2');\n"
+ " onExited: eventOrder.push('exited2');\n"
+ " }\n"
+ "}",
+ QUrl());
+
+ QScopedPointer<QObject> object(component.create());
+ QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
+ QVERIFY(item);
+ item->setParentItem(window.contentItem());
+
+ QMimeData data;
+
+ QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction,
+ Qt::MouseButtons(), Qt::KeyboardModifiers());
+ QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 150), Qt::CopyAction,
+ Qt::MouseButtons(), Qt::KeyboardModifiers());
+ QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 250), Qt::CopyAction,
+ Qt::MouseButtons(), Qt::KeyboardModifiers());
+
+ const QList<QVariant> eventOrder = item->property("eventOrder").toList();
+ QCOMPARE(eventOrder,
+ QList<QVariant>({ u"entered1"_qs, u"exited1"_qs, u"entered2"_qs, u"exited2"_qs }));
+}
+
QTEST_MAIN(tst_QQuickDropArea)
#include "tst_qquickdroparea.moc"