diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index afea2eb0a9e..c1fcdbb2dd4 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -897,8 +897,9 @@ void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event) event->ignore(); if (m_dragTarget) { // Send DragLeave to previous QDragLeaveEvent leaveEvent; - QGuiApplication::forwardEvent(m_dragTarget, &leaveEvent, event); + QWidget *dragTarget = m_dragTarget; m_dragTarget = nullptr; + QGuiApplication::forwardEvent(dragTarget, &leaveEvent, event); } } else { const QPoint mapped = widget->mapFromGlobal(m_widget->mapToGlobal(event->position().toPoint())); @@ -912,8 +913,9 @@ void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event) } else { if (m_dragTarget) { // Send DragLeave to previous QDragLeaveEvent leaveEvent; - QGuiApplication::forwardEvent(m_dragTarget, &leaveEvent, event); + QWidget *dragTarget = m_dragTarget; m_dragTarget = nullptr; + QGuiApplication::forwardEvent(dragTarget, &leaveEvent, event); } // widget might have been deleted when handling the leaveEvent if (widget) { @@ -935,9 +937,11 @@ void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event) void QWidgetWindow::handleDragLeaveEvent(QDragLeaveEvent *event) { - if (m_dragTarget) - QGuiApplication::forwardEvent(m_dragTarget, event); - m_dragTarget = nullptr; + if (m_dragTarget) { + QWidget *dragTarget = m_dragTarget; + m_dragTarget = nullptr; + QGuiApplication::forwardEvent(dragTarget, event); + } } void QWidgetWindow::handleDropEvent(QDropEvent *event) @@ -949,10 +953,11 @@ void QWidgetWindow::handleDropEvent(QDropEvent *event) } const QPoint mapped = m_dragTarget->mapFromGlobal(m_widget->mapToGlobal(event->position().toPoint())); QDropEvent translated(mapped, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers()); - QGuiApplication::forwardEvent(m_dragTarget, &translated, event); + QWidget *dragTarget = m_dragTarget; + m_dragTarget = nullptr; + QGuiApplication::forwardEvent(dragTarget, &translated, event); event->setAccepted(translated.isAccepted()); event->setDropAction(translated.dropAction()); - m_dragTarget = nullptr; } #endif // QT_CONFIG(draganddrop) diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp index 689a65518e0..09956e69a23 100644 --- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -82,6 +82,7 @@ private slots: void tst_dnd(); void tst_dnd_events(); void tst_dnd_propagation(); + void tst_dnd_destroyOnDrop(); #endif void tst_qtbug35600(); @@ -917,6 +918,78 @@ void tst_QWidget_window::tst_dnd_propagation() QCOMPARE(target.mDndEvents, "enter leave enter drop "); } + +class ReparentSelfOnDropWidget : public QWidget +{ +public: + ReparentSelfOnDropWidget(QWidget *newFutureParent) + : m_newFutureParent(newFutureParent) + { + setAcceptDrops(true); + + const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry(); + auto width = availableGeometry.width() / 6; + auto height = availableGeometry.height() / 4; + + setGeometry(availableGeometry.x() + 200, availableGeometry.y() + 200, width, height); + + QLabel *label = new QLabel(QStringLiteral("Test"), this); + label->setGeometry(40, 40, 60, 60); + label->setAcceptDrops(true); + } + + void dragEnterEvent(QDragEnterEvent *event) override + { + event->accept(); + } + + void dragMoveEvent(QDragMoveEvent *event) override + { + event->acceptProposedAction(); + } + + void dropEvent(QDropEvent *event) override + { + event->accept(); + // Turn 'this' from a top-level widget to a child widget. + // This destroys the QWidgetWindow since the widget is no longer top-level. + setParent(m_newFutureParent); + } + +private: + QWidget *m_newFutureParent; +}; + +void tst_QWidget_window::tst_dnd_destroyOnDrop() +{ + if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) + QSKIP("Wayland: This fails. Figure out why."); + + QMimeData mimeData; + mimeData.setText(QLatin1String("testmimetext")); + + QWidget newParent; + newParent.resize(400, 400); + newParent.show(); + QVERIFY(QTest::qWaitForWindowActive(&newParent)); + + ReparentSelfOnDropWidget *target = new ReparentSelfOnDropWidget(&newParent); + target->show(); + QVERIFY(QTest::qWaitForWindowActive(target)); + + Qt::DropActions supportedActions = Qt::DropAction::CopyAction; + QWindow *window = target->windowHandle(); + + auto posInsideDropTarget = QHighDpi::toNativePixels(QPoint(20, 20), window->screen()); + auto posInsideLabel = QHighDpi::toNativePixels(QPoint(60, 60), window->screen()); + + QWindowSystemInterface::handleDrag(window, &mimeData, posInsideDropTarget, supportedActions, {}, {}); + QWindowSystemInterface::handleDrag(window, &mimeData, posInsideLabel, supportedActions, {}, {}); + QWindowSystemInterface::handleDrop(window, &mimeData, posInsideLabel, supportedActions, {}, {}); + + QGuiApplication::processEvents(); +} + #endif void tst_QWidget_window::tst_qtbug35600()