From 56384a854aeaa5d3275c158c80a07082949468da Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Fri, 18 Mar 2016 13:22:19 -0700 Subject: QCocoaMenus: Use mix-in pattern to implement menu hierarchy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To solve menu item roles from their text, we need to find its depth in the menubar hierarchy. Unfortunately, there's no trivial way to access that hierarchy from the QPA side, so we need to come with an ad-hoc solution. Previously, we were using a dynamic proprety to keep track of the 'parent' object. However, as the life span of the different objects has changed since 09acf326dbc6b7b67f21a36, we need a way to keep track of the parent's existence. This is what we do in this patch by having both QCocoaMenu and QCocoaMenuItem also inherit QCocoaMenuObject. This class' sole role is to store the menu hierarchy's parent object and wrap it in a QPointer. Change-Id: Ia18d95171af76d26f6325eef04c77b40d99c4285 Reviewed-by: Morten Johan Sørvig Reviewed-by: J-P Nurmi Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoamenu.h | 2 +- src/plugins/platforms/cocoa/qcocoamenu.mm | 10 +++++----- src/plugins/platforms/cocoa/qcocoamenubar.mm | 2 +- src/plugins/platforms/cocoa/qcocoamenuitem.h | 22 ++++++++++++++++++---- src/plugins/platforms/cocoa/qcocoamenuitem.mm | 16 +++++++++------- 5 files changed, 34 insertions(+), 18 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h index 5064d89585..c975de166d 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.h +++ b/src/plugins/platforms/cocoa/qcocoamenu.h @@ -43,7 +43,7 @@ QT_BEGIN_NAMESPACE class QCocoaMenuBar; -class QCocoaMenu : public QPlatformMenu +class QCocoaMenu : public QPlatformMenu, public QCocoaMenuObject { public: QCocoaMenu(); diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 21a3799859..6ed7aa0e06 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -265,8 +265,8 @@ QCocoaMenu::QCocoaMenu() : QCocoaMenu::~QCocoaMenu() { foreach (QCocoaMenuItem *item, m_menuItems) { - if (COCOA_MENU_ANCESTOR(item) == this) - SET_COCOA_MENU_ANCESTOR(item, 0); + if (item->menuParent() == this) + item->setMenuParent(0); } QMacAutoReleasePool pool; @@ -344,7 +344,7 @@ void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem) } else { [m_nativeMenu addItem: item->nsItem()]; } - SET_COCOA_MENU_ANCESTOR(item, this); + item->setMenuParent(this); } void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem) @@ -356,8 +356,8 @@ void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem) return; } - if (COCOA_MENU_ANCESTOR(menuItem) == this) - SET_COCOA_MENU_ANCESTOR(menuItem, 0); + if (cocoaItem->menuParent() == this) + cocoaItem->setMenuParent(0); m_menuItems.removeOne(cocoaItem); if (!cocoaItem->isMerged()) { diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index ac4d29fc52..ac48a0e310 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -314,7 +314,7 @@ void QCocoaMenuBar::updateMenuBarImmediately() continue; NSMenuItem *item = mb->nativeItemForMenu(menu); menu->setAttachedItem(item); - SET_COCOA_MENU_ANCESTOR(menu, mb); + menu->setMenuParent(mb); // force a sync? mb->syncMenu(menu); menu->syncModalState(disableForModal); diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h index ada4b13df1..5f7215596c 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.h +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h @@ -49,7 +49,24 @@ QT_BEGIN_NAMESPACE class QCocoaMenu; -class QCocoaMenuItem : public QPlatformMenuItem +class QCocoaMenuObject +{ +public: + void setMenuParent(QObject *o) + { + parent = o; + } + + QObject *menuParent() const + { + return parent; + } + +private: + QPointer parent; +}; + +class QCocoaMenuItem : public QPlatformMenuItem, public QCocoaMenuObject { public: QCocoaMenuItem(); @@ -112,9 +129,6 @@ private: int m_iconSize; }; -#define COCOA_MENU_ANCESTOR(m) ((m)->property("_qCocoaMenuAncestor").value()) -#define SET_COCOA_MENU_ANCESTOR(m, ancestor) (m)->setProperty("_qCocoaMenuAncestor", QVariant::fromValue(ancestor)) - QT_END_NAMESPACE #endif diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index e274448620..0f422843e0 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -105,8 +105,8 @@ QCocoaMenuItem::~QCocoaMenuItem() { QMacAutoReleasePool pool; - if (m_menu && COCOA_MENU_ANCESTOR(m_menu) == this) - SET_COCOA_MENU_ANCESTOR(m_menu, 0); + if (m_menu && m_menu->menuParent() == this) + m_menu->setMenuParent(0); if (m_merged) { [m_native setHidden:YES]; } else { @@ -132,14 +132,14 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu) return; if (m_menu) { - if (COCOA_MENU_ANCESTOR(m_menu) == this) - SET_COCOA_MENU_ANCESTOR(m_menu, 0); + if (m_menu->menuParent() == this) + m_menu->setMenuParent(0); } QMacAutoReleasePool pool; m_menu = static_cast(menu); if (m_menu) { - SET_COCOA_MENU_ANCESTOR(m_menu, this); + m_menu->setMenuParent(this); } else { // we previously had a menu, but no longer // clear out our item so the nexy sync() call builds a new one @@ -229,12 +229,14 @@ NSMenuItem *QCocoaMenuItem::sync() mergeItem = [loader preferencesMenuItem]; break; case TextHeuristicRole: { - QObject *p = COCOA_MENU_ANCESTOR(this); + QObject *p = menuParent(); int depth = 1; QCocoaMenuBar *menubar = 0; while (depth < 3 && p && !(menubar = qobject_cast(p))) { ++depth; - p = COCOA_MENU_ANCESTOR(p); + QCocoaMenuObject *menuObject = dynamic_cast(p); + Q_ASSERT(menuObject); + p = menuObject->menuParent(); } if (depth == 3 || !menubar) break; // Menu item too deep in the hierarchy, or not connected to any menubar -- cgit v1.2.3