QCocoaMenu: Keep a reference to the containing menu item

This allows the menu to tell its containing item the menu got
deleted. This removes the need to reset the COCOA_MENU_ANCESTOR
property value, which would crash since QCocoaMenuItem::m_menu
would be a dangling pointer.

Task-number: QTBUG-41587
Change-Id: Ia3408ef85cf823bfddbc2c41d6534e43bf14ed29
Reviewed-by: Morten Johan Sørvig <morten.sorvig@digia.com>
This commit is contained in:
Gabriel de Dietrich 2014-09-25 19:53:49 +02:00
parent 9dcc3a5728
commit 996054f5e6
4 changed files with 36 additions and 3 deletions

View File

@ -94,6 +94,10 @@ public:
QList<QCocoaMenuItem *> merged() const;
void setMenuBar(QCocoaMenuBar *menuBar);
QCocoaMenuBar *menuBar() const;
void setContainingMenuItem(QCocoaMenuItem *menuItem);
QCocoaMenuItem *containingMenuItem() const;
private:
QCocoaMenuItem *itemOrNull(int index) const;
void insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem);
@ -106,6 +110,7 @@ private:
bool m_visible;
quintptr m_tag;
QCocoaMenuBar *m_menuBar;
QCocoaMenuItem *m_containingMenuItem;
};
QT_END_NAMESPACE

View File

@ -222,7 +222,8 @@ QCocoaMenu::QCocoaMenu() :
m_enabled(true),
m_visible(true),
m_tag(0),
m_menuBar(0)
m_menuBar(0),
m_containingMenuItem(0)
{
m_delegate = [[QCocoaMenuDelegate alloc] initWithMenu:this];
m_nativeItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
@ -238,6 +239,10 @@ QCocoaMenu::~QCocoaMenu()
if (COCOA_MENU_ANCESTOR(item) == this)
SET_COCOA_MENU_ANCESTOR(item, 0);
}
if (m_containingMenuItem)
m_containingMenuItem->clearMenu(this);
QCocoaAutoReleasePool pool;
[m_nativeItem setSubmenu:nil];
[m_nativeMenu release];
@ -567,4 +572,14 @@ QCocoaMenuBar *QCocoaMenu::menuBar() const
return m_menuBar;
}
void QCocoaMenu::setContainingMenuItem(QCocoaMenuItem *menuItem)
{
m_containingMenuItem = menuItem;
}
QCocoaMenuItem *QCocoaMenu::containingMenuItem() const
{
return m_containingMenuItem;
}
QT_END_NAMESPACE

View File

@ -101,6 +101,7 @@ public:
inline bool isSeparator() const { return m_isSeparator; }
QCocoaMenu *menu() const { return m_menu; }
void clearMenu(QCocoaMenu *menu);
MenuRole effectiveRole() const;
private:

View File

@ -131,13 +131,19 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu)
{
if (menu == m_menu)
return;
if (m_menu && COCOA_MENU_ANCESTOR(m_menu) == this)
SET_COCOA_MENU_ANCESTOR(m_menu, 0);
if (m_menu) {
if (COCOA_MENU_ANCESTOR(m_menu) == this)
SET_COCOA_MENU_ANCESTOR(m_menu, 0);
if (m_menu->containingMenuItem() == this)
m_menu->setContainingMenuItem(0);
}
QCocoaAutoReleasePool pool;
m_menu = static_cast<QCocoaMenu *>(menu);
if (m_menu) {
SET_COCOA_MENU_ANCESTOR(m_menu, this);
m_menu->setContainingMenuItem(this);
} else {
// we previously had a menu, but no longer
// clear out our item so the nexy sync() call builds a new one
@ -146,6 +152,12 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu)
}
}
void QCocoaMenuItem::clearMenu(QCocoaMenu *menu)
{
if (menu == m_menu)
m_menu = 0;
}
void QCocoaMenuItem::setVisible(bool isVisible)
{
m_isVisible = isVisible;