NSMenuItem/NSMenu - set the submenu properly

... in case the submenu is set from a slot, attached to the aboutToShow()
signal. Normally, with a 'statically' pre-populated menu, we set 'submenu'
property on a menu item from 'updateItem' callback in our menu delegate.
After that, AppKit calls our delegate's willOpen call back and this is
where we emit 'aboutToShow'. Unfortunately, if an application tries to
create a nested menu 'dynamically' at this point, it never becomes 'submenu'
of the item, since 'updateItem' was already handled at this point.

We catch this case in QCocoaMenuItem and call setAttachedItem if needed.

Fixes: QTBUG-76060
Change-Id: I676bf1d8529b9ddbfc90e4dff422b39668b7a5fa
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Timur Pocheptsov 2019-06-21 13:37:40 +02:00
parent a7cbb8c639
commit 5b5e8f78fe
4 changed files with 24 additions and 0 deletions

View File

@ -92,6 +92,9 @@ public:
bool isOpen() const;
void setIsOpen(bool isOpen);
bool isAboutToShow() const;
void setIsAboutToShow(bool isAbout);
void timerEvent(QTimerEvent *e) override;
void syncMenuItem_helper(QPlatformMenuItem *menuItem, bool menubarUpdate);
@ -111,6 +114,7 @@ private:
bool m_parentEnabled:1;
bool m_visible:1;
bool m_isOpen:1;
bool m_isAboutToShow:1;
};
QT_END_NAMESPACE

View File

@ -178,6 +178,16 @@ void QCocoaMenu::setIsOpen(bool isOpen)
m_isOpen = isOpen;
}
bool QCocoaMenu::isAboutToShow() const
{
return m_isAboutToShow;
}
void QCocoaMenu::setIsAboutToShow(bool isAbout)
{
m_isAboutToShow = isAbout;
}
void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem)
{
QMacAutoReleasePool pool;

View File

@ -140,6 +140,12 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu)
if (menu == m_menu)
return;
bool setAttached = false;
if ([m_native.menu isKindOfClass:[QCocoaNSMenu class]]) {
auto parentMenu = static_cast<QCocoaNSMenu *>(m_native.menu);
setAttached = parentMenu.platformMenu && parentMenu.platformMenu->isAboutToShow();
}
if (m_menu && m_menu->menuParent() == this) {
m_menu->setMenuParent(nullptr);
// Free the menu from its parent's influence
@ -153,6 +159,8 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu)
if (m_menu) {
m_menu->setMenuParent(this);
m_menu->propagateEnabledState(isEnabled());
if (setAttached)
m_menu->setAttachedItem(m_native);
} else {
// we previously had a menu, but no longer
// clear out our item so the nexy sync() call builds a new one

View File

@ -195,7 +195,9 @@ static NSString *qt_mac_removePrivateUnicode(NSString *string)
return;
platformMenu->setIsOpen(true);
platformMenu->setIsAboutToShow(true);
emit platformMenu->aboutToShow();
platformMenu->setIsAboutToShow(false);
}
- (void)menuDidClose:(NSMenu *)menu