diff options
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoamenubar.mm')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenubar.mm | 81 |
1 files changed, 52 insertions, 29 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index 23aae466df..5298997271 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -13,6 +13,8 @@ #include <QtGui/QGuiApplication> #include <QtCore/QDebug> +#include <QtGui/private/qguiapplication_p.h> + QT_BEGIN_NAMESPACE static QList<QCocoaMenuBar*> static_menubars; @@ -21,6 +23,11 @@ QCocoaMenuBar::QCocoaMenuBar() { static_menubars.append(this); + // clicks into the menu bar should close all popup windows + static QMacNotificationObserver menuBarClickObserver(nil, NSMenuDidBeginTrackingNotification, ^{ + QGuiApplicationPrivate::instance()->closeAllPopups(); + }); + m_nativeMenu = [[NSMenu alloc] init]; #ifdef QT_COCOA_ENABLE_MENU_DEBUG qDebug() << "Construct QCocoaMenuBar" << this << m_nativeMenu; @@ -32,7 +39,7 @@ QCocoaMenuBar::~QCocoaMenuBar() #ifdef QT_COCOA_ENABLE_MENU_DEBUG qDebug() << "~QCocoaMenuBar" << this; #endif - for (auto menu : qAsConst(m_menus)) { + for (auto menu : std::as_const(m_menus)) { if (!menu) continue; NSMenuItem *item = nativeItemForMenu(menu); @@ -158,18 +165,6 @@ void QCocoaMenuBar::syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate) for (QCocoaMenuItem *item : cocoaMenu->items()) cocoaMenu->syncMenuItem_helper(item, menubarUpdate); - const QString captionNoAmpersand = QString::fromNSString(cocoaMenu->nsMenu().title) - .remove(u'&'); - 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()) { // If the NSMenu has no visible items, or only separators, we should hide it @@ -233,7 +228,7 @@ QCocoaWindow *QCocoaMenuBar::findWindowForMenubar() QCocoaMenuBar *QCocoaMenuBar::findGlobalMenubar() { - for (auto *menubar : qAsConst(static_menubars)) { + for (auto *menubar : std::as_const(static_menubars)) { if (menubar->m_window.isNull()) return menubar; } @@ -274,7 +269,7 @@ void QCocoaMenuBar::updateMenuBarImmediately() #endif bool disableForModal = mb->shouldDisable(cw); - for (auto menu : qAsConst(mb->m_menus)) { + for (auto menu : std::as_const(mb->m_menus)) { if (!menu) continue; NSMenuItem *item = mb->nativeItemForMenu(menu); @@ -306,6 +301,22 @@ void QCocoaMenuBar::updateMenuBarImmediately() [NSApp setMainMenu:mb->nsMenu()]; insertWindowMenu(); [loader qtTranslateApplicationMenu]; + + for (auto menu : std::as_const(mb->m_menus)) { + if (!menu) + continue; + + const QString captionNoAmpersand = QString::fromNSString(menu->nsMenu().title).remove(u'&'); + if (captionNoAmpersand != QCoreApplication::translate("QCocoaMenu", "Edit")) + continue; + + NSMenuItem *item = mb->nativeItemForMenu(menu); + auto *nsMenu = item.submenu; + if ([nsMenu indexOfItemWithTarget:NSApp andAction:@selector(startDictation:)] == -1) { + // AppKit was not able to recognize the special role of this menu item. + mb->insertDefaultEditItems(menu); + } + } } void QCocoaMenuBar::insertWindowMenu() @@ -327,18 +338,27 @@ void QCocoaMenuBar::insertWindowMenu() [mainMenu insertItem:winMenuItem atIndex:mainMenu.itemArray.count]; app.windowsMenu = winMenuItem.submenu; - // Windows, created and 'ordered front' before, will not be in this menu: + // Windows that have already been ordered in at this point have already been + // evaluated by AppKit via _addToWindowsMenuIfNecessary and added to the menu, + // but since the menu didn't exist at that point the addition was a noop. + // Instead of trying to duplicate the logic AppKit uses for deciding if + // a window should be part of the Window menu we toggle one of the settings + // that definitely will affect this, which results in AppKit reevaluating the + // situation and adding the window to the menu if necessary. for (NSWindow *win in app.windows) { - if (win.title && ![win.title isEqualToString:@""]) - [app addWindowsItem:win title:win.title filename:NO]; + win.excludedFromWindowsMenu = !win.excludedFromWindowsMenu; + win.excludedFromWindowsMenu = !win.excludedFromWindowsMenu; } } QList<QCocoaMenuItem*> QCocoaMenuBar::merged() const { QList<QCocoaMenuItem*> r; - for (auto menu : qAsConst(m_menus)) + for (auto menu : std::as_const(m_menus)) { + if (!menu) + continue; r.append(menu->merged()); + } return r; } @@ -357,10 +377,10 @@ bool QCocoaMenuBar::shouldDisable(QCocoaWindow *active) const // When there is an application modal window on screen, the entries of // the menubar should be disabled. The exception in Qt is that if the // modal window is the only window on screen, then we enable the menu bar. - for (auto *window : qAsConst(topWindows)) { + for (auto *window : std::as_const(topWindows)) { if (window->isVisible() && window->modality() == Qt::ApplicationModal) { // check for other visible windows - for (auto *other : qAsConst(topWindows)) { + for (auto *other : std::as_const(topWindows)) { if ((window != other) && (other->isVisible())) { // INVARIANT: we found another visible window // on screen other than our modalWidget. We therefore @@ -381,8 +401,8 @@ bool QCocoaMenuBar::shouldDisable(QCocoaWindow *active) const QPlatformMenu *QCocoaMenuBar::menuForTag(quintptr tag) const { - for (auto menu : qAsConst(m_menus)) - if (menu->tag() == tag) + for (auto menu : std::as_const(m_menus)) + if (menu && menu->tag() == tag) return menu; return nullptr; @@ -390,10 +410,13 @@ QPlatformMenu *QCocoaMenuBar::menuForTag(quintptr tag) const NSMenuItem *QCocoaMenuBar::itemForRole(QPlatformMenuItem::MenuRole role) { - for (auto menu : qAsConst(m_menus)) - for (auto *item : menu->items()) - if (item->effectiveRole() == role) - return item->nsItem(); + for (auto menu : std::as_const(m_menus)) { + if (menu) { + for (auto *item : menu->items()) + if (item->effectiveRole() == role) + return item->nsItem(); + } + } return nil; } @@ -411,7 +434,7 @@ void QCocoaMenuBar::insertDefaultEditItems(QCocoaMenu *menu) NSMenu *nsEditMenu = menu->nsMenu(); if ([nsEditMenu itemAtIndex:nsEditMenu.numberOfItems - 1].action == @selector(orderFrontCharacterPalette:)) { - for (auto defaultEditMenuItem : qAsConst(m_defaultEditMenuItems)) { + for (auto defaultEditMenuItem : std::as_const(m_defaultEditMenuItems)) { if (menu->items().contains(defaultEditMenuItem)) menu->removeMenuItem(defaultEditMenuItem); } @@ -437,7 +460,7 @@ void QCocoaMenuBar::insertDefaultEditItems(QCocoaMenu *menu) m_defaultEditMenuItems << separator << dictationItem << emojiItem; } - for (auto defaultEditMenuItem : qAsConst(m_defaultEditMenuItems)) { + for (auto defaultEditMenuItem : std::as_const(m_defaultEditMenuItems)) { if (menu->items().contains(defaultEditMenuItem)) menu->removeMenuItem(defaultEditMenuItem); menu->insertMenuItem(defaultEditMenuItem, nullptr); |