diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2016-03-21 09:02:57 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2016-03-21 09:02:57 +0100 |
commit | 6cb8121a44ee0f94f2c9fcb075d1d3c802d8c5c7 (patch) | |
tree | 25822898b71068f820d25a9e8372dfb348190ec1 /src/plugins/platforms/cocoa | |
parent | 96740193e1e0f0608f67660811a44b696924ad4c (diff) | |
parent | 2e02de165115c9d67ac343ff0960ed80f9c09bc8 (diff) |
Merge remote-tracking branch 'origin/5.6' into 5.7
Conflicts:
src/widgets/styles/qgtkstyle_p.cpp
tests/auto/corelib/io/qtextstream/test/test.pro
tests/auto/corelib/plugin/plugin.pro
Change-Id: I512bc1b36acf3933ed2b96c00f476ee3819c1f4b
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoabackingstore.h | 4 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaintegration.mm | 10 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenu.h | 13 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenu.mm | 78 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenubar.h | 6 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenubar.mm | 115 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenuitem.h | 3 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenuitem.mm | 17 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 11 |
9 files changed, 132 insertions, 125 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index 18673a3667..fa05626d18 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -57,7 +57,11 @@ public: QPaintDevice *paintDevice() Q_DECL_OVERRIDE; void flush(QWindow *widget, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; +#ifndef QT_NO_OPENGL QImage toImage() const Q_DECL_OVERRIDE; +#else + QImage toImage() const; // No QPlatformBackingStore::toImage() for NO_OPENGL builds. +#endif void resize (const QSize &size, const QRegion &) Q_DECL_OVERRIDE; bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE; void beginPaint(const QRegion ®ion) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index f98ddbb14f..c021a551a7 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -428,14 +428,18 @@ void QCocoaIntegration::updateScreens() } siblings << screen; } + + // Set virtual siblings list. All screens in mScreens are siblings, because we ignored the + // mirrors. Note that some of the screens we update the siblings list for here may be deleted + // below, but update anyway to keep the to-be-deleted screens out of the siblings list. + foreach (QCocoaScreen* screen, mScreens) + screen->setVirtualSiblings(siblings); + // Now the leftovers in remainingScreens are no longer current, so we can delete them. foreach (QCocoaScreen* screen, remainingScreens) { mScreens.removeOne(screen); destroyScreen(screen); } - // All screens in mScreens are siblings, because we ignored the mirrors. - foreach (QCocoaScreen* screen, mScreens) - screen->setVirtualSiblings(siblings); } QCocoaScreen *QCocoaIntegration::screenAtIndex(int index) diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h index 64299c6cd2..64eeabcc2d 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.h +++ b/src/plugins/platforms/cocoa/qcocoamenu.h @@ -81,8 +81,6 @@ public: inline NSMenu *nsMenu() const { return m_nativeMenu; } - inline NSMenuItem *nsMenuItem() const - { return m_nativeItem; } inline bool isVisible() const { return m_visible; } @@ -91,11 +89,9 @@ public: QList<QCocoaMenuItem *> items() const; QList<QCocoaMenuItem *> merged() const; - void setMenuBar(QCocoaMenuBar *menuBar); - QCocoaMenuBar *menuBar() const; - void setContainingMenuItem(QCocoaMenuItem *menuItem); - QCocoaMenuItem *containingMenuItem() const; + void setAttachedItem(NSMenuItem *item); + NSMenuItem *attachedItem() const; private: QCocoaMenuItem *itemOrNull(int index) const; @@ -103,13 +99,10 @@ private: QList<QCocoaMenuItem *> m_menuItems; NSMenu *m_nativeMenu; - NSMenuItem *m_nativeItem; - NSObject *m_delegate; + NSMenuItem *m_attachedItem; bool m_enabled; bool m_visible; quintptr m_tag; - QCocoaMenuBar *m_menuBar; - QCocoaMenuItem *m_containingMenuItem; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 8c576c7cbe..3fc98c071f 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -102,6 +102,28 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate); return self; } +- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu +{ + Q_ASSERT(m_menu->nsMenu() == menu); + return m_menu->items().count(); +} + +- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel +{ + Q_UNUSED(index); + Q_ASSERT(m_menu->nsMenu() == menu); + if (shouldCancel) { + // TODO detach all submenus + return NO; + } + + QCocoaMenuItem *menuItem = reinterpret_cast<QCocoaMenuItem *>(item.tag); + if (m_menu->items().contains(menuItem)) { + if (QCocoaMenu *itemSubmenu = menuItem->menu()) + itemSubmenu->setAttachedItem(item); + } + return YES; +} - (void)menu:(NSMenu*)menu willHighlightItem:(NSMenuItem*)item { @@ -234,20 +256,16 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate); QT_BEGIN_NAMESPACE QCocoaMenu::QCocoaMenu() : + m_attachedItem(0), m_enabled(true), m_visible(true), - m_tag(0), - m_menuBar(0), - m_containingMenuItem(0) + m_tag(0) { QMacAutoReleasePool pool; - m_delegate = [[QCocoaMenuDelegate alloc] initWithMenu:this]; - m_nativeItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; m_nativeMenu = [[NSMenu alloc] initWithTitle:@"Untitled"]; [m_nativeMenu setAutoenablesItems:YES]; - m_nativeMenu.delegate = (QCocoaMenuDelegate *) m_delegate; - [m_nativeItem setSubmenu:m_nativeMenu]; + m_nativeMenu.delegate = [[QCocoaMenuDelegate alloc] initWithMenu:this]; } QCocoaMenu::~QCocoaMenu() @@ -257,14 +275,11 @@ QCocoaMenu::~QCocoaMenu() SET_COCOA_MENU_ANCESTOR(item, 0); } - if (m_containingMenuItem) - m_containingMenuItem->clearMenu(this); - QMacAutoReleasePool pool; - [m_nativeItem setSubmenu:nil]; + NSObject *delegate = m_nativeMenu.delegate; + m_nativeMenu.delegate = nil; + [delegate release]; [m_nativeMenu release]; - [m_delegate release]; - [m_nativeItem release]; } void QCocoaMenu::setText(const QString &text) @@ -272,7 +287,6 @@ void QCocoaMenu::setText(const QString &text) QMacAutoReleasePool pool; QString stripped = qt_mac_removeAmpersandEscapes(text); [m_nativeMenu setTitle:QCFString::toNSString(stripped)]; - [m_nativeItem setTitle:QCFString::toNSString(stripped)]; } void QCocoaMenu::setMinimumWidth(int width) @@ -313,17 +327,13 @@ void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem * void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem) { - [item->nsItem() setTarget:m_delegate]; + item->nsItem().target = m_nativeMenu.delegate; if (!item->menu()) [item->nsItem() setAction:@selector(itemFired:)]; if (item->isMerged()) return; - if ([item->nsItem() menu]) { - qWarning("Menu item is already in a menu, remove it from the other menu first before inserting"); - return; - } // if the item we're inserting before is merged, skip along until // we find a non-merged real item to insert ahead of. while (beforeItem && beforeItem->isMerged()) { @@ -451,12 +461,11 @@ void QCocoaMenu::setEnabled(bool enabled) bool QCocoaMenu::isEnabled() const { - return [m_nativeItem isEnabled]; + return m_attachedItem ? [m_attachedItem isEnabled] : m_enabled; } void QCocoaMenu::setVisible(bool visible) { - [m_nativeItem setSubmenu:(visible ? m_nativeMenu : nil)]; m_visible = visible; } @@ -593,8 +602,6 @@ void QCocoaMenu::syncModalState(bool modal) if (!m_enabled) modal = true; - [m_nativeItem setEnabled:!modal]; - foreach (QCocoaMenuItem *item, m_menuItems) { if (item->menu()) { // recurse into submenus item->menu()->syncModalState(modal); @@ -605,25 +612,24 @@ void QCocoaMenu::syncModalState(bool modal) } } -void QCocoaMenu::setMenuBar(QCocoaMenuBar *menuBar) +void QCocoaMenu::setAttachedItem(NSMenuItem *item) { - m_menuBar = menuBar; - SET_COCOA_MENU_ANCESTOR(this, menuBar); -} + if (item == m_attachedItem) + return; -QCocoaMenuBar *QCocoaMenu::menuBar() const -{ - return m_menuBar; -} + if (m_attachedItem) + m_attachedItem.submenu = nil; + + m_attachedItem = item; + + if (m_attachedItem) + m_attachedItem.submenu = m_nativeMenu; -void QCocoaMenu::setContainingMenuItem(QCocoaMenuItem *menuItem) -{ - m_containingMenuItem = menuItem; } -QCocoaMenuItem *QCocoaMenu::containingMenuItem() const +NSMenuItem *QCocoaMenu::attachedItem() const { - return m_containingMenuItem; + return m_attachedItem; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h index 0521bcd430..7ce2059450 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.h +++ b/src/plugins/platforms/cocoa/qcocoamenubar.h @@ -77,10 +77,10 @@ private: static QCocoaMenuBar *findGlobalMenubar(); bool shouldDisable(QCocoaWindow *active) const; - void insertNativeMenu(QCocoaMenu *menu, QCocoaMenu *beforeMenu); - void removeNativeMenu(QCocoaMenu *menu); - QList<QCocoaMenu*> m_menus; + NSMenuItem *nativeItemForMenu(QCocoaMenu *menu) const; + + QList<QPointer<QCocoaMenu> > m_menus; NSMenu *m_nativeMenu; QCocoaWindow *m_window; }; diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index c9a42e9d8e..e8b3823012 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -57,7 +57,6 @@ static inline QCocoaMenuLoader *getMenuLoader() return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)]; } - QCocoaMenuBar::QCocoaMenuBar() : m_window(0) { @@ -74,11 +73,20 @@ QCocoaMenuBar::~QCocoaMenuBar() #ifdef QT_COCOA_ENABLE_MENU_DEBUG qDebug() << "~QCocoaMenuBar" << this; #endif + foreach (QCocoaMenu *menu, m_menus) { + if (!menu) + continue; + NSMenuItem *item = nativeItemForMenu(menu); + if (menu->attachedItem() == item) + menu->setAttachedItem(nil); + } + [m_nativeMenu release]; static_menubars.removeOne(this); if (m_window && m_window->menubar() == this) { m_window->setMenubar(0); + // Delete the children first so they do not cause // the native menu items to be hidden after // the menu bar was updated @@ -87,24 +95,6 @@ QCocoaMenuBar::~QCocoaMenuBar() } } -void QCocoaMenuBar::insertNativeMenu(QCocoaMenu *menu, QCocoaMenu *beforeMenu) -{ - QMacAutoReleasePool pool; - - if (beforeMenu) { - NSUInteger nativeIndex = [m_nativeMenu indexOfItem:beforeMenu->nsMenuItem()]; - [m_nativeMenu insertItem: menu->nsMenuItem() atIndex: nativeIndex]; - } else { - [m_nativeMenu addItem: menu->nsMenuItem()]; - } - - menu->setMenuBar(this); - syncMenu(static_cast<QPlatformMenu *>(menu)); - if (menu->isVisible()) { - [m_nativeMenu setSubmenu: menu->nsMenu() forItem: menu->nsMenuItem()]; - } -} - void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *before) { QCocoaMenu *menu = static_cast<QCocoaMenu *>(platformMenu); @@ -113,31 +103,40 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor qDebug() << "QCocoaMenuBar" << this << "insertMenu" << menu << "before" << before; #endif - if (m_menus.contains(menu)) { + if (m_menus.contains(QPointer<QCocoaMenu>(menu))) { qWarning("This menu already belongs to the menubar, remove it first"); return; } - if (beforeMenu && !m_menus.contains(beforeMenu)) { + if (beforeMenu && !m_menus.contains(QPointer<QCocoaMenu>(beforeMenu))) { qWarning("The before menu does not belong to the menubar"); return; } - m_menus.insert(beforeMenu ? m_menus.indexOf(beforeMenu) : m_menus.size(), menu); - if (!menu->menuBar()) - insertNativeMenu(menu, beforeMenu); - if (m_window && m_window->window()->isActive()) - updateMenuBarImmediately(); -} + int insertionIndex = beforeMenu ? m_menus.indexOf(beforeMenu) : m_menus.size(); + m_menus.insert(insertionIndex, menu); + + { + QMacAutoReleasePool pool; + NSMenuItem *item = [[[NSMenuItem alloc] init] autorelease]; + item.tag = reinterpret_cast<NSInteger>(menu); + + if (beforeMenu) { + // QMenuBar::toNSMenu() exposes the native menubar and + // the user could have inserted its own items in there. + // Same remark applies to removeMenu(). + NSMenuItem *beforeItem = nativeItemForMenu(beforeMenu); + NSInteger nativeIndex = [m_nativeMenu indexOfItem:beforeItem]; + [m_nativeMenu insertItem:item atIndex:nativeIndex]; + } else { + [m_nativeMenu addItem:item]; + } + } -void QCocoaMenuBar::removeNativeMenu(QCocoaMenu *menu) -{ - QMacAutoReleasePool pool; + syncMenu(menu); - if (menu->menuBar() == this) - menu->setMenuBar(0); - NSUInteger realIndex = [m_nativeMenu indexOfItem:menu->nsMenuItem()]; - [m_nativeMenu removeItemAtIndex: realIndex]; + if (m_window && m_window->window()->isActive()) + updateMenuBarImmediately(); } void QCocoaMenuBar::removeMenu(QPlatformMenu *platformMenu) @@ -147,8 +146,17 @@ void QCocoaMenuBar::removeMenu(QPlatformMenu *platformMenu) qWarning("Trying to remove a menu that does not belong to the menubar"); return; } + + NSMenuItem *item = nativeItemForMenu(menu); + if (menu->attachedItem() == item) + menu->setAttachedItem(nil); m_menus.removeOne(menu); - removeNativeMenu(menu); + + QMacAutoReleasePool pool; + + // See remark in insertMenu(). + NSInteger nativeIndex = [m_nativeMenu indexOfItem:item]; + [m_nativeMenu removeItemAtIndex:nativeIndex]; } void QCocoaMenuBar::syncMenu(QPlatformMenu *menu) @@ -170,7 +178,16 @@ void QCocoaMenuBar::syncMenu(QPlatformMenu *menu) break; } } - [cocoaMenu->nsMenuItem() setHidden:shouldHide]; + + nativeItemForMenu(cocoaMenu).hidden = shouldHide; +} + +NSMenuItem *QCocoaMenuBar::nativeItemForMenu(QCocoaMenu *menu) const +{ + if (!menu) + return nil; + + return [m_nativeMenu itemWithTag:reinterpret_cast<NSInteger>(menu)]; } void QCocoaMenuBar::handleReparent(QWindow *newParentWindow) @@ -297,24 +314,16 @@ void QCocoaMenuBar::updateMenuBarImmediately() qDebug() << "QCocoaMenuBar" << "updateMenuBarImmediately" << cw; #endif bool disableForModal = mb->shouldDisable(cw); - // force a sync? - foreach (QCocoaMenu *m, mb->m_menus) { - mb->syncMenu(m); - m->syncModalState(disableForModal); - } - // reparent shared menu items if necessary. - // We browse the list in reverse order to be sure that the next items are redrawn before the current ones, - // in this way we are sure that "beforeMenu" (see below) is part of the native menu before "m" is redraw - for (int i = mb->m_menus.size() - 1; i >= 0; i--) { - QCocoaMenu *m = mb->m_menus.at(i); - QCocoaMenuBar *menuBar = m->menuBar(); - if (menuBar != mb) { - QCocoaMenu *beforeMenu = i < (mb->m_menus.size() - 1) ? mb->m_menus.at(i + 1) : 0; - if (menuBar) - menuBar->removeNativeMenu(m); - mb->insertNativeMenu(m, beforeMenu); - } + foreach (QCocoaMenu *menu, mb->m_menus) { + if (!menu) + continue; + NSMenuItem *item = mb->nativeItemForMenu(menu); + menu->setAttachedItem(item); + SET_COCOA_MENU_ANCESTOR(menu, mb); + // force a sync? + mb->syncMenu(menu); + menu->syncModalState(disableForModal); } QCocoaMenuLoader *loader = getMenuLoader(); diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h index 0d6f67959b..bba9ce3963 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.h +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h @@ -93,7 +93,6 @@ public: inline bool isSeparator() const { return m_isSeparator; } QCocoaMenu *menu() const { return m_menu; } - void clearMenu(QCocoaMenu *menu); MenuRole effectiveRole() const; private: @@ -105,7 +104,7 @@ private: QString m_text; bool m_textSynced; QIcon m_icon; - QCocoaMenu *m_menu; + QPointer<QCocoaMenu> m_menu; bool m_isVisible; bool m_enabled; bool m_isSeparator; diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 9e4f0b9ad1..de0271ce4d 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -142,15 +142,12 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu) 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); } QMacAutoReleasePool 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 @@ -159,12 +156,6 @@ 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; @@ -226,14 +217,6 @@ NSMenuItem *QCocoaMenuItem::sync() m_native = nil; } - if (m_menu) { - if (m_native != m_menu->nsMenuItem()) { - [m_native release]; - m_native = [m_menu->nsMenuItem() retain]; - [m_native setTag:reinterpret_cast<NSInteger>(this)]; - } - } - if ((m_role != NoRole && !m_textSynced) || m_merged) { NSMenuItem *mergeItem = nil; QCocoaMenuLoader *loader = getMenuLoader(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index eb65f7e061..b501358acc 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -414,6 +414,7 @@ QCocoaWindow::~QCocoaWindow() #endif QMacAutoReleasePool pool; + [m_nsWindow makeFirstResponder:nil]; [m_nsWindow setContentView:nil]; [m_nsWindow.helper detachFromPlatformWindow]; if (m_isNSWindowChild) { @@ -1004,7 +1005,15 @@ void QCocoaWindow::raise() [parentNSWindow removeChildWindow:m_nsWindow]; [parentNSWindow addChildWindow:m_nsWindow ordered:NSWindowAbove]; } else { - [m_nsWindow orderFront: m_nsWindow]; + { + // Clean up autoreleased temp objects from orderFront immediately. + // Failure to do so has been observed to cause leaks also beyond any outer + // autorelease pool (for example around a complete QWindow + // construct-show-raise-hide-delete cyle), counter to expected autoreleasepool + // behavior. + QMacAutoReleasePool pool; + [m_nsWindow orderFront: m_nsWindow]; + } static bool raiseProcess = qt_mac_resolveOption(true, "QT_MAC_SET_RAISE_PROCESS"); if (raiseProcess) { ProcessSerialNumber psn; |