7ca546dd79784f9c3c53249a44b9310d0d71289f
[profile/ivi/qtbase.git] / src / plugins / platforms / cocoa / qmenu_mac.mm
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qmenu_mac.h"
43
44 #include <Cocoa/Cocoa.h>
45
46 #include "qmenu.h"
47 #include "qhash.h"
48 #include <qdebug.h>
49 #include "qapplication.h"
50 #include "qregexp.h"
51 #include "qtoolbar.h"
52 #include "qevent.h"
53 #include "qstyle.h"
54 #include "qwidgetaction.h"
55
56 #include <private/qmenu_p.h>
57 #include <private/qmenubar_p.h>
58 #include <private/qguiapplication_p.h>
59
60 #include "qcocoahelpers.h"
61 #include "qcocoaapplication.h"
62 #include "qcocoamenuloader.h"
63 #include "qcocoamenu.h"
64 #include "qcocoahelpers.h"
65 #include "qcocoaautoreleasepool.h"
66
67 QT_BEGIN_NAMESPACE
68
69 /*****************************************************************************
70   QMenu debug facilities
71  *****************************************************************************/
72
73 /*****************************************************************************
74   QMenu globals
75  *****************************************************************************/
76 bool qt_mac_no_menubar_merge = false;
77 bool qt_mac_quit_menu_item_enabled = true;
78 int qt_mac_menus_open_count = 0;
79
80 static OSMenuRef qt_mac_create_menu(QWidget *w);
81
82 static struct {
83     QPointer<QMenuBar> qmenubar;
84     bool modal;
85 } qt_mac_current_menubar = { 0, false };
86
87
88
89
90 /*****************************************************************************
91   Externals
92  *****************************************************************************/
93 extern OSViewRef qt_mac_hiview_for(const QWidget *w); //qwidget_mac.cpp
94 extern IconRef qt_mac_create_iconref(const QPixmap &px); //qpixmap_mac.cpp
95 extern QWidget * mac_keyboard_grabber; //qwidget_mac.cpp
96 extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); //qapplication_xxx.cpp
97 RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp
98 void qt_mac_dispose_rgn(RgnHandle r); //qregion_mac.cpp
99
100 /*****************************************************************************
101   QMenu utility functions
102  *****************************************************************************/
103 bool qt_mac_watchingAboutToShow(QMenu *menu)
104 {
105     return menu; /* && menu->receivers(SIGNAL(aboutToShow()));*/
106 }
107
108 static int qt_mac_CountMenuItems(OSMenuRef menu)
109 {
110     if (menu) {
111         return [menu numberOfItems];
112     }
113     return 0;
114 }
115
116 void qt_mac_menu_collapseSeparators(NSMenu * theMenu, bool collapse)
117 {
118     QCocoaAutoReleasePool pool;
119     OSMenuRef menu = static_cast<OSMenuRef>(theMenu);
120     if (collapse) {
121         bool previousIsSeparator = true; // setting to true kills all the separators placed at the top.
122         NSMenuItem *previousItem = nil;
123
124         NSArray *itemArray = [menu itemArray];
125         for (unsigned int i = 0; i < [itemArray count]; ++i) {
126             NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]);
127             if ([item isSeparatorItem]) {
128                 [item setHidden:previousIsSeparator];
129             }
130
131             if (![item isHidden]) {
132                 previousItem = item;
133                 previousIsSeparator = ([previousItem isSeparatorItem]);
134             }
135         }
136
137         // We now need to check the final item since we don't want any separators at the end of the list.
138         if (previousItem && previousIsSeparator)
139             [previousItem setHidden:YES];
140     } else {
141         NSArray *itemArray = [menu itemArray];
142         for (unsigned int i = 0; i < [itemArray count]; ++i) {
143             NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]);
144             if (QAction *action = reinterpret_cast<QAction *>([item tag]))
145                 [item setHidden:!action->isVisible()];
146         }
147     }
148 }
149
150 #ifndef QT_NO_TRANSLATION
151 static const char *application_menu_strings[] = {
152     QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Services"),
153     QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide %1"),
154     QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide Others"),
155     QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Show All"),
156     QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Preferences..."),
157     QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1"),
158     QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","About %1")
159     };
160
161 QString qt_mac_applicationmenu_string(int type)
162 {
163     QString menuString = QString::fromLatin1(application_menu_strings[type]);
164     QString translated = qApp->translate("QMenuBar", application_menu_strings[type]);
165     if (translated != menuString)
166         return translated;
167     else
168         return qApp->translate("MAC_APPLICATION_MENU",
169                                application_menu_strings[type]);
170 }
171 #endif
172
173
174 static quint32 constructModifierMask(quint32 accel_key)
175 {
176     quint32 ret = 0;
177     const bool dontSwap = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
178     if ((accel_key & Qt::CTRL) == Qt::CTRL)
179         ret |= (dontSwap ? NSControlKeyMask : NSCommandKeyMask);
180     if ((accel_key & Qt::META) == Qt::META)
181         ret |= (dontSwap ? NSCommandKeyMask : NSControlKeyMask);
182     if ((accel_key & Qt::ALT) == Qt::ALT)
183         ret |= NSAlternateKeyMask;
184     if ((accel_key & Qt::SHIFT) == Qt::SHIFT)
185         ret |= NSShiftKeyMask;
186     return ret;
187 }
188
189 static void cancelAllMenuTracking()
190 {
191     QCocoaAutoReleasePool pool;
192     NSMenu *mainMenu = [NSApp mainMenu];
193     [mainMenu cancelTracking];
194     for (NSMenuItem *item in [mainMenu itemArray]) {
195         if ([item submenu]) {
196             [[item submenu] cancelTracking];
197         }
198     }
199 }
200
201 static bool actualMenuItemVisibility(const QCocoaMenuBar *mbp,
202                                      const QCocoaMenuAction *action)
203 {
204     bool visible = action->action->isVisible();
205     if (visible && action->action->text() == QString(QChar(0x14)))
206         return false;
207
208     if (visible && action->action->menu() && !action->action->menu()->actions().isEmpty() &&
209 /* ###        !qt_mac_CountMenuItems(cocoaMenu->macMenu(mbp->apple_menu)) &&*/
210         !qt_mac_watchingAboutToShow(action->action->menu())) {
211         return false;
212     }
213     return visible;
214 }
215
216 static inline void syncNSMenuItemVisiblity(NSMenuItem *menuItem, bool actionVisibility)
217 {
218     [menuItem setHidden:NO];
219     [menuItem setHidden:YES];
220     [menuItem setHidden:!actionVisibility];
221 }
222
223 static inline void syncNSMenuItemEnabled(NSMenuItem *menuItem, bool enabled)
224 {
225     [menuItem setEnabled:NO];
226     [menuItem setEnabled:YES];
227     [menuItem setEnabled:enabled];
228 }
229
230 static inline void syncMenuBarItemsVisiblity(const QCocoaMenuBar *mac_menubar)
231 {
232     const QList<QCocoaMenuAction *> &menubarActions = mac_menubar->actionItems;
233     for (int i = 0; i < menubarActions.size(); ++i) {
234         const QCocoaMenuAction *action = menubarActions.at(i);
235         syncNSMenuItemVisiblity(action->menuItem, actualMenuItemVisibility(mac_menubar, action));
236     }
237 }
238
239 static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader()
240 {
241     return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)];
242 }
243
244 static NSMenuItem *createNSMenuItem(const QString &title)
245 {
246     NSMenuItem *item = [[NSMenuItem alloc] 
247                          initWithTitle:qt_mac_QStringToNSString(title)
248                          action:@selector(qtDispatcherToQAction:) keyEquivalent:@""];
249     [item setTarget:nil];
250     return item;
251 }
252
253 // helper that recurses into a menu structure and en/dis-ables them
254 void qt_mac_set_modal_state_helper_recursive(OSMenuRef menu, OSMenuRef merge, bool on)
255 {
256     bool modalWindowOnScreen = qApp->activeModalWidget() != 0;
257     for (NSMenuItem *item in [menu itemArray]) {
258         OSMenuRef submenu = [item submenu];
259         if (submenu != merge) {
260             if (submenu)
261                 qt_mac_set_modal_state_helper_recursive(submenu, merge, on);
262             if (!on) {
263                 // The item should follow what the QAction has.
264                 if ([item tag]) {
265                     QAction *action = reinterpret_cast<QAction *>([item tag]);
266                     syncNSMenuItemEnabled(item, action->isEnabled());
267                 } else {
268                     syncNSMenuItemEnabled(item, YES);
269                 }
270                 // We sneak in some extra code here to handle a menu problem:
271                 // If there is no window on screen, we cannot set 'nil' as
272                 // menu item target, because then cocoa will disable the item
273                 // (guess it assumes that there will be no first responder to
274                 // catch the trigger anyway?) OTOH, If we have a modal window,
275                 // then setting the menu loader as target will make cocoa not
276                 // deliver the trigger because the loader is then seen as modally
277                 // shaddowed). So either way there are shortcomings. Instead, we
278                 // decide the target as late as possible:
279                 [item setTarget:modalWindowOnScreen ? nil : getMenuLoader()];
280             } else {
281                 syncNSMenuItemEnabled(item, NO);
282             }
283         }
284     }
285 }
286
287 //toggling of modal state
288 static void qt_mac_set_modal_state(OSMenuRef menu, bool on)
289 {
290     OSMenuRef merge = QCocoaMenu::mergeMenuHash.value(menu);
291     qt_mac_set_modal_state_helper_recursive(menu, merge, on);
292     // I'm ignoring the special items now, since they should get handled via a syncAction()
293 }
294
295 bool qt_mac_menubar_is_open()
296 {
297     return qt_mac_menus_open_count > 0;
298 }
299
300 QCocoaMenuAction::~QCocoaMenuAction()
301 {
302     [menu release];
303     // Update the menu item if this action still owns it. For some items
304     // (like 'Quit') ownership will be transferred between all menu bars...
305     if (action && action.data() == reinterpret_cast<QAction *>([menuItem tag])) {
306         QAction::MenuRole role = action->menuRole();
307         // Check if the item is owned by Qt, and should be hidden to keep it from causing
308         // problems. Do it for everything but the quit menu item since that should always
309         // be visible.
310         if (role > QAction::ApplicationSpecificRole && role < QAction::QuitRole) {
311             [menuItem setHidden:YES];
312         } else if (role == QAction::TextHeuristicRole
313                    && menuItem != [getMenuLoader() quitMenuItem]) {
314             [menuItem setHidden:YES];
315         }
316         [menuItem setTag:nil];
317     }
318     [menuItem release];
319 }
320
321 static NSMenuItem *qt_mac_menu_merge_action(OSMenuRef merge, QCocoaMenuAction *action)
322 {
323     if (qt_mac_no_menubar_merge || action->action->menu() || action->action->isSeparator()
324             || action->action->menuRole() == QAction::NoRole)
325         return 0;
326
327     QString t = qt_mac_removeMnemonics(action->action->text().toLower());
328     int st = t.lastIndexOf(QLatin1Char('\t'));
329     if (st != -1)
330         t.remove(st, t.length()-st);
331     t.replace(QRegExp(QString::fromLatin1("\\.*$")), QLatin1String("")); //no ellipses
332     //now the fun part
333     NSMenuItem *ret = 0;
334     QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
335
336     switch (action->action->menuRole()) {
337     case QAction::NoRole:
338         ret = 0;
339         break;
340     case QAction::ApplicationSpecificRole:
341         ret = [loader appSpecificMenuItem];
342         break;
343     case QAction::AboutRole:
344         ret = [loader aboutMenuItem];
345         break;
346     case QAction::AboutQtRole:
347         ret = [loader aboutQtMenuItem];
348         break;
349     case QAction::QuitRole:
350         ret = [loader quitMenuItem];
351         break;
352     case QAction::PreferencesRole:
353         ret = [loader preferencesMenuItem];
354         break;
355     case QAction::TextHeuristicRole: {
356         QString aboutString = QMenuBar::tr("About").toLower();
357         if (t.startsWith(aboutString) || t.endsWith(aboutString)) {
358             if (t.indexOf(QRegExp(QString::fromLatin1("qt$"), Qt::CaseInsensitive)) == -1) {
359                 ret = [loader aboutMenuItem];
360             } else {
361                 ret = [loader aboutQtMenuItem];
362             }
363         } else if (t.startsWith(QMenuBar::tr("Config").toLower())
364                    || t.startsWith(QMenuBar::tr("Preference").toLower())
365                    || t.startsWith(QMenuBar::tr("Options").toLower())
366                    || t.startsWith(QMenuBar::tr("Setting").toLower())
367                    || t.startsWith(QMenuBar::tr("Setup").toLower())) {
368             ret = [loader preferencesMenuItem];
369         } else if (t.startsWith(QMenuBar::tr("Quit").toLower())
370                    || t.startsWith(QMenuBar::tr("Exit").toLower())) {
371             ret = [loader quitMenuItem];
372         }
373     }
374         break;
375     }
376
377     if (QMenuMergeList *list = QCocoaMenu::mergeMenuItemsHash.value(merge)) {
378         for(int i = 0; i < list->size(); ++i) {
379             const QMenuMergeItem &item = list->at(i);
380             if (item.menuItem == ret && item.action)
381                 return 0;
382         }
383     }
384
385     return ret;
386 }
387
388 static QString qt_mac_menu_merge_text(QCocoaMenuAction *action)
389 {
390     QString ret;
391     extern QString qt_mac_applicationmenu_string(int type);
392     QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
393     if (action->action->menuRole() == QAction::ApplicationSpecificRole)
394         ret = action->action->text();
395     else if (action->menuItem == [loader aboutMenuItem]) {
396         ret = qt_mac_applicationmenu_string(6).arg(qt_mac_applicationName());
397     } else if (action->menuItem == [loader aboutQtMenuItem]) {
398         if (action->action->text() == QString("About Qt"))
399             ret = QMenuBar::tr("About Qt");
400         else
401             ret = action->action->text();
402     } else if (action->menuItem == [loader preferencesMenuItem]) {
403         ret = qt_mac_applicationmenu_string(4);
404     } else if (action->menuItem == [loader quitMenuItem]) {
405         ret = qt_mac_applicationmenu_string(5).arg(qt_mac_applicationName());
406     }
407     return ret;
408 }
409
410 static QKeySequence qt_mac_menu_merge_accel(QCocoaMenuAction *action)
411 {
412     QKeySequence ret;
413     QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
414     if (action->action->menuRole() == QAction::ApplicationSpecificRole)
415         ret = action->action->shortcut();
416     else if (action->menuItem == [loader preferencesMenuItem])
417         ret = QKeySequence(QKeySequence::Preferences);
418     else if (action->menuItem == [loader quitMenuItem])
419         ret = QKeySequence(QKeySequence::Quit);
420     return ret;
421 }
422
423 void Q_WIDGETS_EXPORT qt_mac_set_menubar_icons(bool b)
424 { QApplication::instance()->setAttribute(Qt::AA_DontShowIconsInMenus, !b); }
425 void Q_WIDGETS_EXPORT qt_mac_set_native_menubar(bool b)
426 {  QApplication::instance()->setAttribute(Qt::AA_DontUseNativeMenuBar, !b); }
427 void Q_WIDGETS_EXPORT qt_mac_set_menubar_merge(bool b) { qt_mac_no_menubar_merge = !b; }
428
429 /*****************************************************************************
430   QMenu bindings
431  *****************************************************************************/
432
433 QCocoaMenuAction::QCocoaMenuAction()
434     : menuItem(0)
435     , ignore_accel(0), merged(0), menu(0)
436 {
437
438 }
439
440 QCocoaMenu::QCocoaMenu(QMenu *a_qtMenu) : menu(0), qtMenu(a_qtMenu)
441 {
442 }
443
444 QCocoaMenu::~QCocoaMenu()
445 {
446     QCocoaAutoReleasePool pool;
447     while (actionItems.size()) {
448         QCocoaMenuAction *action = static_cast<QCocoaMenuAction *>(actionItems.takeFirst());
449         if (QMenuMergeList *list = mergeMenuItemsHash.value(action->menu)) {
450             int i = 0;
451             while (i < list->size()) {
452                 const QMenuMergeItem &item = list->at(i);
453                 if (item.action == action)
454                     list->removeAt(i);
455                 else
456                     ++i;
457             }
458         }
459         delete action;
460     }
461     mergeMenuHash.remove(menu);
462     mergeMenuItemsHash.remove(menu);
463     [menu release];
464 }
465
466
467 void QCocoaMenu::addAction(QAction *a, QAction *before)
468 {
469     QCocoaMenuAction *action = new QCocoaMenuAction;
470     action->action = a;
471     action->ignore_accel = 0;
472     action->merged = 0;
473     action->menu = 0;
474
475     QCocoaMenuAction *cocoaBefore = findAction(before);
476     addAction(action, cocoaBefore);
477 }
478
479
480 void QCocoaMenu::addAction(QCocoaMenuAction *action, QCocoaMenuAction *before)
481 {
482     QCocoaAutoReleasePool pool;
483     if (!action)
484         return;
485     int before_index = actionItems.indexOf(before);
486     if (before_index < 0) {
487         before = 0;
488         before_index = actionItems.size();
489     }
490     actionItems.insert(before_index, action);
491
492     [menu retain];
493     [action->menu release];
494     action->menu = menu;
495
496     /* When the action is considered a mergable action it
497        will stay that way, until removed.. */
498     if (!qt_mac_no_menubar_merge) {
499         OSMenuRef merge = QCocoaMenu::mergeMenuHash.value(menu);
500         if (merge) {
501             if (NSMenuItem *cmd = qt_mac_menu_merge_action(merge, action)) {
502                 action->merged = 1;
503                 [merge retain];
504                 [action->menu release];
505                 action->menu = merge;
506                 [cmd retain];
507                 [cmd setAction:@selector(qtDispatcherToQAction:)];
508                 [cmd setTarget:nil];
509                 [action->menuItem release];
510                 action->menuItem = cmd;
511                 QMenuMergeList *list = QCocoaMenu::mergeMenuItemsHash.value(merge);
512                 if (!list) {
513                     list = new QMenuMergeList;
514                     QCocoaMenu::mergeMenuItemsHash.insert(merge, list);
515                 }
516                 list->append(QMenuMergeItem(cmd, action));
517             }
518         }
519     }
520
521     NSMenuItem *newItem = action->menuItem;
522     if (newItem == 0) {
523         newItem = createNSMenuItem(action->action->text());
524         action->menuItem = newItem;
525         if (before) {
526             [menu insertItem:newItem atIndex:qMax(before_index, 0)];
527         } else {
528             [menu addItem:newItem];
529         }
530     } else {
531         [newItem setEnabled:YES];
532         // ###
533         //[newItem setEnabled:!QApplicationPrivate::modalState()];
534
535     }
536     [newItem setTag:long(static_cast<QAction *>(action->action))];
537     syncAction(action);
538 }
539
540 void QCocoaMenu::syncAction(QAction *a)
541 {
542     syncAction(findAction(a));
543 }
544
545 void QCocoaMenu::removeAction(QAction *a)
546 {
547     removeAction(findAction(a));
548 }
549
550 QCocoaMenuAction *QCocoaMenu::findAction(QAction *action) const
551 {
552     for (int i = 0; i < actionItems.size(); i++) {
553         QCocoaMenuAction *act = actionItems[i];
554         if (action == act->action)
555             return act;
556     }
557     return 0;
558 }
559
560
561 // return an autoreleased string given a QKeySequence (currently only looks at the first one).
562 NSString *keySequenceToKeyEqivalent(const QKeySequence &accel)
563 {
564     quint32 accel_key = (accel[0] & ~(Qt::MODIFIER_MASK | Qt::UNICODE_ACCEL));
565     QChar cocoa_key = qt_mac_qtKey2CocoaKey(Qt::Key(accel_key));
566     if (cocoa_key.isNull())
567         cocoa_key = QChar(accel_key).toLower().unicode();
568     return [NSString stringWithCharacters:&cocoa_key.unicode() length:1];
569 }
570
571 // return the cocoa modifier mask for the QKeySequence (currently only looks at the first one).
572 NSUInteger keySequenceModifierMask(const QKeySequence &accel)
573 {
574     return constructModifierMask(accel[0]);
575 }
576
577 void QCocoaMenu::syncAction(QCocoaMenuAction *action)
578 {
579     if (!action)
580         return;
581
582     NSMenuItem *item = action->menuItem;
583     if (!item)
584         return;
585
586     QCocoaAutoReleasePool pool;
587     NSMenu *menu = [item menu];
588     bool actionVisible = action->action->isVisible();
589     [item setHidden:!actionVisible];
590     if (!actionVisible)
591         return;
592
593     int itemIndex = [menu indexOfItem:item];
594     Q_ASSERT(itemIndex != -1);
595     if (action->action->isSeparator()) {
596         action->menuItem = [NSMenuItem separatorItem];
597         [action->menuItem retain];
598         [menu insertItem: action->menuItem atIndex:itemIndex];
599         [menu removeItem:item];
600         [item release];
601         item = action->menuItem;
602         return;
603     } else if ([item isSeparatorItem]) {
604         // I'm no longer a separator...
605         action->menuItem = createNSMenuItem(action->action->text());
606         [menu insertItem:action->menuItem atIndex:itemIndex];
607         [menu removeItem:item];
608         [item release];
609         item = action->menuItem;
610     }
611
612     //find text (and accel)
613     action->ignore_accel = 0;
614     QString text = action->action->text();
615     QKeySequence accel = action->action->shortcut();
616     {
617         int st = text.lastIndexOf(QLatin1Char('\t'));
618         if (st != -1) {
619             action->ignore_accel = 1;
620             accel = QKeySequence(text.right(text.length()-(st+1)));
621             text.remove(st, text.length()-st);
622         }
623     }
624     {
625         QString cmd_text = qt_mac_menu_merge_text(action);
626         if (!cmd_text.isEmpty()) {
627             text = cmd_text;
628             accel = qt_mac_menu_merge_accel(action);
629         }
630     }
631     // Show multiple key sequences as part of the menu text.
632     if (accel.count() > 1)
633         text += QLatin1String(" (") + accel.toString(QKeySequence::NativeText) + QLatin1String(")");
634
635 #if 0
636     QString finalString = qt_mac_removeMnemonics(text);
637 #else
638     QString finalString = qt_mac_removeMnemonics(text);
639 #endif
640     // Cocoa Font and title
641     if (action->action->font().resolve()) {
642         const QFont &actionFont = action->action->font();
643         NSFont *customMenuFont = [NSFont fontWithName:qt_mac_QStringToNSString(actionFont.family())
644                                   size:actionFont.pointSize()];
645         NSArray *keys = [NSArray arrayWithObjects:NSFontAttributeName, nil];
646         NSArray *objects = [NSArray arrayWithObjects:customMenuFont, nil];
647         NSDictionary *attributes = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
648         NSAttributedString *str = [[[NSAttributedString alloc] initWithString:qt_mac_QStringToNSString(finalString)
649                                  attributes:attributes] autorelease];
650        [item setAttributedTitle: str];
651     } else {
652             [item setTitle: qt_mac_QStringToNSString(finalString)];
653     }
654
655     if (action->action->menuRole() == QAction::AboutRole || action->action->menuRole() == QAction::QuitRole)
656         [item setTitle:qt_mac_QStringToNSString(text)];
657     else
658         [item setTitle:qt_mac_QStringToNSString(qt_mac_removeMnemonics(text))];
659
660     // Cocoa Enabled
661     [item setEnabled: action->action->isEnabled()];
662
663     // Cocoa icon
664     NSImage *nsimage = 0;
665     if (!action->action->icon().isNull() && action->action->isIconVisibleInMenu()) {
666         nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(action->action->icon().pixmap(16, QIcon::Normal)));
667     }
668     [item setImage:nsimage];
669     [nsimage release];
670
671     if (action->action->menu()) { //submenu
672         QCocoaMenu *cocoaMenu = static_cast<QCocoaMenu *>(action->action->menu()->platformMenu());
673         NSMenu *subMenu = cocoaMenu->macMenu();
674         if ([subMenu supermenu] && [subMenu supermenu] != [item menu]) {
675             // The menu is already a sub-menu of another one. Cocoa will throw an exception,
676             // in such cases. For the time being, a new QMenu with same set of actions is the
677             // only workaround.
678             action->action->setEnabled(false);
679         } else {
680             [item setSubmenu:subMenu];
681         }
682     } else { //respect some other items
683         [item setSubmenu:0];
684         // No key equivalent set for multiple key QKeySequence.
685         if (accel.count() == 1) {
686             [item setKeyEquivalent:keySequenceToKeyEqivalent(accel)];
687             [item setKeyEquivalentModifierMask:keySequenceModifierMask(accel)];
688         } else {
689             [item setKeyEquivalent:@""];
690             [item setKeyEquivalentModifierMask:NSCommandKeyMask];
691         }
692     }
693     //mark glyph
694     [item setState:action->action->isChecked() ?  NSOnState : NSOffState];
695 }
696
697 void QCocoaMenu::removeAction(QCocoaMenuAction *action)
698 {
699     if (!action)
700         return;
701     QCocoaAutoReleasePool pool;
702     if (action->merged) {
703         if (reinterpret_cast<QAction *>([action->menuItem tag]) == action->action) {
704             QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
705             [action->menuItem setEnabled:false];
706             if (action->menuItem != [loader quitMenuItem]
707                 && action->menuItem != [loader preferencesMenuItem]) {
708                 [[action->menuItem menu] removeItem:action->menuItem];
709             }
710         }
711     } else {
712         [[action->menuItem menu] removeItem:action->menuItem];
713     }
714     actionItems.removeAll(action);
715 }
716
717 OSMenuRef QCocoaMenu::macMenu(OSMenuRef merge)
718 {
719     if (menu)
720         return menu;
721     menu = qt_mac_create_menu(qtMenu);
722     if (merge) {
723         mergeMenuHash.insert(menu, merge);
724     }
725     QList<QAction*> items = qtMenu->actions();
726     for(int i = 0; i < items.count(); i++)
727         addAction(items[i], 0);
728     syncSeparatorsCollapsible(qtMenu->separatorsCollapsible());
729     return menu;
730 }
731
732 /*!
733   \internal
734 */
735 void
736 QCocoaMenu::syncSeparatorsCollapsible(bool collapse)
737 {
738     qt_mac_menu_collapseSeparators(menu, collapse);
739 }
740
741 /*!
742   \internal
743 */
744 void QCocoaMenu::setMenuEnabled(bool enable)
745 {
746     QCocoaAutoReleasePool pool;
747     if (enable) {
748         for (int i = 0; i < actionItems.count(); ++i) {
749             QCocoaMenuAction *menuItem = static_cast<QCocoaMenuAction *>(actionItems.at(i));
750             if (menuItem && menuItem->action && menuItem->action->isEnabled()) {
751                 [menuItem->menuItem setEnabled:true];
752             }
753         }
754     } else {
755         NSMenu *menu = menu;
756         for (NSMenuItem *item in [menu itemArray]) {
757             [item setEnabled:false];
758         }
759     }
760 }
761
762 /*!
763     \internal
764
765     This function will return the OSMenuRef used to create the native menu bar
766     bindings.
767
768     If Qt is built against Carbon, the OSMenuRef is a MenuRef that can be used
769     with Carbon's Menu Manager API.
770
771     If Qt is built against Cocoa, the OSMenuRef is a NSMenu pointer.
772
773     \warning This function is not portable.
774
775     \sa QMenuBar::macMenu()
776 */
777 /// OSMenuRef QMenu::macMenu(OSMenuRef merge) { return d_func()->macMenu(merge); }
778
779 /*****************************************************************************
780   QMenuBar bindings
781  *****************************************************************************/
782 typedef QHash<QWidget *, QMenuBar *> MenuBarHash;
783 Q_GLOBAL_STATIC(MenuBarHash, menubars)
784 static QMenuBar *fallback = 0;
785
786 QCocoaMenuBar::QCocoaMenuBar(QMenuBar *a_qtMenuBar) : menu(0), apple_menu(0), qtMenuBar(a_qtMenuBar)
787 {
788     macCreateMenuBar(qtMenuBar->parentWidget());
789 }
790
791 QCocoaMenuBar::~QCocoaMenuBar()
792 {
793     for(QList<QCocoaMenuAction*>::Iterator it = actionItems.begin(); it != actionItems.end(); ++it)
794         delete (*it);
795     [apple_menu release];
796     [menu release];
797 }
798 void QCocoaMenuBar::handleReparent(QWidget *newParent)
799 {
800     if (macWidgetHasNativeMenubar(newParent)) {
801         // If the new parent got a native menubar from before, keep that
802         // menubar rather than replace it with this one (because a parents
803         // menubar has precedence over children menubars).
804         macDestroyMenuBar();
805         macCreateMenuBar(newParent);
806      }
807
808 }
809
810 void QCocoaMenuBar::addAction(QAction *action, QAction *beforeAction)
811 {
812     if (action->isSeparator() || !menu)
813         return;
814     QCocoaMenuAction *cocoaAction = new QCocoaMenuAction;
815     cocoaAction->action = action;
816     cocoaAction->ignore_accel = 1;
817     QCocoaMenuAction *cocoaBeforeAction = findAction(beforeAction);
818     addAction(cocoaAction, cocoaBeforeAction);
819 }
820
821 void QCocoaMenuBar::addAction(QCocoaMenuAction *action, QCocoaMenuAction *before)
822 {
823     if (!action || !menu)
824         return;
825
826     int before_index = actionItems.indexOf(before);
827     if (before_index < 0) {
828         before = 0;
829         before_index = actionItems.size();
830     }
831     actionItems.insert(before_index, action);
832
833     MenuItemIndex index = actionItems.size()-1;
834
835     action->menu = menu;
836     QCocoaAutoReleasePool pool;
837     [action->menu retain];
838     NSMenuItem *newItem = createNSMenuItem(action->action->text());
839     action->menuItem = newItem;
840
841     if (before) {
842         [menu insertItem:newItem atIndex:qMax(1, before_index + 1)];
843         index = before_index;
844     } else {
845         [menu addItem:newItem];
846     }
847     [newItem setTag:long(static_cast<QAction *>(action->action))];
848     syncAction(action);
849 }
850
851
852 void QCocoaMenuBar::syncAction(QCocoaMenuAction *action)
853 {
854     if (!action || !menu)
855         return;
856
857     QCocoaAutoReleasePool pool;
858     NSMenuItem *item = action->menuItem;
859
860     OSMenuRef submenu = 0;
861     bool release_submenu = false;
862     if (action->action->menu()) {
863         QCocoaMenu *cocoaMenu = static_cast<QCocoaMenu *>(action->action->menu()->platformMenu());
864         if (!cocoaMenu) {
865
866         }
867
868         if ((submenu = cocoaMenu->macMenu(apple_menu))) {
869             if ([submenu supermenu] && [submenu supermenu] != [item menu])
870                 return;
871             else
872                 [item setSubmenu:submenu];
873         }
874     }
875
876     if (submenu) {
877         bool visible = actualMenuItemVisibility(this, action);
878         [item setSubmenu: submenu];
879         [submenu setTitle:qt_mac_QStringToNSString(qt_mac_removeMnemonics(action->action->text()))];
880         syncNSMenuItemVisiblity(item, visible);
881         if (release_submenu) { //no pointers to it
882             [submenu release];
883         }
884     } else {
885         qWarning("QMenu: No OSMenuRef created for popup menu");
886     }
887 }
888
889
890 void QCocoaMenuBar::removeAction(QCocoaMenuAction *action)
891 {
892     if (!action || !menu)
893         return;
894     QCocoaAutoReleasePool pool;
895     [action->menu removeItem:action->menuItem];
896     actionItems.removeAll(action);
897 }
898
899 void QCocoaMenuBar::syncAction(QAction *a)
900 {
901     syncAction(findAction(a));
902 }
903
904 void QCocoaMenuBar::removeAction(QAction *a)
905 {
906     removeAction(findAction(a));
907 }
908
909 QCocoaMenuAction *QCocoaMenuBar::findAction(QAction *action) const
910 {
911     for (int i = 0; i < actionItems.size(); i++) {
912         QCocoaMenuAction *act = actionItems[i];
913         if (action == act->action)
914             return act;
915     }
916     return 0;
917 }
918
919 bool QCocoaMenuBar::macWidgetHasNativeMenubar(QWidget *widget)
920 {
921     // This function is different from q->isNativeMenuBar(), as
922     // it returns true only if a native menu bar is actually
923     // _created_.
924     if (!widget)
925         return false;
926     return menubars()->contains(widget->window());
927 }
928
929 void QCocoaMenuBar::macCreateMenuBar(QWidget *parent)
930 {
931     static int dontUseNativeMenuBar = -1;
932     // We call the isNativeMenuBar function here
933     // because that will make sure that local overrides
934     // are dealt with correctly. q->isNativeMenuBar() will, if not
935     // overridden, depend on the attribute Qt::AA_DontUseNativeMenuBar:
936     bool qt_mac_no_native_menubar = !qtMenuBar->isNativeMenuBar();
937     if (qt_mac_no_native_menubar == false && dontUseNativeMenuBar < 0) {
938         // The menubar is set to be native. Let's check (one time only
939         // for all menubars) if this is OK with the rest of the environment.
940         // As a result, Qt::AA_DontUseNativeMenuBar is set. NB: the application
941         // might still choose to not respect, or change, this flag.
942         bool isPlugin = QApplication::testAttribute(Qt::AA_MacPluginApplication);
943         bool environmentSaysNo = !qgetenv("QT_MAC_NO_NATIVE_MENUBAR").isEmpty();
944         dontUseNativeMenuBar = isPlugin || environmentSaysNo;
945         QApplication::instance()->setAttribute(Qt::AA_DontUseNativeMenuBar, dontUseNativeMenuBar);
946         qt_mac_no_native_menubar = !qtMenuBar->isNativeMenuBar();
947     }
948     if (qt_mac_no_native_menubar == false) {
949         // INVARIANT: Use native menubar.
950         macUpdateMenuBar();
951         if (!parent && !fallback) {
952             fallback = qtMenuBar;
953         } else if (parent && parent->isWindow()) {
954             menubars()->insert(qtMenuBar->window(), qtMenuBar);
955         }
956     }
957 }
958
959 void QCocoaMenuBar::macDestroyMenuBar()
960 {
961     QCocoaAutoReleasePool pool;
962     if (fallback == qtMenuBar)
963         fallback = 0;
964     QWidget *tlw = qtMenuBar->window();
965     menubars()->remove(tlw);
966
967     if (!qt_mac_current_menubar.qmenubar || qt_mac_current_menubar.qmenubar == qtMenuBar) {
968         QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
969         [loader removeActionsFromAppMenu];
970         QCocoaMenuBar::macUpdateMenuBar();
971     }
972 }
973
974 OSMenuRef QCocoaMenuBar::macMenu()
975 {
976     if (!qtMenuBar->isNativeMenuBar()) {
977         return 0;
978     } else if (!menu) {
979         menu = qt_mac_create_menu(qtMenuBar);
980         ProcessSerialNumber mine, front;
981         if (GetCurrentProcess(&mine) == noErr && GetFrontProcess(&front) == noErr) {
982             if (!qt_mac_no_menubar_merge && !apple_menu) {
983                 apple_menu = qt_mac_create_menu(qtMenuBar);
984                 [apple_menu setTitle:qt_mac_QStringToNSString(QString(QChar(0x14)))];
985                 NSMenuItem *apple_menuItem = [[NSMenuItem alloc] init];
986                 [apple_menuItem setSubmenu:menu];
987                 [apple_menu addItem:apple_menuItem];
988                 [apple_menuItem release];
989             }
990             if (apple_menu) {
991                 QCocoaMenu::mergeMenuHash.insert(menu, apple_menu);
992             }
993             QList<QAction*> items = qtMenuBar->actions();
994             for(int i = 0; i < items.count(); i++)
995                 addAction(items[i], 0);
996         }
997     }
998     return menu;
999 }
1000
1001 /*!
1002     \internal
1003
1004     This function will return the OSMenuRef used to create the native menu bar
1005     bindings. This OSMenuRef is then set as the root menu for the Menu
1006     Manager.
1007
1008     \warning This function is not portable.
1009
1010     \sa QMenu::macMenu()
1011 */
1012 //OSMenuRef QMenuBar::macMenu() { return d_func()->macMenu(); }
1013
1014 /* !
1015     \internal
1016     Ancestor function that crosses windows (QWidget::isAncestorOf
1017     only considers widgets within the same window).
1018 */
1019 static bool qt_mac_is_ancestor(QWidget* possibleAncestor, QWidget *child)
1020 {
1021     if (!possibleAncestor)
1022         return false;
1023
1024     QWidget * current = child->parentWidget();
1025     while (current != 0) {
1026         if (current == possibleAncestor)
1027             return true;
1028         current = current->parentWidget();
1029     }
1030     return false;
1031 }
1032
1033 /* !
1034     \internal
1035     Returns true if the entries of menuBar should be disabled,
1036     based on the modality type of modalWidget.
1037 */
1038 static bool qt_mac_should_disable_menu(QMenuBar *menuBar)
1039 {
1040     QWidget *modalWidget = qApp->activeModalWidget();
1041     if (!modalWidget)
1042         return false;
1043
1044     if (menuBar && menuBar == menubars()->value(modalWidget))
1045         // The menu bar is owned by the modal widget.
1046         // In that case we should enable it:
1047         return false;
1048
1049     // When there is an application modal window on screen, the entries of
1050     // the menubar should be disabled. The exception in Qt is that if the
1051     // modal window is the only window on screen, then we enable the menu bar.
1052     QWidget *w = modalWidget;
1053     QWidgetList topLevelWidgets = QApplication::topLevelWidgets();
1054     while (w) {
1055         if (w->isVisible() && w->windowModality() == Qt::ApplicationModal) {
1056             for (int i=0; i<topLevelWidgets.size(); ++i) {
1057                 QWidget *top = topLevelWidgets.at(i);
1058                 if (w != top && top->isVisible()) {
1059                     // INVARIANT: we found another visible window
1060                     // on screen other than our modalWidget. We therefore
1061                     // disable the menu bar to follow normal modality logic:
1062                     return true;
1063                 }
1064             }
1065             // INVARIANT: We have only one window on screen that happends
1066             // to be application modal. We choose to enable the menu bar
1067             // in that case to e.g. enable the quit menu item.
1068             return false;
1069         }
1070         w = w->parentWidget();
1071     }
1072
1073     // INVARIANT: modalWidget is window modal. Disable menu entries
1074     // if the menu bar belongs to an ancestor of modalWidget. If menuBar
1075     // is nil, we understand it as the default menu bar set by the nib:
1076     return menuBar ? qt_mac_is_ancestor(menuBar->parentWidget(), modalWidget) : false;
1077 }
1078
1079 static QWidget *findWindowThatShouldDisplayMenubar()
1080 {
1081     QWidget *w = qApp->activeWindow();
1082
1083     if (!w) {
1084         // We have no active window on screen. Try to
1085         // find a window from the list of top levels:
1086         QWidgetList tlws = QApplication::topLevelWidgets();
1087         for(int i = 0; i < tlws.size(); ++i) {
1088             QWidget *tlw = tlws.at(i);
1089             if ((tlw->isVisible() && tlw->windowType() != Qt::Tool &&
1090                 tlw->windowType() != Qt::Popup)) {
1091                 w = tlw;
1092                 break;
1093             }
1094         }
1095     }
1096
1097     return w;
1098 }
1099
1100 static QMenuBar *findMenubarForWindow(QWidget *w)
1101 {
1102     QMenuBar *mb = 0;
1103     if (w) {
1104         mb = menubars()->value(w);
1105
1106 #if 0
1107 // ###
1108 //#ifndef QT_NO_MAINWINDOW
1109         QDockWidget *dw = qobject_cast<QDockWidget *>(w);
1110         if (!mb && dw) {
1111             QMainWindow *mw = qobject_cast<QMainWindow *>(dw->parentWidget());
1112             if (mw && (mb = menubars()->value(mw)))
1113                 w = mw;
1114         }
1115 #endif
1116         while(w && !mb)
1117             mb = menubars()->value((w = w->parentWidget()));
1118     }
1119
1120     if (!mb) {
1121         // We could not find a menu bar for the window. Lets
1122         // check if we have a global (parentless) menu bar instead:
1123         mb = fallback;
1124     }
1125
1126     return mb;
1127 }
1128
1129 void qt_mac_clear_menubar()
1130 {
1131     if (QApplication::testAttribute(Qt::AA_MacPluginApplication))
1132         return;
1133
1134     QCocoaAutoReleasePool pool;
1135     QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
1136     NSMenu *menu = [loader menu];
1137     [loader ensureAppMenuInMenu:menu];
1138     [NSApp setMainMenu:menu];
1139     const bool modal = qt_mac_should_disable_menu(0);
1140     if (qt_mac_current_menubar.qmenubar || modal != qt_mac_current_menubar.modal)
1141         qt_mac_set_modal_state(menu, modal);
1142     qt_mac_current_menubar.qmenubar = 0;
1143     qt_mac_current_menubar.modal = modal;
1144 }
1145
1146 /*!
1147   \internal
1148
1149   This function will update the current menu bar and set it as the
1150   active menu bar in the Menu Manager.
1151
1152   \warning This function is not portable.
1153 */
1154 void QCocoaMenuBar::macUpdateMenuBar()
1155 {
1156     [getMenuLoader() performSelectorOnMainThread: @selector(qtUpdateMenubar) withObject: nil waitUntilDone: NO];
1157 }
1158
1159 bool QCocoaMenuBar::macUpdateMenuBarImmediatly()
1160 {
1161     bool ret = false;
1162     cancelAllMenuTracking();
1163     QWidget *w = findWindowThatShouldDisplayMenubar();
1164     QMenuBar *mb = findMenubarForWindow(w);
1165
1166     // ###  extern bool qt_mac_app_fullscreen; //qapplication_mac.mm
1167     bool qt_mac_app_fullscreen = false;
1168     // We need to see if we are in full screen mode, if so we need to
1169     // switch the full screen mode to be able to show or hide the menubar.
1170     if(w && mb) {
1171         // This case means we are creating a menubar, check if full screen
1172         if(w->isFullScreen()) {
1173             // Ok, switch to showing the menubar when hovering over it.
1174             SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
1175             qt_mac_app_fullscreen = true;
1176         }
1177     } else if(w) {
1178         // Removing a menubar
1179         if(w->isFullScreen()) {
1180             // Ok, switch to not showing the menubar when hovering on it
1181             SetSystemUIMode(kUIModeAllHidden, 0);
1182             qt_mac_app_fullscreen = true;
1183         }
1184     }
1185
1186     if (mb && mb->isNativeMenuBar()) {
1187
1188         // ###
1189         bool modal = false;
1190         //bool modal = QGuiApplicationPrivate::modalState();
1191         QCocoaAutoReleasePool pool;
1192         if (OSMenuRef menu = reinterpret_cast<QCocoaMenuBar *>(mb->platformMenuBar())->macMenu()) {
1193             QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
1194             [loader ensureAppMenuInMenu:menu];
1195             [NSApp setMainMenu:menu];
1196             syncMenuBarItemsVisiblity(reinterpret_cast<QCocoaMenuBar *>(mb->platformMenuBar()));
1197
1198             if (OSMenuRef tmpMerge = QCocoaMenu::mergeMenuHash.value(menu)) {
1199                 if (QMenuMergeList *mergeList
1200                         = QCocoaMenu::mergeMenuItemsHash.value(tmpMerge)) {
1201                     const int mergeListSize = mergeList->size();
1202
1203                     for (int i = 0; i < mergeListSize; ++i) {
1204                         const QMenuMergeItem &mergeItem = mergeList->at(i);
1205                         // Ideally we would call QCocoaMenu::syncAction, but that requires finding
1206                         // the original QMen and likely doing more work than we need.
1207                         // For example, enabled is handled below.
1208                         [mergeItem.menuItem setTag:reinterpret_cast<long>(
1209                                                     static_cast<QAction *>(mergeItem.action->action))];
1210                         [mergeItem.menuItem setHidden:!(mergeItem.action->action->isVisible())];
1211                     }
1212                 }
1213             }
1214             // Check if menu is modally shaddowed and should  be disabled:
1215             modal = qt_mac_should_disable_menu(mb);
1216             if (mb != qt_mac_current_menubar.qmenubar || modal != qt_mac_current_menubar.modal)
1217                 qt_mac_set_modal_state(menu, modal);
1218         }
1219         qt_mac_current_menubar.qmenubar = mb;
1220         qt_mac_current_menubar.modal = modal;
1221         ret = true;
1222     } else if (qt_mac_current_menubar.qmenubar && qt_mac_current_menubar.qmenubar->isNativeMenuBar()) {
1223         // INVARIANT: The currently active menu bar (if any) is not native. But we do have a
1224         // native menu bar from before. So we need to decide whether or not is should be enabled:
1225         const bool modal = qt_mac_should_disable_menu(qt_mac_current_menubar.qmenubar);
1226         if (modal != qt_mac_current_menubar.modal) {
1227             ret = true;
1228             if (OSMenuRef menu = reinterpret_cast<QCocoaMenuBar *>(qt_mac_current_menubar.qmenubar->platformMenuBar())->macMenu()) {
1229                 QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
1230                 [loader ensureAppMenuInMenu:menu];
1231                 [NSApp setMainMenu:menu];
1232                 syncMenuBarItemsVisiblity(reinterpret_cast<QCocoaMenuBar *>(qt_mac_current_menubar.qmenubar->platformMenuBar()));
1233                 qt_mac_set_modal_state(menu, modal);
1234             }
1235             qt_mac_current_menubar.modal = modal;
1236         }
1237     }
1238
1239     if (!ret) {
1240         qt_mac_clear_menubar();
1241     }
1242     return ret;
1243 }
1244
1245 QHash<OSMenuRef, OSMenuRef> QCocoaMenu::mergeMenuHash;
1246 QHash<OSMenuRef, QMenuMergeList*> QCocoaMenu::mergeMenuItemsHash;
1247
1248 bool QCocoaMenu::merged(const QAction *action) const
1249 {
1250     if (OSMenuRef merge = mergeMenuHash.value(menu)) {
1251         if (QMenuMergeList *list = mergeMenuItemsHash.value(merge)) {
1252             for(int i = 0; i < list->size(); ++i) {
1253                 const QMenuMergeItem &item = list->at(i);
1254                 if (item.action->action == action)
1255                     return true;
1256             }
1257         }
1258     }
1259     return false;
1260 }
1261
1262 //creation of the OSMenuRef
1263 static OSMenuRef qt_mac_create_menu(QWidget *w)
1264 {
1265     OSMenuRef ret;
1266     if (QMenu *qmenu = qobject_cast<QMenu *>(w)){
1267         ret = [[QT_MANGLE_NAMESPACE(QNativeCocoaMenu) alloc] initWithQMenu:qmenu];
1268     } else {
1269         ret = [[NSMenu alloc] init];
1270     }
1271     return ret;
1272 }
1273
1274 QT_END_NAMESPACE