1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/mac/carbon/menu.cpp 
   3 // Purpose:     wxMenu, wxMenuBar, wxMenuItem 
   4 // Author:      Stefan Csomor 
   8 // Copyright:   (c) Stefan Csomor 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  13 // headers & declarations 
  14 // ============================================================================ 
  19 #include "wx/wxprec.h" 
  28     #include "wx/menuitem.h" 
  31 #include "wx/mac/uma.h" 
  33 // other standard headers 
  34 // ---------------------- 
  37 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
) 
  38 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxEvtHandler
) 
  40 // the (popup) menu title has this special id 
  41 static const int idMenuTitle 
= -3; 
  43 static const short kwxMacAppleMenuId 
= 1 ; 
  46 // Find an item given the Macintosh Menu Reference 
  48 WX_DECLARE_HASH_MAP(MenuRef
, wxMenu
*, wxPointerHash
, wxPointerEqual
, MacMenuMap
); 
  50 static MacMenuMap wxWinMacMenuList
; 
  52 wxMenu 
*wxFindMenuFromMacMenu(MenuRef inMenuRef
) 
  54     MacMenuMap::iterator node 
= wxWinMacMenuList
.find(inMenuRef
); 
  56     return (node 
== wxWinMacMenuList
.end()) ? NULL 
: node
->second
; 
  59 void wxAssociateMenuWithMacMenu(MenuRef inMenuRef
, wxMenu 
*menu
) ; 
  60 void wxAssociateMenuWithMacMenu(MenuRef inMenuRef
, wxMenu 
*menu
) 
  62     // adding NULL MenuRef is (first) surely a result of an error and 
  63     // (secondly) breaks menu command processing 
  64     wxCHECK_RET( inMenuRef 
!= (MenuRef
) NULL
, wxT("attempt to add a NULL MenuRef to menu list") ); 
  66     wxWinMacMenuList
[inMenuRef
] = menu
; 
  69 void wxRemoveMacMenuAssociation(wxMenu 
*menu
) ; 
  70 void wxRemoveMacMenuAssociation(wxMenu 
*menu
) 
  72    // iterate over all the elements in the class 
  73     MacMenuMap::iterator it
; 
  74     for ( it 
= wxWinMacMenuList
.begin(); it 
!= wxWinMacMenuList
.end(); ++it 
) 
  76         if ( it
->second 
== menu 
) 
  78             wxWinMacMenuList
.erase(it
); 
  84 void wxInsertMenuItemsInMenu(wxMenu
* menu
, MenuRef wm
, MenuItemIndex insertAfter
) 
  86     wxMenuItemList::compatibility_iterator node
; 
  88     wxMenu 
*subMenu 
= NULL 
; 
  89     bool newItems 
= false; 
  91     for (node 
= menu
->GetMenuItems().GetFirst(); node
; node 
= node
->GetNext()) 
  93         item 
= (wxMenuItem 
*)node
->GetData(); 
  94         subMenu 
= item
->GetSubMenu() ; 
  97             wxInsertMenuItemsInMenu(subMenu
, (MenuRef
)subMenu
->GetHMenu(), 0); 
  99         if ( item
->IsSeparator() ) 
 102                 InsertMenuItemTextWithCFString( wm
, 
 103                     CFSTR(""), insertAfter
, kMenuItemAttrSeparator
, 0); 
 110                 entry 
= wxAcceleratorEntry::Create( item
->GetItemLabel() ) ; 
 112             MenuItemIndex winListPos 
= (MenuItemIndex
)-1; 
 113             OSStatus err 
= GetIndMenuItemWithCommandID(wm
, 
 114                         wxIdToMacCommand ( item
->GetId() ), 1, NULL
, &winListPos
); 
 116             if ( wm 
&& err 
== menuItemNotFoundErr 
) 
 118                 // NB: the only way to determine whether or not we should add 
 119                 // a separator is to know if we've added menu items to the menu 
 120                 // before the separator. 
 122                 UMAInsertMenuItem(wm
, wxStripMenuCodes(item
->GetItemLabel()) , wxFont::GetDefaultEncoding(), insertAfter
, entry
); 
 123                 SetMenuItemCommandID( wm 
, insertAfter
+1 , wxIdToMacCommand ( item
->GetId() ) ) ; 
 124                 SetMenuItemRefCon( wm 
, insertAfter
+1 , (URefCon
) item 
) ; 
 132 // ============================================================================ 
 134 // ============================================================================ 
 135 static void wxMenubarUnsetInvokingWindow( wxMenu 
*menu 
) ; 
 136 static void wxMenubarSetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
); 
 140 // Construct a menu with optional title (then use append) 
 143 short wxMenu::s_macNextMenuId 
= 3 ; 
 145 short wxMenu::s_macNextMenuId 
= 2 ; 
 150 _wxMenuAt(const wxMenuList 
&menuList
, size_t pos
) 
 152     wxMenuList::compatibility_iterator menuIter 
= menuList
.GetFirst(); 
 155         menuIter 
= menuIter
->GetNext(); 
 157     return menuIter
->GetData() ; 
 163     m_startRadioGroup 
= -1; 
 166     m_macMenuId 
= s_macNextMenuId
++; 
 167     m_hMenu 
= UMANewMenu(m_macMenuId
, m_title
, wxFont::GetDefaultEncoding() ); 
 171         wxLogLastError(wxT("UMANewMenu failed")); 
 174     wxAssociateMenuWithMacMenu( (MenuRef
)m_hMenu 
, this ) ; 
 176     // if we have a title, insert it in the beginning of the menu 
 177     if ( !m_title
.empty() ) 
 179         Append(idMenuTitle
, m_title
) ; 
 186     wxRemoveMacMenuAssociation( this ) ; 
 187     if (MAC_WXHMENU(m_hMenu
)) 
 188         ::DisposeMenu(MAC_WXHMENU(m_hMenu
)); 
 193     // not available on the mac platform 
 196 void wxMenu::Attach(wxMenuBarBase 
*menubar
) 
 198     wxMenuBase::Attach(menubar
); 
 203 // function appends a new item or submenu to the menu 
 204 // append a new item or submenu to the menu 
 205 bool wxMenu::DoInsertOrAppend(wxMenuItem 
*pItem
, size_t pos
) 
 207     wxASSERT_MSG( pItem 
!= NULL
, wxT("can't append NULL item to the menu") ); 
 209     if ( pItem
->IsSeparator() ) 
 211         if ( pos 
== (size_t)-1 ) 
 212             AppendMenuItemTextWithCFString( MAC_WXHMENU(m_hMenu
), 
 213                 CFSTR(""), kMenuItemAttrSeparator
, 0,NULL
); 
 215             InsertMenuItemTextWithCFString( MAC_WXHMENU(m_hMenu
), 
 216                 CFSTR(""), pos
, kMenuItemAttrSeparator
, 0); 
 220         wxMenu 
*pSubMenu 
= pItem
->GetSubMenu() ; 
 221         if ( pSubMenu 
!= NULL 
) 
 223             wxASSERT_MSG( pSubMenu
->m_hMenu 
!= NULL 
, wxT("invalid submenu added")); 
 224             pSubMenu
->m_menuParent 
= this ; 
 226             if (wxMenuBar::MacGetInstalledMenuBar() == GetMenuBar()) 
 227                 pSubMenu
->MacBeforeDisplay( true ) ; 
 229             if ( pos 
== (size_t)-1 ) 
 230                 UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu
), wxStripMenuCodes(pItem
->GetItemLabel()), wxFont::GetDefaultEncoding(), pSubMenu
->m_macMenuId
); 
 232                 UMAInsertSubMenuItem(MAC_WXHMENU(m_hMenu
), wxStripMenuCodes(pItem
->GetItemLabel()), wxFont::GetDefaultEncoding(), pos
, pSubMenu
->m_macMenuId
); 
 234             pItem
->UpdateItemBitmap() ; 
 235             pItem
->UpdateItemStatus() ; 
 239             if ( pos 
== (size_t)-1 ) 
 241                 UMAAppendMenuItem(MAC_WXHMENU(m_hMenu
), wxT("a") , wxFont::GetDefaultEncoding() ); 
 242                 pos 
= CountMenuItems(MAC_WXHMENU(m_hMenu
)) ; 
 246                 // MacOS counts menu items from 1 and inserts after, therefore having the 
 247                 // same effect as wx 0 based and inserting before, we must correct pos 
 248                 // after however for updates to be correct 
 249                 UMAInsertMenuItem(MAC_WXHMENU(m_hMenu
), wxT("a"), wxFont::GetDefaultEncoding(), pos
); 
 253             SetMenuItemCommandID( MAC_WXHMENU(m_hMenu
) , pos 
, wxIdToMacCommand ( pItem
->GetId() ) ) ; 
 254             SetMenuItemRefCon( MAC_WXHMENU(m_hMenu
) , pos 
, (URefCon
) pItem 
) ; 
 255             pItem
->UpdateItemText() ; 
 256             pItem
->UpdateItemBitmap() ; 
 257             pItem
->UpdateItemStatus() ; 
 259             if ( pItem
->GetId() == idMenuTitle 
) 
 260                 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu
) , pos 
, false ) ; 
 264     // if we're already attached to the menubar, we must update it 
 265     if ( IsAttached() && GetMenuBar()->IsAttached() ) 
 266         GetMenuBar()->Refresh(); 
 271 void wxMenu::EndRadioGroup() 
 273     // we're not inside a radio group any longer 
 274     m_startRadioGroup 
= -1; 
 277 wxMenuItem
* wxMenu::DoAppend(wxMenuItem 
*item
) 
 279     wxCHECK_MSG( item
, NULL
, _T("NULL item in wxMenu::DoAppend") ); 
 283     if ( item
->GetKind() == wxITEM_RADIO 
) 
 285         int count 
= GetMenuItemCount(); 
 287         if ( m_startRadioGroup 
== -1 ) 
 289             // start a new radio group 
 290             m_startRadioGroup 
= count
; 
 292             // for now it has just one element 
 293             item
->SetAsRadioGroupStart(); 
 294             item
->SetRadioGroupEnd(m_startRadioGroup
); 
 296             // ensure that we have a checked item in the radio group 
 299         else // extend the current radio group 
 301             // we need to update its end item 
 302             item
->SetRadioGroupStart(m_startRadioGroup
); 
 303             wxMenuItemList::compatibility_iterator node 
= GetMenuItems().Item(m_startRadioGroup
); 
 307                 node
->GetData()->SetRadioGroupEnd(count
); 
 311                 wxFAIL_MSG( _T("where is the radio group start item?") ); 
 315     else // not a radio item 
 320     if ( !wxMenuBase::DoAppend(item
) || !DoInsertOrAppend(item
) ) 
 324         // check the item initially 
 330 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem 
*item
) 
 332     if (wxMenuBase::DoInsert(pos
, item
) && DoInsertOrAppend(item
, pos
)) 
 338 wxMenuItem 
*wxMenu::DoRemove(wxMenuItem 
*item
) 
 340     // we need to find the items position in the child list 
 342     wxMenuItemList::compatibility_iterator node 
= GetMenuItems().GetFirst(); 
 344     for ( pos 
= 0; node
; pos
++ ) 
 346         if ( node
->GetData() == item 
) 
 349         node 
= node
->GetNext(); 
 352     // DoRemove() (unlike Remove) can only be called for existing item! 
 353     wxCHECK_MSG( node
, NULL
, wxT("bug in wxMenu::Remove logic") ); 
 355     ::DeleteMenuItem(MAC_WXHMENU(m_hMenu
) , pos 
+ 1); 
 357     if ( IsAttached() && GetMenuBar()->IsAttached() ) 
 358         // otherwise, the change won't be visible 
 359         GetMenuBar()->Refresh(); 
 361     // and from internal data structures 
 362     return wxMenuBase::DoRemove(item
); 
 365 void wxMenu::SetTitle(const wxString
& label
) 
 368     UMASetMenuTitle(MAC_WXHMENU(m_hMenu
) , label 
, wxFont::GetDefaultEncoding() ) ; 
 371 bool wxMenu::ProcessCommand(wxCommandEvent 
& event
) 
 373     bool processed 
= false; 
 375     // Try the menu's event handler 
 376     if ( /* !processed && */ GetEventHandler()) 
 377         processed 
= GetEventHandler()->SafelyProcessEvent(event
); 
 379     // Try the window the menu was popped up from 
 380     // (and up through the hierarchy) 
 381     wxWindow 
*win 
= GetInvokingWindow(); 
 382     if ( !processed 
&& win 
) 
 383         processed 
= win
->HandleWindowEvent(event
); 
 388 // --------------------------------------------------------------------------- 
 390 // --------------------------------------------------------------------------- 
 392 wxWindow 
*wxMenu::GetWindow() const 
 394     if ( m_invokingWindow 
!= NULL 
) 
 395         return m_invokingWindow
; 
 396     else if ( GetMenuBar() != NULL
) 
 397         return (wxWindow 
*) GetMenuBar()->GetFrame(); 
 402 // helper functions returning the mac menu position for a certain item, note that this is 
 403 // mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0 
 405 int wxMenu::MacGetIndexFromId( int id 
) 
 408     wxMenuItemList::compatibility_iterator node 
= GetMenuItems().GetFirst(); 
 409     for ( pos 
= 0; node
; pos
++ ) 
 411         if ( node
->GetData()->GetId() == id 
) 
 414         node 
= node
->GetNext(); 
 423 int wxMenu::MacGetIndexFromItem( wxMenuItem 
*pItem 
) 
 426     wxMenuItemList::compatibility_iterator node 
= GetMenuItems().GetFirst(); 
 427     for ( pos 
= 0; node
; pos
++ ) 
 429         if ( node
->GetData() == pItem 
) 
 432         node 
= node
->GetNext(); 
 441 void wxMenu::MacEnableMenu( bool bDoEnable 
) 
 443     UMAEnableMenuItem(MAC_WXHMENU(m_hMenu
) , 0 , bDoEnable 
) ; 
 448 // MacOS needs to know about submenus somewhere within this menu 
 449 // before it can be displayed, also hide special menu items 
 450 // like preferences that are handled by the OS 
 451 void wxMenu::MacBeforeDisplay( bool isSubMenu 
) 
 453     wxMenuItem
* previousItem 
= NULL 
; 
 455     wxMenuItemList::compatibility_iterator node
; 
 458     for (pos 
= 0, node 
= GetMenuItems().GetFirst(); node
; node 
= node
->GetNext(), pos
++) 
 460         item 
= (wxMenuItem 
*)node
->GetData(); 
 461         wxMenu
* subMenu 
= item
->GetSubMenu() ; 
 464             subMenu
->MacBeforeDisplay( true ) ; 
 468             // what we do here is to hide the special items which are 
 469             // shown in the application menu anyhow -- it doesn't make 
 470             // sense to show them in their normal place as well 
 471             if ( item
->GetId() == wxApp::s_macAboutMenuItemId 
|| 
 472                     item
->GetId() == wxApp::s_macPreferencesMenuItemId 
|| 
 473                     item
->GetId() == wxApp::s_macExitMenuItemId 
) 
 476                 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ), 
 477                                           pos 
+ 1, kMenuItemAttrHidden
, 0 ); 
 479                 // also check for a separator which was used just to 
 480                 // separate this item from the others, so don't leave 
 481                 // separator at the menu start or end nor 2 consecutive 
 483                 wxMenuItemList::compatibility_iterator nextNode 
= node
->GetNext(); 
 484                 wxMenuItem 
*next 
= nextNode 
? nextNode
->GetData() : NULL
; 
 487                 if ( !previousItem 
&& next 
&& next
->IsSeparator() ) 
 489                     // next (i.e. second as we must be first) item is 
 490                     // the separator to hide 
 491                     wxASSERT_MSG( pos 
== 0, _T("should be the menu start") ); 
 494                 else if ( GetMenuItems().GetCount() == pos 
+ 1 && 
 495                             previousItem 
!= NULL 
&& 
 496                                 previousItem
->IsSeparator() ) 
 498                     // prev item is a trailing separator we want to hide 
 501                 else if ( previousItem 
&& previousItem
->IsSeparator() && 
 502                             next 
&& next
->IsSeparator() ) 
 504                     // two consecutive separators, this is one too many 
 507                 else // no separators to hide 
 514                     // hide the separator as well 
 515                     ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ), 
 523         previousItem 
= item 
; 
 527         ::InsertMenu(MAC_WXHMENU( GetHMenu()), -1); 
 530 // undo all changes from the MacBeforeDisplay call 
 531 void wxMenu::MacAfterDisplay( bool isSubMenu 
) 
 534         ::DeleteMenu(MacGetMenuId()); 
 536     wxMenuItemList::compatibility_iterator node
; 
 539     for (node 
= GetMenuItems().GetFirst(); node
; node 
= node
->GetNext()) 
 541         item 
= (wxMenuItem 
*)node
->GetData(); 
 542         wxMenu
* subMenu 
= item
->GetSubMenu() ; 
 545             subMenu
->MacAfterDisplay( true ) ; 
 549             // no need to undo hidings 
 554 wxInt32 
wxMenu::MacHandleCommandProcess( wxMenuItem
* item
, int id
, wxWindow
* targetWindow 
) 
 556     OSStatus result 
= eventNotHandledErr 
; 
 557     if (item
->IsCheckable()) 
 558         item
->Check( !item
->IsChecked() ) ; 
 560     if ( SendEvent( id 
, item
->IsCheckable() ? item
->IsChecked() : -1 ) ) 
 564         if ( targetWindow 
!= NULL 
) 
 566             wxCommandEvent 
event(wxEVT_COMMAND_MENU_SELECTED 
, id
); 
 567             event
.SetEventObject(targetWindow
); 
 568             event
.SetInt(item
->IsCheckable() ? item
->IsChecked() : -1); 
 570             if ( targetWindow
->HandleWindowEvent(event
) ) 
 577 wxInt32 
wxMenu::MacHandleCommandUpdateStatus(wxMenuItem
* WXUNUSED(item
), 
 579                                              wxWindow
* targetWindow
) 
 581     OSStatus result 
= eventNotHandledErr 
; 
 582     wxUpdateUIEvent 
event(id
); 
 583     event
.SetEventObject( this ); 
 585     bool processed 
= false; 
 587     // Try the menu's event handler 
 589         wxEvtHandler 
*handler 
= GetEventHandler(); 
 591             processed 
= handler
->ProcessEvent(event
); 
 594     // Try the window the menu was popped up from 
 595     // (and up through the hierarchy) 
 598         const wxMenuBase 
*menu 
= this; 
 601             wxWindow 
*win 
= menu
->GetInvokingWindow(); 
 604                 processed 
= win
->HandleWindowEvent(event
); 
 608             menu 
= menu
->GetParent(); 
 612     if ( !processed 
&& targetWindow 
!= NULL
) 
 614         processed 
= targetWindow
->HandleWindowEvent(event
); 
 619         // if anything changed, update the changed attribute 
 620         if (event
.GetSetText()) 
 621             SetLabel(id
, event
.GetText()); 
 622         if (event
.GetSetChecked()) 
 623             Check(id
, event
.GetChecked()); 
 624         if (event
.GetSetEnabled()) 
 625             Enable(id
, event
.GetEnabled()); 
 636 Mac Implementation note : 
 638 The Mac has only one global menubar, so we attempt to install the currently 
 639 active menubar from a frame, we currently don't take into account mdi-frames 
 640 which would ask for menu-merging 
 642 Secondly there is no mac api for changing a menubar that is not the current 
 643 menubar, so we have to wait for preparing the actual menubar until the 
 644 wxMenubar is to be used 
 646 We can in subsequent versions use MacInstallMenuBar to provide some sort of 
 647 auto-merge for MDI in case this will be necessary 
 651 wxMenuBar
* wxMenuBar::s_macInstalledMenuBar 
= NULL 
; 
 652 wxMenuBar
* wxMenuBar::s_macCommonMenuBar 
= NULL 
; 
 653 bool     wxMenuBar::s_macAutoWindowMenu 
= true ; 
 654 WXHMENU  
wxMenuBar::s_macWindowMenuHandle 
= NULL 
; 
 656 void wxMenuBar::Init() 
 658     m_eventHandler 
= this; 
 659     m_menuBarFrame 
= NULL
; 
 660     m_invokingWindow 
= (wxWindow
*) NULL
; 
 663 wxMenuBar::wxMenuBar() 
 668 wxMenuBar::wxMenuBar( long WXUNUSED(style
) ) 
 673 wxMenuBar::wxMenuBar(size_t count
, wxMenu 
*menus
[], const wxString titles
[], long WXUNUSED(style
)) 
 677     m_titles
.Alloc(count
); 
 679     for ( size_t i 
= 0; i 
< count
; i
++ ) 
 681         m_menus
.Append(menus
[i
]); 
 682         m_titles
.Add(titles
[i
]); 
 684         menus
[i
]->Attach(this); 
 688 wxMenuBar::~wxMenuBar() 
 690     if (s_macCommonMenuBar 
== this) 
 691         s_macCommonMenuBar 
= NULL
; 
 693     if (s_macInstalledMenuBar 
== this) 
 696         s_macInstalledMenuBar 
= NULL
; 
 700 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground
), const wxRect 
*WXUNUSED(rect
)) 
 702     wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") ); 
 707 void wxMenuBar::MacInstallMenuBar() 
 709     if ( s_macInstalledMenuBar 
== this ) 
 712     MenuBarHandle menubar 
= NULL 
; 
 714     menubar 
= NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ; 
 716     ::SetMenuBar( menubar 
) ; 
 717     DisposeMenuBar( menubar 
) ; 
 718     MenuHandle appleMenu 
= NULL 
; 
 720     verify_noerr( CreateNewMenu( kwxMacAppleMenuId 
, 0 , &appleMenu 
) ) ; 
 721     verify_noerr( SetMenuTitleWithCFString( appleMenu 
, CFSTR( "\x14" ) ) ); 
 723     // Add About/Preferences separator only on OS X 
 724     // KH/RN: Separator is always present on 10.3 but not on 10.2 
 725     // However, the change from 10.2 to 10.3 suggests it is preferred 
 726     InsertMenuItemTextWithCFString( appleMenu
, 
 727                 CFSTR(""), 0, kMenuItemAttrSeparator
, 0); 
 728     InsertMenuItemTextWithCFString( appleMenu
, 
 729                 CFSTR("About..."), 0, 0, 0); 
 730     MacInsertMenu( appleMenu 
, 0 ) ; 
 732     // if we have a mac help menu, clean it up before adding new items 
 733     MenuHandle helpMenuHandle 
; 
 734     MenuItemIndex firstUserHelpMenuItem 
; 
 736     if ( UMAGetHelpMenuDontCreate( &helpMenuHandle 
, &firstUserHelpMenuItem
) == noErr 
) 
 738         for ( int i 
= CountMenuItems( helpMenuHandle 
) ; i 
>= firstUserHelpMenuItem 
; --i 
) 
 739             DeleteMenuItem( helpMenuHandle 
, i 
) ; 
 743         helpMenuHandle 
= NULL 
; 
 746     if ( wxApp::s_macPreferencesMenuItemId
) 
 748         wxMenuItem 
*item 
= FindItem( wxApp::s_macPreferencesMenuItemId 
, NULL 
) ; 
 749         if ( item 
== NULL 
|| !(item
->IsEnabled()) ) 
 750             DisableMenuCommand( NULL 
, kHICommandPreferences 
) ; 
 752             EnableMenuCommand( NULL 
, kHICommandPreferences 
) ; 
 755     // Unlike preferences which may or may not exist, the Quit item should be always 
 756     // enabled unless it is added by the application and then disabled, otherwise 
 757     // a program would be required to add an item with wxID_EXIT in order to get the 
 758     // Quit menu item to be enabled, which seems a bit burdensome. 
 759     if ( wxApp::s_macExitMenuItemId
) 
 761         wxMenuItem 
*item 
= FindItem( wxApp::s_macExitMenuItemId 
, NULL 
) ; 
 762         if ( item 
!= NULL 
&& !(item
->IsEnabled()) ) 
 763             DisableMenuCommand( NULL 
, kHICommandQuit 
) ; 
 765             EnableMenuCommand( NULL 
, kHICommandQuit 
) ; 
 768     wxString strippedHelpMenuTitle 
= wxStripMenuCodes( wxApp::s_macHelpMenuTitleName 
) ; 
 769     wxString strippedTranslatedHelpMenuTitle 
= wxStripMenuCodes( wxString( _("&Help") ) ) ; 
 770     wxMenuList::compatibility_iterator menuIter 
= m_menus
.GetFirst(); 
 771     for (size_t i 
= 0; i 
< m_menus
.GetCount(); i
++, menuIter 
= menuIter
->GetNext()) 
 773         wxMenuItemList::compatibility_iterator node
; 
 775         wxMenu
* menu 
= menuIter
->GetData() , *subMenu 
= NULL 
; 
 776         wxString strippedMenuTitle 
= wxStripMenuCodes(m_titles
[i
]); 
 778         if ( strippedMenuTitle 
== wxT("?") || strippedMenuTitle 
== strippedHelpMenuTitle 
|| strippedMenuTitle 
== strippedTranslatedHelpMenuTitle 
) 
 780             for (node 
= menu
->GetMenuItems().GetFirst(); node
; node 
= node
->GetNext()) 
 782                 item 
= (wxMenuItem 
*)node
->GetData(); 
 783                 subMenu 
= item
->GetSubMenu() ; 
 786                     // we don't support hierarchical menus in the help menu yet 
 790                     if ( item
->GetId() != wxApp::s_macAboutMenuItemId 
) 
 792                         // we have found a user help menu and an item other than the about item, 
 793                         // so we can create the mac help menu now, if we haven't created it yet 
 794                         if ( helpMenuHandle 
== NULL 
) 
 796                             if ( UMAGetHelpMenu( &helpMenuHandle 
, &firstUserHelpMenuItem
) != noErr 
) 
 798                                 helpMenuHandle 
= NULL 
; 
 804                     if ( item
->IsSeparator() ) 
 806                         if ( helpMenuHandle 
) 
 807                             AppendMenuItemTextWithCFString( helpMenuHandle
, 
 808                                 CFSTR(""), kMenuItemAttrSeparator
, 0,NULL
); 
 813                             entry 
= wxAcceleratorEntry::Create( item
->GetItemLabel() ) ; 
 815                         if ( item
->GetId() == wxApp::s_macAboutMenuItemId 
) 
 817                             // this will be taken care of below 
 821                             if ( helpMenuHandle 
) 
 823                                 UMAAppendMenuItem(helpMenuHandle
, wxStripMenuCodes(item
->GetItemLabel()) , wxFont::GetDefaultEncoding(), entry
); 
 824                                 SetMenuItemCommandID( helpMenuHandle 
, CountMenuItems(helpMenuHandle
) , wxIdToMacCommand ( item
->GetId() ) ) ; 
 825                                 SetMenuItemRefCon( helpMenuHandle 
, CountMenuItems(helpMenuHandle
) , (URefCon
) item 
) ; 
 835         else if ( ( m_titles
[i
] == wxT("Window") || m_titles
[i
] == wxT("&Window") ) 
 836                 && GetAutoWindowMenu() ) 
 838             if ( MacGetWindowMenuHMenu() == NULL 
) 
 840                 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle 
) ; 
 843             MenuRef wm 
= (MenuRef
)MacGetWindowMenuHMenu(); 
 847             // get the insertion point in the standard menu 
 848             MenuItemIndex winListStart
; 
 849             GetIndMenuItemWithCommandID(wm
, 
 850                         kHICommandWindowListSeparator
, 1, NULL
, &winListStart
); 
 852             // add a separator so that the standard items and the custom items 
 853             // aren't mixed together, but only if this is the first run 
 854             OSStatus err 
= GetIndMenuItemWithCommandID(wm
, 
 855                         'WXWM', 1, NULL
, NULL
); 
 857             if ( err 
== menuItemNotFoundErr 
) 
 859                 InsertMenuItemTextWithCFString( wm
, 
 860                         CFSTR(""), winListStart
-1, kMenuItemAttrSeparator
, 'WXWM'); 
 863             wxInsertMenuItemsInMenu(menu
, wm
, winListStart
); 
 867             UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , m_titles
[i
], m_font
.GetEncoding()  ) ; 
 868             menu
->MacBeforeDisplay(false) ; 
 870             ::InsertMenu(MAC_WXHMENU(_wxMenuAt(m_menus
, i
)->GetHMenu()), 0); 
 874     // take care of the about menu item wherever it is 
 877         wxMenuItem 
*aboutMenuItem 
= FindItem(wxApp::s_macAboutMenuItemId 
, &aboutMenu
) ; 
 881                 entry 
= wxAcceleratorEntry::Create( aboutMenuItem
->GetItemLabel() ) ; 
 882             UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId 
) , 1 , wxStripMenuCodes ( aboutMenuItem
->GetItemLabel() ) , wxFont::GetDefaultEncoding() ); 
 883             UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId 
) , 1 , true ); 
 884             SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId 
) , 1 , kHICommandAbout 
) ; 
 885             SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId 
) , 1 , (URefCon
)aboutMenuItem 
) ; 
 886             UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId 
) , 1 , entry 
) ; 
 890     if ( GetAutoWindowMenu() ) 
 892         if ( MacGetWindowMenuHMenu() == NULL 
) 
 893             CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle 
) ; 
 895         InsertMenu( (MenuHandle
) MacGetWindowMenuHMenu() , 0 ) ; 
 899     s_macInstalledMenuBar 
= this; 
 902 void wxMenuBar::EnableTop(size_t pos
, bool enable
) 
 904     wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") ); 
 906     _wxMenuAt(m_menus
, pos
)->MacEnableMenu( enable 
) ; 
 910 bool wxMenuBar::Enable(bool enable
) 
 912     wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") ); 
 915     for (i 
= 0; i 
< GetMenuCount(); i
++) 
 916         EnableTop(i
, enable
); 
 921 void wxMenuBar::SetMenuLabel(size_t pos
, const wxString
& label
) 
 923     wxCHECK_RET( pos 
< GetMenuCount(), wxT("invalid menu index") ); 
 925     m_titles
[pos
] = label
; 
 930     _wxMenuAt(m_menus
, pos
)->SetTitle( label 
) ; 
 932     if (wxMenuBar::s_macInstalledMenuBar 
== this) // are we currently installed ? 
 934         ::SetMenuBar( GetMenuBar() ) ; 
 939 wxString 
wxMenuBar::GetMenuLabel(size_t pos
) const 
 941     wxCHECK_MSG( pos 
< GetMenuCount(), wxEmptyString
, 
 942                  wxT("invalid menu index in wxMenuBar::GetMenuLabel") ); 
 944     return m_titles
[pos
]; 
 947 int wxMenuBar::FindMenu(const wxString
& title
) 
 949     wxString menuTitle 
= wxStripMenuCodes(title
); 
 951     size_t count 
= GetMenuCount(); 
 952     for ( size_t i 
= 0; i 
< count
; i
++ ) 
 954         wxString title 
= wxStripMenuCodes(m_titles
[i
]); 
 955         if ( menuTitle 
== title 
) 
 962 // --------------------------------------------------------------------------- 
 963 // wxMenuBar construction 
 964 // --------------------------------------------------------------------------- 
 966 wxMenu 
*wxMenuBar::Replace(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 968     wxMenu 
*menuOld 
= wxMenuBarBase::Replace(pos
, menu
, title
); 
 972     m_titles
[pos
] = title
; 
 976         if (s_macInstalledMenuBar 
== this) 
 978             menuOld
->MacAfterDisplay( false ) ; 
 979             ::DeleteMenu( menuOld
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ; 
 981             menu
->MacBeforeDisplay( false ) ; 
 982             UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title 
, m_font
.GetEncoding() ) ; 
 983             if ( pos 
== m_menus
.GetCount() - 1) 
 984                 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ; 
 986                 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos 
+ 1)->MacGetMenuId() ) ; 
 992     if (m_invokingWindow
) 
 993         wxMenubarSetInvokingWindow( menu
, m_invokingWindow 
); 
 998 bool wxMenuBar::Insert(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
1000     if ( !wxMenuBarBase::Insert(pos
, menu
, title
) ) 
1003     m_titles
.Insert(title
, pos
); 
1005     UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title 
, m_font
.GetEncoding() ) ; 
1007     if ( IsAttached() && s_macInstalledMenuBar 
== this ) 
1009         if (s_macInstalledMenuBar 
== this) 
1011             menu
->MacBeforeDisplay( false ) ; 
1013             if ( pos 
== (size_t) -1  || pos 
+ 1 == m_menus
.GetCount() ) 
1014                 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ; 
1016                 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+1)->MacGetMenuId() ) ; 
1022     if (m_invokingWindow
) 
1023         wxMenubarSetInvokingWindow( menu
, m_invokingWindow 
); 
1028 wxMenu 
*wxMenuBar::Remove(size_t pos
) 
1030     wxMenu 
*menu 
= wxMenuBarBase::Remove(pos
); 
1036         if (s_macInstalledMenuBar 
== this) 
1037             ::DeleteMenu( menu
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ; 
1042     m_titles
.RemoveAt(pos
); 
1047 bool wxMenuBar::Append(wxMenu 
*menu
, const wxString
& title
) 
1049     WXHMENU submenu 
= menu 
? menu
->GetHMenu() : 0; 
1050         wxCHECK_MSG( submenu
, false, wxT("can't append invalid menu to menubar") ); 
1052     if ( !wxMenuBarBase::Append(menu
, title
) ) 
1055     m_titles
.Add(title
); 
1057     UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title 
, m_font
.GetEncoding() ) ; 
1061         if (s_macInstalledMenuBar 
== this) 
1063             menu
->MacBeforeDisplay( false ) ; 
1064             ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ; 
1070     // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables 
1071     // adding menu later on. 
1072     if (m_invokingWindow
) 
1073         wxMenubarSetInvokingWindow( menu
, m_invokingWindow 
); 
1078 static void wxMenubarUnsetInvokingWindow( wxMenu 
*menu 
) 
1080     menu
->SetInvokingWindow( (wxWindow
*) NULL 
); 
1081     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
1085         wxMenuItem 
*menuitem 
= node
->GetData(); 
1086         if (menuitem
->IsSubMenu()) 
1087             wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu() ); 
1089         node 
= node
->GetNext(); 
1093 static void wxMenubarSetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
) 
1095     menu
->SetInvokingWindow( win 
); 
1096     wxMenuItem 
*menuitem
; 
1097     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
1101         menuitem 
= node
->GetData(); 
1102         if (menuitem
->IsSubMenu()) 
1103             wxMenubarSetInvokingWindow( menuitem
->GetSubMenu() , win 
); 
1105         node 
= node
->GetNext(); 
1109 void wxMenuBar::UnsetInvokingWindow() 
1111     m_invokingWindow 
= (wxWindow
*) NULL
; 
1113     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
1117         menu 
= node
->GetData(); 
1118         wxMenubarUnsetInvokingWindow( menu 
); 
1120         node 
= node
->GetNext(); 
1124 void wxMenuBar::SetInvokingWindow(wxFrame 
*frame
) 
1126     m_invokingWindow 
= frame
; 
1128     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
1132         menu 
= node
->GetData(); 
1133         wxMenubarSetInvokingWindow( menu
, frame 
); 
1135         node 
= node
->GetNext(); 
1139 void wxMenuBar::Detach() 
1141     wxMenuBarBase::Detach() ; 
1144 void wxMenuBar::Attach(wxFrame 
*frame
) 
1146     wxMenuBarBase::Attach( frame 
) ; 
1149 // --------------------------------------------------------------------------- 
1150 // wxMenuBar searching for menu items 
1151 // --------------------------------------------------------------------------- 
1153 // Find the itemString in menuString, and return the item id or wxNOT_FOUND 
1154 int wxMenuBar::FindMenuItem(const wxString
& menuString
, 
1155                             const wxString
& itemString
) const 
1157     wxString menuLabel 
= wxStripMenuCodes(menuString
); 
1158     size_t count 
= GetMenuCount(); 
1159     for ( size_t i 
= 0; i 
< count
; i
++ ) 
1161         wxString title 
= wxStripMenuCodes(m_titles
[i
]); 
1162         if ( menuLabel 
== title 
) 
1163             return _wxMenuAt(m_menus
, i
)->FindItem(itemString
); 
1169 wxMenuItem 
*wxMenuBar::FindItem(int id
, wxMenu 
**itemMenu
) const 
1174     wxMenuItem 
*item 
= NULL
; 
1175     size_t count 
= GetMenuCount(); 
1176     for ( size_t i 
= 0; !item 
&& (i 
< count
); i
++ ) 
1177         item 
= _wxMenuAt(m_menus
, i
)->FindItem(id
, itemMenu
);