1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the plugins of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qcocoamenuloader.h"
44 #include <QtCore/private/qcore_mac_p.h>
45 #include <QtCore/qcoreapplication.h>
46 #include <QtCore/qdir.h>
47 #include <QtCore/qstring.h>
49 QT_FORWARD_DECLARE_CLASS(QCFString)
50 QT_FORWARD_DECLARE_CLASS(QString)
52 #ifndef QT_NO_TRANSLATION
54 extern QString qt_mac_applicationmenu_string(int type);
61 Loads and instantiates the main app menu from the menu nib file(s).
63 The main app menu contains the Quit, Hide About, Preferences entries, and
64 The reason for having the nib file is that those can not be created
65 programmatically. To ease deployment the nib files are stored in Qt resources
66 and written to QDir::temp() before loading. (Earlier Qt versions used
67 to require having the nib file in the QtGui framework.)
69 void qt_mac_loadMenuNib(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader)
71 // Create qt_menu.nib dir in temp.
72 QDir temp = QDir::temp();
73 temp.mkdir("qt_menu.nib");
74 QString nibDir = temp.canonicalPath() + QLatin1String("/") + QLatin1String("qt_menu.nib/");
75 if (!QDir(nibDir).exists()) {
76 qWarning("qt_mac_loadMenuNib: could not create nib directory in temp");
80 // Copy nib files from resources to temp.
81 QDir nibResource(":/trolltech/mac/qt_menu.nib/");
82 if (!nibResource.exists()) {
83 qWarning("qt_mac_loadMenuNib: could not load nib from resources");
86 foreach (const QFileInfo &file, nibResource.entryInfoList()) {
87 QFile::copy(file.absoluteFilePath(), nibDir + QLatin1String("/") + file.fileName());
90 // Load and instantiate nib file from temp
91 NSURL *nibUrl = [NSURL fileURLWithPath : reinterpret_cast<const NSString *>(QCFString::toCFStringRef(nibDir))];
93 NSNib *nib = [[NSNib alloc] initWithContentsOfURL : nibUrl];
96 qWarning("qt_mac_loadMenuNib: could not load nib from temp");
99 bool ok = [nib instantiateNibWithOwner : qtMenuLoader topLevelObjects : nil];
101 qWarning("qt_mac_loadMenuNib: could not instantiate nib");
107 @implementation QT_MANGLE_NAMESPACE(QCocoaMenuLoader)
111 servicesItem = [[appMenu itemWithTitle:@"Services"] retain];
112 hideAllOthersItem = [[appMenu itemWithTitle:@"Hide Others"] retain];
113 showAllItem = [[appMenu itemWithTitle:@"Show All"] retain];
115 // Get the names in the nib to match the app name set by Qt.
116 const NSString *appName = reinterpret_cast<const NSString*>(QCFString::toCFStringRef(qAppName()));
117 [quitItem setTitle:[[quitItem title] stringByReplacingOccurrencesOfString:@"NewApplication"
118 withString:const_cast<NSString *>(appName)]];
119 [hideItem setTitle:[[hideItem title] stringByReplacingOccurrencesOfString:@"NewApplication"
120 withString:const_cast<NSString *>(appName)]];
121 [aboutItem setTitle:[[aboutItem title] stringByReplacingOccurrencesOfString:@"NewApplication"
122 withString:const_cast<NSString *>(appName)]];
124 // Disable the items that don't do anything. If someone associates a QAction with them
125 // They should get synced back in.
126 [preferencesItem setEnabled:NO];
127 [preferencesItem setHidden:YES];
128 [aboutItem setEnabled:NO];
129 [aboutItem setHidden:YES];
132 - (void)ensureAppMenuInMenu:(NSMenu *)menu
134 // The application menu is the menu in the menu bar that contains the
135 // 'Quit' item. When changing menu bar (e.g when switching between
136 // windows with different menu bars), we never recreate this menu, but
137 // instead pull it out the current menu bar and place into the new one:
138 NSMenu *mainMenu = [NSApp mainMenu];
139 if ([NSApp mainMenu] == menu)
140 return; // nothing to do (menu is the current menu bar)!
145 // Grab the app menu out of the current menu.
146 int numItems = [mainMenu numberOfItems];
147 NSMenuItem *oldAppMenuItem = 0;
148 for (int i = 0; i < numItems; ++i) {
149 NSMenuItem *item = [mainMenu itemAtIndex:i];
150 if ([item submenu] == appMenu) {
151 oldAppMenuItem = item;
152 [oldAppMenuItem retain];
153 [mainMenu removeItemAtIndex:i];
158 if (oldAppMenuItem) {
159 [oldAppMenuItem setSubmenu:nil];
160 [oldAppMenuItem release];
161 NSMenuItem *appMenuItem = [[NSMenuItem alloc] initWithTitle:@"Apple"
162 action:nil keyEquivalent:@""];
163 [appMenuItem setSubmenu:appMenu];
164 [menu insertItem:appMenuItem atIndex:0];
168 - (void)removeActionsFromAppMenu
170 for (NSMenuItem *item in [appMenu itemArray])
176 [servicesItem release];
177 [hideAllOthersItem release];
178 [showAllItem release];
180 [lastAppSpecificItem release];
188 return [[theMenu retain] autorelease];
191 - (NSMenu *)applicationMenu
193 return [[appMenu retain] autorelease];
196 - (NSMenuItem *)quitMenuItem
198 return [[quitItem retain] autorelease];
201 - (NSMenuItem *)preferencesMenuItem
203 return [[preferencesItem retain] autorelease];
206 - (NSMenuItem *)aboutMenuItem
208 return [[aboutItem retain] autorelease];
211 - (NSMenuItem *)aboutQtMenuItem
213 return [[aboutQtItem retain] autorelease];
216 - (NSMenuItem *)hideMenuItem
218 return [[hideItem retain] autorelease];
221 - (NSMenuItem *)appSpecificMenuItem
223 // Create an App-Specific menu item, insert it into the menu and return
224 // it as an autorelease item.
225 NSMenuItem *item = [[NSMenuItem alloc] init];
228 if (lastAppSpecificItem == nil) {
229 location = [appMenu indexOfItem:aboutQtItem];
231 location = [appMenu indexOfItem:lastAppSpecificItem];
232 [lastAppSpecificItem release];
234 lastAppSpecificItem = item; // Keep track of this for later (i.e., don't release it)
235 [appMenu insertItem:item atIndex:location + 1];
237 return [[item retain] autorelease];
240 - (BOOL) acceptsFirstResponder
245 - (void)terminate:(id)sender
247 [NSApp terminate:sender];
250 - (void)orderFrontStandardAboutPanel:(id)sender
252 [NSApp orderFrontStandardAboutPanel:sender];
255 - (void)hideOtherApplications:(id)sender
257 [NSApp hideOtherApplications:sender];
260 - (void)unhideAllApplications:(id)sender
262 [NSApp unhideAllApplications:sender];
265 - (void)hide:(id)sender
270 - (void)qtUpdateMenubar
272 // QMenuBarPrivate::macUpdateMenuBarImmediatly();
275 - (void)qtTranslateApplicationMenu
278 #ifndef QT_NO_TRANSLATION
279 [servicesItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(0))];
280 [hideItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(1).arg(qAppName()))];
281 [hideAllOthersItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(2))];
282 [showAllItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(3))];
283 [preferencesItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(4))];
284 [quitItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(5).arg(qAppName()))];
285 [aboutItem setTitle: qt_mac_QStringToNSString(qt_mac_applicationmenu_string(6).arg(qAppName()))];
290 - (IBAction)qtDispatcherToQAction:(id)sender
293 QScopedLoopLevelCounter loopLevelCounter(QApplicationPrivate::instance()->threadData);
294 NSMenuItem *item = static_cast<NSMenuItem *>(sender);
295 if (QAction *action = reinterpret_cast<QAction *>([item tag])) {
297 } else if (item == quitItem) {
298 // We got here because someone was once the quitItem, but it has been
299 // abandoned (e.g., the menubar was deleted). In the meantime, just do
300 // normal QApplication::quit().
306 - (void)orderFrontCharacterPalette:(id)sender
308 [NSApp orderFrontCharacterPalette:sender];