aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquickwindow.cpp9
-rw-r--r--tests/auto/quick/qquickwindow/data/hoverCrash.qml36
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp21
3 files changed, 65 insertions, 1 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 377228e6bf..525c3d1a0e 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1414,6 +1414,7 @@ void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
Qt::KeyboardModifiers modifiers, bool &accepted)
{
+ Q_Q(QQuickWindow);
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
@@ -1463,7 +1464,13 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
for (int i = startIdx; i >= 0; i--) {
QQuickItem *itemToHover = itemsToHover[i];
- if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
+ QQuickItemPrivate *itemToHoverPrivate = QQuickItemPrivate::get(itemToHover);
+ // The item may be about to be deleted or reparented to another window
+ // due to another hover event delivered in this function. If that is the
+ // case, sending a hover event here will cause a crash or other bad
+ // behavior when the leave event is generated. Checking
+ // itemToHoverPrivate->window here prevents that case.
+ if (itemToHoverPrivate->window == q && itemToHoverPrivate->hoverEnabled) {
hoverItems.prepend(itemToHover);
sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
}
diff --git a/tests/auto/quick/qquickwindow/data/hoverCrash.qml b/tests/auto/quick/qquickwindow/data/hoverCrash.qml
new file mode 100644
index 0000000000..936d9e4f43
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/data/hoverCrash.qml
@@ -0,0 +1,36 @@
+import QtQuick 2.0
+import QtQuick.Window 2.0 as Window
+
+Window.Window {
+ width: 200
+ height: 200
+ color: "#00FF00"
+ Column {
+ Rectangle {
+ objectName: 'item1'
+ color: 'red'
+ width: 100
+ height: 100
+ MouseArea {
+ id: area
+ anchors.fill: parent
+ hoverEnabled: true
+ }
+ }
+
+ Loader {
+ objectName: 'item2'
+ width: 100
+ height: 100
+ active: area.containsMouse
+ sourceComponent: Rectangle {
+ color: 'blue'
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index fbbc77c31c..4a61746344 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -328,6 +328,8 @@ private slots:
void blockClosing();
+ void crashWhenHoverItemDeleted();
+
#ifndef QT_NO_CURSOR
void cursor();
#endif
@@ -1487,6 +1489,25 @@ void tst_qquickwindow::blockClosing()
QTRY_VERIFY(!window->isVisible());
}
+void tst_qquickwindow::crashWhenHoverItemDeleted()
+{
+ // QTBUG-32771
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("hoverCrash.qml"));
+ QQuickWindow* window = qobject_cast<QQuickWindow *>(component.create());
+ QVERIFY(window);
+ window->show();
+ QTest::qWaitForWindowExposed(window);
+
+ // Simulate a move from the first rectangle to the second. Crash will happen in here
+ // Moving instantaneously from (0, 99) to (0, 102) does not cause the crash
+ for (int i = 99; i < 102; ++i)
+ {
+ QTest::mouseMove(window, QPoint(0, i));
+ }
+}
+
QTEST_MAIN(tst_qquickwindow)
#include "tst_qquickwindow.moc"