Fix hover event crash
It was possible for a hover event to be sent to a QQuickItem that has already been scheduled to be deleted (through deleteLater()). This lead to an access on an already-freed object when the leave event is generated. This change ensures that the item is part of a scene before generating the hover enter event. Task-number: QTBUG-32771 Change-Id: I69adb6bbd0ae52c70a6bda4e6c918b7671549a4c Reviewed-by: Alan Alpert <aalpert@blackberry.com>
This commit is contained in:
parent
602bec1286
commit
b00a120d4d
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue