From 51d416cdfd909aacd5047632a7cc1661a158731a Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 11 Jan 2021 17:03:21 +0100 Subject: Fix popups with exit transitions blocking mouse events when destroyed If a popup had an exit transition set and was destroyed upon e.g. being rejected, it would not destroy its modal dimmer, and so events would not go through to popups that were beneath it even after it was destroyed. QQuickPopup's destructor does indirectly attempt to call finalizeExitTransition() through a setParentItem(nullptr) call, but prepareExitTransition() returns false if it sees that the exit transition is already running, and so transitionExit() never calls finished(). This patch fixes the problem by explicitly calling finalizeExitTransition() in QQuickPopup's destructor if the exit transition is running. Fixes: QTBUG-89673 Pick-to: 5.15 6.0 Change-Id: I468fae52f6a83ac314877c67d062028634bb7e17 Reviewed-by: Volker Hilsheimer --- src/quicktemplates2/qquickpopup.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index 455b0425..f54b610c 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -51,6 +51,8 @@ QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcDimmer, "qt.quick.controls.popup.dimmer") + /*! \qmltype Popup \inherits QtObject @@ -499,8 +501,10 @@ void QQuickPopupPrivate::finalizeExitTransition() { Q_Q(QQuickPopup); getPositioner()->setParentItem(nullptr); - popupItem->setParentItem(nullptr); - popupItem->setVisible(false); + if (popupItem) { + popupItem->setParentItem(nullptr); + popupItem->setVisible(false); + } destroyOverlay(); if (hadActiveFocusBeforeExitTransition && window) { @@ -531,8 +535,10 @@ void QQuickPopupPrivate::finalizeExitTransition() hadActiveFocusBeforeExitTransition = false; emit q->visibleChanged(); emit q->closed(); - popupItem->setScale(prevScale); - popupItem->setOpacity(prevOpacity); + if (popupItem) { + popupItem->setScale(prevScale); + popupItem->setOpacity(prevOpacity); + } } void QQuickPopupPrivate::opened() @@ -733,6 +739,8 @@ static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQ if (component) component->completeCreate(); } + qCDebug(lcDimmer) << "finished creating dimmer from component" << component + << "for popup" << popup << "with parent" << parent << "- item is:" << item; return item; } @@ -759,6 +767,7 @@ void QQuickPopupPrivate::createOverlay() void QQuickPopupPrivate::destroyOverlay() { if (dimmer) { + qCDebug(lcDimmer) << "destroying dimmer" << dimmer; dimmer->setParentItem(nullptr); dimmer->deleteLater(); dimmer = nullptr; @@ -857,6 +866,12 @@ QQuickPopup::~QQuickPopup() d->popupItem = nullptr; delete d->positioner; d->positioner = nullptr; + + // If the popup is destroyed before the exit transition finishes, + // the necessary cleanup (removing modal dimmers that block mouse events, + // emitting closed signal, etc.) won't happen. That's why we do it manually here. + if (d->transitionState == QQuickPopupPrivate::ExitTransition && d->transitionManager.isRunning()) + d->finalizeExitTransition(); } /*! -- cgit v1.2.3