@@ -271,6 +271,8 @@ void TouchRegistry::addCandidateOwnerForTouch(int id, QQuickItem *candidate)
271271 this, &TouchRegistry::rejectCandidateOwnerForTouch);
272272
273273 touchInfo->candidates.append(candidateInfo);
274+
275+ connect(candidate, &QObject::destroyed, this, [=](){ pruneNullCandidatesForTouch(id); });
274276}
275277
276278void TouchRegistry::addTouchWatcher(int touchId, QQuickItem *watcher)
@@ -296,25 +298,53 @@ void TouchRegistry::removeCandidateOwnerForTouch(int id, QQuickItem *candidate)
296298 Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
297299 if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
298300
299− int indexRemoved = -1;
300301
301302 // TODO: check if the candidate is in fact the owner of the touch
302303
303− for (int i = 0; i < touchInfo->candidates.count() && indexRemoved == -1; ++i) {
304− CandidateInfo &candidateInfo = touchInfo->candidates[i];
305− if (candidateInfo.item == candidate) {
306− Q_ASSERT(i > 0 || candidateInfo.state == CandidateInfo::Undecided);
307− if (i == 0 && candidateInfo.state != CandidateInfo::Undecided) {
308− qCritical("TouchRegistry: touch owner is being removed.");
309− }
310− delete candidateInfo.inactivityTimer;
311− candidateInfo.inactivityTimer = nullptr;
312− touchInfo->candidates.removeAt(i);
313− indexRemoved = i;
304+ bool removed = false;
305+ for (int i = 0; i < touchInfo->candidates.count() && !removed; ++i) {
306+ if (touchInfo->candidates[i].item == candidate) {
307+ removeCandidateOwnerForTouchByIndex(touchInfo, i);
308+ removed = true;
314309 }
315310 }
311+}
312+
313+void TouchRegistry::pruneNullCandidatesForTouch(int touchId)
314+{
315+ #if TOUCHREGISTRY_DEBUG
316+ UG_DEBUG << "pruneNullCandidatesForTouch touchId" << touchId;
317+ #endif
318+
319+ Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchId);
320+ if (!touchInfo) {
321+ // doesn't matter as touch is already gone.
322+ return;
323+ }
316324
317− if (indexRemoved == 0) {
325+ int i = 0;
326+ while (i < touchInfo->candidates.count()) {
327+ if (touchInfo->candidates[i].item.isNull()) {
328+ removeCandidateOwnerForTouchByIndex(touchInfo, i);
329+ } else {
330+ ++i;
331+ }
332+ }
333+}
334+
335+void TouchRegistry::removeCandidateOwnerForTouchByIndex(Pool<TouchRegistry::TouchInfo>::Iterator &touchInfo,
336+ int candidateIndex)
337+{
338+ // TODO: check if the candidate is in fact the owner of the touch
339+
340+ Q_ASSERT(candidateIndex < touchInfo->candidates.count());
341+
342+ if (candidateIndex == 0 && touchInfo->candidates[candidateIndex].state != CandidateInfo::Undecided) {
343+ qCritical("TouchRegistry: touch owner is being removed.");
344+ }
345+ removeCandidateHelper(touchInfo, candidateIndex);
346+
347+ if (candidateIndex == 0) {
318348 // the top candidate has been removed. if the new top candidate
319349 // wants the touch let him know he's now the owner.
320350 if (touchInfo->isOwned()) {
@@ -359,6 +389,7 @@ void TouchRegistry::requestTouchOwnership(int id, QQuickItem *candidate)
359389 touchInfo->candidates.append(candidateInfo);
360390 // it's the last one
361391 candidateIndex = touchInfo->candidates.count() - 1;
392+ connect(candidate, &QObject::destroyed, this, [=](){ pruneNullCandidatesForTouch(id); });
362393 }
363394
364395 // If it's the top candidate it means it's now the owner. Let
@@ -430,7 +461,7 @@ void TouchRegistry::rejectCandidateOwnerForTouch(int id, QQuickItem *candidate)
430461 QCoreApplication::sendEvent(candidate, &lostOwnershipEvent);
431462 }
432463
433− touchInfo->candidates.removeAt(rejectedCandidateIndex);
464+ removeCandidateHelper(touchInfo, rejectedCandidateIndex);
434465
435466 if (rejectedCandidateIndex == 0) {
436467 // the top candidate has been removed. if the new top candidate
@@ -441,6 +472,21 @@ void TouchRegistry::rejectCandidateOwnerForTouch(int id, QQuickItem *candidate)
441472 }
442473}
443474
475+void TouchRegistry::removeCandidateHelper(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex)
476+{
477+ {
478+ CandidateInfo &candidateInfo = touchInfo->candidates[candidateIndex];
479+
480+ delete candidateInfo.inactivityTimer;
481+ candidateInfo.inactivityTimer = nullptr;
482+
483+ if (candidateInfo.item) {
484+ disconnect(candidateInfo.item.data(), nullptr, this, nullptr);
485+ }
486+ }
487+ touchInfo->candidates.removeAt(candidateIndex);
488+}
489+
444490////////////////////////////////////// TouchRegistry::TouchInfo ////////////////////////////////////
445491
446492TouchRegistry::TouchInfo::TouchInfo(int id)