diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-08-31 08:58:40 +0200 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-09-08 07:20:10 +0200 |
commit | 03d62322b239772e0440cee9ce7576147239f339 (patch) | |
tree | dfabec731a35aed532a8763b5aac9ba2ce39b3b5 /src/widgets/widgets/qcombobox.cpp | |
parent | 6cf4c5b98fb0e3f30379d79003ab587aadebbce7 (diff) |
QComboBox on macOS: guard against destruction while native popup is open
Since showing the native popup on macOS is blocking and processes events
the QComboBox might get destroyed while the popup is open. Guard against
this by using QPointer and returning early (dismissing the scope guard
that would otherwise reset the menu's parent, writing to freed memory).
The problem is then that the native popup remains visible, as the
destructor of QComboBox calls cleanupNativeCombobox which destroys the
platform menu (i.e. the QCocoaMenu instance), but that doesn't dismiss()
the popup. Add a call to dismiss() to the QCocoaMenu destructor to make
sure that destroying the menu closes it first.
Fixes: QTBUG-116155
Pick-to: 6.6 6.5
Change-Id: If0ac19796603667f4c8e80c302710dc4c9aded50
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Diffstat (limited to 'src/widgets/widgets/qcombobox.cpp')
-rw-r--r-- | src/widgets/widgets/qcombobox.cpp | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index 4d6ce39007..97e6153b08 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -2469,12 +2469,13 @@ void QComboBoxPrivate::cleanupNativePopup() if (!m_platformMenu) return; + m_platformMenu->setVisible(false); int count = int(m_platformMenu->tag()); for (int i = 0; i < count; ++i) m_platformMenu->menuItemAt(i)->deleteLater(); delete m_platformMenu; - m_platformMenu = 0; + m_platformMenu = nullptr; } /*! @@ -2531,15 +2532,18 @@ bool QComboBoxPrivate::showNativePopup() else if (q->testAttribute(Qt::WA_MacMiniSize)) offset = QPoint(-2, 6); + [[maybe_unused]] QPointer<QComboBox> guard(q); const QRect targetRect = QRect(tlw->mapFromGlobal(q->mapToGlobal(offset)), QSize()); m_platformMenu->showPopup(tlw, QHighDpi::toNativePixels(targetRect, tlw), currentItem); #ifdef Q_OS_MACOS - // The Cocoa popup will swallow any mouse release event. - // We need to fake one here to un-press the button. - QMouseEvent mouseReleased(QEvent::MouseButtonRelease, q->pos(), q->mapToGlobal(QPoint(0, 0)), - Qt::LeftButton, Qt::MouseButtons(Qt::LeftButton), {}); - QCoreApplication::sendEvent(q, &mouseReleased); + if (guard) { + // The Cocoa popup will swallow any mouse release event. + // We need to fake one here to un-press the button. + QMouseEvent mouseReleased(QEvent::MouseButtonRelease, q->pos(), q->mapToGlobal(QPoint(0, 0)), + Qt::LeftButton, Qt::MouseButtons(Qt::LeftButton), {}); + QCoreApplication::sendEvent(q, &mouseReleased); + } #endif return true; @@ -3116,7 +3120,10 @@ void QComboBoxPrivate::showPopupFromMouseEvent(QMouseEvent *e) // viewContainer(), we avoid creating the QComboBoxPrivateContainer. viewContainer()->initialClickPosition = q->mapToGlobal(e->position().toPoint()); } + QPointer<QComboBox> guard = q; q->showPopup(); + if (!guard) + return; // The code below ensures that regular mousepress and pick item still works // If it was not called the viewContainer would ignore event since it didn't have // a mousePressEvent first. |