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
->GetText() ) ; 
 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
->GetText()) , 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
->GetText()), wxFont::GetDefaultEncoding(), pSubMenu
->m_macMenuId
); 
 232                 UMAInsertSubMenuItem(MAC_WXHMENU(m_hMenu
), wxStripMenuCodes(pItem
->GetText()), 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()->ProcessEvent(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
->GetEventHandler()->ProcessEvent(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 ) ; 
 469             // what we do here is to hide the special items which are 
 470             // shown in the application menu anyhow -- it doesn't make 
 471             // sense to show them in their normal place as well 
 472             if ( item
->GetId() == wxApp::s_macAboutMenuItemId 
|| 
 473                 ( UMAGetSystemVersion() >= 0x1000 && ( 
 474                     item
->GetId() == wxApp::s_macPreferencesMenuItemId 
|| 
 475                     item
->GetId() == wxApp::s_macExitMenuItemId 
) ) ) 
 478                 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ), 
 479                                           pos 
+ 1, kMenuItemAttrHidden
, 0 ); 
 481                 // also check for a separator which was used just to 
 482                 // separate this item from the others, so don't leave 
 483                 // separator at the menu start or end nor 2 consecutive 
 485                 wxMenuItemList::compatibility_iterator nextNode 
= node
->GetNext(); 
 486                 wxMenuItem 
*next 
= nextNode 
? nextNode
->GetData() : NULL
; 
 489                 if ( !previousItem 
&& next 
&& next
->IsSeparator() ) 
 491                     // next (i.e. second as we must be first) item is 
 492                     // the separator to hide 
 493                     wxASSERT_MSG( pos 
== 0, _T("should be the menu start") ); 
 496                 else if ( GetMenuItems().GetCount() == pos 
+ 1 && 
 497                             previousItem 
!= NULL 
&& 
 498                                 previousItem
->IsSeparator() ) 
 500                     // prev item is a trailing separator we want to hide 
 503                 else if ( previousItem 
&& previousItem
->IsSeparator() && 
 504                             next 
&& next
->IsSeparator() ) 
 506                     // two consecutive separators, this is one too many 
 509                 else // no separators to hide 
 516                     // hide the separator as well 
 517                     ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ), 
 523 #endif // TARGET_CARBON 
 526         previousItem 
= item 
; 
 530         ::InsertMenu(MAC_WXHMENU( GetHMenu()), -1); 
 533 // undo all changes from the MacBeforeDisplay call 
 534 void wxMenu::MacAfterDisplay( bool isSubMenu 
) 
 537         ::DeleteMenu(MacGetMenuId()); 
 539     wxMenuItemList::compatibility_iterator node
; 
 542     for (node 
= GetMenuItems().GetFirst(); node
; node 
= node
->GetNext()) 
 544         item 
= (wxMenuItem 
*)node
->GetData(); 
 545         wxMenu
* subMenu 
= item
->GetSubMenu() ; 
 548             subMenu
->MacAfterDisplay( true ) ; 
 552             // no need to undo hidings 
 561 Mac Implementation note : 
 563 The Mac has only one global menubar, so we attempt to install the currently 
 564 active menubar from a frame, we currently don't take into account mdi-frames 
 565 which would ask for menu-merging 
 567 Secondly there is no mac api for changing a menubar that is not the current 
 568 menubar, so we have to wait for preparing the actual menubar until the 
 569 wxMenubar is to be used 
 571 We can in subsequent versions use MacInstallMenuBar to provide some sort of 
 572 auto-merge for MDI in case this will be necessary 
 576 wxMenuBar
* wxMenuBar::s_macInstalledMenuBar 
= NULL 
; 
 577 wxMenuBar
* wxMenuBar::s_macCommonMenuBar 
= NULL 
; 
 578 bool     wxMenuBar::s_macAutoWindowMenu 
= true ; 
 579 WXHMENU  
wxMenuBar::s_macWindowMenuHandle 
= NULL 
; 
 581 void wxMenuBar::Init() 
 583     m_eventHandler 
= this; 
 584     m_menuBarFrame 
= NULL
; 
 585     m_invokingWindow 
= (wxWindow
*) NULL
; 
 588 wxMenuBar::wxMenuBar() 
 593 wxMenuBar::wxMenuBar( long WXUNUSED(style
) ) 
 598 wxMenuBar::wxMenuBar(size_t count
, wxMenu 
*menus
[], const wxString titles
[], long WXUNUSED(style
)) 
 602     m_titles
.Alloc(count
); 
 604     for ( size_t i 
= 0; i 
< count
; i
++ ) 
 606         m_menus
.Append(menus
[i
]); 
 607         m_titles
.Add(titles
[i
]); 
 609         menus
[i
]->Attach(this); 
 613 wxMenuBar::~wxMenuBar() 
 615     if (s_macCommonMenuBar 
== this) 
 616         s_macCommonMenuBar 
= NULL
; 
 618     if (s_macInstalledMenuBar 
== this) 
 621         s_macInstalledMenuBar 
= NULL
; 
 625 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground
), const wxRect 
*WXUNUSED(rect
)) 
 627     wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") ); 
 632 void wxMenuBar::MacInstallMenuBar() 
 634     if ( s_macInstalledMenuBar 
== this ) 
 637     MenuBarHandle menubar 
= NULL 
; 
 639 #if TARGET_API_MAC_OSX 
 640     menubar 
= NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ; 
 642     menubar 
= NewHandleClear( 12 ) ; 
 643     (*menubar
)[3] = 0x0a ; 
 646     ::SetMenuBar( menubar 
) ; 
 647     DisposeMenuBar( menubar 
) ; 
 648     MenuHandle appleMenu 
= NULL 
; 
 650     verify_noerr( CreateNewMenu( kwxMacAppleMenuId 
, 0 , &appleMenu 
) ) ; 
 651     verify_noerr( SetMenuTitleWithCFString( appleMenu 
, CFSTR( "\x14" ) ) ); 
 653     // Add About/Preferences separator only on OS X 
 654     // KH/RN: Separator is always present on 10.3 but not on 10.2 
 655     // However, the change from 10.2 to 10.3 suggests it is preferred 
 656 #if TARGET_API_MAC_OSX 
 657     InsertMenuItemTextWithCFString( appleMenu
, 
 658                 CFSTR(""), 0, kMenuItemAttrSeparator
, 0); 
 660     InsertMenuItemTextWithCFString( appleMenu
, 
 661                 CFSTR("About..."), 0, 0, 0); 
 662     MacInsertMenu( appleMenu 
, 0 ) ; 
 664     // if we have a mac help menu, clean it up before adding new items 
 665     MenuHandle helpMenuHandle 
; 
 666     MenuItemIndex firstUserHelpMenuItem 
; 
 668     if ( UMAGetHelpMenuDontCreate( &helpMenuHandle 
, &firstUserHelpMenuItem
) == noErr 
) 
 670         for ( int i 
= CountMenuItems( helpMenuHandle 
) ; i 
>= firstUserHelpMenuItem 
; --i 
) 
 671             DeleteMenuItem( helpMenuHandle 
, i 
) ; 
 675         helpMenuHandle 
= NULL 
; 
 679     if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId
) 
 681         wxMenuItem 
*item 
= FindItem( wxApp::s_macPreferencesMenuItemId 
, NULL 
) ; 
 682         if ( item 
== NULL 
|| !(item
->IsEnabled()) ) 
 683             DisableMenuCommand( NULL 
, kHICommandPreferences 
) ; 
 685             EnableMenuCommand( NULL 
, kHICommandPreferences 
) ; 
 688     // Unlike preferences which may or may not exist, the Quit item should be always 
 689     // enabled unless it is added by the application and then disabled, otherwise 
 690     // a program would be required to add an item with wxID_EXIT in order to get the 
 691     // Quit menu item to be enabled, which seems a bit burdensome. 
 692     if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macExitMenuItemId
) 
 694         wxMenuItem 
*item 
= FindItem( wxApp::s_macExitMenuItemId 
, NULL 
) ; 
 695         if ( item 
!= NULL 
&& !(item
->IsEnabled()) ) 
 696             DisableMenuCommand( NULL 
, kHICommandQuit 
) ; 
 698             EnableMenuCommand( NULL 
, kHICommandQuit 
) ; 
 702     wxString strippedHelpMenuTitle 
= wxStripMenuCodes( wxApp::s_macHelpMenuTitleName 
) ; 
 703     wxString strippedTranslatedHelpMenuTitle 
= wxStripMenuCodes( wxString( _("&Help") ) ) ; 
 704     wxMenuList::compatibility_iterator menuIter 
= m_menus
.GetFirst(); 
 705     for (size_t i 
= 0; i 
< m_menus
.GetCount(); i
++, menuIter 
= menuIter
->GetNext()) 
 707         wxMenuItemList::compatibility_iterator node
; 
 709         wxMenu
* menu 
= menuIter
->GetData() , *subMenu 
= NULL 
; 
 710         wxString strippedMenuTitle 
= wxStripMenuCodes(m_titles
[i
]); 
 712         if ( strippedMenuTitle 
== wxT("?") || strippedMenuTitle 
== strippedHelpMenuTitle 
|| strippedMenuTitle 
== strippedTranslatedHelpMenuTitle 
) 
 714             for (node 
= menu
->GetMenuItems().GetFirst(); node
; node 
= node
->GetNext()) 
 716                 item 
= (wxMenuItem 
*)node
->GetData(); 
 717                 subMenu 
= item
->GetSubMenu() ; 
 720                     // we don't support hierarchical menus in the help menu yet 
 724                     if ( item
->GetId() != wxApp::s_macAboutMenuItemId 
) 
 726                         // we have found a user help menu and an item other than the about item, 
 727                         // so we can create the mac help menu now, if we haven't created it yet 
 728                         if ( helpMenuHandle 
== NULL 
) 
 730                             if ( UMAGetHelpMenu( &helpMenuHandle 
, &firstUserHelpMenuItem
) != noErr 
) 
 732                                 helpMenuHandle 
= NULL 
; 
 738                     if ( item
->IsSeparator() ) 
 740                         if ( helpMenuHandle 
) 
 741                             AppendMenuItemTextWithCFString( helpMenuHandle
, 
 742                                 CFSTR(""), kMenuItemAttrSeparator
, 0,NULL
); 
 747                             entry 
= wxAcceleratorEntry::Create( item
->GetText() ) ; 
 749                         if ( item
->GetId() == wxApp::s_macAboutMenuItemId 
) 
 751                             // this will be taken care of below 
 755                             if ( helpMenuHandle 
) 
 757                                 UMAAppendMenuItem(helpMenuHandle
, wxStripMenuCodes(item
->GetText()) , wxFont::GetDefaultEncoding(), entry
); 
 758                                 SetMenuItemCommandID( helpMenuHandle 
, CountMenuItems(helpMenuHandle
) , wxIdToMacCommand ( item
->GetId() ) ) ; 
 759                                 SetMenuItemRefCon( helpMenuHandle 
, CountMenuItems(helpMenuHandle
) , (URefCon
) item 
) ; 
 769         else if ( ( m_titles
[i
] == wxT("Window") || m_titles
[i
] == wxT("&Window") ) 
 770                 && GetAutoWindowMenu() ) 
 772             if ( MacGetWindowMenuHMenu() == NULL 
) 
 774                 CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle 
) ; 
 777             MenuRef wm 
= (MenuRef
)MacGetWindowMenuHMenu(); 
 781             // get the insertion point in the standard menu 
 782             MenuItemIndex winListStart
; 
 783             GetIndMenuItemWithCommandID(wm
, 
 784                         kHICommandWindowListSeparator
, 1, NULL
, &winListStart
); 
 786             // add a separator so that the standard items and the custom items 
 787             // aren't mixed together, but only if this is the first run 
 788             OSStatus err 
= GetIndMenuItemWithCommandID(wm
, 
 789                         'WXWM', 1, NULL
, NULL
); 
 791             if ( err 
== menuItemNotFoundErr 
) 
 793                 InsertMenuItemTextWithCFString( wm
, 
 794                         CFSTR(""), winListStart
-1, kMenuItemAttrSeparator
, 'WXWM'); 
 797             wxInsertMenuItemsInMenu(menu
, wm
, winListStart
); 
 801             UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , m_titles
[i
], m_font
.GetEncoding()  ) ; 
 802             menu
->MacBeforeDisplay(false) ; 
 804             ::InsertMenu(MAC_WXHMENU(_wxMenuAt(m_menus
, i
)->GetHMenu()), 0); 
 808     // take care of the about menu item wherever it is 
 811         wxMenuItem 
*aboutMenuItem 
= FindItem(wxApp::s_macAboutMenuItemId 
, &aboutMenu
) ; 
 815                 entry 
= wxAcceleratorEntry::Create( aboutMenuItem
->GetText() ) ; 
 816             UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId 
) , 1 , wxStripMenuCodes ( aboutMenuItem
->GetText() ) , wxFont::GetDefaultEncoding() ); 
 817             UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId 
) , 1 , true ); 
 818             SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId 
) , 1 , kHICommandAbout 
) ; 
 819             SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId 
) , 1 , (URefCon
)aboutMenuItem 
) ; 
 820             UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId 
) , 1 , entry 
) ; 
 824     if ( GetAutoWindowMenu() ) 
 826         if ( MacGetWindowMenuHMenu() == NULL 
) 
 827             CreateStandardWindowMenu( 0 , (MenuHandle
*) &s_macWindowMenuHandle 
) ; 
 829         InsertMenu( (MenuHandle
) MacGetWindowMenuHMenu() , 0 ) ; 
 833     s_macInstalledMenuBar 
= this; 
 836 void wxMenuBar::EnableTop(size_t pos
, bool enable
) 
 838     wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") ); 
 840     _wxMenuAt(m_menus
, pos
)->MacEnableMenu( enable 
) ; 
 844 bool wxMenuBar::Enable(bool enable
) 
 846     wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") ); 
 849     for (i 
= 0; i 
< GetMenuCount(); i
++) 
 850         EnableTop(i
, enable
); 
 855 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
) 
 857     wxCHECK_RET( pos 
< GetMenuCount(), wxT("invalid menu index") ); 
 859     m_titles
[pos
] = label
; 
 864     _wxMenuAt(m_menus
, pos
)->SetTitle( label 
) ; 
 866     if (wxMenuBar::s_macInstalledMenuBar 
== this) // are we currently installed ? 
 868         ::SetMenuBar( GetMenuBar() ) ; 
 873 wxString 
wxMenuBar::GetLabelTop(size_t pos
) const 
 875     wxCHECK_MSG( pos 
< GetMenuCount(), wxEmptyString
, 
 876                  wxT("invalid menu index in wxMenuBar::GetLabelTop") ); 
 878     return m_titles
[pos
]; 
 881 int wxMenuBar::FindMenu(const wxString
& title
) 
 883     wxString menuTitle 
= wxStripMenuCodes(title
); 
 885     size_t count 
= GetMenuCount(); 
 886     for ( size_t i 
= 0; i 
< count
; i
++ ) 
 888         wxString title 
= wxStripMenuCodes(m_titles
[i
]); 
 889         if ( menuTitle 
== title 
) 
 896 // --------------------------------------------------------------------------- 
 897 // wxMenuBar construction 
 898 // --------------------------------------------------------------------------- 
 900 wxMenu 
*wxMenuBar::Replace(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 902     wxMenu 
*menuOld 
= wxMenuBarBase::Replace(pos
, menu
, title
); 
 906     m_titles
[pos
] = title
; 
 910         if (s_macInstalledMenuBar 
== this) 
 912             menuOld
->MacAfterDisplay( false ) ; 
 913             ::DeleteMenu( menuOld
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ; 
 915             menu
->MacBeforeDisplay( false ) ; 
 916             UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title 
, m_font
.GetEncoding() ) ; 
 917             if ( pos 
== m_menus
.GetCount() - 1) 
 918                 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ; 
 920                 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos 
+ 1)->MacGetMenuId() ) ; 
 926     if (m_invokingWindow
) 
 927         wxMenubarSetInvokingWindow( menu
, m_invokingWindow 
); 
 932 bool wxMenuBar::Insert(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 934     if ( !wxMenuBarBase::Insert(pos
, menu
, title
) ) 
 937     m_titles
.Insert(title
, pos
); 
 939     UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title 
, m_font
.GetEncoding() ) ; 
 941     if ( IsAttached() && s_macInstalledMenuBar 
== this ) 
 943         if (s_macInstalledMenuBar 
== this) 
 945             menu
->MacBeforeDisplay( false ) ; 
 947             if ( pos 
== (size_t) -1  || pos 
+ 1 == m_menus
.GetCount() ) 
 948                 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ; 
 950                 ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , _wxMenuAt(m_menus
, pos
+1)->MacGetMenuId() ) ; 
 956     if (m_invokingWindow
) 
 957         wxMenubarSetInvokingWindow( menu
, m_invokingWindow 
); 
 962 wxMenu 
*wxMenuBar::Remove(size_t pos
) 
 964     wxMenu 
*menu 
= wxMenuBarBase::Remove(pos
); 
 970         if (s_macInstalledMenuBar 
== this) 
 971             ::DeleteMenu( menu
->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ; 
 976     m_titles
.RemoveAt(pos
); 
 981 bool wxMenuBar::Append(wxMenu 
*menu
, const wxString
& title
) 
 983     WXHMENU submenu 
= menu 
? menu
->GetHMenu() : 0; 
 984         wxCHECK_MSG( submenu
, false, wxT("can't append invalid menu to menubar") ); 
 986     if ( !wxMenuBarBase::Append(menu
, title
) ) 
 991     UMASetMenuTitle( MAC_WXHMENU(menu
->GetHMenu()) , title 
, m_font
.GetEncoding() ) ; 
 995         if (s_macInstalledMenuBar 
== this) 
 997             menu
->MacBeforeDisplay( false ) ; 
 998             ::InsertMenu( MAC_WXHMENU(menu
->GetHMenu()) , 0 ) ; 
1004     // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables 
1005     // adding menu later on. 
1006     if (m_invokingWindow
) 
1007         wxMenubarSetInvokingWindow( menu
, m_invokingWindow 
); 
1012 static void wxMenubarUnsetInvokingWindow( wxMenu 
*menu 
) 
1014     menu
->SetInvokingWindow( (wxWindow
*) NULL 
); 
1015     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
1019         wxMenuItem 
*menuitem 
= node
->GetData(); 
1020         if (menuitem
->IsSubMenu()) 
1021             wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu() ); 
1023         node 
= node
->GetNext(); 
1027 static void wxMenubarSetInvokingWindow( wxMenu 
*menu
, wxWindow 
*win 
) 
1029     menu
->SetInvokingWindow( win 
); 
1030     wxMenuItem 
*menuitem
; 
1031     wxMenuItemList::compatibility_iterator node 
= menu
->GetMenuItems().GetFirst(); 
1035         menuitem 
= node
->GetData(); 
1036         if (menuitem
->IsSubMenu()) 
1037             wxMenubarSetInvokingWindow( menuitem
->GetSubMenu() , win 
); 
1039         node 
= node
->GetNext(); 
1043 void wxMenuBar::UnsetInvokingWindow() 
1045     m_invokingWindow 
= (wxWindow
*) NULL
; 
1047     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
1051         menu 
= node
->GetData(); 
1052         wxMenubarUnsetInvokingWindow( menu 
); 
1054         node 
= node
->GetNext(); 
1058 void wxMenuBar::SetInvokingWindow(wxFrame 
*frame
) 
1060     m_invokingWindow 
= frame
; 
1062     wxMenuList::compatibility_iterator node 
= m_menus
.GetFirst(); 
1066         menu 
= node
->GetData(); 
1067         wxMenubarSetInvokingWindow( menu
, frame 
); 
1069         node 
= node
->GetNext(); 
1073 void wxMenuBar::Detach() 
1075     wxMenuBarBase::Detach() ; 
1078 void wxMenuBar::Attach(wxFrame 
*frame
) 
1080     wxMenuBarBase::Attach( frame 
) ; 
1083 // --------------------------------------------------------------------------- 
1084 // wxMenuBar searching for menu items 
1085 // --------------------------------------------------------------------------- 
1087 // Find the itemString in menuString, and return the item id or wxNOT_FOUND 
1088 int wxMenuBar::FindMenuItem(const wxString
& menuString
, 
1089                             const wxString
& itemString
) const 
1091     wxString menuLabel 
= wxStripMenuCodes(menuString
); 
1092     size_t count 
= GetMenuCount(); 
1093     for ( size_t i 
= 0; i 
< count
; i
++ ) 
1095         wxString title 
= wxStripMenuCodes(m_titles
[i
]); 
1096         if ( menuLabel 
== title 
) 
1097             return _wxMenuAt(m_menus
, i
)->FindItem(itemString
); 
1103 wxMenuItem 
*wxMenuBar::FindItem(int id
, wxMenu 
**itemMenu
) const 
1108     wxMenuItem 
*item 
= NULL
; 
1109     size_t count 
= GetMenuCount(); 
1110     for ( size_t i 
= 0; !item 
&& (i 
< count
); i
++ ) 
1111         item 
= _wxMenuAt(m_menus
, i
)->FindItem(id
, itemMenu
);