Cocoa: Enable native menus.
[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     if (menu == 0)
470         return;
471
472     QCocoaMenuAction *action = new QCocoaMenuAction;
473     action->action = a;
474     action->ignore_accel = 0;
475     action->merged = 0;
476     action->menu = 0;
477
478     QCocoaMenuAction *cocoaBefore = findAction(before);
479     addAction(action, cocoaBefore);
480 }
481
482
483 void QCocoaMenu::addAction(QCocoaMenuAction *action, QCocoaMenuAction *before)
484 {
485     QCocoaAutoReleasePool pool;
486     if (!action)
487         return;
488     int before_index = actionItems.indexOf(before);
489     if (before_index < 0) {
490         before = 0;
491         before_index = actionItems.size();
492     }
493     actionItems.insert(before_index, action);
494
495     [menu retain];
496     [action->menu release];
497     action->menu = menu;
498
499     /* When the action is considered a mergable action it
500        will stay that way, until removed.. */
501     if (!qt_mac_no_menubar_merge) {
502         OSMenuRef merge = QCocoaMenu::mergeMenuHash.value(menu);
503         if (merge) {
504             if (NSMenuItem *cmd = qt_mac_menu_merge_action(merge, action)) {
505                 action->merged = 1;
506                 [merge retain];
507                 [action->menu release];
508                 action->menu = merge;
509                 [cmd retain];
510                 [cmd setAction:@selector(qtDispatcherToQAction:)];
511                 [cmd setTarget:nil];
512                 [action->menuItem release];
513                 action->menuItem = cmd;
514                 QMenuMergeList *list = QCocoaMenu::mergeMenuItemsHash.value(merge);
515                 if (!list) {
516                     list = new QMenuMergeList;
517                     QCocoaMenu::mergeMenuItemsHash.insert(merge, list);
518                 }
519                 list->append(QMenuMergeItem(cmd, action));
520             }
521         }
522     }
523
524     NSMenuItem *newItem = action->menuItem;
525     if (newItem == 0) {
526         newItem = createNSMenuItem(action->action->text());
527         action->menuItem = newItem;
528         if (before) {
529             [menu insertItem:newItem atIndex:qMax(before_index, 0)];
530         } else {
531             [menu addItem:newItem];
532         }
533     } else {
534         [newItem setEnabled:YES];
535         // ###
536         //[newItem setEnabled:!QApplicationPrivate::modalState()];
537
538     }
539     [newItem setTag:long(static_cast<QAction *>(action->action))];
540     syncAction(action);
541 }
542
543 void QCocoaMenu::syncAction(QAction *a)
544 {
545     syncAction(findAction(a));
546 }
547
548 void QCocoaMenu::removeAction(QAction *a)
549 {
550     removeAction(findAction(a));
551 }
552
553 QCocoaMenuAction *QCocoaMenu::findAction(QAction *action) const
554 {
555     for (int i = 0; i < actionItems.size(); i++) {
556         QCocoaMenuAction *act = actionItems[i];
557         if (action == act->action)
558             return act;
559     }
560     return 0;
561 }
562
563
564 // return an autoreleased string given a QKeySequence (currently only looks at the first one).
565 NSString *keySequenceToKeyEqivalent(const QKeySequence &accel)
566 {
567     quint32 accel_key = (accel[0] & ~(Qt::MODIFIER_MASK | Qt::UNICODE_ACCEL));
568     QChar cocoa_key = qt_mac_qtKey2CocoaKey(Qt::Key(accel_key));
569     if (cocoa_key.isNull())
570         cocoa_key = QChar(accel_key).toLower().unicode();
571     return [NSString stringWithCharacters:&cocoa_key.unicode() length:1];
572 }
573
574 // return the cocoa modifier mask for the QKeySequence (currently only looks at the first one).
575 NSUInteger keySequenceModifierMask(const QKeySequence &accel)
576 {
577     return constructModifierMask(accel[0]);
578 }
579
580 void QCocoaMenu::syncAction(QCocoaMenuAction *action)
581 {
582     if (!action)
583         return;
584
585     NSMenuItem *item = action->menuItem;
586     if (!item)
587         return;
588
589     QCocoaAutoReleasePool pool;
590     NSMenu *menu = [item menu];
591     bool actionVisible = action->action->isVisible();
592     [item setHidden:!actionVisible];
593     if (!actionVisible)
594         return;
595
596     int itemIndex = [menu indexOfItem:item];
597     Q_ASSERT(itemIndex != -1);
598     if (action->action->isSeparator()) {
599         action->menuItem = [NSMenuItem separatorItem];
600         [action->menuItem retain];
601         [menu insertItem: action->menuItem atIndex:itemIndex];
602         [menu removeItem:item];
603         [item release];
604         item = action->menuItem;
605         return;
606     } else if ([item isSeparatorItem]) {
607         // I'm no longer a separator...
608         action->menuItem = createNSMenuItem(action->action->text());
609         [menu insertItem:action->menuItem atIndex:itemIndex];
610         [menu removeItem:item];
611         [item release];
612         item = action->menuItem;
613     }
614
615     //find text (and accel)
616     action->ignore_accel = 0;
617     QString text = action->action->text();
618     QKeySequence accel = action->action->shortcut();
619     {
620         int st = text.lastIndexOf(QLatin1Char('\t'));
621         if (st != -1) {
622             action->ignore_accel = 1;
623             accel = QKeySequence(text.right(text.length()-(st+1)));
624             text.remove(st, text.length()-st);
625         }
626     }
627     {
628         QString cmd_text = qt_mac_menu_merge_text(action);
629         if (!cmd_text.isEmpty()) {
630             text = cmd_text;
631             accel = qt_mac_menu_merge_accel(action);
632         }
633     }
634     // Show multiple key sequences as part of the menu text.
635     if (accel.count() > 1)
636         text += QLatin1String(" (") + accel.toString(QKeySequence::NativeText) + QLatin1String(")");
637
638 #if 0
639     QString finalString = qt_mac_removeMnemonics(text);
640 #else
641     QString finalString = qt_mac_removeMnemonics(text);
642 #endif
643     // Cocoa Font and title
644     if (action->action->font().resolve()) {
645         const QFont &actionFont = action->action->font();
646         NSFont *customMenuFont = [NSFont fontWithName:qt_mac_QStringToNSString(actionFont.family())
647                                   size:actionFont.pointSize()];
648         NSArray *keys = [NSArray arrayWithObjects:NSFontAttributeName, nil];
649         NSArray *objects = [NSArray arrayWithObjects:customMenuFont, nil];
650         NSDictionary *attributes = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
651         NSAttributedString *str = [[[NSAttributedString alloc] initWithString:qt_mac_QStringToNSString(finalString)
652                                  attributes:attributes] autorelease];
653        [item setAttributedTitle: str];
654     } else {
655             [item setTitle: qt_mac_QStringToNSString(finalString)];
656     }
657
658     if (action->action->menuRole() == QAction::AboutRole || action->action->menuRole() == QAction::QuitRole)
659         [item setTitle:qt_mac_QStringToNSString(text)];
660     else
661         [item setTitle:qt_mac_QStringToNSString(qt_mac_removeMnemonics(text))];
662
663     // Cocoa Enabled
664     [item setEnabled: action->action->isEnabled()];
665
666     // Cocoa icon
667     NSImage *nsimage = 0;
668     if (!action->action->icon().isNull() && action->action->isIconVisibleInMenu()) {
669         nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(action->action->icon().pixmap(16, QIcon::Normal)));
670     }
671     [item setImage:nsimage];
672     [nsimage release];
673
674     if (action->action->menu()) { //submenu
675         QCocoaMenu *cocoaMenu = static_cast<QCocoaMenu *>(action->action->menu()->platformMenu());
676         NSMenu *subMenu = cocoaMenu->macMenu();
677         if ([subMenu supermenu] && [subMenu supermenu] != [item menu]) {
678             // The menu is already a sub-menu of another one. Cocoa will throw an exception,
679             // in such cases. For the time being, a new QMenu with same set of actions is the
680             // only workaround.
681             action->action->setEnabled(false);
682         } else {
683             [item setSubmenu:subMenu];
684         }
685     } else { //respect some other items
686         [item setSubmenu:0];
687         // No key equivalent set for multiple key QKeySequence.
688         if (accel.count() == 1) {
689             [item setKeyEquivalent:keySequenceToKeyEqivalent(accel)];
690             [item setKeyEquivalentModifierMask:keySequenceModifierMask(accel)];
691         } else {
692             [item setKeyEquivalent:@""];
693             [item setKeyEquivalentModifierMask:NSCommandKeyMask];
694         }
695     }
696     //mark glyph
697     [item setState:action->action->isChecked() ?  NSOnState : NSOffState];
698 }
699
700 void QCocoaMenu::removeAction(QCocoaMenuAction *action)
701 {
702     if (!action)
703         return;
704     QCocoaAutoReleasePool pool;
705     if (action->merged) {
706         if (reinterpret_cast<QAction *>([action->menuItem tag]) == action->action) {
707             QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
708             [action->menuItem setEnabled:false];
709             if (action->menuItem != [loader quitMenuItem]
710                 && action->menuItem != [loader preferencesMenuItem]) {
711                 [[action->menuItem menu] removeItem:action->menuItem];
712             }
713         }
714     } else {
715         [[action->menuItem menu] removeItem:action->menuItem];
716     }
717     actionItems.removeAll(action);
718 }
719
720 OSMenuRef QCocoaMenu::macMenu(OSMenuRef merge)
721 {
722     if (menu)
723         return menu;
724     menu = qt_mac_create_menu(qtMenu);
725     if (merge) {
726         mergeMenuHash.insert(menu, merge);
727     }
728     QList<QAction*> items = qtMenu->actions();
729     for(int i = 0; i < items.count(); i++)
730         addAction(items[i], 0);
731     syncSeparatorsCollapsible(qtMenu->separatorsCollapsible());
732     return menu;
733 }
734
735 /*!
736   \internal
737 */
738 void
739 QCocoaMenu::syncSeparatorsCollapsible(bool collapse)
740 {
741     qt_mac_menu_collapseSeparators(menu, collapse);
742 }
743
744 /*!
745   \internal
746 */
747 void QCocoaMenu::setMenuEnabled(bool enable)
748 {
749     QCocoaAutoReleasePool pool;
750     if (enable) {
751         for (int i = 0; i < actionItems.count(); ++i) {
752             QCocoaMenuAction *menuItem = static_cast<QCocoaMenuAction *>(actionItems.at(i));
753             if (menuItem && menuItem->action && menuItem->action->isEnabled()) {
754                 [menuItem->menuItem setEnabled:true];
755             }
756         }
757     } else {
758         NSMenu *menu = menu;
759         for (NSMenuItem *item in [menu itemArray]) {
760             [item setEnabled:false];
761         }
762     }
763 }
764
765 /*!
766     \internal
767
768     This function will return the OSMenuRef used to create the native menu bar
769     bindings.
770
771     If Qt is built against Carbon, the OSMenuRef is a MenuRef that can be used
772     with Carbon's Menu Manager API.
773
774     If Qt is built against Cocoa, the OSMenuRef is a NSMenu pointer.
775
776     \warning This function is not portable.
777
778     \sa QMenuBar::macMenu()
779 */
780 /// OSMenuRef QMenu::macMenu(OSMenuRef merge) { return d_func()->macMenu(merge); }
781
782 /*****************************************************************************
783   QMenuBar bindings
784  *****************************************************************************/
785 typedef QHash<QWidget *, QMenuBar *> MenuBarHash;
786 Q_GLOBAL_STATIC(MenuBarHash, menubars)
787 static QMenuBar *fallback = 0;
788
789 QCocoaMenuBar::QCocoaMenuBar(QMenuBar *a_qtMenuBar) : menu(0), apple_menu(0), qtMenuBar(a_qtMenuBar)
790 {
791     macCreateMenuBar(qtMenuBar->parentWidget());
792 }
793
794 QCocoaMenuBar::~QCocoaMenuBar()
795 {
796     for(QList<QCocoaMenuAction*>::Iterator it = actionItems.begin(); it != actionItems.end(); ++it)
797         delete (*it);
798     [apple_menu release];
799     [menu release];
800 }
801 void QCocoaMenuBar::handleReparent(QWidget *newParent)
802 {
803     if (macWidgetHasNativeMenubar(newParent)) {
804         // If the new parent got a native menubar from before, keep that
805         // menubar rather than replace it with this one (because a parents
806         // menubar has precedence over children menubars).
807         macDestroyMenuBar();
808         macCreateMenuBar(newParent);
809      }
810
811 }
812
813 void QCocoaMenuBar::addAction(QAction *action, QAction *beforeAction)
814 {
815     if (action->isSeparator() || !menu)
816         return;
817     QCocoaMenuAction *cocoaAction = new QCocoaMenuAction;
818     cocoaAction->action = action;
819     cocoaAction->ignore_accel = 1;
820     QCocoaMenuAction *cocoaBeforeAction = findAction(beforeAction);
821     addAction(cocoaAction, cocoaBeforeAction);
822 }
823
824 void QCocoaMenuBar::addAction(QCocoaMenuAction *action, QCocoaMenuAction *before)
825 {
826     if (!action || !menu)
827         return;
828
829     int before_index = actionItems.indexOf(before);
830     if (before_index < 0) {
831         before = 0;
832         before_index = actionItems.size();
833     }
834     actionItems.insert(before_index, action);
835
836     MenuItemIndex index = actionItems.size()-1;
837
838     action->menu = menu;
839     QCocoaAutoReleasePool pool;
840     [action->menu retain];
841     NSMenuItem *newItem = createNSMenuItem(action->action->text());
842     action->menuItem = newItem;
843
844     if (before) {
845         [menu insertItem:newItem atIndex:qMax(1, before_index + 1)];
846         index = before_index;
847     } else {
848         [menu addItem:newItem];
849     }
850     [newItem setTag:long(static_cast<QAction *>(action->action))];
851     syncAction(action);
852 }
853
854
855 void QCocoaMenuBar::syncAction(QCocoaMenuAction *action)
856 {
857     if (!action || !menu)
858         return;
859
860     QCocoaAutoReleasePool pool;
861     NSMenuItem *item = action->menuItem;
862
863     OSMenuRef submenu = 0;
864     bool release_submenu = false;
865     if (action->action->menu()) {
866         QCocoaMenu *cocoaMenu = static_cast<QCocoaMenu *>(action->action->menu()->platformMenu());
867         if (!cocoaMenu) {
868
869         }
870
871         if ((submenu = cocoaMenu->macMenu(apple_menu))) {
872             if ([submenu supermenu] && [submenu supermenu] != [item menu])
873                 return;
874             else
875                 [item setSubmenu:submenu];
876         }
877     }
878
879     if (submenu) {
880         bool visible = actualMenuItemVisibility(this, action);
881         [item setSubmenu: submenu];
882         [submenu setTitle:qt_mac_QStringToNSString(qt_mac_removeMnemonics(action->action->text()))];
883         syncNSMenuItemVisiblity(item, visible);
884         if (release_submenu) { //no pointers to it
885             [submenu release];
886         }
887     } else {
888         qWarning("QMenu: No OSMenuRef created for popup menu");
889     }
890 }
891
892
893 void QCocoaMenuBar::removeAction(QCocoaMenuAction *action)
894 {
895     if (!action || !menu)
896         return;
897     QCocoaAutoReleasePool pool;
898     [action->menu removeItem:action->menuItem];
899     actionItems.removeAll(action);
900 }
901
902 void QCocoaMenuBar::syncAction(QAction *a)
903 {
904     syncAction(findAction(a));
905 }
906
907 void QCocoaMenuBar::removeAction(QAction *a)
908 {
909     removeAction(findAction(a));
910 }
911
912 QCocoaMenuAction *QCocoaMenuBar::findAction(QAction *action) const
913 {
914     for (int i = 0; i < actionItems.size(); i++) {
915         QCocoaMenuAction *act = actionItems[i];
916         if (action == act->action)
917             return act;
918     }
919     return 0;
920 }
921
922 bool QCocoaMenuBar::macWidgetHasNativeMenubar(QWidget *widget)
923 {
924     // This function is different from q->isNativeMenuBar(), as
925     // it returns true only if a native menu bar is actually
926     // _created_.
927     if (!widget)
928         return false;
929     return menubars()->contains(widget->window());
930 }
931
932 void QCocoaMenuBar::macCreateMenuBar(QWidget *parent)
933 {
934     static int dontUseNativeMenuBar = -1;
935     // We call the isNativeMenuBar function here
936     // because that will make sure that local overrides
937     // are dealt with correctly. q->isNativeMenuBar() will, if not
938     // overridden, depend on the attribute Qt::AA_DontUseNativeMenuBar:
939     bool qt_mac_no_native_menubar = !qtMenuBar->isNativeMenuBar();
940     if (qt_mac_no_native_menubar == false && dontUseNativeMenuBar < 0) {
941         // The menubar is set to be native. Let's check (one time only
942         // for all menubars) if this is OK with the rest of the environment.
943         // As a result, Qt::AA_DontUseNativeMenuBar is set. NB: the application
944         // might still choose to not respect, or change, this flag.
945         bool isPlugin = QApplication::testAttribute(Qt::AA_MacPluginApplication);
946         bool environmentSaysNo = !qgetenv("QT_MAC_NO_NATIVE_MENUBAR").isEmpty();
947         dontUseNativeMenuBar = isPlugin || environmentSaysNo;
948         QApplication::instance()->setAttribute(Qt::AA_DontUseNativeMenuBar, dontUseNativeMenuBar);
949         qt_mac_no_native_menubar = !qtMenuBar->isNativeMenuBar();
950     }
951     if (qt_mac_no_native_menubar == false) {
952         // INVARIANT: Use native menubar.
953         macUpdateMenuBar();
954         if (!parent && !fallback) {
955             fallback = qtMenuBar;
956         } else if (parent && parent->isWindow()) {
957             menubars()->insert(qtMenuBar->window(), qtMenuBar);
958         }
959     }
960 }
961
962 void QCocoaMenuBar::macDestroyMenuBar()
963 {
964     QCocoaAutoReleasePool pool;
965     if (fallback == qtMenuBar)
966         fallback = 0;
967     QWidget *tlw = qtMenuBar->window();
968     menubars()->remove(tlw);
969
970     if (!qt_mac_current_menubar.qmenubar || qt_mac_current_menubar.qmenubar == qtMenuBar) {
971         QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
972         [loader removeActionsFromAppMenu];
973         QCocoaMenuBar::macUpdateMenuBar();
974     }
975 }
976
977 OSMenuRef QCocoaMenuBar::macMenu()
978 {
979     if (!qtMenuBar->isNativeMenuBar()) {
980         return 0;
981     } else if (!menu) {
982         menu = qt_mac_create_menu(qtMenuBar);
983         ProcessSerialNumber mine, front;
984         if (GetCurrentProcess(&mine) == noErr && GetFrontProcess(&front) == noErr) {
985             if (!qt_mac_no_menubar_merge && !apple_menu) {
986                 apple_menu = qt_mac_create_menu(qtMenuBar);
987                 [apple_menu setTitle:qt_mac_QStringToNSString(QString(QChar(0x14)))];
988                 NSMenuItem *apple_menuItem = [[NSMenuItem alloc] init];
989                 [apple_menuItem setSubmenu:menu];
990                 [apple_menu addItem:apple_menuItem];
991                 [apple_menuItem release];
992             }
993             if (apple_menu) {
994                 QCocoaMenu::mergeMenuHash.insert(menu, apple_menu);
995             }
996             QList<QAction*> items = qtMenuBar->actions();
997             for(int i = 0; i < items.count(); i++)
998                 addAction(items[i], 0);
999         }
1000     }
1001     return menu;
1002 }
1003
1004 /*!
1005     \internal
1006
1007     This function will return the OSMenuRef used to create the native menu bar
1008     bindings. This OSMenuRef is then set as the root menu for the Menu
1009     Manager.
1010
1011     \warning This function is not portable.
1012
1013     \sa QMenu::macMenu()
1014 */
1015 //OSMenuRef QMenuBar::macMenu() { return d_func()->macMenu(); }
1016
1017 /* !
1018     \internal
1019     Ancestor function that crosses windows (QWidget::isAncestorOf
1020     only considers widgets within the same window).
1021 */
1022 static bool qt_mac_is_ancestor(QWidget* possibleAncestor, QWidget *child)
1023 {
1024     if (!possibleAncestor)
1025         return false;
1026
1027     QWidget * current = child->parentWidget();
1028     while (current != 0) {
1029         if (current == possibleAncestor)
1030             return true;
1031         current = current->parentWidget();
1032     }
1033     return false;
1034 }
1035
1036 /* !
1037     \internal
1038     Returns true if the entries of menuBar should be disabled,
1039     based on the modality type of modalWidget.
1040 */
1041 static bool qt_mac_should_disable_menu(QMenuBar *menuBar)
1042 {
1043     QWidget *modalWidget = qApp->activeModalWidget();
1044     if (!modalWidget)
1045         return false;
1046
1047     if (menuBar && menuBar == menubars()->value(modalWidget))
1048         // The menu bar is owned by the modal widget.
1049         // In that case we should enable it:
1050         return false;
1051
1052     // When there is an application modal window on screen, the entries of
1053     // the menubar should be disabled. The exception in Qt is that if the
1054     // modal window is the only window on screen, then we enable the menu bar.
1055     QWidget *w = modalWidget;
1056     QWidgetList topLevelWidgets = QApplication::topLevelWidgets();
1057     while (w) {
1058         if (w->isVisible() && w->windowModality() == Qt::ApplicationModal) {
1059             for (int i=0; i<topLevelWidgets.size(); ++i) {
1060                 QWidget *top = topLevelWidgets.at(i);
1061                 if (w != top && top->isVisible()) {
1062                     // INVARIANT: we found another visible window
1063                     // on screen other than our modalWidget. We therefore
1064                     // disable the menu bar to follow normal modality logic:
1065                     return true;
1066                 }
1067             }
1068             // INVARIANT: We have only one window on screen that happends
1069             // to be application modal. We choose to enable the menu bar
1070             // in that case to e.g. enable the quit menu item.
1071             return false;
1072         }
1073         w = w->parentWidget();
1074     }
1075
1076     // INVARIANT: modalWidget is window modal. Disable menu entries
1077     // if the menu bar belongs to an ancestor of modalWidget. If menuBar
1078     // is nil, we understand it as the default menu bar set by the nib:
1079     return menuBar ? qt_mac_is_ancestor(menuBar->parentWidget(), modalWidget) : false;
1080 }
1081
1082 static QWidget *findWindowThatShouldDisplayMenubar()
1083 {
1084     QWidget *w = qApp->activeWindow();
1085
1086     if (!w) {
1087         // We have no active window on screen. Try to
1088         // find a window from the list of top levels:
1089         QWidgetList tlws = QApplication::topLevelWidgets();
1090         for(int i = 0; i < tlws.size(); ++i) {
1091             QWidget *tlw = tlws.at(i);
1092             if ((tlw->isVisible() && tlw->windowType() != Qt::Tool &&
1093                 tlw->windowType() != Qt::Popup)) {
1094                 w = tlw;
1095                 break;
1096             }
1097         }
1098     }
1099
1100     return w;
1101 }
1102
1103 static QMenuBar *findMenubarForWindow(QWidget *w)
1104 {
1105     QMenuBar *mb = 0;
1106     if (w) {
1107         mb = menubars()->value(w);
1108
1109 #if 0
1110 // ###
1111 //#ifndef QT_NO_MAINWINDOW
1112         QDockWidget *dw = qobject_cast<QDockWidget *>(w);
1113         if (!mb && dw) {
1114             QMainWindow *mw = qobject_cast<QMainWindow *>(dw->parentWidget());
1115             if (mw && (mb = menubars()->value(mw)))
1116                 w = mw;
1117         }
1118 #endif
1119         while(w && !mb)
1120             mb = menubars()->value((w = w->parentWidget()));
1121     }
1122
1123     if (!mb) {
1124         // We could not find a menu bar for the window. Lets
1125         // check if we have a global (parentless) menu bar instead:
1126         mb = fallback;
1127     }
1128
1129     return mb;
1130 }
1131
1132 void qt_mac_clear_menubar()
1133 {
1134     if (QApplication::testAttribute(Qt::AA_MacPluginApplication))
1135         return;
1136
1137     QCocoaAutoReleasePool pool;
1138     QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
1139     NSMenu *menu = [loader menu];
1140     [loader ensureAppMenuInMenu:menu];
1141     [NSApp setMainMenu:menu];
1142     const bool modal = qt_mac_should_disable_menu(0);
1143     if (qt_mac_current_menubar.qmenubar || modal != qt_mac_current_menubar.modal)
1144         qt_mac_set_modal_state(menu, modal);
1145     qt_mac_current_menubar.qmenubar = 0;
1146     qt_mac_current_menubar.modal = modal;
1147 }
1148
1149 /*!
1150   \internal
1151
1152   This function will update the current menu bar and set it as the
1153   active menu bar in the Menu Manager.
1154
1155   \warning This function is not portable.
1156 */
1157 void QCocoaMenuBar::macUpdateMenuBar()
1158 {
1159     [getMenuLoader() performSelectorOnMainThread: @selector(qtUpdateMenubar) withObject: nil waitUntilDone: NO];
1160 }
1161
1162 bool QCocoaMenuBar::macUpdateMenuBarImmediatly()
1163 {
1164     bool ret = false;
1165     cancelAllMenuTracking();
1166     QWidget *w = findWindowThatShouldDisplayMenubar();
1167     QMenuBar *mb = findMenubarForWindow(w);
1168
1169     // ###  extern bool qt_mac_app_fullscreen; //qapplication_mac.mm
1170     bool qt_mac_app_fullscreen = false;
1171     // We need to see if we are in full screen mode, if so we need to
1172     // switch the full screen mode to be able to show or hide the menubar.
1173     if(w && mb) {
1174         // This case means we are creating a menubar, check if full screen
1175         if(w->isFullScreen()) {
1176             // Ok, switch to showing the menubar when hovering over it.
1177             SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
1178             qt_mac_app_fullscreen = true;
1179         }
1180     } else if(w) {
1181         // Removing a menubar
1182         if(w->isFullScreen()) {
1183             // Ok, switch to not showing the menubar when hovering on it
1184             SetSystemUIMode(kUIModeAllHidden, 0);
1185             qt_mac_app_fullscreen = true;
1186         }
1187     }
1188
1189     if (mb && mb->isNativeMenuBar()) {
1190
1191         // ###
1192         bool modal = false;
1193         //bool modal = QGuiApplicationPrivate::modalState();
1194         QCocoaAutoReleasePool pool;
1195         if (OSMenuRef menu = reinterpret_cast<QCocoaMenuBar *>(mb->platformMenuBar())->macMenu()) {
1196             QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
1197             [loader ensureAppMenuInMenu:menu];
1198             [NSApp setMainMenu:menu];
1199             syncMenuBarItemsVisiblity(reinterpret_cast<QCocoaMenuBar *>(mb->platformMenuBar()));
1200
1201             if (OSMenuRef tmpMerge = QCocoaMenu::mergeMenuHash.value(menu)) {
1202                 if (QMenuMergeList *mergeList
1203                         = QCocoaMenu::mergeMenuItemsHash.value(tmpMerge)) {
1204                     const int mergeListSize = mergeList->size();
1205
1206                     for (int i = 0; i < mergeListSize; ++i) {
1207                         const QMenuMergeItem &mergeItem = mergeList->at(i);
1208                         // Ideally we would call QCocoaMenu::syncAction, but that requires finding
1209                         // the original QMen and likely doing more work than we need.
1210                         // For example, enabled is handled below.
1211                         [mergeItem.menuItem setTag:reinterpret_cast<long>(
1212                                                     static_cast<QAction *>(mergeItem.action->action))];
1213                         [mergeItem.menuItem setHidden:!(mergeItem.action->action->isVisible())];
1214                     }
1215                 }
1216             }
1217             // Check if menu is modally shaddowed and should  be disabled:
1218             modal = qt_mac_should_disable_menu(mb);
1219             if (mb != qt_mac_current_menubar.qmenubar || modal != qt_mac_current_menubar.modal)
1220                 qt_mac_set_modal_state(menu, modal);
1221         }
1222         qt_mac_current_menubar.qmenubar = mb;
1223         qt_mac_current_menubar.modal = modal;
1224         ret = true;
1225     } else if (qt_mac_current_menubar.qmenubar && qt_mac_current_menubar.qmenubar->isNativeMenuBar()) {
1226         // INVARIANT: The currently active menu bar (if any) is not native. But we do have a
1227         // native menu bar from before. So we need to decide whether or not is should be enabled:
1228         const bool modal = qt_mac_should_disable_menu(qt_mac_current_menubar.qmenubar);
1229         if (modal != qt_mac_current_menubar.modal) {
1230             ret = true;
1231             if (OSMenuRef menu = reinterpret_cast<QCocoaMenuBar *>(qt_mac_current_menubar.qmenubar->platformMenuBar())->macMenu()) {
1232                 QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
1233                 [loader ensureAppMenuInMenu:menu];
1234                 [NSApp setMainMenu:menu];
1235                 syncMenuBarItemsVisiblity(reinterpret_cast<QCocoaMenuBar *>(qt_mac_current_menubar.qmenubar->platformMenuBar()));
1236                 qt_mac_set_modal_state(menu, modal);
1237             }
1238             qt_mac_current_menubar.modal = modal;
1239         }
1240     }
1241
1242     if (!ret) {
1243         qt_mac_clear_menubar();
1244     }
1245     return ret;
1246 }
1247
1248 QHash<OSMenuRef, OSMenuRef> QCocoaMenu::mergeMenuHash;
1249 QHash<OSMenuRef, QMenuMergeList*> QCocoaMenu::mergeMenuItemsHash;
1250
1251 bool QCocoaMenu::merged(const QAction *action) const
1252 {
1253     if (OSMenuRef merge = mergeMenuHash.value(menu)) {
1254         if (QMenuMergeList *list = mergeMenuItemsHash.value(merge)) {
1255             for(int i = 0; i < list->size(); ++i) {
1256                 const QMenuMergeItem &item = list->at(i);
1257                 if (item.action->action == action)
1258                     return true;
1259             }
1260         }
1261     }
1262     return false;
1263 }
1264
1265 //creation of the OSMenuRef
1266 static OSMenuRef qt_mac_create_menu(QWidget *w)
1267 {
1268     OSMenuRef ret;
1269     if (QMenu *qmenu = qobject_cast<QMenu *>(w)){
1270         ret = [[QT_MANGLE_NAMESPACE(QNativeCocoaMenu) alloc] initWithQMenu:qmenu];
1271     } else {
1272         ret = [[NSMenu alloc] init];
1273     }
1274     return ret;
1275 }
1276
1277 QT_END_NAMESPACE