src/gui/widgets/qmenu_mac.mm
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qmenu.h"
       
    43 #include "qhash.h"
       
    44 #include <qdebug.h>
       
    45 #include "qapplication.h"
       
    46 #include <private/qt_mac_p.h>
       
    47 #include "qregexp.h"
       
    48 #include "qmainwindow.h"
       
    49 #include "qdockwidget.h"
       
    50 #include "qtoolbar.h"
       
    51 #include "qevent.h"
       
    52 #include "qstyle.h"
       
    53 #include "qwidgetaction.h"
       
    54 #include "qmacnativewidget_mac.h"
       
    55 
       
    56 #include <private/qapplication_p.h>
       
    57 #include <private/qcocoaapplication_mac_p.h>
       
    58 #include <private/qmenu_p.h>
       
    59 #include <private/qmenubar_p.h>
       
    60 #include <private/qcocoamenuloader_mac_p.h>
       
    61 #include <private/qcocoamenu_mac_p.h>
       
    62 #include <private/qt_cocoa_helpers_mac_p.h>
       
    63 #include <Cocoa/Cocoa.h>
       
    64 
       
    65 QT_BEGIN_NAMESPACE
       
    66 
       
    67 /*****************************************************************************
       
    68   QMenu debug facilities
       
    69  *****************************************************************************/
       
    70 
       
    71 /*****************************************************************************
       
    72   QMenu globals
       
    73  *****************************************************************************/
       
    74 bool qt_mac_no_menubar_merge = false;
       
    75 bool qt_mac_quit_menu_item_enabled = true;
       
    76 int qt_mac_menus_open_count = 0;
       
    77 
       
    78 static OSMenuRef qt_mac_create_menu(QWidget *w);
       
    79 
       
    80 #ifndef QT_MAC_USE_COCOA
       
    81 static uint qt_mac_menu_static_cmd_id = 'QT00';
       
    82 const UInt32 kMenuCreatorQt = 'cute';
       
    83 enum {
       
    84     kMenuPropertyQAction = 'QAcT',
       
    85     kMenuPropertyQWidget = 'QWId',
       
    86     kMenuPropertyCausedQWidget = 'QCAU',
       
    87     kMenuPropertyMergeMenu = 'QApP',
       
    88     kMenuPropertyMergeList = 'QAmL',
       
    89     kMenuPropertyWidgetActionWidget = 'QWid',
       
    90     kMenuPropertyWidgetMenu = 'QWMe',
       
    91 
       
    92     kHICommandAboutQt = 'AOQT',
       
    93     kHICommandCustomMerge = 'AQt0'
       
    94 };
       
    95 #endif
       
    96 
       
    97 static struct {
       
    98     QPointer<QMenuBar> qmenubar;
       
    99     bool modal;
       
   100 } qt_mac_current_menubar = { 0, false };
       
   101 
       
   102 
       
   103 
       
   104 
       
   105 /*****************************************************************************
       
   106   Externals
       
   107  *****************************************************************************/
       
   108 extern OSViewRef qt_mac_hiview_for(const QWidget *w); //qwidget_mac.cpp
       
   109 extern HIViewRef qt_mac_hiview_for(OSWindowRef w); //qwidget_mac.cpp
       
   110 extern IconRef qt_mac_create_iconref(const QPixmap &px); //qpixmap_mac.cpp
       
   111 extern QWidget * mac_keyboard_grabber; //qwidget_mac.cpp
       
   112 extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); //qapplication_xxx.cpp
       
   113 RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp
       
   114 void qt_mac_dispose_rgn(RgnHandle r); //qregion_mac.cpp
       
   115 
       
   116 /*****************************************************************************
       
   117   QMenu utility functions
       
   118  *****************************************************************************/
       
   119 bool qt_mac_watchingAboutToShow(QMenu *menu)
       
   120 {
       
   121     return menu && menu->receivers(SIGNAL(aboutToShow()));
       
   122 }
       
   123 
       
   124 static int qt_mac_CountMenuItems(OSMenuRef menu)
       
   125 {
       
   126     if (menu) {
       
   127 #ifndef QT_MAC_USE_COCOA
       
   128         int ret = 0;
       
   129         const int items = CountMenuItems(menu);
       
   130         for(int i = 0; i < items; i++) {
       
   131             MenuItemAttributes attr;
       
   132             if (GetMenuItemAttributes(menu, i+1, &attr) == noErr &&
       
   133                attr & kMenuItemAttrHidden)
       
   134                 continue;
       
   135             ++ret;
       
   136         }
       
   137         return ret;
       
   138 #else
       
   139         return [menu numberOfItems];
       
   140 #endif
       
   141     }
       
   142     return 0;
       
   143 }
       
   144 
       
   145 static quint32 constructModifierMask(quint32 accel_key)
       
   146 {
       
   147     quint32 ret = 0;
       
   148     const bool dontSwap = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
       
   149 #ifndef QT_MAC_USE_COCOA
       
   150     if ((accel_key & Qt::ALT) == Qt::ALT)
       
   151         ret |= kMenuOptionModifier;
       
   152     if ((accel_key & Qt::SHIFT) == Qt::SHIFT)
       
   153         ret |= kMenuShiftModifier;
       
   154     if (dontSwap) {
       
   155         if ((accel_key & Qt::META) != Qt::META)
       
   156             ret |= kMenuNoCommandModifier;
       
   157         if ((accel_key & Qt::CTRL) == Qt::CTRL)
       
   158             ret |= kMenuControlModifier;
       
   159     } else {
       
   160         if ((accel_key & Qt::CTRL) != Qt::CTRL)
       
   161             ret |= kMenuNoCommandModifier;
       
   162         if ((accel_key & Qt::META) == Qt::META)
       
   163             ret |= kMenuControlModifier;
       
   164     }
       
   165 #else
       
   166     if ((accel_key & Qt::CTRL) == Qt::CTRL)
       
   167         ret |= (dontSwap ? NSControlKeyMask : NSCommandKeyMask);
       
   168     if ((accel_key & Qt::META) == Qt::META)
       
   169         ret |= (dontSwap ? NSCommandKeyMask : NSControlKeyMask);
       
   170     if ((accel_key & Qt::ALT) == Qt::ALT)
       
   171         ret |= NSAlternateKeyMask;
       
   172     if ((accel_key & Qt::SHIFT) == Qt::SHIFT)
       
   173         ret |= NSShiftKeyMask;
       
   174 #endif
       
   175     return ret;
       
   176 }
       
   177 
       
   178 static bool actualMenuItemVisibility(const QMenuBarPrivate::QMacMenuBarPrivate *mbp,
       
   179                                      const QMacMenuAction *action)
       
   180 {
       
   181     bool visible = action->action->isVisible();
       
   182     if (visible && action->action->text() == QString(QChar(0x14)))
       
   183         return false;
       
   184     if (visible && action->action->menu() && !action->action->menu()->actions().isEmpty() &&
       
   185         !qt_mac_CountMenuItems(action->action->menu()->macMenu(mbp->apple_menu)) &&
       
   186         !qt_mac_watchingAboutToShow(action->action->menu())) {
       
   187         return false;
       
   188     }
       
   189     return visible;
       
   190 }
       
   191 
       
   192 #ifndef QT_MAC_USE_COCOA
       
   193 bool qt_mac_activate_action(MenuRef menu, uint command, QAction::ActionEvent action_e, bool by_accel)
       
   194 {
       
   195     //fire event
       
   196     QMacMenuAction *action = 0;
       
   197     if (GetMenuCommandProperty(menu, command, kMenuCreatorQt, kMenuPropertyQAction, sizeof(action), 0, &action) != noErr) {
       
   198         QMenuMergeList *list = 0;
       
   199         GetMenuItemProperty(menu, 0, kMenuCreatorQt, kMenuPropertyMergeList,
       
   200                             sizeof(list), 0, &list);
       
   201         if (!list && qt_mac_current_menubar.qmenubar && qt_mac_current_menubar.qmenubar->isNativeMenuBar()) {
       
   202             MenuRef apple_menu = qt_mac_current_menubar.qmenubar->d_func()->mac_menubar->apple_menu;
       
   203             GetMenuItemProperty(apple_menu, 0, kMenuCreatorQt, kMenuPropertyMergeList, sizeof(list), 0, &list);
       
   204             if (list)
       
   205                 menu = apple_menu;
       
   206         }
       
   207         if (list) {
       
   208             for(int i = 0; i < list->size(); ++i) {
       
   209                 QMenuMergeItem item = list->at(i);
       
   210                 if (item.command == command && item.action) {
       
   211                     action = item.action;
       
   212                     break;
       
   213                 }
       
   214             }
       
   215         }
       
   216         if (!action)
       
   217             return false;
       
   218     }
       
   219 
       
   220     if (action_e == QAction::Trigger && by_accel && action->ignore_accel) //no, not a real accel (ie tab)
       
   221         return false;
       
   222 
       
   223     // Unhighlight the highlighted menu item before triggering the action to
       
   224     // prevent items from staying highlighted while a modal dialog is shown.
       
   225     // This also fixed the problem that parentless modal dialogs leave
       
   226     // the menu item highlighted (since the menu bar is cleared for these types of dialogs).
       
   227     if (action_e == QAction::Trigger)
       
   228         HiliteMenu(0);
       
   229 
       
   230     action->action->activate(action_e);
       
   231 
       
   232     //now walk up firing for each "caused" widget (like in the platform independent menu)
       
   233     QWidget *caused = 0;
       
   234     if (GetMenuItemProperty(menu, 0, kMenuCreatorQt, kMenuPropertyCausedQWidget, sizeof(caused), 0, &caused) == noErr) {
       
   235         MenuRef caused_menu = 0;
       
   236         if (QMenu *qmenu2 = qobject_cast<QMenu*>(caused))
       
   237             caused_menu = qmenu2->macMenu();
       
   238         else if (QMenuBar *qmenubar2 = qobject_cast<QMenuBar*>(caused))
       
   239             caused_menu = qmenubar2->macMenu();
       
   240         else
       
   241             caused_menu = 0;
       
   242         while(caused_menu) {
       
   243             //fire
       
   244             QWidget *widget = 0;
       
   245             GetMenuItemProperty(caused_menu, 0, kMenuCreatorQt, kMenuPropertyQWidget, sizeof(widget), 0, &widget);
       
   246             if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) {
       
   247                 if (action_e == QAction::Trigger) {
       
   248                     emit qmenu->triggered(action->action);
       
   249                 } else if (action_e == QAction::Hover) {
       
   250                     action->action->showStatusText(widget);
       
   251                     emit qmenu->hovered(action->action);
       
   252                 }
       
   253             } else if (QMenuBar *qmenubar = qobject_cast<QMenuBar*>(widget)) {
       
   254                 if (action_e == QAction::Trigger) {
       
   255                     emit qmenubar->triggered(action->action);
       
   256                 } else if (action_e == QAction::Hover) {
       
   257                     action->action->showStatusText(widget);
       
   258                     emit qmenubar->hovered(action->action);
       
   259                 }
       
   260                 break; //nothing more..
       
   261             }
       
   262 
       
   263             //walk up
       
   264             if (GetMenuItemProperty(caused_menu, 0, kMenuCreatorQt, kMenuPropertyCausedQWidget,
       
   265                                    sizeof(caused), 0, &caused) != noErr)
       
   266                 break;
       
   267             if (QMenu *qmenu2 = qobject_cast<QMenu*>(caused))
       
   268                 caused_menu = qmenu2->macMenu();
       
   269             else if (QMenuBar *qmenubar2 = qobject_cast<QMenuBar*>(caused))
       
   270                 caused_menu = qmenubar2->macMenu();
       
   271             else
       
   272                 caused_menu = 0;
       
   273         }
       
   274     }
       
   275     return true;
       
   276 }
       
   277 
       
   278 //lookup a QMacMenuAction in a menu
       
   279 static int qt_mac_menu_find_action(MenuRef menu, MenuCommand cmd)
       
   280 {
       
   281     MenuItemIndex ret_idx;
       
   282     MenuRef ret_menu;
       
   283     if (GetIndMenuItemWithCommandID(menu, cmd, 1, &ret_menu, &ret_idx) == noErr) {
       
   284         if (ret_menu == menu)
       
   285             return (int)ret_idx;
       
   286     }
       
   287     return -1;
       
   288 }
       
   289 static int qt_mac_menu_find_action(MenuRef menu, QMacMenuAction *action)
       
   290 {
       
   291     return qt_mac_menu_find_action(menu, action->command);
       
   292 }
       
   293 
       
   294 typedef QMultiHash<OSMenuRef, EventHandlerRef> EventHandlerHash;
       
   295 Q_GLOBAL_STATIC(EventHandlerHash, menu_eventHandlers_hash)
       
   296 
       
   297 static EventTypeSpec widget_in_menu_events[] = {
       
   298     { kEventClassMenu, kEventMenuMeasureItemWidth },
       
   299     { kEventClassMenu, kEventMenuMeasureItemHeight },
       
   300     { kEventClassMenu, kEventMenuDrawItem },
       
   301     { kEventClassMenu, kEventMenuCalculateSize }
       
   302 };
       
   303 
       
   304 static OSStatus qt_mac_widget_in_menu_eventHandler(EventHandlerCallRef er, EventRef event, void *)
       
   305 {
       
   306     UInt32 ekind = GetEventKind(event);
       
   307     UInt32 eclass = GetEventClass(event);
       
   308     OSStatus result = eventNotHandledErr;
       
   309     switch (eclass) {
       
   310     case kEventClassMenu:
       
   311         switch (ekind) {
       
   312         default:
       
   313             break;
       
   314         case kEventMenuMeasureItemWidth: {
       
   315             MenuItemIndex item;
       
   316             GetEventParameter(event, kEventParamMenuItemIndex, typeMenuItemIndex,
       
   317                               0, sizeof(item), 0, &item);
       
   318             OSMenuRef menu;
       
   319             GetEventParameter(event, kEventParamDirectObject, typeMenuRef, 0, sizeof(menu), 0, &menu);
       
   320             QWidget *widget;
       
   321             if (GetMenuItemProperty(menu, item, kMenuCreatorQt, kMenuPropertyWidgetActionWidget,
       
   322                                  sizeof(widget), 0, &widget) == noErr) {
       
   323                 short width = short(widget->sizeHint().width());
       
   324                 SetEventParameter(event, kEventParamMenuItemWidth, typeSInt16,
       
   325                                   sizeof(short), &width);
       
   326                 result = noErr;
       
   327             }
       
   328             break; }
       
   329         case kEventMenuMeasureItemHeight: {
       
   330             MenuItemIndex item;
       
   331             GetEventParameter(event, kEventParamMenuItemIndex, typeMenuItemIndex,
       
   332                               0, sizeof(item), 0, &item);
       
   333             OSMenuRef menu;
       
   334             GetEventParameter(event, kEventParamDirectObject, typeMenuRef, 0, sizeof(menu), 0, &menu);
       
   335             QWidget *widget;
       
   336             if (GetMenuItemProperty(menu, item, kMenuCreatorQt, kMenuPropertyWidgetActionWidget,
       
   337                                      sizeof(widget), 0, &widget) == noErr && widget) {
       
   338                 short height = short(widget->sizeHint().height());
       
   339                 SetEventParameter(event, kEventParamMenuItemHeight, typeSInt16,
       
   340                                   sizeof(short), &height);
       
   341                 result = noErr;
       
   342             }
       
   343             break; }
       
   344         case kEventMenuDrawItem:
       
   345             result = noErr;
       
   346             break;
       
   347         case kEventMenuCalculateSize: {
       
   348             result = CallNextEventHandler(er, event);
       
   349             if (result == noErr) {
       
   350                 OSMenuRef menu;
       
   351                 GetEventParameter(event, kEventParamDirectObject, typeMenuRef, 0, sizeof(menu), 0, &menu);
       
   352                 HIViewRef content;
       
   353                 HIMenuGetContentView(menu, kThemeMenuTypePullDown, &content);
       
   354                 UInt16 count = CountMenuItems(menu);
       
   355                 for (MenuItemIndex i = 1; i <= count; ++i) {
       
   356                     QWidget *widget;
       
   357                     if (GetMenuItemProperty(menu, i, kMenuCreatorQt, kMenuPropertyWidgetActionWidget,
       
   358                             sizeof(widget), 0, &widget) == noErr && widget) {
       
   359                         RgnHandle itemRgn = qt_mac_get_rgn();
       
   360                         GetControlRegion(content, i, itemRgn);
       
   361 
       
   362                         Rect bounds;
       
   363                         GetRegionBounds( itemRgn, &bounds );
       
   364                         qt_mac_dispose_rgn(itemRgn);
       
   365                         widget->setGeometry(bounds.left, bounds.top,
       
   366                                             bounds.right - bounds.left, bounds.bottom - bounds.top);
       
   367                     }
       
   368                 }
       
   369             }
       
   370             break; }
       
   371         }
       
   372     }
       
   373     return result;
       
   374 }
       
   375 
       
   376 //handling of events for menurefs created by Qt..
       
   377 static EventTypeSpec menu_events[] = {
       
   378     { kEventClassCommand, kEventCommandProcess },
       
   379     { kEventClassMenu, kEventMenuTargetItem },
       
   380     { kEventClassMenu, kEventMenuOpening },
       
   381     { kEventClassMenu, kEventMenuClosed }
       
   382 };
       
   383 
       
   384 // Special case for kEventMenuMatchKey, see qt_mac_create_menu below.
       
   385 static EventTypeSpec menu_menu_events[] = {
       
   386     { kEventClassMenu, kEventMenuMatchKey }
       
   387 };
       
   388 
       
   389 OSStatus qt_mac_menu_event(EventHandlerCallRef er, EventRef event, void *)
       
   390 {
       
   391     QScopedLoopLevelCounter loopLevelCounter(QApplicationPrivate::instance()->threadData);
       
   392 
       
   393     bool handled_event = true;
       
   394     UInt32 ekind = GetEventKind(event), eclass = GetEventClass(event);
       
   395     switch(eclass) {
       
   396     case kEventClassCommand:
       
   397         if (ekind == kEventCommandProcess) {
       
   398             UInt32 context;
       
   399             GetEventParameter(event, kEventParamMenuContext, typeUInt32,
       
   400                               0, sizeof(context), 0, &context);
       
   401             HICommand cmd;
       
   402             GetEventParameter(event, kEventParamDirectObject, typeHICommand,
       
   403                               0, sizeof(cmd), 0, &cmd);
       
   404             if (!mac_keyboard_grabber && (context & kMenuContextKeyMatching)) {
       
   405                 QMacMenuAction *action = 0;
       
   406                 if (GetMenuCommandProperty(cmd.menu.menuRef, cmd.commandID, kMenuCreatorQt,
       
   407                                           kMenuPropertyQAction, sizeof(action), 0, &action) == noErr) {
       
   408                     QWidget *widget = 0;
       
   409                     if (qApp->activePopupWidget())
       
   410                         widget = (qApp->activePopupWidget()->focusWidget() ?
       
   411                                   qApp->activePopupWidget()->focusWidget() : qApp->activePopupWidget());
       
   412                     else if (QApplicationPrivate::focus_widget)
       
   413                         widget = QApplicationPrivate::focus_widget;
       
   414                     if (widget) {
       
   415                         int key = action->action->shortcut();
       
   416                         QKeyEvent accel_ev(QEvent::ShortcutOverride, (key & (~Qt::KeyboardModifierMask)),
       
   417                                            Qt::KeyboardModifiers(key & Qt::KeyboardModifierMask));
       
   418                         accel_ev.ignore();
       
   419                         qt_sendSpontaneousEvent(widget, &accel_ev);
       
   420                         if (accel_ev.isAccepted()) {
       
   421                             handled_event = false;
       
   422                             break;
       
   423                         }
       
   424                     }
       
   425                 }
       
   426             }
       
   427             handled_event = qt_mac_activate_action(cmd.menu.menuRef, cmd.commandID,
       
   428                                                    QAction::Trigger, context & kMenuContextKeyMatching);
       
   429         }
       
   430         break;
       
   431     case kEventClassMenu: {
       
   432         MenuRef menu;
       
   433         GetEventParameter(event, kEventParamDirectObject, typeMenuRef, NULL, sizeof(menu), NULL, &menu);
       
   434         if (ekind == kEventMenuMatchKey) {
       
   435             // Don't activate any actions if we are showing a native modal dialog,
       
   436             // the key events should go to the dialog in this case.
       
   437             if (QApplicationPrivate::native_modal_dialog_active)
       
   438                 return menuItemNotFoundErr;
       
   439 
       
   440              handled_event = false;
       
   441         } else if (ekind == kEventMenuTargetItem) {
       
   442             MenuCommand command;
       
   443             GetEventParameter(event, kEventParamMenuCommand, typeMenuCommand,
       
   444                               0, sizeof(command), 0, &command);
       
   445             handled_event = qt_mac_activate_action(menu, command, QAction::Hover, false);
       
   446         } else if (ekind == kEventMenuOpening || ekind == kEventMenuClosed) {
       
   447             qt_mac_menus_open_count += (ekind == kEventMenuOpening) ? 1 : -1;
       
   448             MenuRef mr;
       
   449             GetEventParameter(event, kEventParamDirectObject, typeMenuRef,
       
   450                               0, sizeof(mr), 0, &mr);
       
   451 
       
   452             QWidget *widget = 0;
       
   453             if (GetMenuItemProperty(mr, 0, kMenuCreatorQt, kMenuPropertyQWidget, sizeof(widget), 0, &widget) == noErr) {
       
   454                 if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) {
       
   455                     handled_event = true;
       
   456                     if (ekind == kEventMenuOpening) {
       
   457                         emit qmenu->aboutToShow();
       
   458 
       
   459                         int merged = 0;
       
   460                         const QMenuPrivate::QMacMenuPrivate *mac_menu = qmenu->d_func()->mac_menu;
       
   461                         const int ActionItemsCount = mac_menu->actionItems.size();
       
   462                         for(int i = 0; i < ActionItemsCount; ++i) {
       
   463                             QMacMenuAction *action = mac_menu->actionItems.at(i);
       
   464                             if (action->action->isSeparator()) {
       
   465                                 bool hide = false;
       
   466                                 if(!action->action->isVisible()) {
       
   467                                     hide = true;
       
   468                                 } else if (merged && merged == i) {
       
   469                                     hide = true;
       
   470                                 } else {
       
   471                                     for(int l = i+1; l < mac_menu->actionItems.size(); ++l) {
       
   472                                         QMacMenuAction *action = mac_menu->actionItems.at(l);
       
   473                                         if (action->merged) {
       
   474                                             hide = true;
       
   475                                         } else if (action->action->isSeparator()) {
       
   476                                             if (hide)
       
   477                                                 break;
       
   478                                         } else if (!action->merged) {
       
   479                                             hide = false;
       
   480                                             break;
       
   481                                         }
       
   482                                     }
       
   483                                 }
       
   484 
       
   485                                 const int index = qt_mac_menu_find_action(mr, action);
       
   486                                 if (hide) {
       
   487                                     ++merged;
       
   488                                     ChangeMenuItemAttributes(mr, index, kMenuItemAttrHidden, 0);
       
   489                                 } else {
       
   490                                     ChangeMenuItemAttributes(mr, index, 0, kMenuItemAttrHidden);
       
   491                                 }
       
   492                             } else if (action->merged) {
       
   493                                 ++merged;
       
   494                             }
       
   495                         }
       
   496                     } else {
       
   497                         emit qmenu->aboutToHide();
       
   498                     }
       
   499                 }
       
   500             }
       
   501         } else {
       
   502             handled_event = false;
       
   503         }
       
   504         break; }
       
   505     default:
       
   506         handled_event = false;
       
   507         break;
       
   508     }
       
   509     if (!handled_event) //let the event go through
       
   510         return CallNextEventHandler(er, event);
       
   511     return noErr; //we eat the event
       
   512 }
       
   513 static EventHandlerRef mac_menu_event_handler = 0;
       
   514 static EventHandlerUPP mac_menu_eventUPP = 0;
       
   515 static void qt_mac_cleanup_menu_event()
       
   516 {
       
   517     if (mac_menu_event_handler) {
       
   518         RemoveEventHandler(mac_menu_event_handler);
       
   519         mac_menu_event_handler = 0;
       
   520     }
       
   521     if (mac_menu_eventUPP) {
       
   522         DisposeEventHandlerUPP(mac_menu_eventUPP);
       
   523         mac_menu_eventUPP = 0;
       
   524     }
       
   525 }
       
   526 static inline void qt_mac_create_menu_event_handler()
       
   527 {
       
   528     if (!mac_menu_event_handler) {
       
   529         mac_menu_eventUPP = NewEventHandlerUPP(qt_mac_menu_event);
       
   530         InstallEventHandler(GetApplicationEventTarget(), mac_menu_eventUPP,
       
   531                             GetEventTypeCount(menu_events), menu_events, 0,
       
   532                             &mac_menu_event_handler);
       
   533         qAddPostRoutine(qt_mac_cleanup_menu_event);
       
   534     }
       
   535 }
       
   536 
       
   537 
       
   538 //enabling of commands
       
   539 static void qt_mac_command_set_enabled(MenuRef menu, UInt32 cmd, bool b)
       
   540 {
       
   541     if (cmd == kHICommandQuit)
       
   542         qt_mac_quit_menu_item_enabled = b;
       
   543 
       
   544     if (b) {
       
   545         EnableMenuCommand(menu, cmd);
       
   546         if (MenuRef dock_menu = GetApplicationDockTileMenu())
       
   547             EnableMenuCommand(dock_menu, cmd);
       
   548     } else {
       
   549         DisableMenuCommand(menu, cmd);
       
   550         if (MenuRef dock_menu = GetApplicationDockTileMenu())
       
   551             DisableMenuCommand(dock_menu, cmd);
       
   552     }
       
   553 }
       
   554 
       
   555 static bool qt_mac_auto_apple_menu(MenuCommand cmd)
       
   556 {
       
   557     return (cmd == kHICommandPreferences || cmd == kHICommandQuit);
       
   558 }
       
   559 
       
   560 static void qt_mac_get_accel(quint32 accel_key, quint32 *modif, quint32 *key) {
       
   561     if (modif) {
       
   562         *modif = constructModifierMask(accel_key);
       
   563     }
       
   564 
       
   565     accel_key &= ~(Qt::MODIFIER_MASK | Qt::UNICODE_ACCEL);
       
   566     if (key) {
       
   567         *key = 0;
       
   568         if (accel_key == Qt::Key_Return)
       
   569             *key = kMenuReturnGlyph;
       
   570         else if (accel_key == Qt::Key_Enter)
       
   571             *key = kMenuEnterGlyph;
       
   572         else if (accel_key == Qt::Key_Tab)
       
   573             *key = kMenuTabRightGlyph;
       
   574         else if (accel_key == Qt::Key_Backspace)
       
   575             *key = kMenuDeleteLeftGlyph;
       
   576         else if (accel_key == Qt::Key_Delete)
       
   577             *key = kMenuDeleteRightGlyph;
       
   578         else if (accel_key == Qt::Key_Escape)
       
   579             *key = kMenuEscapeGlyph;
       
   580         else if (accel_key == Qt::Key_PageUp)
       
   581             *key = kMenuPageUpGlyph;
       
   582         else if (accel_key == Qt::Key_PageDown)
       
   583             *key = kMenuPageDownGlyph;
       
   584         else if (accel_key == Qt::Key_Up)
       
   585             *key = kMenuUpArrowGlyph;
       
   586         else if (accel_key == Qt::Key_Down)
       
   587             *key = kMenuDownArrowGlyph;
       
   588         else if (accel_key == Qt::Key_Left)
       
   589             *key = kMenuLeftArrowGlyph;
       
   590         else if (accel_key == Qt::Key_Right)
       
   591             *key = kMenuRightArrowGlyph;
       
   592         else if (accel_key == Qt::Key_CapsLock)
       
   593             *key = kMenuCapsLockGlyph;
       
   594         else if (accel_key >= Qt::Key_F1 && accel_key <= Qt::Key_F15)
       
   595             *key = (accel_key - Qt::Key_F1) + kMenuF1Glyph;
       
   596         else if (accel_key == Qt::Key_Home)
       
   597             *key = kMenuNorthwestArrowGlyph;
       
   598         else if (accel_key == Qt::Key_End)
       
   599             *key = kMenuSoutheastArrowGlyph;
       
   600     }
       
   601 }
       
   602 #else // Cocoa
       
   603 static inline void syncNSMenuItemVisiblity(NSMenuItem *menuItem, bool actionVisibility)
       
   604 {
       
   605     [menuItem setHidden:NO];
       
   606     [menuItem setHidden:YES];
       
   607     [menuItem setHidden:!actionVisibility];
       
   608 }
       
   609 
       
   610 static inline void syncNSMenuItemEnabled(NSMenuItem *menuItem, bool enabled)
       
   611 {
       
   612     [menuItem setEnabled:NO];
       
   613     [menuItem setEnabled:YES];
       
   614     [menuItem setEnabled:enabled];
       
   615 }
       
   616 
       
   617 static inline void syncMenuBarItemsVisiblity(const QMenuBarPrivate::QMacMenuBarPrivate *mac_menubar)
       
   618 {
       
   619     const QList<QMacMenuAction *> &menubarActions = mac_menubar->actionItems;
       
   620     for (int i = 0; i < menubarActions.size(); ++i) {
       
   621         const QMacMenuAction *action = menubarActions.at(i);
       
   622         syncNSMenuItemVisiblity(action->menuItem, actualMenuItemVisibility(mac_menubar, action));
       
   623     }
       
   624 }
       
   625 
       
   626 static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader()
       
   627 {
       
   628     return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)];
       
   629 }
       
   630 
       
   631 static NSMenuItem *createNSMenuItem(const QString &title)
       
   632 {
       
   633     NSMenuItem *item = [[NSMenuItem alloc] 
       
   634                          initWithTitle:qt_mac_QStringToNSString(title)
       
   635                          action:@selector(qtDispatcherToQAction:) keyEquivalent:@""];
       
   636     [item setTarget:getMenuLoader()];
       
   637     return item;
       
   638 }
       
   639 #endif
       
   640 
       
   641 
       
   642 
       
   643 // helper that recurses into a menu structure and en/dis-ables them
       
   644 void qt_mac_set_modal_state_helper_recursive(OSMenuRef menu, OSMenuRef merge, bool on)
       
   645 {
       
   646 #ifndef QT_MAC_USE_COCOA
       
   647     for (int i = 0; i < CountMenuItems(menu); i++) {
       
   648         OSMenuRef submenu;
       
   649         GetMenuItemHierarchicalMenu(menu, i+1, &submenu);
       
   650         if (submenu != merge) {
       
   651             if (submenu)
       
   652                 qt_mac_set_modal_state_helper_recursive(submenu, merge, on);
       
   653             if (on)
       
   654                 DisableMenuItem(submenu, 0);
       
   655             else
       
   656                 EnableMenuItem(submenu, 0);
       
   657         }
       
   658     }
       
   659 #else
       
   660     for (NSMenuItem *item in [menu itemArray]) {
       
   661         OSMenuRef submenu = [item submenu];
       
   662         if (submenu != merge) {
       
   663             if (submenu)
       
   664                 qt_mac_set_modal_state_helper_recursive(submenu, merge, on);
       
   665             if (!on) {
       
   666                 // The item should follow what the QAction has.
       
   667                 if ([item tag]) {
       
   668                     QAction *action = reinterpret_cast<QAction *>([item tag]);
       
   669                      syncNSMenuItemEnabled(item, action->isEnabled());
       
   670                  } else {
       
   671                      syncNSMenuItemEnabled(item, YES);
       
   672                  }
       
   673             } else {
       
   674                 syncNSMenuItemEnabled(item, NO);
       
   675             }
       
   676         }
       
   677     }
       
   678 #endif
       
   679 }
       
   680 
       
   681 //toggling of modal state
       
   682 static void qt_mac_set_modal_state(OSMenuRef menu, bool on)
       
   683 {
       
   684 #ifndef QT_MAC_USE_COCOA
       
   685     OSMenuRef merge = 0;
       
   686     GetMenuItemProperty(menu, 0, kMenuCreatorQt, kMenuPropertyMergeMenu,
       
   687             sizeof(merge), 0, &merge);
       
   688 
       
   689     qt_mac_set_modal_state_helper_recursive(menu, merge, on);
       
   690 
       
   691     UInt32 commands[] = { kHICommandQuit, kHICommandPreferences, kHICommandAbout, kHICommandAboutQt, 0 };
       
   692     for(int c = 0; commands[c]; c++) {
       
   693         bool enabled = !on;
       
   694         if (enabled) {
       
   695             QMacMenuAction *action = 0;
       
   696             GetMenuCommandProperty(menu, commands[c], kMenuCreatorQt, kMenuPropertyQAction,
       
   697                     sizeof(action), 0, &action);
       
   698             if (!action && merge) {
       
   699                 GetMenuCommandProperty(merge, commands[c], kMenuCreatorQt, kMenuPropertyQAction,
       
   700                         sizeof(action), 0, &action);
       
   701                 if (!action) {
       
   702                     QMenuMergeList *list = 0;
       
   703                     GetMenuItemProperty(merge, 0, kMenuCreatorQt, kMenuPropertyMergeList,
       
   704                             sizeof(list), 0, &list);
       
   705                     for(int i = 0; list && i < list->size(); ++i) {
       
   706                         QMenuMergeItem item = list->at(i);
       
   707                         if (item.command == commands[c] && item.action) {
       
   708                             action = item.action;
       
   709                             break;
       
   710                         }
       
   711                     }
       
   712                 }
       
   713             }
       
   714 
       
   715             if (!action) {
       
   716                 if (commands[c] != kHICommandQuit)
       
   717                     enabled = false;
       
   718             } else {
       
   719                 enabled = action->action ? action->action->isEnabled() : 0;
       
   720             }
       
   721         }
       
   722         qt_mac_command_set_enabled(menu, commands[c], enabled);
       
   723     }
       
   724 #else
       
   725     OSMenuRef merge = QMenuPrivate::mergeMenuHash.value(menu);
       
   726     qt_mac_set_modal_state_helper_recursive(menu, merge, on);
       
   727     // I'm ignoring the special items now, since they should get handled via a syncAction()
       
   728 #endif
       
   729 }
       
   730 
       
   731 bool qt_mac_menubar_is_open()
       
   732 {
       
   733     return qt_mac_menus_open_count > 0;
       
   734 }
       
   735 
       
   736 void qt_mac_clear_menubar()
       
   737 {
       
   738     if (QApplication::testAttribute(Qt::AA_MacPluginApplication))
       
   739         return;
       
   740 
       
   741 #ifndef QT_MAC_USE_COCOA
       
   742     MenuRef clear_menu = 0;
       
   743     if (CreateNewMenu(0, 0, &clear_menu) == noErr) {
       
   744         SetRootMenu(clear_menu);
       
   745         ReleaseMenu(clear_menu);
       
   746     } else {
       
   747         qWarning("QMenu: Internal error at %s:%d", __FILE__, __LINE__);
       
   748     }
       
   749     ClearMenuBar();
       
   750     qt_mac_command_set_enabled(0, kHICommandPreferences, false);
       
   751     InvalMenuBar();
       
   752 #else
       
   753     QMacCocoaAutoReleasePool pool;
       
   754     QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
       
   755     NSMenu *menu = [loader menu];
       
   756     [loader ensureAppMenuInMenu:menu];
       
   757     [NSApp setMainMenu:menu];
       
   758 #endif
       
   759 }
       
   760 
       
   761 
       
   762 QMacMenuAction::~QMacMenuAction()
       
   763 {
       
   764 #ifdef QT_MAC_USE_COCOA
       
   765     [menu release];
       
   766     if (action) {
       
   767         QAction::MenuRole role = action->menuRole();
       
   768         // Check if the item is owned by Qt, and should be hidden to keep it from causing
       
   769         // problems. Do it for everything but the quit menu item since that should always
       
   770         // be visible.
       
   771         if (role > QAction::ApplicationSpecificRole && role < QAction::QuitRole) {
       
   772             [menuItem setHidden:YES];
       
   773         } else if (role == QAction::TextHeuristicRole
       
   774                    && menuItem != [getMenuLoader() quitMenuItem]) {
       
   775             [menuItem setHidden:YES];
       
   776         }
       
   777     }
       
   778     [menuItem setTag:nil];
       
   779     [menuItem release];
       
   780 #endif
       
   781 }
       
   782 
       
   783 #ifndef QT_MAC_USE_COCOA
       
   784 static MenuCommand qt_mac_menu_merge_action(MenuRef merge, QMacMenuAction *action)
       
   785 #else
       
   786 static NSMenuItem *qt_mac_menu_merge_action(OSMenuRef merge, QMacMenuAction *action)
       
   787 #endif
       
   788 {
       
   789     if (qt_mac_no_menubar_merge || action->action->menu() || action->action->isSeparator()
       
   790             || action->action->menuRole() == QAction::NoRole)
       
   791         return 0;
       
   792 
       
   793     QString t = qt_mac_removeMnemonics(action->action->text().toLower());
       
   794     int st = t.lastIndexOf(QLatin1Char('\t'));
       
   795     if (st != -1)
       
   796         t.remove(st, t.length()-st);
       
   797     t.replace(QRegExp(QString::fromLatin1("\\.*$")), QLatin1String("")); //no ellipses
       
   798     //now the fun part
       
   799 #ifndef QT_MAC_USE_COCOA
       
   800     MenuCommand ret = 0;
       
   801 #else
       
   802     NSMenuItem *ret = 0;
       
   803     QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
       
   804 #endif
       
   805     switch (action->action->menuRole()) {
       
   806     case QAction::NoRole:
       
   807         ret = 0;
       
   808         break;
       
   809     case QAction::ApplicationSpecificRole:
       
   810 #ifndef QT_MAC_USE_COCOA
       
   811         {
       
   812             QMenuMergeList *list = 0;
       
   813             if (GetMenuItemProperty(merge, 0, kMenuCreatorQt, kMenuPropertyMergeList,
       
   814                         sizeof(list), 0, &list) == noErr && list) {
       
   815                 MenuCommand lastCustom = kHICommandCustomMerge;
       
   816                 for(int i = 0; i < list->size(); ++i) {
       
   817                     QMenuMergeItem item = list->at(i);
       
   818                     if (item.command == lastCustom)
       
   819                         ++lastCustom;
       
   820                 }
       
   821                 ret = lastCustom;
       
   822             } else {
       
   823                 // The list hasn't been created, so, must be the first one.
       
   824                 ret = kHICommandCustomMerge;
       
   825             }
       
   826         }
       
   827 #else
       
   828         ret = [loader appSpecificMenuItem];
       
   829 #endif
       
   830         break;
       
   831     case QAction::AboutRole:
       
   832 #ifndef QT_MAC_USE_COCOA
       
   833         ret = kHICommandAbout;
       
   834 #else
       
   835         ret = [loader aboutMenuItem];
       
   836 #endif
       
   837         break;
       
   838     case QAction::AboutQtRole:
       
   839 #ifndef QT_MAC_USE_COCOA
       
   840         ret = kHICommandAboutQt;
       
   841 #else
       
   842         ret = [loader aboutQtMenuItem];
       
   843 #endif
       
   844         break;
       
   845     case QAction::QuitRole:
       
   846 #ifndef QT_MAC_USE_COCOA
       
   847         ret = kHICommandQuit;
       
   848 #else
       
   849         ret = [loader quitMenuItem];
       
   850 #endif
       
   851         break;
       
   852     case QAction::PreferencesRole:
       
   853 #ifndef QT_MAC_USE_COCOA
       
   854         ret = kHICommandPreferences;
       
   855 #else
       
   856         ret = [loader preferencesMenuItem];
       
   857 #endif
       
   858         break;
       
   859     case QAction::TextHeuristicRole: {
       
   860         QString aboutString = QMenuBar::tr("About").toLower();
       
   861         if (t.startsWith(aboutString) || t.endsWith(aboutString)) {
       
   862             if (t.indexOf(QRegExp(QString::fromLatin1("qt$"), Qt::CaseInsensitive)) == -1) {
       
   863 #ifndef QT_MAC_USE_COCOA
       
   864                 ret = kHICommandAbout;
       
   865 #else
       
   866                 ret = [loader aboutMenuItem];
       
   867 #endif
       
   868             } else {
       
   869 #ifndef QT_MAC_USE_COCOA
       
   870                 ret = kHICommandAboutQt;
       
   871 #else
       
   872                 ret = [loader aboutQtMenuItem];
       
   873 #endif
       
   874             }
       
   875         } else if (t.startsWith(QMenuBar::tr("Config").toLower())
       
   876                    || t.startsWith(QMenuBar::tr("Preference").toLower())
       
   877                    || t.startsWith(QMenuBar::tr("Options").toLower())
       
   878                    || t.startsWith(QMenuBar::tr("Setting").toLower())
       
   879                    || t.startsWith(QMenuBar::tr("Setup").toLower())) {
       
   880 #ifndef QT_MAC_USE_COCOA
       
   881             ret = kHICommandPreferences;
       
   882 #else
       
   883             ret = [loader preferencesMenuItem];
       
   884 #endif
       
   885         } else if (t.startsWith(QMenuBar::tr("Quit").toLower())
       
   886                    || t.startsWith(QMenuBar::tr("Exit").toLower())) {
       
   887 #ifndef QT_MAC_USE_COCOA
       
   888             ret = kHICommandQuit;
       
   889 #else
       
   890             ret = [loader quitMenuItem];
       
   891 #endif
       
   892         }
       
   893     }
       
   894         break;
       
   895     }
       
   896 
       
   897 #ifndef QT_MAC_USE_COCOA
       
   898     QMenuMergeList *list = 0;
       
   899     if (GetMenuItemProperty(merge, 0, kMenuCreatorQt, kMenuPropertyMergeList,
       
   900                            sizeof(list), 0, &list) == noErr && list) {
       
   901         for(int i = 0; i < list->size(); ++i) {
       
   902             QMenuMergeItem item = list->at(i);
       
   903             if (item.command == ret && item.action)
       
   904                 return 0;
       
   905         }
       
   906     }
       
   907 
       
   908     QAction *cmd_action = 0;
       
   909     if (GetMenuCommandProperty(merge, ret, kMenuCreatorQt, kMenuPropertyQAction,
       
   910                               sizeof(cmd_action), 0, &cmd_action) == noErr && cmd_action)
       
   911         return 0; //already taken
       
   912 #else
       
   913     if (QMenuMergeList *list = QMenuPrivate::mergeMenuItemsHash.value(merge)) {
       
   914         for(int i = 0; i < list->size(); ++i) {
       
   915             const QMenuMergeItem &item = list->at(i);
       
   916             if (item.menuItem == ret && item.action)
       
   917                 return 0;
       
   918         }
       
   919     }
       
   920 
       
   921 #endif
       
   922     return ret;
       
   923 }
       
   924 
       
   925 static QString qt_mac_menu_merge_text(QMacMenuAction *action)
       
   926 {
       
   927     QString ret;
       
   928 #ifdef QT_MAC_USE_COCOA
       
   929     QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
       
   930 #endif
       
   931     if (action->action->menuRole() == QAction::ApplicationSpecificRole)
       
   932         ret = action->action->text();
       
   933 #ifndef QT_MAC_USE_COCOA
       
   934     else if (action->command == kHICommandAbout)
       
   935         ret = QMenuBar::tr("About %1").arg(qAppName());
       
   936     else if (action->command == kHICommandAboutQt)
       
   937         ret = QMenuBar::tr("About Qt");
       
   938     else if (action->command == kHICommandPreferences)
       
   939         ret = QMenuBar::tr("Preferences");
       
   940     else if (action->command == kHICommandQuit)
       
   941         ret = QMenuBar::tr("Quit %1").arg(qAppName());
       
   942 #else
       
   943     else if (action->menuItem == [loader aboutMenuItem])
       
   944         ret = QMenuBar::tr("About %1").arg(qAppName());
       
   945     else if (action->menuItem == [loader aboutQtMenuItem])
       
   946         ret = QMenuBar::tr("About Qt");
       
   947     else if (action->menuItem == [loader preferencesMenuItem])
       
   948         ret = QMenuBar::tr("Preferences");
       
   949     else if (action->menuItem == [loader quitMenuItem])
       
   950         ret = QMenuBar::tr("Quit %1").arg(qAppName());
       
   951 #endif
       
   952     return ret;
       
   953 }
       
   954 
       
   955 static QKeySequence qt_mac_menu_merge_accel(QMacMenuAction *action)
       
   956 {
       
   957     QKeySequence ret;
       
   958 #ifdef QT_MAC_USE_COCOA
       
   959     QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
       
   960 #endif
       
   961     if (action->action->menuRole() == QAction::ApplicationSpecificRole)
       
   962         ret = action->action->shortcut();
       
   963 #ifndef QT_MAC_USE_COCOA
       
   964     else if (action->command == kHICommandPreferences)
       
   965         ret = QKeySequence(QKeySequence::Preferences);
       
   966     else if (action->command == kHICommandQuit)
       
   967         ret = QKeySequence(QKeySequence::Quit);
       
   968 #else
       
   969     else if (action->menuItem == [loader preferencesMenuItem])
       
   970         ret = QKeySequence(QKeySequence::Preferences);
       
   971     else if (action->menuItem == [loader quitMenuItem])
       
   972         ret = QKeySequence(QKeySequence::Quit);
       
   973 #endif
       
   974     return ret;
       
   975 }
       
   976 
       
   977 void Q_GUI_EXPORT qt_mac_set_menubar_icons(bool b)
       
   978 { QApplication::instance()->setAttribute(Qt::AA_DontShowIconsInMenus, !b); }
       
   979 void Q_GUI_EXPORT qt_mac_set_native_menubar(bool b)
       
   980 {  QApplication::instance()->setAttribute(Qt::AA_DontUseNativeMenuBar, !b); }
       
   981 void Q_GUI_EXPORT qt_mac_set_menubar_merge(bool b) { qt_mac_no_menubar_merge = !b; }
       
   982 
       
   983 /*****************************************************************************
       
   984   QMenu bindings
       
   985  *****************************************************************************/
       
   986 QMenuPrivate::QMacMenuPrivate::QMacMenuPrivate() : menu(0)
       
   987 {
       
   988 }
       
   989 
       
   990 QMenuPrivate::QMacMenuPrivate::~QMacMenuPrivate()
       
   991 {
       
   992 #ifndef QT_MAC_USE_COCOA
       
   993     for(QList<QMacMenuAction*>::Iterator it = actionItems.begin(); it != actionItems.end(); ++it) {
       
   994         QMacMenuAction *action = (*it);
       
   995         RemoveMenuCommandProperty(action->menu, action->command, kMenuCreatorQt, kMenuPropertyQAction);
       
   996         if (action->merged) {
       
   997             QMenuMergeList *list = 0;
       
   998             GetMenuItemProperty(action->menu, 0, kMenuCreatorQt, kMenuPropertyMergeList,
       
   999                                 sizeof(list), 0, &list);
       
  1000             for(int i = 0; list && i < list->size(); ) {
       
  1001                 QMenuMergeItem item = list->at(i);
       
  1002                 if (item.action == action)
       
  1003                     list->removeAt(i);
       
  1004                 else
       
  1005                     ++i;
       
  1006             }
       
  1007         }
       
  1008         delete action;
       
  1009     }
       
  1010     if (menu) {
       
  1011         EventHandlerHash::iterator it = menu_eventHandlers_hash()->find(menu);
       
  1012         while (it != menu_eventHandlers_hash()->end() && it.key() == menu) {
       
  1013             RemoveEventHandler(it.value());
       
  1014             ++it;
       
  1015         }
       
  1016         menu_eventHandlers_hash()->remove(menu);
       
  1017         ReleaseMenu(menu);
       
  1018     }
       
  1019 #else
       
  1020     QMacCocoaAutoReleasePool pool;
       
  1021     while (actionItems.size()) {
       
  1022         QMacMenuAction *action = actionItems.takeFirst();
       
  1023         if (QMenuMergeList *list = mergeMenuItemsHash.value(action->menu)) {
       
  1024             int i = 0;
       
  1025             while (i < list->size()) {
       
  1026                 const QMenuMergeItem &item = list->at(i);
       
  1027                 if (item.action == action)
       
  1028                     list->removeAt(i);
       
  1029                 else
       
  1030                     ++i;
       
  1031             }
       
  1032         }
       
  1033         delete action;
       
  1034     }
       
  1035     mergeMenuHash.remove(menu);
       
  1036     mergeMenuItemsHash.remove(menu);
       
  1037     [menu release];
       
  1038 #endif
       
  1039 }
       
  1040 
       
  1041 void
       
  1042 QMenuPrivate::QMacMenuPrivate::addAction(QAction *a, QMacMenuAction *before, QMenuPrivate *qmenu)
       
  1043 {
       
  1044     QMacMenuAction *action = new QMacMenuAction;
       
  1045     action->action = a;
       
  1046     action->ignore_accel = 0;
       
  1047     action->merged = 0;
       
  1048     action->menu = 0;
       
  1049 #ifndef QT_MAC_USE_COCOA
       
  1050     action->command = qt_mac_menu_static_cmd_id++;
       
  1051 #endif
       
  1052     addAction(action, before, qmenu);
       
  1053 }
       
  1054 
       
  1055 void
       
  1056 QMenuPrivate::QMacMenuPrivate::addAction(QMacMenuAction *action, QMacMenuAction *before, QMenuPrivate *qmenu)
       
  1057 {
       
  1058 #ifdef QT_MAC_USE_COCOA
       
  1059     QMacCocoaAutoReleasePool pool;
       
  1060     Q_UNUSED(qmenu);
       
  1061 #endif
       
  1062     if (!action)
       
  1063         return;
       
  1064     int before_index = actionItems.indexOf(before);
       
  1065     if (before_index < 0) {
       
  1066         before = 0;
       
  1067         before_index = actionItems.size();
       
  1068     }
       
  1069     actionItems.insert(before_index, action);
       
  1070 
       
  1071 #ifndef QT_MAC_USE_COCOA
       
  1072     int index = qt_mac_menu_find_action(menu, action);
       
  1073 #else
       
  1074     [menu retain];
       
  1075     [action->menu release];
       
  1076 #endif
       
  1077     action->menu = menu;
       
  1078 
       
  1079     /* When the action is considered a mergable action it
       
  1080        will stay that way, until removed.. */
       
  1081     if (!qt_mac_no_menubar_merge) {
       
  1082 #ifndef QT_MAC_USE_COCOA
       
  1083         MenuRef merge = 0;
       
  1084         GetMenuItemProperty(menu, 0, kMenuCreatorQt, kMenuPropertyMergeMenu,
       
  1085                             sizeof(merge), 0, &merge);
       
  1086 #else
       
  1087         OSMenuRef merge = QMenuPrivate::mergeMenuHash.value(menu);
       
  1088 #endif
       
  1089         if (merge) {
       
  1090 #ifndef QT_MAC_USE_COCOA
       
  1091             if (MenuCommand cmd = qt_mac_menu_merge_action(merge, action)) {
       
  1092                 action->merged = 1;
       
  1093                 action->menu = merge;
       
  1094                 action->command = cmd;
       
  1095                 if (qt_mac_auto_apple_menu(cmd))
       
  1096                     index = 0; //no need
       
  1097 
       
  1098                 QMenuMergeList *list = 0;
       
  1099                 if (GetMenuItemProperty(merge, 0, kMenuCreatorQt, kMenuPropertyMergeList,
       
  1100                                        sizeof(list), 0, &list) != noErr || !list) {
       
  1101                     list = new QMenuMergeList;
       
  1102                     SetMenuItemProperty(merge, 0, kMenuCreatorQt, kMenuPropertyMergeList,
       
  1103                                         sizeof(list), &list);
       
  1104                 }
       
  1105                 list->append(QMenuMergeItem(cmd, action));
       
  1106             }
       
  1107 #else
       
  1108             if (NSMenuItem *cmd = qt_mac_menu_merge_action(merge, action)) {
       
  1109                 action->merged = 1;
       
  1110                 [merge retain];
       
  1111                 [action->menu release];
       
  1112                 action->menu = merge;
       
  1113                 [cmd retain];
       
  1114                 [cmd setAction:@selector(qtDispatcherToQAction:)];
       
  1115                 [cmd setTarget:getMenuLoader()];
       
  1116                 [action->menuItem release];
       
  1117                 action->menuItem = cmd;
       
  1118                 QMenuMergeList *list = QMenuPrivate::mergeMenuItemsHash.value(merge);
       
  1119                 if (!list) {
       
  1120                     list = new QMenuMergeList;
       
  1121                     QMenuPrivate::mergeMenuItemsHash.insert(merge, list);
       
  1122                 }
       
  1123                 list->append(QMenuMergeItem(cmd, action));
       
  1124             }
       
  1125 #endif
       
  1126         }
       
  1127     }
       
  1128 
       
  1129 #ifdef QT_MAC_USE_COCOA
       
  1130     NSMenuItem *newItem = action->menuItem;
       
  1131 #endif
       
  1132     if (
       
  1133 #ifndef QT_MAC_USE_COCOA
       
  1134         index == -1
       
  1135 #else
       
  1136         newItem == 0
       
  1137 #endif
       
  1138        ) {
       
  1139 #ifndef QT_MAC_USE_COCOA
       
  1140         index = before_index;
       
  1141         MenuItemAttributes attr = kMenuItemAttrAutoRepeat;
       
  1142 #else
       
  1143         newItem = createNSMenuItem(action->action->text());
       
  1144         action->menuItem = newItem;
       
  1145 #endif
       
  1146         if (before) {
       
  1147 #ifndef QT_MAC_USE_COCOA
       
  1148             InsertMenuItemTextWithCFString(action->menu, 0, qMax(before_index, 0), attr, action->command);
       
  1149 #else
       
  1150             [menu insertItem:newItem atIndex:qMax(before_index, 0)];
       
  1151 #endif
       
  1152         } else {
       
  1153 #ifndef QT_MAC_USE_COCOA
       
  1154             // Append the menu item to the menu. If it is a kHICommandAbout or a kHICommandAboutQt append
       
  1155             // a separator also (to get a separator above "Preferences"), but make sure that we don't
       
  1156             // add separators between two "about" items.
       
  1157 
       
  1158             // Build a set of all commands that could possibly be before the separator.
       
  1159             QSet<MenuCommand> mergedItems;
       
  1160             mergedItems.insert(kHICommandAbout);
       
  1161             mergedItems.insert(kHICommandAboutQt);
       
  1162             mergedItems.insert(kHICommandCustomMerge);
       
  1163 
       
  1164             QMenuMergeList *list = 0;
       
  1165             if (GetMenuItemProperty(action->menu, 0, kMenuCreatorQt, kMenuPropertyMergeList,
       
  1166                         sizeof(list), 0, &list) == noErr && list) {
       
  1167                 for (int i = 0; i < list->size(); ++i) {
       
  1168                     MenuCommand command = list->at(i).command;
       
  1169                     if (command > kHICommandCustomMerge) {
       
  1170                         mergedItems.insert(command);
       
  1171                     }
       
  1172                 }
       
  1173             }
       
  1174 
       
  1175             const int itemCount = CountMenuItems(action->menu);
       
  1176             MenuItemAttributes testattr;
       
  1177             GetMenuItemAttributes(action->menu, itemCount , &testattr);
       
  1178             if (mergedItems.contains(action->command)
       
  1179                  && (testattr & kMenuItemAttrSeparator)) {
       
  1180                 InsertMenuItemTextWithCFString(action->menu, 0, qMax(itemCount - 1, 0), attr, action->command);
       
  1181                 index = itemCount;
       
  1182             } else {
       
  1183                 MenuItemIndex tmpIndex;
       
  1184                 AppendMenuItemTextWithCFString(action->menu, 0, attr, action->command, &tmpIndex);
       
  1185                 index = tmpIndex;
       
  1186                 if (mergedItems.contains(action->command))
       
  1187                     AppendMenuItemTextWithCFString(action->menu, 0, kMenuItemAttrSeparator, 0, &tmpIndex);
       
  1188             }
       
  1189 #else
       
  1190             [menu addItem:newItem];
       
  1191 #endif
       
  1192         }
       
  1193 
       
  1194         QWidget *widget = qmenu ? qmenu->widgetItems.value(qmenu->actions.indexOf(action->action)) : 0;
       
  1195         if (widget) {
       
  1196 #ifndef QT_MAC_USE_COCOA
       
  1197             ChangeMenuAttributes(action->menu, kMenuAttrDoNotCacheImage, 0);
       
  1198             attr = kMenuItemAttrCustomDraw;
       
  1199             SetMenuItemProperty(action->menu, index, kMenuCreatorQt, kMenuPropertyWidgetActionWidget,
       
  1200                                 sizeof(QWidget *), &widget);
       
  1201             HIViewRef content;
       
  1202             HIMenuGetContentView(action->menu, kThemeMenuTypePullDown, &content);
       
  1203 
       
  1204             EventHandlerRef eventHandlerRef;
       
  1205             InstallMenuEventHandler(action->menu, qt_mac_widget_in_menu_eventHandler,
       
  1206                                     GetEventTypeCount(widget_in_menu_events),
       
  1207                                     widget_in_menu_events, 0, &eventHandlerRef);
       
  1208             menu_eventHandlers_hash()->insert(action->menu, eventHandlerRef);
       
  1209 
       
  1210             QWidget *menuWidget = 0;
       
  1211             GetMenuItemProperty(action->menu, 0, kMenuCreatorQt, kMenuPropertyWidgetMenu,
       
  1212                                 sizeof(menuWidget), 0, &menuWidget);
       
  1213             if(!menuWidget) {
       
  1214                 menuWidget = new QMacNativeWidget(content);
       
  1215                 SetMenuItemProperty(menu, 0, kMenuCreatorQt, kMenuPropertyWidgetMenu,
       
  1216                                     sizeof(menuWidget), &menuWidget);
       
  1217                 menuWidget->show();
       
  1218             }
       
  1219             widget->setParent(menuWidget);
       
  1220 #else
       
  1221             QMacNativeWidget *container = new QMacNativeWidget(0);
       
  1222             container->resize(widget->sizeHint());
       
  1223             widget->setAttribute(Qt::WA_LayoutUsesWidgetRect);
       
  1224             widget->setParent(container);
       
  1225 
       
  1226             NSView *containerView = qt_mac_nativeview_for(container);
       
  1227             [containerView setAutoresizesSubviews:YES];
       
  1228             [containerView setAutoresizingMask:NSViewWidthSizable];
       
  1229             [qt_mac_nativeview_for(widget) setAutoresizingMask:NSViewWidthSizable];
       
  1230 
       
  1231             [newItem setView:containerView];
       
  1232             container->show();
       
  1233 #endif
       
  1234             widget->show();
       
  1235         }
       
  1236 
       
  1237     } else {
       
  1238 #ifndef QT_MAC_USE_COCOA
       
  1239         qt_mac_command_set_enabled(action->menu, action->command, !QApplicationPrivate::modalState());
       
  1240 #else
       
  1241         [newItem setEnabled:!QApplicationPrivate::modalState()];
       
  1242 #endif
       
  1243     }
       
  1244 #ifndef QT_MAC_USE_COCOA
       
  1245     SetMenuCommandProperty(action->menu, action->command, kMenuCreatorQt, kMenuPropertyQAction,
       
  1246                            sizeof(action), &action);
       
  1247 #else
       
  1248     [newItem setTag:long(static_cast<QAction *>(action->action))];
       
  1249 #endif
       
  1250     syncAction(action);
       
  1251 }
       
  1252 
       
  1253 // return an autoreleased string given a QKeySequence (currently only looks at the first one).
       
  1254 NSString *keySequenceToKeyEqivalent(const QKeySequence &accel)
       
  1255 {
       
  1256     quint32 accel_key = (accel[0] & ~(Qt::MODIFIER_MASK | Qt::UNICODE_ACCEL));
       
  1257     extern QChar qt_macSymbolForQtKey(int key); // qkeysequence.cpp
       
  1258     QChar keyEquiv = qt_macSymbolForQtKey(accel_key);
       
  1259     if (keyEquiv.isNull()) {
       
  1260         if (accel_key >= Qt::Key_F1 && accel_key <= Qt::Key_F15)
       
  1261             keyEquiv = (accel_key - Qt::Key_F1) + NSF1FunctionKey;
       
  1262         else
       
  1263             keyEquiv = unichar(QChar(accel_key).toLower().unicode());
       
  1264     }
       
  1265     return [NSString stringWithCharacters:&keyEquiv.unicode() length:1];
       
  1266 }
       
  1267 
       
  1268 // return the cocoa modifier mask for the QKeySequence (currently only looks at the first one).
       
  1269 NSUInteger keySequenceModifierMask(const QKeySequence &accel)
       
  1270 {
       
  1271     return constructModifierMask(accel[0]);
       
  1272 }
       
  1273 
       
  1274 void
       
  1275 QMenuPrivate::QMacMenuPrivate::syncAction(QMacMenuAction *action)
       
  1276 {
       
  1277     if (!action)
       
  1278         return;
       
  1279 
       
  1280 #ifndef QT_MAC_USE_COCOA
       
  1281     const int index = qt_mac_menu_find_action(action->menu, action);
       
  1282     if (index == -1)
       
  1283         return;
       
  1284 #else
       
  1285     NSMenuItem *item = action->menuItem;
       
  1286     if (!item)
       
  1287         return;
       
  1288 #endif
       
  1289 
       
  1290 #ifndef QT_MAC_USE_COCOA
       
  1291     if (!action->action->isVisible()) {
       
  1292         ChangeMenuItemAttributes(action->menu, index, kMenuItemAttrHidden, 0);
       
  1293         return;
       
  1294     }
       
  1295     ChangeMenuItemAttributes(action->menu, index, 0, kMenuItemAttrHidden);
       
  1296 #else
       
  1297     QMacCocoaAutoReleasePool pool;
       
  1298     NSMenu *menu = [item menu];
       
  1299     bool actionVisible = action->action->isVisible();
       
  1300     [item setHidden:!actionVisible];
       
  1301     if (!actionVisible)
       
  1302         return;
       
  1303 #endif
       
  1304 
       
  1305 #ifndef QT_MAC_USE_COCOA
       
  1306     if (action->action->isSeparator()) {
       
  1307         ChangeMenuItemAttributes(action->menu, index, kMenuItemAttrSeparator, 0);
       
  1308         return;
       
  1309     }
       
  1310     ChangeMenuItemAttributes(action->menu, index, 0, kMenuItemAttrSeparator);
       
  1311 #else
       
  1312     int itemIndex = [menu indexOfItem:item];
       
  1313     Q_ASSERT(itemIndex != -1);
       
  1314     if (action->action->isSeparator()) {
       
  1315         action->menuItem = [NSMenuItem separatorItem];
       
  1316         [action->menuItem retain];
       
  1317         [menu insertItem: action->menuItem atIndex:itemIndex];
       
  1318         [menu removeItem:item];
       
  1319         [item release];
       
  1320         item = action->menuItem;
       
  1321         return;
       
  1322     } else if ([item isSeparatorItem]) {
       
  1323         // I'm no longer a separator...
       
  1324         action->menuItem = createNSMenuItem(action->action->text());
       
  1325         [menu insertItem:action->menuItem atIndex:itemIndex];
       
  1326         [menu removeItem:item];
       
  1327         [item release];
       
  1328         item = action->menuItem;
       
  1329     }
       
  1330 #endif
       
  1331 
       
  1332     //find text (and accel)
       
  1333     action->ignore_accel = 0;
       
  1334     QString text = action->action->text();
       
  1335     QKeySequence accel = action->action->shortcut();
       
  1336     {
       
  1337         int st = text.lastIndexOf(QLatin1Char('\t'));
       
  1338         if (st != -1) {
       
  1339             action->ignore_accel = 1;
       
  1340             accel = QKeySequence(text.right(text.length()-(st+1)));
       
  1341             text.remove(st, text.length()-st);
       
  1342         }
       
  1343     }
       
  1344     {
       
  1345         QString cmd_text = qt_mac_menu_merge_text(action);
       
  1346         if (!cmd_text.isEmpty()) {
       
  1347             text = cmd_text;
       
  1348             accel = qt_mac_menu_merge_accel(action);
       
  1349         }
       
  1350     }
       
  1351     // Show multiple key sequences as part of the menu text.
       
  1352     if (accel.count() > 1)
       
  1353         text += QLatin1String(" (") + accel.toString(QKeySequence::NativeText) + QLatin1String(")");
       
  1354 
       
  1355     QString finalString = qt_mac_removeMnemonics(text);
       
  1356 
       
  1357 #ifndef QT_MAC_USE_COCOA
       
  1358     MenuItemDataRec data;
       
  1359     memset(&data, '\0', sizeof(data));
       
  1360 
       
  1361     //Carbon text
       
  1362     data.whichData |= kMenuItemDataCFString;
       
  1363     QCFString cfstring(finalString);  // Hold the reference to the end of the function.
       
  1364     data.cfText = cfstring;
       
  1365 
       
  1366     // Carbon enabled
       
  1367     data.whichData |= kMenuItemDataEnabled;
       
  1368     data.enabled = action->action->isEnabled();
       
  1369     // Carbon icon
       
  1370     data.whichData |= kMenuItemDataIconHandle;
       
  1371     if (!action->action->icon().isNull()
       
  1372             && action->action->isIconVisibleInMenu()) {
       
  1373         data.iconType = kMenuIconRefType;
       
  1374         data.iconHandle = (Handle)qt_mac_create_iconref(action->action->icon().pixmap(16, QIcon::Normal));
       
  1375     } else {
       
  1376         data.iconType = kMenuNoIcon;
       
  1377     }
       
  1378     if (action->action->font().resolve()) { // Carbon font
       
  1379         if (action->action->font().bold())
       
  1380             data.style |= bold;
       
  1381         if (action->action->font().underline())
       
  1382             data.style |= underline;
       
  1383         if (action->action->font().italic())
       
  1384             data.style |= italic;
       
  1385         if (data.style)
       
  1386             data.whichData |= kMenuItemDataStyle;
       
  1387         data.whichData |= kMenuItemDataFontID;
       
  1388         data.fontID = action->action->font().macFontID();
       
  1389     }
       
  1390 #else
       
  1391     // Cocoa Font and title
       
  1392     if (action->action->font().resolve()) {
       
  1393         const QFont &actionFont = action->action->font();
       
  1394         NSFont *customMenuFont = [NSFont fontWithName:qt_mac_QStringToNSString(actionFont.family())
       
  1395                                   size:actionFont.pointSize()];
       
  1396         NSArray *keys = [NSArray arrayWithObjects:NSFontAttributeName, nil];
       
  1397         NSArray *objects = [NSArray arrayWithObjects:customMenuFont, nil];
       
  1398         NSDictionary *attributes = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
       
  1399         NSAttributedString *str = [[[NSAttributedString alloc] initWithString:qt_mac_QStringToNSString(finalString)
       
  1400                                  attributes:attributes] autorelease];
       
  1401        [item setAttributedTitle: str];
       
  1402     } else {
       
  1403         [item setTitle: qt_mac_QStringToNSString(finalString)];
       
  1404     }
       
  1405     [item setTitle:qt_mac_QStringToNSString(qt_mac_removeMnemonics(text))];
       
  1406 
       
  1407     // Cocoa Enabled
       
  1408     [item setEnabled: action->action->isEnabled()];
       
  1409 
       
  1410     // Cocoa icon
       
  1411     NSImage *nsimage = 0;
       
  1412     if (!action->action->icon().isNull() && action->action->isIconVisibleInMenu()) {
       
  1413         nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(action->action->icon().pixmap(16, QIcon::Normal)));
       
  1414     }
       
  1415     [item setImage:nsimage];
       
  1416     [nsimage release];
       
  1417 #endif
       
  1418 
       
  1419     if (action->action->menu()) { //submenu
       
  1420 #ifndef QT_MAC_USE_COCOA
       
  1421         data.whichData |= kMenuItemDataSubmenuHandle;
       
  1422         data.submenuHandle = action->action->menu()->macMenu();
       
  1423         QWidget *caused = 0;
       
  1424         GetMenuItemProperty(action->menu, 0, kMenuCreatorQt, kMenuPropertyQWidget, sizeof(caused), 0, &caused);
       
  1425         SetMenuItemProperty(data.submenuHandle, 0, kMenuCreatorQt, kMenuPropertyCausedQWidget, sizeof(caused), &caused);
       
  1426 #else
       
  1427         NSMenu *subMenu  = static_cast<NSMenu *>(action->action->menu()->macMenu());
       
  1428         if ([subMenu supermenu] && [subMenu supermenu] != [item menu]) {
       
  1429             // The menu is already a sub-menu of another one. Cocoa will throw an exception,
       
  1430             // in such cases. For the time being, a new QMenu with same set of actions is the
       
  1431             // only workaround.
       
  1432             action->action->setEnabled(false);
       
  1433         } else {
       
  1434             [item setSubmenu:subMenu];
       
  1435         }
       
  1436 #endif
       
  1437     } else { //respect some other items
       
  1438 #ifndef QT_MAC_USE_COCOA
       
  1439         //shortcuts (say we are setting them all so that we can also clear them).
       
  1440         data.whichData |= kMenuItemDataCmdKey;
       
  1441         data.whichData |= kMenuItemDataCmdKeyModifiers;
       
  1442         data.whichData |= kMenuItemDataCmdKeyGlyph;
       
  1443         if (accel.count() == 1) {
       
  1444             qt_mac_get_accel(accel[0], (quint32*)&data.cmdKeyModifiers, (quint32*)&data.cmdKeyGlyph);
       
  1445             if (data.cmdKeyGlyph == 0)
       
  1446                 data.cmdKey = (UniChar)accel[0];
       
  1447         }
       
  1448 #else
       
  1449         [item setSubmenu:0];
       
  1450         // No key equivalent set for multiple key QKeySequence.
       
  1451         if (accel.count() == 1) {
       
  1452             [item setKeyEquivalent:keySequenceToKeyEqivalent(accel)];
       
  1453             [item setKeyEquivalentModifierMask:keySequenceModifierMask(accel)];
       
  1454         } else {
       
  1455             [item setKeyEquivalent:@""];
       
  1456             [item setKeyEquivalentModifierMask:NSCommandKeyMask];
       
  1457         }
       
  1458 #endif
       
  1459     }
       
  1460 #ifndef QT_MAC_USE_COCOA
       
  1461     //mark glyph
       
  1462     data.whichData |= kMenuItemDataMark;
       
  1463     if (action->action->isChecked()) {
       
  1464 #if 0
       
  1465         if (action->action->actionGroup() &&
       
  1466            action->action->actionGroup()->isExclusive())
       
  1467             data.mark = diamondMark;
       
  1468         else
       
  1469 #endif
       
  1470             data.mark = checkMark;
       
  1471     } else {
       
  1472         data.mark = noMark;
       
  1473     }
       
  1474 
       
  1475     //actually set it
       
  1476     SetMenuItemData(action->menu, action->command, true, &data);
       
  1477 
       
  1478     // Free up memory
       
  1479     if (data.iconHandle)
       
  1480         ReleaseIconRef(IconRef(data.iconHandle));
       
  1481 #else
       
  1482     //mark glyph
       
  1483     [item setState:action->action->isChecked() ?  NSOnState : NSOffState];
       
  1484 #endif
       
  1485 }
       
  1486 
       
  1487 void
       
  1488 QMenuPrivate::QMacMenuPrivate::removeAction(QMacMenuAction *action)
       
  1489 {
       
  1490     if (!action)
       
  1491         return;
       
  1492 #ifndef QT_MAC_USE_COCOA
       
  1493     if (action->command == kHICommandQuit || action->command == kHICommandPreferences)
       
  1494         qt_mac_command_set_enabled(action->menu, action->command, false);
       
  1495     else
       
  1496         DeleteMenuItem(action->menu, qt_mac_menu_find_action(action->menu, action));
       
  1497 #else
       
  1498     QMacCocoaAutoReleasePool pool;
       
  1499     if (action->merged) {
       
  1500         if (reinterpret_cast<QAction *>([action->menuItem tag]) == action->action) {
       
  1501             QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
       
  1502             [action->menuItem setEnabled:false];
       
  1503             if (action->menuItem != [loader quitMenuItem]
       
  1504                 && action->menuItem != [loader preferencesMenuItem]) {
       
  1505                 [[action->menuItem menu] removeItem:action->menuItem];
       
  1506             }
       
  1507         }
       
  1508     } else {
       
  1509         [[action->menuItem menu] removeItem:action->menuItem];
       
  1510     }
       
  1511 #endif
       
  1512     actionItems.removeAll(action);
       
  1513 }
       
  1514 
       
  1515 OSMenuRef
       
  1516 QMenuPrivate::macMenu(OSMenuRef merge)
       
  1517 {
       
  1518     Q_UNUSED(merge);
       
  1519     Q_Q(QMenu);
       
  1520     if (mac_menu && mac_menu->menu)
       
  1521         return mac_menu->menu;
       
  1522     if (!mac_menu)
       
  1523         mac_menu = new QMacMenuPrivate;
       
  1524     mac_menu->menu = qt_mac_create_menu(q);
       
  1525     if (merge) {
       
  1526 #ifndef QT_MAC_USE_COCOA
       
  1527         SetMenuItemProperty(mac_menu->menu, 0, kMenuCreatorQt, kMenuPropertyMergeMenu, sizeof(merge), &merge);
       
  1528 #else
       
  1529         mergeMenuHash.insert(mac_menu->menu, merge);
       
  1530 #endif
       
  1531     }
       
  1532     QList<QAction*> items = q->actions();
       
  1533     for(int i = 0; i < items.count(); i++)
       
  1534         mac_menu->addAction(items[i], 0, this);
       
  1535     syncSeparatorsCollapsible(collapsibleSeparators);
       
  1536     return mac_menu->menu;
       
  1537 }
       
  1538 
       
  1539 /*!
       
  1540   \internal
       
  1541 */
       
  1542 void
       
  1543 QMenuPrivate::syncSeparatorsCollapsible(bool collapse)
       
  1544 {
       
  1545 #ifndef QT_MAC_USE_COCOA
       
  1546     if (collapse)
       
  1547         ChangeMenuAttributes(mac_menu->menu, kMenuAttrCondenseSeparators, 0);
       
  1548     else
       
  1549         ChangeMenuAttributes(mac_menu->menu, 0, kMenuAttrCondenseSeparators);
       
  1550 #else
       
  1551     qt_mac_menu_collapseSeparators(mac_menu->menu, collapse);
       
  1552 #endif
       
  1553 }
       
  1554 
       
  1555 
       
  1556 
       
  1557 /*!
       
  1558   \internal
       
  1559 */
       
  1560 void QMenuPrivate::setMacMenuEnabled(bool enable)
       
  1561 {
       
  1562     if (!macMenu(0))
       
  1563         return;
       
  1564 
       
  1565     QMacCocoaAutoReleasePool pool;
       
  1566     if (enable) {
       
  1567         for (int i = 0; i < mac_menu->actionItems.count(); ++i) {
       
  1568             QMacMenuAction *menuItem = mac_menu->actionItems.at(i);
       
  1569             if (menuItem && menuItem->action && menuItem->action->isEnabled()) {
       
  1570 #ifndef QT_MAC_USE_COCOA
       
  1571                 // Only enable those items which contains an enabled QAction.
       
  1572                 // i == 0 -> the menu itself, hence i + 1 for items.
       
  1573                 EnableMenuItem(mac_menu->menu, i + 1);
       
  1574 #else
       
  1575                 [menuItem->menuItem setEnabled:true];
       
  1576 #endif
       
  1577             }
       
  1578         }
       
  1579     } else {
       
  1580 #ifndef QT_MAC_USE_COCOA
       
  1581         DisableAllMenuItems(mac_menu->menu);
       
  1582 #else
       
  1583         NSMenu *menu = mac_menu->menu;
       
  1584         for (NSMenuItem *item in [menu itemArray]) {
       
  1585             [item setEnabled:false];
       
  1586         }
       
  1587 #endif
       
  1588     }
       
  1589 }
       
  1590 
       
  1591 /*!
       
  1592     \internal
       
  1593 
       
  1594     This function will return the OSMenuRef used to create the native menu bar
       
  1595     bindings.
       
  1596 
       
  1597     If Qt is built against Carbon, the OSMenuRef is a MenuRef that can be used
       
  1598     with Carbon's Menu Manager API.
       
  1599 
       
  1600     If Qt is built against Cocoa, the OSMenuRef is a NSMenu pointer.
       
  1601 
       
  1602     \warning This function is not portable.
       
  1603 
       
  1604     \sa QMenuBar::macMenu()
       
  1605 */
       
  1606 OSMenuRef QMenu::macMenu(OSMenuRef merge) { return d_func()->macMenu(merge); }
       
  1607 
       
  1608 /*****************************************************************************
       
  1609   QMenuBar bindings
       
  1610  *****************************************************************************/
       
  1611 typedef QHash<QWidget *, QMenuBar *> MenuBarHash;
       
  1612 Q_GLOBAL_STATIC(MenuBarHash, menubars)
       
  1613 static QMenuBar *fallback = 0;
       
  1614 QMenuBarPrivate::QMacMenuBarPrivate::QMacMenuBarPrivate() : menu(0), apple_menu(0)
       
  1615 {
       
  1616 }
       
  1617 
       
  1618 QMenuBarPrivate::QMacMenuBarPrivate::~QMacMenuBarPrivate()
       
  1619 {
       
  1620     for(QList<QMacMenuAction*>::Iterator it = actionItems.begin(); it != actionItems.end(); ++it)
       
  1621         delete (*it);
       
  1622 #ifndef QT_MAC_USE_COCOA
       
  1623     if (apple_menu) {
       
  1624         QMenuMergeList *list = 0;
       
  1625         GetMenuItemProperty(apple_menu, 0, kMenuCreatorQt, kMenuPropertyMergeList,
       
  1626                             sizeof(list), 0, &list);
       
  1627         if (list) {
       
  1628             RemoveMenuItemProperty(apple_menu, 0, kMenuCreatorQt, kMenuPropertyMergeList);
       
  1629             delete list;
       
  1630         }
       
  1631         ReleaseMenu(apple_menu);
       
  1632     }
       
  1633     if (menu)
       
  1634         ReleaseMenu(menu);
       
  1635 #else
       
  1636     [apple_menu release];
       
  1637     [menu release];
       
  1638 #endif
       
  1639 }
       
  1640 
       
  1641 void
       
  1642 QMenuBarPrivate::QMacMenuBarPrivate::addAction(QAction *a, QMacMenuAction *before)
       
  1643 {
       
  1644     if (a->isSeparator() || !menu)
       
  1645         return;
       
  1646     QMacMenuAction *action = new QMacMenuAction;
       
  1647     action->action = a;
       
  1648     action->ignore_accel = 1;
       
  1649 #ifndef QT_MAC_USE_COCOA
       
  1650     action->command = qt_mac_menu_static_cmd_id++;
       
  1651 #endif
       
  1652     addAction(action, before);
       
  1653 }
       
  1654 
       
  1655 void
       
  1656 QMenuBarPrivate::QMacMenuBarPrivate::addAction(QMacMenuAction *action, QMacMenuAction *before)
       
  1657 {
       
  1658     if (!action || !menu)
       
  1659         return;
       
  1660 
       
  1661     int before_index = actionItems.indexOf(before);
       
  1662     if (before_index < 0) {
       
  1663         before = 0;
       
  1664         before_index = actionItems.size();
       
  1665     }
       
  1666     actionItems.insert(before_index, action);
       
  1667 
       
  1668     MenuItemIndex index = actionItems.size()-1;
       
  1669 
       
  1670     action->menu = menu;
       
  1671 #ifdef QT_MAC_USE_COCOA
       
  1672     QMacCocoaAutoReleasePool pool;
       
  1673     [action->menu retain];
       
  1674     NSMenuItem *newItem = createNSMenuItem(action->action->text());
       
  1675     action->menuItem = newItem;
       
  1676 #endif
       
  1677     if (before) {
       
  1678 #ifndef QT_MAC_USE_COCOA
       
  1679         InsertMenuItemTextWithCFString(action->menu, 0, qMax(1, before_index+1), 0, action->command);
       
  1680 #else
       
  1681         [menu insertItem:newItem atIndex:qMax(1, before_index + 1)];
       
  1682 #endif
       
  1683         index = before_index;
       
  1684     } else {
       
  1685 #ifndef QT_MAC_USE_COCOA
       
  1686         AppendMenuItemTextWithCFString(action->menu, 0, 0, action->command, &index);
       
  1687 #else
       
  1688         [menu addItem:newItem];
       
  1689 #endif
       
  1690     }
       
  1691 #ifndef QT_MAC_USE_COCOA
       
  1692     SetMenuItemProperty(action->menu, index, kMenuCreatorQt, kMenuPropertyQAction, sizeof(action),
       
  1693                         &action);
       
  1694 #else
       
  1695     [newItem setTag:long(static_cast<QAction *>(action->action))];
       
  1696 #endif
       
  1697     syncAction(action);
       
  1698 }
       
  1699 
       
  1700 void
       
  1701 QMenuBarPrivate::QMacMenuBarPrivate::syncAction(QMacMenuAction *action)
       
  1702 {
       
  1703     if (!action || !menu)
       
  1704         return;
       
  1705 #ifndef QT_MAC_USE_COCOA
       
  1706     const int index = qt_mac_menu_find_action(action->menu, action);
       
  1707 #else
       
  1708     QMacCocoaAutoReleasePool pool;
       
  1709     NSMenuItem *item = action->menuItem;
       
  1710 #endif
       
  1711 
       
  1712     OSMenuRef submenu = 0;
       
  1713     bool release_submenu = false;
       
  1714     if (action->action->menu()) {
       
  1715         if ((submenu = action->action->menu()->macMenu(apple_menu))) {
       
  1716 #ifndef QT_MAC_USE_COCOA
       
  1717             QWidget *caused = 0;
       
  1718             GetMenuItemProperty(action->menu, 0, kMenuCreatorQt, kMenuPropertyQWidget, sizeof(caused), 0, &caused);
       
  1719             SetMenuItemProperty(submenu, 0, kMenuCreatorQt, kMenuPropertyCausedQWidget, sizeof(caused), &caused);
       
  1720 #else
       
  1721             if ([submenu supermenu] && [submenu supermenu] != [item menu])
       
  1722                 return;
       
  1723             else
       
  1724                 [item setSubmenu:submenu];
       
  1725 #endif
       
  1726         }
       
  1727 #ifndef QT_MAC_USE_COCOA
       
  1728     } else { // create a submenu to act as menu
       
  1729         release_submenu = true;
       
  1730         CreateNewMenu(0, 0, &submenu);
       
  1731 #endif
       
  1732     }
       
  1733 
       
  1734     if (submenu) {
       
  1735         bool visible = actualMenuItemVisibility(this, action);
       
  1736 #ifndef QT_MAC_USE_COCOA
       
  1737         SetMenuItemHierarchicalMenu(action->menu, index, submenu);
       
  1738         SetMenuTitleWithCFString(submenu, QCFString(qt_mac_removeMnemonics(action->action->text())));
       
  1739         if (visible)
       
  1740             ChangeMenuAttributes(submenu, 0, kMenuAttrHidden);
       
  1741         else
       
  1742             ChangeMenuAttributes(submenu, kMenuAttrHidden, 0);
       
  1743 #else
       
  1744         [item setSubmenu: submenu];
       
  1745         [submenu setTitle:qt_mac_QStringToNSString(qt_mac_removeMnemonics(action->action->text()))];
       
  1746         syncNSMenuItemVisiblity(item, visible);
       
  1747 #endif
       
  1748         if (release_submenu) { //no pointers to it
       
  1749 #ifndef QT_MAC_USE_COCOA
       
  1750             ReleaseMenu(submenu);
       
  1751 #else
       
  1752             [submenu release];
       
  1753 #endif
       
  1754         }
       
  1755     } else {
       
  1756         qWarning("QMenu: No OSMenuRef created for popup menu");
       
  1757     }
       
  1758 }
       
  1759 
       
  1760 void
       
  1761 QMenuBarPrivate::QMacMenuBarPrivate::removeAction(QMacMenuAction *action)
       
  1762 {
       
  1763     if (!action || !menu)
       
  1764         return;
       
  1765 #ifndef QT_MAC_USE_COCOA
       
  1766     DeleteMenuItem(action->menu, qt_mac_menu_find_action(action->menu, action));
       
  1767 #else
       
  1768     QMacCocoaAutoReleasePool pool;
       
  1769     [action->menu removeItem:action->menuItem];
       
  1770 #endif
       
  1771     actionItems.removeAll(action);
       
  1772 }
       
  1773 
       
  1774 bool QMenuBarPrivate::macWidgetHasNativeMenubar(QWidget *widget)
       
  1775 {
       
  1776     // This function is different from q->isNativeMenuBar(), as
       
  1777     // it returns true only if a native menu bar is actually
       
  1778     // _created_.
       
  1779     if (!widget)
       
  1780         return false;
       
  1781     return menubars()->contains(widget->window());
       
  1782 }
       
  1783 
       
  1784 void
       
  1785 QMenuBarPrivate::macCreateMenuBar(QWidget *parent)
       
  1786 {
       
  1787     Q_Q(QMenuBar);
       
  1788     static int dontUseNativeMenuBar = -1;
       
  1789     // We call the isNativeMenuBar function here
       
  1790     // because that will make sure that local overrides
       
  1791     // are dealt with correctly. q->isNativeMenuBar() will, if not
       
  1792     // overridden, depend on the attribute Qt::AA_DontUseNativeMenuBar:
       
  1793     bool qt_mac_no_native_menubar = !q->isNativeMenuBar();
       
  1794     if (qt_mac_no_native_menubar == false && dontUseNativeMenuBar < 0) {
       
  1795         // The menubar is set to be native. Let's check (one time only
       
  1796         // for all menubars) if this is OK with the rest of the environment.
       
  1797         // As a result, Qt::AA_DontUseNativeMenuBar is set. NB: the application
       
  1798         // might still choose to not respect, or change, this flag.
       
  1799         bool isPlugin = QApplication::testAttribute(Qt::AA_MacPluginApplication);
       
  1800         bool environmentSaysNo = !qgetenv("QT_MAC_NO_NATIVE_MENUBAR").isEmpty();
       
  1801         dontUseNativeMenuBar = isPlugin || environmentSaysNo;
       
  1802         QApplication::instance()->setAttribute(Qt::AA_DontUseNativeMenuBar, dontUseNativeMenuBar);
       
  1803         qt_mac_no_native_menubar = !q->isNativeMenuBar();
       
  1804     }
       
  1805     if (qt_mac_no_native_menubar == false) {
       
  1806         // INVARIANT: Use native menubar.
       
  1807         extern void qt_event_request_menubarupdate(); //qapplication_mac.cpp
       
  1808         qt_event_request_menubarupdate();
       
  1809         if (!parent && !fallback) {
       
  1810             fallback = q;
       
  1811             mac_menubar = new QMacMenuBarPrivate;
       
  1812         } else if (parent && parent->isWindow()) {
       
  1813             menubars()->insert(q->window(), q);
       
  1814             mac_menubar = new QMacMenuBarPrivate;
       
  1815         }
       
  1816     }
       
  1817 }
       
  1818 
       
  1819 void QMenuBarPrivate::macDestroyMenuBar()
       
  1820 {
       
  1821     Q_Q(QMenuBar);
       
  1822     QMacCocoaAutoReleasePool pool;
       
  1823     if (fallback == q)
       
  1824         fallback = 0;
       
  1825     delete mac_menubar;
       
  1826     QWidget *tlw = q->window();
       
  1827     menubars()->remove(tlw);
       
  1828     mac_menubar = 0;
       
  1829 
       
  1830     if (qt_mac_current_menubar.qmenubar == q) {
       
  1831         extern void qt_event_request_menubarupdate(); //qapplication_mac.cpp
       
  1832         qt_event_request_menubarupdate();
       
  1833     }
       
  1834 }
       
  1835 
       
  1836 OSMenuRef QMenuBarPrivate::macMenu()
       
  1837 {
       
  1838     Q_Q(QMenuBar);
       
  1839     if (!q->isNativeMenuBar() || !mac_menubar) {
       
  1840         return 0;
       
  1841     } else if (!mac_menubar->menu) {
       
  1842         mac_menubar->menu = qt_mac_create_menu(q);
       
  1843         ProcessSerialNumber mine, front;
       
  1844         if (GetCurrentProcess(&mine) == noErr && GetFrontProcess(&front) == noErr) {
       
  1845             if (!qt_mac_no_menubar_merge && !mac_menubar->apple_menu) {
       
  1846                 mac_menubar->apple_menu = qt_mac_create_menu(q);
       
  1847 #ifndef QT_MAC_USE_COCOA
       
  1848                 MenuItemIndex index;
       
  1849                 AppendMenuItemTextWithCFString(mac_menubar->menu, 0, 0, 0, &index);
       
  1850 
       
  1851                 SetMenuTitleWithCFString(mac_menubar->apple_menu, QCFString(QString(QChar(0x14))));
       
  1852                 SetMenuItemHierarchicalMenu(mac_menubar->menu, index, mac_menubar->apple_menu);
       
  1853                 SetMenuItemProperty(mac_menubar->apple_menu, 0, kMenuCreatorQt, kMenuPropertyQWidget, sizeof(q), &q);
       
  1854 #else
       
  1855                 [mac_menubar->apple_menu setTitle:qt_mac_QStringToNSString(QString(QChar(0x14)))];
       
  1856                 NSMenuItem *apple_menuItem = [[NSMenuItem alloc] init];
       
  1857                 [apple_menuItem setSubmenu:mac_menubar->menu];
       
  1858                 [mac_menubar->apple_menu addItem:apple_menuItem];
       
  1859                 [apple_menuItem release];
       
  1860 #endif
       
  1861             }
       
  1862             if (mac_menubar->apple_menu) {
       
  1863 #ifndef QT_MAC_USE_COCOA
       
  1864                 SetMenuItemProperty(mac_menubar->menu, 0, kMenuCreatorQt, kMenuPropertyMergeMenu,
       
  1865                                     sizeof(mac_menubar->apple_menu), &mac_menubar->apple_menu);
       
  1866 #else
       
  1867                 QMenuPrivate::mergeMenuHash.insert(mac_menubar->menu, mac_menubar->apple_menu);
       
  1868 #endif
       
  1869             }
       
  1870             QList<QAction*> items = q->actions();
       
  1871             for(int i = 0; i < items.count(); i++)
       
  1872                 mac_menubar->addAction(items[i]);
       
  1873         }
       
  1874     }
       
  1875     return mac_menubar->menu;
       
  1876 }
       
  1877 
       
  1878 /*!
       
  1879     \internal
       
  1880 
       
  1881     This function will return the OSMenuRef used to create the native menu bar
       
  1882     bindings. This OSMenuRef is then set as the root menu for the Menu
       
  1883     Manager.
       
  1884 
       
  1885     \warning This function is not portable.
       
  1886 
       
  1887     \sa QMenu::macMenu()
       
  1888 */
       
  1889 OSMenuRef QMenuBar::macMenu() { return d_func()->macMenu(); }
       
  1890 
       
  1891 /* !
       
  1892     \internal
       
  1893     Ancestor function that crosses windows (QWidget::isAncestorOf
       
  1894     only considers widgets within the same window).
       
  1895 */
       
  1896 static bool qt_mac_is_ancestor(QWidget* possibleAncestor, QWidget *child)
       
  1897 {
       
  1898     if (!possibleAncestor)
       
  1899         return false;
       
  1900 
       
  1901     QWidget * current = child->parentWidget();
       
  1902     while (current != 0) {
       
  1903         if (current == possibleAncestor)
       
  1904             return true;
       
  1905         current = current->parentWidget();
       
  1906     }
       
  1907     return false;
       
  1908 }
       
  1909 
       
  1910 /* !
       
  1911     \internal
       
  1912     Returns true if the entries of menuBar should be disabled,
       
  1913     based on the modality type of modalWidget.
       
  1914 */
       
  1915 static bool qt_mac_should_disable_menu(QMenuBar *menuBar, QWidget *modalWidget)
       
  1916 {
       
  1917     if (modalWidget == 0 || menuBar == 0)
       
  1918         return false;
       
  1919 
       
  1920     // If there is an application modal window on
       
  1921     // screen, the entries of the menubar should be disabled:
       
  1922     QWidget *w = modalWidget;
       
  1923     while (w) {
       
  1924         if (w->isVisible() && w->windowModality() == Qt::ApplicationModal)
       
  1925             return true;
       
  1926         w = w->parentWidget();
       
  1927     }
       
  1928 
       
  1929     // INVARIANT: modalWidget is window modal. Disable menu entries
       
  1930     // if the menu bar belongs to an ancestor of modalWidget:
       
  1931     return qt_mac_is_ancestor(menuBar->parentWidget(), modalWidget);
       
  1932 }
       
  1933 
       
  1934 static void cancelAllMenuTracking()
       
  1935 {
       
  1936 #ifdef QT_MAC_USE_COCOA
       
  1937     QMacCocoaAutoReleasePool pool;
       
  1938     NSMenu *mainMenu = [NSApp mainMenu];
       
  1939     [mainMenu cancelTracking];
       
  1940     for (NSMenuItem *item in [mainMenu itemArray]) {
       
  1941         if ([item submenu]) {
       
  1942             [[item submenu] cancelTracking];
       
  1943         }
       
  1944     }
       
  1945 #endif
       
  1946 }
       
  1947 
       
  1948 /*!
       
  1949   \internal
       
  1950 
       
  1951   This function will update the current menu bar and set it as the
       
  1952   active menu bar in the Menu Manager.
       
  1953 
       
  1954   \warning This function is not portable.
       
  1955 
       
  1956   \sa QMenu::macMenu(), QMenuBar::macMenu()
       
  1957 */
       
  1958 bool QMenuBar::macUpdateMenuBar()
       
  1959 {
       
  1960     cancelAllMenuTracking();
       
  1961     QMenuBar *mb = 0;
       
  1962     //find a menu bar
       
  1963     QWidget *w = qApp->activeWindow();
       
  1964 
       
  1965     if (!w) {
       
  1966         QWidgetList tlws = QApplication::topLevelWidgets();
       
  1967         for(int i = 0; i < tlws.size(); ++i) {
       
  1968             QWidget *tlw = tlws.at(i);
       
  1969             if ((tlw->isVisible() && tlw->windowType() != Qt::Tool &&
       
  1970                 tlw->windowType() != Qt::Popup)) {
       
  1971                 w = tlw;
       
  1972                 break;
       
  1973             }
       
  1974         }
       
  1975     }
       
  1976     if (w) {
       
  1977         mb = menubars()->value(w);
       
  1978 #ifndef QT_NO_MAINWINDOW
       
  1979         QDockWidget *dw = qobject_cast<QDockWidget *>(w);
       
  1980         if (!mb && dw) {
       
  1981             QMainWindow *mw = qobject_cast<QMainWindow *>(dw->parentWidget());
       
  1982             if (mw && (mb = menubars()->value(mw)))
       
  1983                 w = mw;
       
  1984         }
       
  1985 #endif
       
  1986         while(w && !mb)
       
  1987             mb = menubars()->value((w = w->parentWidget()));
       
  1988     }
       
  1989     if (!mb)
       
  1990         mb = fallback;
       
  1991     //now set it
       
  1992     bool ret = false;
       
  1993     if (mb && mb->isNativeMenuBar()) {
       
  1994 #ifdef QT_MAC_USE_COCOA
       
  1995         QMacCocoaAutoReleasePool pool;
       
  1996 #endif
       
  1997         if (OSMenuRef menu = mb->macMenu()) {
       
  1998 #ifndef QT_MAC_USE_COCOA
       
  1999             SetRootMenu(menu);
       
  2000 #else
       
  2001             QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
       
  2002             [loader ensureAppMenuInMenu:menu];
       
  2003             [NSApp setMainMenu:menu];
       
  2004             syncMenuBarItemsVisiblity(mb->d_func()->mac_menubar);
       
  2005 
       
  2006             if (OSMenuRef tmpMerge = QMenuPrivate::mergeMenuHash.value(menu)) {
       
  2007                 if (QMenuMergeList *mergeList
       
  2008                         = QMenuPrivate::mergeMenuItemsHash.value(tmpMerge)) {
       
  2009                     const int mergeListSize = mergeList->size();
       
  2010 
       
  2011                     for (int i = 0; i < mergeListSize; ++i) {
       
  2012                         const QMenuMergeItem &mergeItem = mergeList->at(i);
       
  2013                         // Ideally we would call QMenuPrivate::syncAction, but that requires finding
       
  2014                         // the original QMen and likely doing more work than we need.
       
  2015                         // For example, enabled is handled below.
       
  2016                         [mergeItem.menuItem setTag:reinterpret_cast<long>(
       
  2017                                                     static_cast<QAction *>(mergeItem.action->action))];
       
  2018                         [mergeItem.menuItem setHidden:!(mergeItem.action->action->isVisible())];
       
  2019                     }
       
  2020                 }
       
  2021             }
       
  2022 #endif
       
  2023             QWidget *modalWidget = qApp->activeModalWidget();
       
  2024             if (mb != menubars()->value(modalWidget)) {
       
  2025                 qt_mac_set_modal_state(menu, qt_mac_should_disable_menu(mb, modalWidget));
       
  2026             }
       
  2027         }
       
  2028         qt_mac_current_menubar.qmenubar = mb;
       
  2029         qt_mac_current_menubar.modal = QApplicationPrivate::modalState();
       
  2030         ret = true;
       
  2031     } else if (qt_mac_current_menubar.qmenubar && qt_mac_current_menubar.qmenubar->isNativeMenuBar()) {
       
  2032         const bool modal = QApplicationPrivate::modalState();
       
  2033         if (modal != qt_mac_current_menubar.modal) {
       
  2034             ret = true;
       
  2035             if (OSMenuRef menu = qt_mac_current_menubar.qmenubar->macMenu()) {
       
  2036 #ifndef QT_MAC_USE_COCOA
       
  2037                 SetRootMenu(menu);
       
  2038 #else
       
  2039                 QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
       
  2040                 [loader ensureAppMenuInMenu:menu];
       
  2041                 [NSApp setMainMenu:menu];
       
  2042                 syncMenuBarItemsVisiblity(qt_mac_current_menubar.qmenubar->d_func()->mac_menubar);
       
  2043 #endif
       
  2044                 QWidget *modalWidget = qApp->activeModalWidget();
       
  2045                 if (qt_mac_current_menubar.qmenubar != menubars()->value(modalWidget)) {
       
  2046                     qt_mac_set_modal_state(menu, qt_mac_should_disable_menu(mb, modalWidget));
       
  2047                 }
       
  2048             }
       
  2049             qt_mac_current_menubar.modal = modal;
       
  2050         }
       
  2051     }
       
  2052     if(!ret)
       
  2053         qt_mac_clear_menubar();
       
  2054     return ret;
       
  2055 }
       
  2056 
       
  2057 QHash<OSMenuRef, OSMenuRef> QMenuPrivate::mergeMenuHash;
       
  2058 QHash<OSMenuRef, QMenuMergeList*> QMenuPrivate::mergeMenuItemsHash;
       
  2059 
       
  2060 bool QMenuPrivate::QMacMenuPrivate::merged(const QAction *action) const
       
  2061 {
       
  2062 #ifndef QT_MAC_USE_COCOA
       
  2063     MenuRef merge = 0;
       
  2064     GetMenuItemProperty(menu, 0, kMenuCreatorQt, kMenuPropertyMergeMenu,
       
  2065             sizeof(merge), 0, &merge);
       
  2066     if (merge) {
       
  2067         QMenuMergeList *list = 0;
       
  2068         if (GetMenuItemProperty(merge, 0, kMenuCreatorQt, kMenuPropertyMergeList,
       
  2069                     sizeof(list), 0, &list) == noErr && list) {
       
  2070             for(int i = 0; i < list->size(); ++i) {
       
  2071                 QMenuMergeItem item = list->at(i);
       
  2072                 if (item.action->action == action)
       
  2073                     return true;
       
  2074             }
       
  2075         }
       
  2076     }
       
  2077 #else
       
  2078     if (OSMenuRef merge = mergeMenuHash.value(menu)) {
       
  2079         if (QMenuMergeList *list = mergeMenuItemsHash.value(merge)) {
       
  2080             for(int i = 0; i < list->size(); ++i) {
       
  2081                 const QMenuMergeItem &item = list->at(i);
       
  2082                 if (item.action->action == action)
       
  2083                     return true;
       
  2084             }
       
  2085         }
       
  2086     }
       
  2087 #endif
       
  2088     return false;
       
  2089 }
       
  2090 
       
  2091 //creation of the OSMenuRef
       
  2092 static OSMenuRef qt_mac_create_menu(QWidget *w)
       
  2093 {
       
  2094     OSMenuRef ret;
       
  2095 #ifndef QT_MAC_USE_COCOA
       
  2096     ret = 0;
       
  2097     if (CreateNewMenu(0, 0, &ret) == noErr) {
       
  2098         qt_mac_create_menu_event_handler();
       
  2099         SetMenuItemProperty(ret, 0, kMenuCreatorQt, kMenuPropertyQWidget, sizeof(w), &w);
       
  2100 
       
  2101         // kEventMenuMatchKey is only sent to the menu itself and not to
       
  2102         // the application, install a separate handler for that event.
       
  2103         EventHandlerRef eventHandlerRef;
       
  2104         InstallMenuEventHandler(ret, qt_mac_menu_event,
       
  2105                                 GetEventTypeCount(menu_menu_events),
       
  2106                                 menu_menu_events, 0, &eventHandlerRef);
       
  2107         menu_eventHandlers_hash()->insert(ret, eventHandlerRef);
       
  2108     } else {
       
  2109         qWarning("QMenu: Internal error");
       
  2110     }
       
  2111 #else
       
  2112     if (QMenu *qmenu = qobject_cast<QMenu *>(w)){
       
  2113         ret = [[QT_MANGLE_NAMESPACE(QCocoaMenu) alloc] initWithQMenu:qmenu];
       
  2114     } else {
       
  2115         ret = [[NSMenu alloc] init];
       
  2116     }
       
  2117 #endif
       
  2118     return ret;
       
  2119 }
       
  2120 
       
  2121 
       
  2122 
       
  2123 QT_END_NAMESPACE