Rename all QWindow properties that have "window" in them
[profile/ivi/qtbase.git] / src / plugins / platforms / cocoa / qcocoamenubar.mm
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <Cocoa/Cocoa.h>
43
44 #include "qcocoamenubar.h"
45 #include "qcocoawindow.h"
46 #include "qcocoamenuloader.h"
47 #include "qcocoaapplication.h" // for custom application category
48 #include "qcocoaautoreleasepool.h"
49
50 #include <QtGui/QGuiApplication>
51 #include <QtCore/QDebug>
52
53 static QList<QCocoaMenuBar*> static_menubars;
54
55 static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader()
56 {
57     return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)];
58 }
59
60
61 QCocoaMenuBar::QCocoaMenuBar() :
62     m_window(0)
63 {
64     static_menubars.append(this);
65
66     m_nativeMenu = [[NSMenu alloc] init];
67 #ifdef QT_COCOA_ENABLE_MENU_DEBUG
68     qDebug() << "Construct QCocoaMenuBar" << this << m_nativeMenu;
69 #endif
70 }
71
72 QCocoaMenuBar::~QCocoaMenuBar()
73 {
74 #ifdef QT_COCOA_ENABLE_MENU_DEBUG
75     qDebug() << "~QCocoaMenuBar" << this;
76 #endif
77     [m_nativeMenu release];
78     static_menubars.removeOne(this);
79
80     if (m_window)
81         m_window->setMenubar(0);
82 }
83
84 void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *before)
85 {
86     QCocoaAutoReleasePool pool;
87     QCocoaMenu *menu = static_cast<QCocoaMenu *>(platformMenu);
88     QCocoaMenu *beforeMenu = static_cast<QCocoaMenu *>(before);
89 #ifdef QT_COCOA_ENABLE_MENU_DEBUG
90     qDebug() << "QCocoaMenuBar" << this << "insertMenu" << menu << "before" << before;
91 #endif
92
93     if (m_menus.contains(menu)) {
94         qWarning() << Q_FUNC_INFO << "This menu already belongs to the menubar, remove it first";
95         return;
96     }
97     if (beforeMenu) {
98         if (!m_menus.contains(beforeMenu)) {
99             qWarning() << Q_FUNC_INFO << "The before menu does not belong to the menubar";
100             return;
101         }
102         m_menus.insert(m_menus.indexOf(beforeMenu), menu);
103         NSUInteger nativeIndex = [m_nativeMenu indexOfItem:beforeMenu->nsMenuItem()];
104         [m_nativeMenu insertItem: menu->nsMenuItem() atIndex: nativeIndex];
105     } else {
106         m_menus.append(menu);
107         [m_nativeMenu addItem: menu->nsMenuItem()];
108     }
109
110     [m_nativeMenu setSubmenu: menu->nsMenu() forItem: menu->nsMenuItem()];
111 }
112
113 void QCocoaMenuBar::removeMenu(QPlatformMenu *platformMenu)
114 {
115     QCocoaMenu *menu = static_cast<QCocoaMenu *>(platformMenu);
116     if (!m_menus.contains(menu)) {
117         qWarning() << Q_FUNC_INFO << "Trying to remove a menu that does not belong to the menubar";
118         return;
119     }
120     m_menus.removeOne(menu);
121
122     NSUInteger realIndex = [m_nativeMenu indexOfItem:menu->nsMenuItem()];
123     [m_nativeMenu removeItemAtIndex: realIndex];
124 }
125
126 void QCocoaMenuBar::syncMenu(QPlatformMenu *menu)
127 {
128     Q_UNUSED(menu);
129 }
130
131 void QCocoaMenuBar::handleReparent(QWindow *newParentWindow)
132 {
133 #ifdef QT_COCOA_ENABLE_MENU_DEBUG
134     qDebug() << "QCocoaMenuBar" << this << "handleReparent" << newParentWindow;
135 #endif
136
137     if (m_window)
138         m_window->setMenubar(NULL);
139
140     if (newParentWindow == NULL) {
141         m_window = NULL;
142     } else {
143         m_window = static_cast<QCocoaWindow*>(newParentWindow->handle());
144         m_window->setMenubar(this);
145     }
146
147     updateMenuBarImmediately();
148 }
149
150 QCocoaWindow *QCocoaMenuBar::findWindowForMenubar()
151 {
152     if (qApp->focusWindow())
153         return static_cast<QCocoaWindow*>(qApp->focusWindow()->handle());
154
155     return NULL;
156 }
157
158 QCocoaMenuBar *QCocoaMenuBar::findGlobalMenubar()
159 {
160     foreach (QCocoaMenuBar *mb, static_menubars) {
161         if (mb->m_window == NULL)
162             return mb;
163     }
164
165     return NULL;
166 }
167
168 void QCocoaMenuBar::updateMenuBarImmediately()
169 {
170     QCocoaAutoReleasePool pool;
171     QCocoaMenuBar *mb = findGlobalMenubar();
172     QCocoaWindow *cw = findWindowForMenubar();
173     if (cw && cw->menubar())
174         mb = cw->menubar();
175
176     if (!mb)
177         return;
178
179 #ifdef QT_COCOA_ENABLE_MENU_DEBUG
180     qDebug() << "QCocoaMenuBar" << "updateMenuBarImmediately" << cw;
181 #endif
182     bool disableForModal = mb->shouldDisable(cw);
183     // force a sync?
184     foreach (QCocoaMenu *m, mb->m_menus) {
185         mb->syncMenu(m);
186         m->syncModalState(disableForModal);
187     }
188
189     QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
190     [loader ensureAppMenuInMenu:mb->nsMenu()];
191
192     NSMutableSet *mergedItems = [[NSMutableSet setWithCapacity:0] retain];
193     foreach (QCocoaMenuItem *m, mb->merged()) {
194         [mergedItems addObject:m->nsItem()];
195         m->syncMerged();
196     }
197
198     // hide+disable all mergeable items we're not currently using
199     for (NSMenuItem *mergeable in [loader mergeable]) {
200         if (![mergedItems containsObject:mergeable]) {
201             [mergeable setHidden:YES];
202             [mergeable setEnabled:NO];
203         }
204     }
205
206     [mergedItems release];
207     [NSApp setMainMenu:mb->nsMenu()];
208     [loader qtTranslateApplicationMenu];
209 }
210
211 QList<QCocoaMenuItem*> QCocoaMenuBar::merged() const
212 {
213     QList<QCocoaMenuItem*> r;
214     foreach (QCocoaMenu* menu, m_menus)
215         r.append(menu->merged());
216
217     return r;
218 }
219
220 bool QCocoaMenuBar::shouldDisable(QCocoaWindow *active) const
221 {
222     if (active && (active->window()->modality() == Qt::NonModal))
223         return false;
224
225     if (m_window == active) {
226         // modal window owns us, we should be enabled!
227         return false;
228     }
229
230     QWindowList topWindows(qApp->topLevelWindows());
231     // When there is an application modal window on screen, the entries of
232     // the menubar should be disabled. The exception in Qt is that if the
233     // modal window is the only window on screen, then we enable the menu bar.
234     foreach (QWindow *w, topWindows) {
235         if (w->isVisible() && w->modality() == Qt::ApplicationModal) {
236             // check for other visible windows
237             foreach (QWindow *other, topWindows) {
238                 if ((w != other) && (other->isVisible())) {
239                     // INVARIANT: we found another visible window
240                     // on screen other than our modalWidget. We therefore
241                     // disable the menu bar to follow normal modality logic:
242                     return true;
243                 }
244             }
245
246             // INVARIANT: We have only one window on screen that happends
247             // to be application modal. We choose to enable the menu bar
248             // in that case to e.g. enable the quit menu item.
249             return false;
250         }
251     }
252
253     return true;
254 }
255
256 QPlatformMenu *QCocoaMenuBar::menuForTag(quintptr tag) const
257 {
258     foreach (QCocoaMenu *menu, m_menus) {
259         if (menu->tag() ==  tag)
260             return menu;
261     }
262
263     return 0;
264 }