QQuickMenu: respect Qt::AA_DontUseNativeMenuWindows

Now that we enable native menus by default for the macOS
style, we also need to make sure that we actually respect
the Qt::AA_DontUseNativeMenuWindows.

Pick-to: 6.8
Change-Id: I2a02b5528110a4e0514fb53c0673653f0086dfe8
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
This commit is contained in:
Richard Moe Gustavsen 2024-06-27 12:18:09 +02:00
parent 744fda3674
commit 399c3c4216
5 changed files with 77 additions and 3 deletions

View File

@ -214,6 +214,9 @@ static const int SUBMENU_DELAY = 225;
is the default when the style doesn't set a popup type).
If you add customizations to a menu, and want those to be used regardless of the
style, you should set the popup type to be \c Popup.Window (or \c Popup.Item) explicitly.
Another alternative is to set the \c Qt::AA_DontUseNativeMenuWindows
\l {Qt::ApplicationAttribute}{application attribute}. This will disable native context
menus for the whole application, irrespective of the style.
Whether a menu will be able to use the preferred type depends on the platform.
\c Popup.Item is supported on all platforms, but \c Popup.Window is
@ -364,9 +367,14 @@ QQuickMenu *QQuickMenuPrivate::rootMenu() const
bool QQuickMenuPrivate::useNativeMenu() const
{
// If we're inside a MenuBar, it'll decide whether or not we
// should be native or not. Otherwise, the root menu (which
// might be this menu) will decide.
if (QGuiApplication::testAttribute(Qt::AA_DontUseNativeMenuWindows))
return false;
// If we're inside a MenuBar, it'll decide whether or not we should be
// native. Otherwise, the root menu (which might be this menu) will decide.
// Note that this is just a preference, QPA can still fail to create a native
// menu. In that case we'll fall back to let QQuickPopup create the menu/popup
// instead, and end up with Window or Item as resolved popup type.
QQuickMenu *root = rootMenu();
if (auto menuBar = QQuickMenuPrivate::get(root)->menuBar.get())
return QQuickMenuBarPrivate::get(menuBar)->useNativeMenu(q_func());

View File

@ -101,6 +101,7 @@ private slots:
void nativeDynamicActions();
void nativeDynamicSubmenus();
void nativeMenuSeparator();
void AA_DontUseNativeMenuWindows();
void dontUseNativeMenuWindowsChanges();
void nativeMixedItems();
void effectivePosition_data();
@ -1841,6 +1842,9 @@ void tst_QQuickMenu::addRemoveSubMenus()
void tst_QQuickMenu::subMenuPopupType()
{
// Undo the setting of AA_DontUseNativeMenuWindows to true from init()
QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows, false);
// Check that all sub-menus will end up with an effective popup
// type equal to the root menu.
QQuickControlsApplicationHelper helper(this, QLatin1String("subMenus.qml"));
@ -2284,6 +2288,9 @@ void tst_QQuickMenu::invalidUrlInImgTag()
void tst_QQuickMenu::nativeStatic()
{
// Undo the setting of AA_DontUseNativeMenuWindows to true from init()
QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows, false);
QQuickControlsApplicationHelper helper(this, QLatin1String("nativeStatic.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
QQuickApplicationWindow *window = helper.appWindow;
@ -2386,6 +2393,9 @@ void tst_QQuickMenu::nativeDynamicActions()
void tst_QQuickMenu::nativeDynamicSubmenus()
{
// Undo the setting of AA_DontUseNativeMenuWindows to true from init()
QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows, false);
QQuickControlsApplicationHelper helper(this, QLatin1String("nativeDynamicSubmenus.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
QQuickApplicationWindow *window = helper.appWindow;
@ -2493,6 +2503,9 @@ void tst_QQuickMenu::nativeDynamicSubmenus()
void tst_QQuickMenu::nativeMenuSeparator()
{
// Undo the setting of AA_DontUseNativeMenuWindows to true from init()
QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows, false);
QQuickControlsApplicationHelper helper(this, QLatin1String("nativeMenuSeparator.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
QQuickApplicationWindow *window = helper.appWindow;
@ -2530,6 +2543,30 @@ void tst_QQuickMenu::nativeMenuSeparator()
}
}
void tst_QQuickMenu::AA_DontUseNativeMenuWindows()
{
// Check that we end up with a non-native menu when AA_DontUseNativeMenuWindows
// is set, even if popupType is Native.
QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
QQuickControlsApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
QQuickApplicationWindow *window = helper.appWindow;
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window));
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
QVERIFY(menu);
QQuickMenuPrivate *menu_d = QQuickMenuPrivate::get(menu);
menu->setPopupType(QQuickPopup::Native);
// Note: since a native menu is blocking, we cannot open it, in case
// the test fails and it actually opens. That would block the test as
// well. So we just check that useNativeMenu returns false for now.
QVERIFY(!menu_d->useNativeMenu());
QVERIFY(!menu_d->maybeNativeHandle());
}
void tst_QQuickMenu::dontUseNativeMenuWindowsChanges()
{
QSKIP("QTBUG-125967 This test will need to be fixed, by using popupType: Popup.Native instead of AA_DontUseNativeMenuWindows.");

View File

@ -209,6 +209,13 @@ ApplicationWindow {
onClicked: subMenu.removeLastAction()
}
}
Row {
Switch {
text: qsTr("Don't use native menu windows")
checked: CppSettings.dontUseNativeMenuWindows
onClicked: CppSettings.dontUseNativeMenuWindows = checked
}
}
}
}

View File

@ -41,3 +41,19 @@ void CppSettings::setPopupType(int newPopupType)
mSettings.setValue("popupType", newPopupType);
emit popupTypeChanged();
}
bool CppSettings::dontUseNativeMenuWindows() const
{
return mSettings.value("dontUseNativeMenuWindows").toBool();
}
void CppSettings::setDontUseNativeMenuWindows(bool dontUseNativeMenuWindows)
{
const bool oldValue = this->dontUseNativeMenuWindows();
if (dontUseNativeMenuWindows == oldValue)
return;
QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows, dontUseNativeMenuWindows);
mSettings.setValue("dontUseNativeMenuWindows", dontUseNativeMenuWindows);
emit dontUseNativeMenuWindowsChanged();
}

View File

@ -13,6 +13,8 @@ class CppSettings : public QObject
Q_OBJECT
Q_PROPERTY(bool dontUseNativeMenuBar READ dontUseNativeMenuBar WRITE setDontUseNativeMenuBar
NOTIFY dontUseNativeMenuBarChanged FINAL)
Q_PROPERTY(bool dontUseNativeMenuWindows READ dontUseNativeMenuWindows WRITE setDontUseNativeMenuWindows
NOTIFY dontUseNativeMenuBarChanged FINAL)
Q_PROPERTY(int popupType READ popupType WRITE setPopupType
NOTIFY popupTypeChanged FINAL)
QML_ELEMENT
@ -27,8 +29,12 @@ public:
int popupType() const;
void setPopupType(int newPopupType);
bool dontUseNativeMenuWindows() const;
void setDontUseNativeMenuWindows(bool newDontUseNativeMenuWindows);
signals:
void dontUseNativeMenuBarChanged();
void dontUseNativeMenuWindowsChanged();
void popupTypeChanged();
private: