diff options
author | Bradley T. Hughes <bradley.hughes@nokia.com> | 2009-12-11 10:38:19 (GMT) |
---|---|---|
committer | Bradley T. Hughes <bradley.hughes@nokia.com> | 2009-12-11 12:02:32 (GMT) |
commit | 05ba6bad6c0927d22ccf026446dfdb9d85b3f03e (patch) | |
tree | a571739da8bb9f706d6623a6e72fd01367ee3fec /src | |
parent | bafc505ea03ff423c02e0380ba6f255e160483a1 (diff) | |
download | Qt-05ba6bad6c0927d22ccf026446dfdb9d85b3f03e.zip Qt-05ba6bad6c0927d22ccf026446dfdb9d85b3f03e.tar.gz Qt-05ba6bad6c0927d22ccf026446dfdb9d85b3f03e.tar.bz2 |
Fix crashes when deleting QWidgets and QGraphicsItems in touch event handlers.
Use QWeakPointer to bail out early if a widget is deleted while we are
delivering/propagating a TouchBegin event.
In QGraphicsScene, we need to make sure that we clear the scene's
active touch points for items that are removed from the scene. This
allows us to detect when an item is removed during TouchBegin event
delivery/propagation. Unlike QWidget, propagation continues since we
use a hit-test instead of the item's hierarchy for propagation.
Task-number: QTBUG-6654
Reviewed-by: bnilsen
Diffstat (limited to 'src')
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 24 | ||||
-rw-r--r-- | src/gui/kernel/qapplication.cpp | 10 |
2 files changed, 29 insertions, 5 deletions
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 27ebb79..2a53456 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -613,6 +613,19 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item) if (item == lastActivePanel) lastActivePanel = 0; + // Cancel active touches + { + QMap<int, QGraphicsItem *>::iterator it = itemForTouchPointId.begin(); + while (it != itemForTouchPointId.end()) { + if (it.value() == item) { + sceneCurrentTouchPoints.remove(it.key()); + it = itemForTouchPointId.erase(it); + } else { + ++it; + } + } + } + // Disable selectionChanged() for individual items ++selectionChanging; int oldSelectedItemsSize = selectedItems.size(); @@ -5679,17 +5692,22 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve touchEvent->setAccepted(acceptTouchEvents); res = acceptTouchEvents && sendEvent(item, touchEvent); eventAccepted = touchEvent->isAccepted(); - item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted); + if (itemForTouchPointId.value(touchEvent->touchPoints().first().id()) == 0) { + // item was deleted + item = 0; + } else { + item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted); + } touchEvent->spont = false; if (res && eventAccepted) { // the first item to accept the TouchBegin gets an implicit grab. for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i); - itemForTouchPointId[touchPoint.id()] = item; + itemForTouchPointId[touchPoint.id()] = item; // can be zero } break; } - if (item->isPanel()) + if (item && item->isPanel()) break; } diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 9f4cd0c..8c63968 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -4092,9 +4092,15 @@ bool QApplication::notify(QObject *receiver, QEvent *e) bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); touchEvent->setWidget(widget); touchEvent->setAccepted(acceptTouchEvents); + QWeakPointer<QWidget> p = widget; res = acceptTouchEvents && d->notify_helper(widget, touchEvent); eventAccepted = touchEvent->isAccepted(); - widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, res && eventAccepted); + if (p.isNull()) { + // widget was deleted + widget = 0; + } else { + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, res && eventAccepted); + } touchEvent->spont = false; if (res && eventAccepted) { // the first widget to accept the TouchBegin gets an implicit grab. @@ -4103,7 +4109,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) d->widgetForTouchPointId[touchPoint.id()] = widget; } break; - } else if (widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) { + } else if (p.isNull() || widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) { break; } QPoint offset = widget->pos(); |