diff options
author | Gabriel de Dietrich <gabriel.dedietrich@qt.io> | 2018-03-28 18:07:30 -0700 |
---|---|---|
committer | Gabriel de Dietrich <gabriel.dedietrich@qt.io> | 2018-04-19 22:19:46 +0000 |
commit | b7be91b5f28cd42e6f9898f480fa12a0cd359a84 (patch) | |
tree | 78a8d28dd227d12afbd95677e8a4932ed1ca319a /src/plugins/platforms/cocoa/qcocoamenubar.mm | |
parent | 0b9a301e89c6473091a9b80552d6e4058d35bbe6 (diff) |
Cocoa Menus: Use the responder chain for menu items target/action
We start by setting the menu item target to nil.
Then, -[qt_itemFired:] action is now in QNSView, which itself is
naturally inserted in the responder chain. This removes the need
to track and change the menu item's target/action when we're
displaying a native dialog. Part of this is possible because we
now derive our own QCocoaNSMenuItem class from NSMenuItem.
We use -[respondsToSelector:] to decide whether the QNSView in
the responder chain should respond to cut:, copy:, etc. And we
only return YES when the view is first responder. The invocation
to these action is forwarded to the same views' -[qt_itemFired:].
Message forwarding is done via forwardInvocation:, but experiments
have shown that it can be done by the sole means of respondsToSelector:
and direct invocation from cut:, copy:, etc. See the usage of the
macro QT_COCOA_DYNAMIC_MENU_ITEM_ACTION.
Menu validation also happens in QNSView and looks for modal windows.
Therefore, -[worksWhenModal] is no longer necessary. Also, since the
target is no longer set, the logic as documented in NSMenuItem.target
won't work anymore.
Most items from QCocoaMenuLoader also become QCocoaNSMenuItem and
get the same target/action, which removes a bit of duplicated (and
outdated) code. A particular case is the Quit item, which gets the
terminate: action set until an actual menu item is added.
Tested with texedit and standard dialogs examples together with
menus, menurama and bigmenucreator manual tests.
We also renamed some functions and variables to reflect common
naming practices.
Change-Id: I9b51d3be3467a666d8c3dcf8585edbc821e0282e
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoamenubar.mm')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenubar.mm | 63 |
1 files changed, 1 insertions, 62 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index 61ac5eb7f0..1b6b5a5de6 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -86,7 +86,6 @@ QCocoaMenuBar::~QCocoaMenuBar() // the menu bar was updated qDeleteAll(children()); updateMenuBarImmediately(); - resetKnownMenuItemsToQt(); } } @@ -259,66 +258,6 @@ QCocoaMenuBar *QCocoaMenuBar::findGlobalMenubar() return NULL; } -void QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder() -{ - // QTBUG-17291: http://forums.macrumors.com/showthread.php?t=1249452 - // When a dialog is opened, shortcuts for actions inside the dialog (cut, paste, ...) - // continue to go through the same menu items which claimed those shortcuts. - // They are not keystrokes which we can intercept in any other way; the OS intercepts them. - // The menu items had to be created by the application. That's why we need roles - // to identify those "special" menu items which can be useful even when non-Qt - // native widgets are in focus. When the native widget is focused it will be the - // first responder, so the menu item needs to have its target be the first responder; - // this is done by setting it to nil. - - // This function will find all menu items on all menus which have - // "special" roles, set the target and also set the standard actions which - // apply to those roles. But afterwards it is necessary to call - // resetKnownMenuItemsToQt() to put back the target and action so that - // those menu items will go back to invoking their associated QActions. - foreach (QCocoaMenuBar *mb, static_menubars) - foreach (QCocoaMenu *m, mb->m_menus) - foreach (QCocoaMenuItem *i, m->items()) { - bool known = true; - switch (i->effectiveRole()) { - case QPlatformMenuItem::CutRole: - [i->nsItem() setAction:@selector(cut:)]; - break; - case QPlatformMenuItem::CopyRole: - [i->nsItem() setAction:@selector(copy:)]; - break; - case QPlatformMenuItem::PasteRole: - [i->nsItem() setAction:@selector(paste:)]; - break; - case QPlatformMenuItem::SelectAllRole: - [i->nsItem() setAction:@selector(selectAll:)]; - break; - // We may discover later that there are other roles/actions which - // are meaningful to standard native widgets; they can be added. - default: - known = false; - break; - } - if (known) - [i->nsItem() setTarget:nil]; - } -} - -void QCocoaMenuBar::resetKnownMenuItemsToQt() -{ - // Undo the effect of redirectKnownMenuItemsToFirstResponder(): - // reset the menu items' target/action. - foreach (QCocoaMenuBar *mb, static_menubars) { - foreach (QCocoaMenu *m, mb->m_menus) { - foreach (QCocoaMenuItem *i, m->items()) { - if (i->effectiveRole() >= QPlatformMenuItem::ApplicationSpecificRole) { - m->setItemTargetAction(i); - } - } - } - } -} - void QCocoaMenuBar::updateMenuBarImmediately() { QMacAutoReleasePool pool; @@ -438,7 +377,7 @@ QPlatformMenu *QCocoaMenuBar::menuForTag(quintptr tag) const return menu; } - return 0; + return nullptr; } NSMenuItem *QCocoaMenuBar::itemForRole(QPlatformMenuItem::MenuRole r) |