From bab177366140df8afe3c0eafef4616bbfc3180af Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 24 Apr 2024 12:31:26 +0800 Subject: [PATCH] QCocoaMenu: fix crash when app quits while menu is open Consider the following QML code: import QtQuick import QtQuick.Controls ApplicationWindow { visible: true Menu { id: menu MenuItem { text: "Some action" } } TapHandler { acceptedButtons: Qt.RightButton onTapped: { exitAppTimer.start() menu.open() } } Timer { id: exitAppTimer interval: 1000 onTriggered: Qt.quit() } } With the new native Qt Quick Menu, this will create a native menu on platforms like macOS. When the user right clicks on the window, a timer is started and a native menu opened. After 1 second, Qt.quit() is called while the menu is still open. As popUpContextMenu is blocking, when the menu is finally closed (by user interaction), control returns to QCocoaMenu::showPopup, but the QCocoaWindow has since been destroyed. Account for this by storing the window in a QPointer. It's not possible to test this as native menus can't be auto-tested. Fixes: QTBUG-124551 Pick-to: 6.5 Change-Id: I14a97073f350c38828b3e16bb157439aeeeb6529 Reviewed-by: Richard Moe Gustavsen (cherry picked from commit 468cb035efe4890c388069eb373a7ae8ef178146) Reviewed-by: Qt Cherry-pick Bot --- src/plugins/platforms/cocoa/qcocoamenu.mm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 7a6999c2cc2..fa88a19d45c 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -326,7 +326,9 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, QPointer guard = this; QPoint pos = QPoint(targetRect.left(), targetRect.top() + targetRect.height()); - QCocoaWindow *cocoaWindow = parentWindow ? static_cast(parentWindow->handle()) : nullptr; + // If the app quits while the menu is open (e.g. through a timer that starts before the menu was opened), + // then the window will have been destroyed before this function finishes executing. Account for that with QPointer. + QPointer cocoaWindow = parentWindow ? static_cast(parentWindow->handle()) : nullptr; NSView *view = cocoaWindow ? cocoaWindow->view() : nil; NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil;