macOS: Prevent recursion when modifying the edit menu

Amends d42cfeb84f, which would result in
infinite recursion when the Edit menu was populated and added to the
menubar after the menubar has been shown.

Add a macOS-only test case that reproduces the crash without the fix.

Fixes: QTBUG-100441
Pick-to: 6.3
Change-Id: I018a7aa7f01558a3b9732b4d6d96a911dc7fbd19
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Volker Hilsheimer 2022-02-08 16:37:29 +01:00
parent 15caa47e4b
commit 851143eff1
2 changed files with 37 additions and 1 deletions

View File

@ -196,8 +196,15 @@ void QCocoaMenuBar::syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate)
const QString captionNoAmpersand = QString::fromNSString(cocoaMenu->nsMenu().title)
.remove(QLatin1Char('&'));
if (captionNoAmpersand == QCoreApplication::translate("QCocoaMenu", "Edit"))
if (captionNoAmpersand == QCoreApplication::translate("QCocoaMenu", "Edit")) {
// prevent recursion from QCocoaMenu::insertMenuItem - when the menu is visible
// it calls syncMenu again. QCocoaMenu::setVisible just sets the bool, which then
// gets evaluated in the code after this block.
const bool wasVisible = cocoaMenu->isVisible();
cocoaMenu->setVisible(false);
insertDefaultEditItems(cocoaMenu);
cocoaMenu->setVisible(wasVisible);
}
BOOL shouldHide = YES;
if (cocoaMenu->isVisible()) {

View File

@ -40,6 +40,7 @@
#include <QVBoxLayout>
#include <QLabel>
#include <QPlainTextEdit>
#include <QTranslator>
#include <qscreen.h>
#include <qobject.h>
@ -144,6 +145,8 @@ private slots:
#ifdef Q_OS_MACOS
void taskQTBUG56275_reinsertMenuInParentlessQMenuBar();
void QTBUG_57404_existingMenuItemException();
void defaultEditMenuItems();
#endif
void QTBUG_25669_menubarActionDoubleTriggered();
void taskQTBUG55966_subMenuRemoved();
@ -1818,6 +1821,32 @@ void tst_QMenuBar::QTBUG_57404_existingMenuItemException()
QTest::qWait(100);
// No crash, all fine. Ideally, there should be only one warning.
}
void tst_QMenuBar::defaultEditMenuItems()
{
class TestTranslator : public QTranslator
{
public:
QString translate(const char *context, const char *sourceText,
const char *disambiguation = nullptr, int n = -1) const override
{
if (QByteArrayView(context) == "QCocoaMenu" && QByteArrayView(sourceText) == "Edit")
return QString("Editieren");
return QTranslator::translate(context, sourceText, disambiguation, n);
}
} testTranslator;
qApp->installTranslator(&testTranslator);
QMainWindow mw;
mw.show();
QVERIFY(QTest::qWaitForWindowActive(&mw));
mw.menuBar()->addMenu("Editieren")->addAction("Undo");
mw.hide();
mw.show();
// this should not crash with infinite recursion
}
#endif // Q_OS_MACOS
void tst_QMenuBar::taskQTBUG55966_subMenuRemoved()