@@ -271,6 +271,8 @@ void TouchRegistry::addCandidateOwnerForTouch(int id, QQuickItem *candidate)
271 this, &TouchRegistry::rejectCandidateOwnerForTouch);
271 this, &TouchRegistry::rejectCandidateOwnerForTouch);
273 touchInfo->candidates.append(candidateInfo);
273 touchInfo->candidates.append(candidateInfo);
275+ connect(candidate, &QObject::destroyed, this, [=](){ pruneNullCandidatesForTouch(id); });
276void TouchRegistry::addTouchWatcher(int touchId, QQuickItem *watcher)
278void TouchRegistry::addTouchWatcher(int touchId, QQuickItem *watcher)
@@ -296,25 +298,53 @@ void TouchRegistry::removeCandidateOwnerForTouch(int id, QQuickItem *candidate)
296 Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
298 Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
297 if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
299 if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
299− int indexRemoved = -1;
301 // TODO: check if the candidate is in fact the owner of the touch
302 // TODO: check if the candidate is in fact the owner of the touch
304+ bool removed = false;
303− for (int i = 0; i < touchInfo->candidates.count() && indexRemoved == -1; ++i) {
305+ for (int i = 0; i < touchInfo->candidates.count() && !removed; ++i) {
304− CandidateInfo &candidateInfo = touchInfo->candidates[i];
306+ if (touchInfo->candidates[i].item == candidate) {
305− if (candidateInfo.item == candidate) {
307+ removeCandidateOwnerForTouchByIndex(touchInfo, i);
306− Q_ASSERT(i > 0 || candidateInfo.state == CandidateInfo::Undecided);
308+ removed = true;
307− if (i == 0 && candidateInfo.state != CandidateInfo::Undecided) {
308− qCritical("TouchRegistry: touch owner is being removed.");
310− delete candidateInfo.inactivityTimer;
311− candidateInfo.inactivityTimer = nullptr;
312− touchInfo->candidates.removeAt(i);
313+void TouchRegistry::pruneNullCandidatesForTouch(int touchId)
315+ #if TOUCHREGISTRY_DEBUG
316+ UG_DEBUG << "pruneNullCandidatesForTouch touchId" << touchId;
319+ Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchId);
321+ // doesn't matter as touch is already gone.
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);
335+void TouchRegistry::removeCandidateOwnerForTouchByIndex(Pool<TouchRegistry::TouchInfo>::Iterator &touchInfo,
338+ // TODO: check if the candidate is in fact the owner of the touch
340+ Q_ASSERT(candidateIndex < touchInfo->candidates.count());
342+ if (candidateIndex == 0 && touchInfo->candidates[candidateIndex].state != CandidateInfo::Undecided) {
343+ qCritical("TouchRegistry: touch owner is being removed.");
345+ removeCandidateHelper(touchInfo, candidateIndex);
347+ if (candidateIndex == 0) {
318 // the top candidate has been removed. if the new top candidate
348 // the top candidate has been removed. if the new top candidate
319 // wants the touch let him know he's now the owner.
349 // wants the touch let him know he's now the owner.
320 if (touchInfo->isOwned()) {
350 if (touchInfo->isOwned()) {
@@ -359,6 +389,7 @@ void TouchRegistry::requestTouchOwnership(int id, QQuickItem *candidate)
359 touchInfo->candidates.append(candidateInfo);
389 touchInfo->candidates.append(candidateInfo);
360 // it's the last one
390 // it's the last one
361 candidateIndex = touchInfo->candidates.count() - 1;
391 candidateIndex = touchInfo->candidates.count() - 1;
392+ connect(candidate, &QObject::destroyed, this, [=](){ pruneNullCandidatesForTouch(id); });
364 // If it's the top candidate it means it's now the owner. Let
395 // 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)
430 QCoreApplication::sendEvent(candidate, &lostOwnershipEvent);
461 QCoreApplication::sendEvent(candidate, &lostOwnershipEvent);
433− touchInfo->candidates.removeAt(rejectedCandidateIndex);
464+ removeCandidateHelper(touchInfo, rejectedCandidateIndex);
435 if (rejectedCandidateIndex == 0) {
466 if (rejectedCandidateIndex == 0) {
436 // the top candidate has been removed. if the new top candidate
467 // the top candidate has been removed. if the new top candidate
@@ -441,6 +472,21 @@ void TouchRegistry::rejectCandidateOwnerForTouch(int id, QQuickItem *candidate)
475+void TouchRegistry::removeCandidateHelper(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex)
478+ CandidateInfo &candidateInfo = touchInfo->candidates[candidateIndex];
480+ delete candidateInfo.inactivityTimer;
481+ candidateInfo.inactivityTimer = nullptr;
483+ if (candidateInfo.item) {
484+ disconnect(candidateInfo.item.data(), nullptr, this, nullptr);
487+ touchInfo->candidates.removeAt(candidateIndex);
444////////////////////////////////////// TouchRegistry::TouchInfo ////////////////////////////////////
490////////////////////////////////////// TouchRegistry::TouchInfo ////////////////////////////////////
446TouchRegistry::TouchInfo::TouchInfo(int id)
492TouchRegistry::TouchInfo::TouchInfo(int id)