|
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 |