~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/widgets/qmenu_mac.mm

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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] != nil) {
 
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] != nil)
 
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
void
 
1775
QMenuBarPrivate::macCreateMenuBar(QWidget *parent)
 
1776
{
 
1777
    Q_Q(QMenuBar);
 
1778
    static int dontUseNativeMenuBar = -1;
 
1779
    // We call the isNativeMenuBar function here
 
1780
    // because that will make sure that local overrides
 
1781
    // are dealt with correctly.
 
1782
    bool qt_mac_no_native_menubar = !q->isNativeMenuBar();
 
1783
    if (qt_mac_no_native_menubar == false && dontUseNativeMenuBar < 0) {
 
1784
        bool isPlugin = QApplication::testAttribute(Qt::AA_MacPluginApplication);
 
1785
        bool environmentSaysNo = !qgetenv("QT_MAC_NO_NATIVE_MENUBAR").isEmpty();
 
1786
        dontUseNativeMenuBar = isPlugin || environmentSaysNo;
 
1787
        QApplication::instance()->setAttribute(Qt::AA_DontUseNativeMenuBar, dontUseNativeMenuBar);
 
1788
        qt_mac_no_native_menubar = !q->isNativeMenuBar();
 
1789
    }
 
1790
    if (!qt_mac_no_native_menubar) {
 
1791
        extern void qt_event_request_menubarupdate(); //qapplication_mac.cpp
 
1792
        qt_event_request_menubarupdate();
 
1793
        if (!parent && !fallback) {
 
1794
            fallback = q;
 
1795
            mac_menubar = new QMacMenuBarPrivate;
 
1796
        } else if (parent && parent->isWindow()) {
 
1797
            menubars()->insert(q->window(), q);
 
1798
            mac_menubar = new QMacMenuBarPrivate;
 
1799
        }
 
1800
    }
 
1801
}
 
1802
 
 
1803
void QMenuBarPrivate::macDestroyMenuBar()
 
1804
{
 
1805
    Q_Q(QMenuBar);
 
1806
    QMacCocoaAutoReleasePool pool;
 
1807
    if (fallback == q)
 
1808
        fallback = 0;
 
1809
    delete mac_menubar;
 
1810
    QWidget *tlw = q->window();
 
1811
    menubars()->remove(tlw);
 
1812
    mac_menubar = 0;
 
1813
 
 
1814
    if (qt_mac_current_menubar.qmenubar == q) {
 
1815
        extern void qt_event_request_menubarupdate(); //qapplication_mac.cpp
 
1816
        qt_event_request_menubarupdate();
 
1817
    }
 
1818
}
 
1819
 
 
1820
OSMenuRef QMenuBarPrivate::macMenu()
 
1821
{
 
1822
    Q_Q(QMenuBar);
 
1823
    if (!q->isNativeMenuBar() || !mac_menubar) {
 
1824
        return 0;
 
1825
    } else if (!mac_menubar->menu) {
 
1826
        mac_menubar->menu = qt_mac_create_menu(q);
 
1827
        ProcessSerialNumber mine, front;
 
1828
        if (GetCurrentProcess(&mine) == noErr && GetFrontProcess(&front) == noErr) {
 
1829
            if (!qt_mac_no_menubar_merge && !mac_menubar->apple_menu) {
 
1830
                mac_menubar->apple_menu = qt_mac_create_menu(q);
 
1831
#ifndef QT_MAC_USE_COCOA
 
1832
                MenuItemIndex index;
 
1833
                AppendMenuItemTextWithCFString(mac_menubar->menu, 0, 0, 0, &index);
 
1834
 
 
1835
                SetMenuTitleWithCFString(mac_menubar->apple_menu, QCFString(QString(QChar(0x14))));
 
1836
                SetMenuItemHierarchicalMenu(mac_menubar->menu, index, mac_menubar->apple_menu);
 
1837
                SetMenuItemProperty(mac_menubar->apple_menu, 0, kMenuCreatorQt, kMenuPropertyQWidget, sizeof(q), &q);
 
1838
#else
 
1839
                [mac_menubar->apple_menu setTitle:qt_mac_QStringToNSString(QString(QChar(0x14)))];
 
1840
                NSMenuItem *apple_menuItem = [[NSMenuItem alloc] init];
 
1841
                [apple_menuItem setSubmenu:mac_menubar->menu];
 
1842
                [mac_menubar->apple_menu addItem:apple_menuItem];
 
1843
                [apple_menuItem release];
 
1844
#endif
 
1845
            }
 
1846
            if (mac_menubar->apple_menu) {
 
1847
#ifndef QT_MAC_USE_COCOA
 
1848
                SetMenuItemProperty(mac_menubar->menu, 0, kMenuCreatorQt, kMenuPropertyMergeMenu,
 
1849
                                    sizeof(mac_menubar->apple_menu), &mac_menubar->apple_menu);
 
1850
#else
 
1851
                QMenuPrivate::mergeMenuHash.insert(mac_menubar->menu, mac_menubar->apple_menu);
 
1852
#endif
 
1853
            }
 
1854
            QList<QAction*> items = q->actions();
 
1855
            for(int i = 0; i < items.count(); i++)
 
1856
                mac_menubar->addAction(items[i]);
 
1857
        }
 
1858
    }
 
1859
    return mac_menubar->menu;
 
1860
}
 
1861
 
 
1862
/*!
 
1863
    \internal
 
1864
 
 
1865
    This function will return the OSMenuRef used to create the native menu bar
 
1866
    bindings. This OSMenuRef is then set as the root menu for the Menu
 
1867
    Manager.
 
1868
 
 
1869
    \warning This function is not portable.
 
1870
 
 
1871
    \sa QMenu::macMenu()
 
1872
*/
 
1873
OSMenuRef QMenuBar::macMenu() { return d_func()->macMenu(); }
 
1874
 
 
1875
/* !
 
1876
    \internal
 
1877
    Ancestor function that crosses windows (QWidget::isAncestorOf
 
1878
    only considers widgets within the same window).
 
1879
*/
 
1880
static bool qt_mac_is_ancestor(QWidget* possibleAncestor, QWidget *child)
 
1881
{
 
1882
    if (!possibleAncestor)
 
1883
        return false;
 
1884
 
 
1885
    QWidget * current = child->parentWidget();
 
1886
    while (current != 0) {
 
1887
        if (current == possibleAncestor)
 
1888
            return true;
 
1889
        current = current->parentWidget();
 
1890
    }
 
1891
    return false;
 
1892
}
 
1893
 
 
1894
/* !
 
1895
    \internal
 
1896
    Returns true if the entries of menuBar should be disabled,
 
1897
    based on the modality type of modalWidget.
 
1898
*/
 
1899
static bool qt_mac_should_disable_menu(QMenuBar *menuBar, QWidget *modalWidget)
 
1900
{
 
1901
    if (modalWidget == 0 || menuBar == 0)
 
1902
        return false;
 
1903
 
 
1904
    // If there is an application modal window on
 
1905
    // screen, the entries of the menubar should be disabled:
 
1906
    QWidget *w = modalWidget;
 
1907
    while (w) {
 
1908
        if (w->isVisible() && w->windowModality() == Qt::ApplicationModal)
 
1909
            return true;
 
1910
        w = w->parentWidget();
 
1911
    }
 
1912
 
 
1913
    // INVARIANT: modalWidget is window modal. Disable menu entries
 
1914
    // if the menu bar belongs to an ancestor of modalWidget:
 
1915
    return qt_mac_is_ancestor(menuBar->parentWidget(), modalWidget);
 
1916
}
 
1917
 
 
1918
static void cancelAllMenuTracking()
 
1919
{
 
1920
#ifdef QT_MAC_USE_COCOA
 
1921
    QMacCocoaAutoReleasePool pool;
 
1922
    NSMenu *mainMenu = [NSApp mainMenu];
 
1923
    [mainMenu cancelTracking];
 
1924
    for (NSMenuItem *item in [mainMenu itemArray]) {
 
1925
        if ([item submenu]) {
 
1926
            [[item submenu] cancelTracking];
 
1927
        }
 
1928
    }
 
1929
#endif
 
1930
}
 
1931
 
 
1932
/*!
 
1933
  \internal
 
1934
 
 
1935
  This function will update the current menu bar and set it as the
 
1936
  active menu bar in the Menu Manager.
 
1937
 
 
1938
  \warning This function is not portable.
 
1939
 
 
1940
  \sa QMenu::macMenu(), QMenuBar::macMenu()
 
1941
*/
 
1942
bool QMenuBar::macUpdateMenuBar()
 
1943
{
 
1944
    cancelAllMenuTracking();
 
1945
    QMenuBar *mb = 0;
 
1946
    //find a menu bar
 
1947
    QWidget *w = qApp->activeWindow();
 
1948
 
 
1949
    if (!w) {
 
1950
        QWidgetList tlws = QApplication::topLevelWidgets();
 
1951
        for(int i = 0; i < tlws.size(); ++i) {
 
1952
            QWidget *tlw = tlws.at(i);
 
1953
            if ((tlw->isVisible() && tlw->windowType() != Qt::Tool &&
 
1954
                tlw->windowType() != Qt::Popup)) {
 
1955
                w = tlw;
 
1956
                break;
 
1957
            }
 
1958
        }
 
1959
    }
 
1960
    if (w) {
 
1961
        mb = menubars()->value(w);
 
1962
#ifndef QT_NO_MAINWINDOW
 
1963
        QDockWidget *dw = qobject_cast<QDockWidget *>(w);
 
1964
        if (!mb && dw) {
 
1965
            QMainWindow *mw = qobject_cast<QMainWindow *>(dw->parentWidget());
 
1966
            if (mw && (mb = menubars()->value(mw)))
 
1967
                w = mw;
 
1968
        }
 
1969
#endif
 
1970
        while(w && !mb)
 
1971
            mb = menubars()->value((w = w->parentWidget()));
 
1972
    }
 
1973
    if (!mb)
 
1974
        mb = fallback;
 
1975
    //now set it
 
1976
    bool ret = false;
 
1977
    if (mb && mb->isNativeMenuBar()) {
 
1978
#ifdef QT_MAC_USE_COCOA
 
1979
        QMacCocoaAutoReleasePool pool;
 
1980
#endif
 
1981
        if (OSMenuRef menu = mb->macMenu()) {
 
1982
#ifndef QT_MAC_USE_COCOA
 
1983
            SetRootMenu(menu);
 
1984
#else
 
1985
            QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
 
1986
            [loader ensureAppMenuInMenu:menu];
 
1987
            [NSApp setMainMenu:menu];
 
1988
            syncMenuBarItemsVisiblity(mb->d_func()->mac_menubar);
 
1989
 
 
1990
            if (OSMenuRef tmpMerge = QMenuPrivate::mergeMenuHash.value(menu)) {
 
1991
                if (QMenuMergeList *mergeList
 
1992
                        = QMenuPrivate::mergeMenuItemsHash.value(tmpMerge)) {
 
1993
                    const int mergeListSize = mergeList->size();
 
1994
 
 
1995
                    for (int i = 0; i < mergeListSize; ++i) {
 
1996
                        const QMenuMergeItem &mergeItem = mergeList->at(i);
 
1997
                        // Ideally we would call QMenuPrivate::syncAction, but that requires finding
 
1998
                        // the original QMen and likely doing more work than we need.
 
1999
                        // For example, enabled is handled below.
 
2000
                        [mergeItem.menuItem setTag:reinterpret_cast<long>(
 
2001
                                                    static_cast<QAction *>(mergeItem.action->action))];
 
2002
                        [mergeItem.menuItem setHidden:!(mergeItem.action->action->isVisible())];
 
2003
                    }
 
2004
                }
 
2005
            }
 
2006
#endif
 
2007
            QWidget *modalWidget = qApp->activeModalWidget();
 
2008
            if (mb != menubars()->value(modalWidget)) {
 
2009
                qt_mac_set_modal_state(menu, qt_mac_should_disable_menu(mb, modalWidget));
 
2010
            }
 
2011
        }
 
2012
        qt_mac_current_menubar.qmenubar = mb;
 
2013
        qt_mac_current_menubar.modal = QApplicationPrivate::modalState();
 
2014
        ret = true;
 
2015
    } else if (qt_mac_current_menubar.qmenubar && qt_mac_current_menubar.qmenubar->isNativeMenuBar()) {
 
2016
        const bool modal = QApplicationPrivate::modalState();
 
2017
        if (modal != qt_mac_current_menubar.modal) {
 
2018
            ret = true;
 
2019
            if (OSMenuRef menu = qt_mac_current_menubar.qmenubar->macMenu()) {
 
2020
#ifndef QT_MAC_USE_COCOA
 
2021
                SetRootMenu(menu);
 
2022
#else
 
2023
                QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
 
2024
                [loader ensureAppMenuInMenu:menu];
 
2025
                [NSApp setMainMenu:menu];
 
2026
                syncMenuBarItemsVisiblity(qt_mac_current_menubar.qmenubar->d_func()->mac_menubar);
 
2027
#endif
 
2028
                QWidget *modalWidget = qApp->activeModalWidget();
 
2029
                if (qt_mac_current_menubar.qmenubar != menubars()->value(modalWidget)) {
 
2030
                    qt_mac_set_modal_state(menu, qt_mac_should_disable_menu(mb, modalWidget));
 
2031
                }
 
2032
            }
 
2033
            qt_mac_current_menubar.modal = modal;
 
2034
        }
 
2035
    }
 
2036
    if(!ret)
 
2037
        qt_mac_clear_menubar();
 
2038
    return ret;
 
2039
}
 
2040
 
 
2041
QHash<OSMenuRef, OSMenuRef> QMenuPrivate::mergeMenuHash;
 
2042
QHash<OSMenuRef, QMenuMergeList*> QMenuPrivate::mergeMenuItemsHash;
 
2043
 
 
2044
bool QMenuPrivate::QMacMenuPrivate::merged(const QAction *action) const
 
2045
{
 
2046
#ifndef QT_MAC_USE_COCOA
 
2047
    MenuRef merge = 0;
 
2048
    GetMenuItemProperty(menu, 0, kMenuCreatorQt, kMenuPropertyMergeMenu,
 
2049
            sizeof(merge), 0, &merge);
 
2050
    if (merge) {
 
2051
        QMenuMergeList *list = 0;
 
2052
        if (GetMenuItemProperty(merge, 0, kMenuCreatorQt, kMenuPropertyMergeList,
 
2053
                    sizeof(list), 0, &list) == noErr && list) {
 
2054
            for(int i = 0; i < list->size(); ++i) {
 
2055
                QMenuMergeItem item = list->at(i);
 
2056
                if (item.action->action == action)
 
2057
                    return true;
 
2058
            }
 
2059
        }
 
2060
    }
 
2061
#else
 
2062
    if (OSMenuRef merge = mergeMenuHash.value(menu)) {
 
2063
        if (QMenuMergeList *list = mergeMenuItemsHash.value(merge)) {
 
2064
            for(int i = 0; i < list->size(); ++i) {
 
2065
                const QMenuMergeItem &item = list->at(i);
 
2066
                if (item.action->action == action)
 
2067
                    return true;
 
2068
            }
 
2069
        }
 
2070
    }
 
2071
#endif
 
2072
    return false;
 
2073
}
 
2074
 
 
2075
//creation of the OSMenuRef
 
2076
static OSMenuRef qt_mac_create_menu(QWidget *w)
 
2077
{
 
2078
    OSMenuRef ret;
 
2079
#ifndef QT_MAC_USE_COCOA
 
2080
    ret = 0;
 
2081
    if (CreateNewMenu(0, 0, &ret) == noErr) {
 
2082
        qt_mac_create_menu_event_handler();
 
2083
        SetMenuItemProperty(ret, 0, kMenuCreatorQt, kMenuPropertyQWidget, sizeof(w), &w);
 
2084
 
 
2085
        // kEventMenuMatchKey is only sent to the menu itself and not to
 
2086
        // the application, install a separate handler for that event.
 
2087
        EventHandlerRef eventHandlerRef;
 
2088
        InstallMenuEventHandler(ret, qt_mac_menu_event,
 
2089
                                GetEventTypeCount(menu_menu_events),
 
2090
                                menu_menu_events, 0, &eventHandlerRef);
 
2091
        menu_eventHandlers_hash()->insert(ret, eventHandlerRef);
 
2092
    } else {
 
2093
        qWarning("QMenu: Internal error");
 
2094
    }
 
2095
#else
 
2096
    if (QMenu *qmenu = qobject_cast<QMenu *>(w)){
 
2097
        ret = [[QT_MANGLE_NAMESPACE(QCocoaMenu) alloc] initWithQMenu:qmenu];
 
2098
    } else {
 
2099
        ret = [[NSMenu alloc] init];
 
2100
    }
 
2101
#endif
 
2102
    return ret;
 
2103
}
 
2104
 
 
2105
 
 
2106
 
 
2107
QT_END_NAMESPACE