diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2021-10-19 19:22:32 +0200 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2021-10-21 16:05:47 +0200 |
commit | d42cfeb84faf154b46f2811b2059946b396fcc12 (patch) | |
tree | 983dd633326c9ceb4908f79066c29a6641bae17e | |
parent | e2fc3246d24e2b3a64ec2005e51efae88cbdc32e (diff) |
macOS: add default Edit menu items, if not added by AppKit
AppKit automatically appends "Start Dictation..." and "Emoji & Symbols"
menu items, after a separator, to a menu in the menu bar that has the
title "Edit" in the operating system language.
Qt applications might however be translated to some other language, in
which case the "Edit" menu is not recognized by AppKit, and the menu
items won't be added. This is bad for accessibility and for users
wanting to type emojis.
If we have a menu that has the title "Edit" as translated in Qt's i18n
system, then create those items manually. To prevent a duplication of
the system- provided menu items, don't add the items if there already
is one with the action being set to the relevant selector. Otherwise,
perform the selector or call the NSApplication method ourselves. This
then results in the relevant keyboard input through regular code paths.
Fixes: QTBUG-79565
Change-Id: Ifd06036211756277550d398034689aca8e770133
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenubar.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenubar.mm | 47 |
2 files changed, 49 insertions, 0 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h index 7186e48829..0054cdf6ad 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.h +++ b/src/plugins/platforms/cocoa/qcocoamenubar.h @@ -80,12 +80,14 @@ private: bool needsImmediateUpdate(); bool shouldDisable(QCocoaWindow *active) const; + void insertDefaultEditItems(QCocoaMenu *menu); NSMenuItem *nativeItemForMenu(QCocoaMenu *menu) const; QList<QPointer<QCocoaMenu> > m_menus; NSMenu *m_nativeMenu; QPointer<QCocoaWindow> m_window; + QList<QPointer<QCocoaMenuItem>> m_defaultEditMenuItems; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index 2e0eeb06e3..524746f952 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -194,6 +194,11 @@ 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(QLatin1Char('&')); + if (captionNoAmpersand == QCoreApplication::translate("QCocoaMenu", "Edit")) + insertDefaultEditItems(cocoaMenu); + BOOL shouldHide = YES; if (cocoaMenu->isVisible()) { // If the NSMenu has no visible items, or only separators, we should hide it @@ -400,6 +405,48 @@ QCocoaWindow *QCocoaMenuBar::cocoaWindow() const return m_window.data(); } +void QCocoaMenuBar::insertDefaultEditItems(QCocoaMenu *menu) +{ + if (menu->items().isEmpty()) + return; + + NSMenu *nsEditMenu = menu->nsMenu(); + if ([nsEditMenu itemAtIndex:nsEditMenu.numberOfItems - 1].action + == @selector(orderFrontCharacterPalette:)) { + for (auto defaultEditMenuItem : qAsConst(m_defaultEditMenuItems)) { + if (menu->items().contains(defaultEditMenuItem)) + menu->removeMenuItem(defaultEditMenuItem); + } + qDeleteAll(m_defaultEditMenuItems); + m_defaultEditMenuItems.clear(); + } else { + if (m_defaultEditMenuItems.isEmpty()) { + QCocoaMenuItem *separator = new QCocoaMenuItem; + separator->setIsSeparator(true); + + QCocoaMenuItem *dictationItem = new QCocoaMenuItem; + dictationItem->setText(QCoreApplication::translate("QCocoaMenuItem", "Start Dictation...")); + QObject::connect(dictationItem, &QPlatformMenuItem::activated, this, []{ + [NSApplication.sharedApplication performSelector:@selector(startDictation:)]; + }); + + QCocoaMenuItem *emojiItem = new QCocoaMenuItem; + emojiItem->setText(QCoreApplication::translate("QCocoaMenuItem", "Emoji && Symbols")); + emojiItem->setShortcut(QKeyCombination(Qt::MetaModifier|Qt::ControlModifier, Qt::Key_Space)); + QObject::connect(emojiItem, &QPlatformMenuItem::activated, this, []{ + [NSApplication.sharedApplication orderFrontCharacterPalette:nil]; + }); + + m_defaultEditMenuItems << separator << dictationItem << emojiItem; + } + for (auto defaultEditMenuItem : qAsConst(m_defaultEditMenuItems)) { + if (menu->items().contains(defaultEditMenuItem)) + menu->removeMenuItem(defaultEditMenuItem); + menu->insertMenuItem(defaultEditMenuItem, nullptr); + } + } +} + QT_END_NAMESPACE #include "moc_qcocoamenubar.cpp" |