]> git.saurik.com Git - wxWidgets.git/blobdiff - src/osx/menu_osx.cpp
changing to allow for 2x ramping up NSApp run
[wxWidgets.git] / src / osx / menu_osx.cpp
index 281c0121db84c37502f38ab97bc39e981b3e1b31..2bf5cede9e763d3240b3f7ccce49acd7b63b6c20 100644 (file)
@@ -4,7 +4,6 @@
 // Author:      Stefan Csomor
 // Modified by:
 // Created:     1998-01-01
 // Author:      Stefan Csomor
 // Modified by:
 // Created:     1998-01-01
-// RCS-ID:      $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $
 // Copyright:   (c) Stefan Csomor
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 // Copyright:   (c) Stefan Csomor
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
@@ -18,6 +17,8 @@
 
 #include "wx/wxprec.h"
 
 
 #include "wx/wxprec.h"
 
+#if wxUSE_MENUS
+
 #include "wx/menu.h"
 
 #ifndef WX_PRECOMP
 #include "wx/menu.h"
 
 #ifndef WX_PRECOMP
@@ -25,6 +26,7 @@
     #include "wx/app.h"
     #include "wx/utils.h"
     #include "wx/frame.h"
     #include "wx/app.h"
     #include "wx/utils.h"
     #include "wx/frame.h"
+    #include "wx/dialog.h"
     #include "wx/menuitem.h"
 #endif
 
     #include "wx/menuitem.h"
 #endif
 
@@ -40,41 +42,23 @@ wxMenuImpl::~wxMenuImpl()
 {
 }
 
 {
 }
 
-IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
-IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
-
-// the (popup) menu title has this special id
+// the (popup) menu title has this special menuid
 static const int idMenuTitle = -3;
 
 // ============================================================================
 // implementation
 // ============================================================================
 static const int idMenuTitle = -3;
 
 // ============================================================================
 // implementation
 // ============================================================================
-static void wxMenubarUnsetInvokingWindow( wxMenu *menu ) ;
-static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win );
 
 // Menus
 
 // Construct a menu with optional title (then use append)
 
 
 // Menus
 
 // Construct a menu with optional title (then use append)
 
-static
-wxMenu *
-_wxMenuAt(const wxMenuList &menuList, size_t pos)
-{
-    wxMenuList::compatibility_iterator menuIter = menuList.GetFirst();
-
-    while (pos-- > 0)
-        menuIter = menuIter->GetNext();
-
-    return menuIter->GetData() ;
-}
-
 void wxMenu::Init()
 {
     m_doBreak = false;
 void wxMenu::Init()
 {
     m_doBreak = false;
-    m_startRadioGroup = -1;
     m_allowRearrange = true;
     m_noEventsMode = false;
     m_allowRearrange = true;
     m_noEventsMode = false;
-    
+
     m_peer = wxMenuImpl::Create( this, wxStripMenuCodes(m_title) );
 
 
     m_peer = wxMenuImpl::Create( this, wxStripMenuCodes(m_title) );
 
 
@@ -103,13 +87,6 @@ void wxMenu::Break()
     // not available on the mac platform
 }
 
     // not available on the mac platform
 }
 
-void wxMenu::Attach(wxMenuBarBase *menubar)
-{
-    wxMenuBase::Attach(menubar);
-
-    EndRadioGroup();
-}
-
 void wxMenu::SetAllowRearrange( bool allow )
 {
     m_allowRearrange = allow;
 void wxMenu::SetAllowRearrange( bool allow )
 {
     m_allowRearrange = allow;
@@ -122,18 +99,20 @@ void wxMenu::SetNoEventsMode( bool noEvents )
 
 // function appends a new item or submenu to the menu
 // append a new item or submenu to the menu
 
 // function appends a new item or submenu to the menu
 // append a new item or submenu to the menu
-bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
+bool wxMenu::DoInsertOrAppend(wxMenuItem *item, size_t pos)
 {
 {
-    wxASSERT_MSG( pItem != NULL, wxT("can't append NULL item to the menu") );
-    m_peer->InsertOrAppend( pItem, pos );
+    wxASSERT_MSG( item != NULL, wxT("can't append NULL item to the menu") );
+    GetPeer()->InsertOrAppend( item, pos );
+
+    bool check = false;
 
 
-    if ( pItem->IsSeparator() )
+    if ( item->IsSeparator() )
     {
         // nothing to do here
     }
     else
     {
     {
         // nothing to do here
     }
     else
     {
-        wxMenu *pSubMenu = pItem->GetSubMenu() ;
+        wxMenu *pSubMenu = item->GetSubMenu() ;
         if ( pSubMenu != NULL )
         {
             wxASSERT_MSG( pSubMenu->GetHMenu() != NULL , wxT("invalid submenu added"));
         if ( pSubMenu != NULL )
         {
             wxASSERT_MSG( pSubMenu->GetHMenu() != NULL , wxT("invalid submenu added"));
@@ -141,77 +120,131 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
 
             pSubMenu->DoRearrange();
         }
 
             pSubMenu->DoRearrange();
         }
-        else
-        { 
-            if ( pItem->GetId() == idMenuTitle )
-                pItem->GetMenu()->Enable( idMenuTitle, false );
-        }
-    }
-
-    // if we're already attached to the menubar, we must update it
-    if ( IsAttached() && GetMenuBar()->IsAttached() )
-        GetMenuBar()->Refresh();
+        else if ( item->IsRadio() )
+        {
+            // If a previous or next item is a radio button, add this radio
+            // button to the existing radio group. Otherwise start a new one
+            // for it.
+            wxMenuItemList& items = GetMenuItems();
 
 
-    return true ;
-}
+            size_t const
+                posItem = pos == (size_t)-1 ? items.GetCount() - 1 : pos;
 
 
-void wxMenu::EndRadioGroup()
-{
-    // we're not inside a radio group any longer
-    m_startRadioGroup = -1;
-}
+            wxMenuItemList::compatibility_iterator node = items.Item(posItem);
+            wxCHECK_MSG( node, false, wxS("New item must have been inserted") );
 
 
-wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
-{
-    wxCHECK_MSG( item, NULL, _T("NULL item in wxMenu::DoAppend") );
+            bool foundGroup = false;
+            if ( node->GetPrevious() )
+            {
+                wxMenuItem* const prev = node->GetPrevious()->GetData();
 
 
-    bool check = false;
+                if ( prev->IsRadio() )
+                {
+                    // This item is in the same group as the preceding one so
+                    // we should use the same starting item, but getting it is
+                    // a bit difficult as we can't query the start radio group
+                    // item for it.
+                    const int groupStart = prev->IsRadioGroupStart()
+                                            ? posItem - 1
+                                            : prev->GetRadioGroupStart();
+                    item->SetRadioGroupStart(groupStart);
+
+                    // We must also account for the new item by incrementing
+                    // the index of the last item in this group.
+                    wxMenuItem* const first = items.Item(groupStart)->GetData();
+                    first->SetRadioGroupEnd(first->GetRadioGroupEnd() + 1);
+
+                    foundGroup = true;
+                }
+            }
 
 
-    if ( item->GetKind() == wxITEM_RADIO )
-    {
-        int count = GetMenuItemCount();
+            if ( !foundGroup && node->GetNext() )
+            {
+                wxMenuItem* const next = node->GetNext()->GetData();
 
 
-        if ( m_startRadioGroup == -1 )
-        {
-            // start a new radio group
-            m_startRadioGroup = count;
+                if ( next->IsRadio() )
+                {
+                    // This item is the new starting item of this group as the
+                    // previous item is not a radio item.
+                    wxASSERT_MSG( next->IsRadioGroupStart(),
+                                  wxS("Where is the start of this group?") );
 
 
-            // for now it has just one element
-            item->SetAsRadioGroupStart();
-            item->SetRadioGroupEnd(m_startRadioGroup);
+                    // The index of the last item of the radio group must be
+                    // incremented to account for the new item.
+                    item->SetAsRadioGroupStart();
+                    item->SetRadioGroupEnd(next->GetRadioGroupEnd() + 1);
 
 
-            // ensure that we have a checked item in the radio group
-            check = true;
-        }
-        else // extend the current radio group
-        {
-            // we need to update its end item
-            item->SetRadioGroupStart(m_startRadioGroup);
-            wxMenuItemList::compatibility_iterator node = GetMenuItems().Item(m_startRadioGroup);
+                    // And the previous start item is not one any longer.
+                    next->SetAsRadioGroupStart(false);
 
 
-            if ( node )
-            {
-                node->GetData()->SetRadioGroupEnd(count);
+                    foundGroup = true;
+                }
             }
             }
-            else
+
+            if ( !foundGroup )
             {
             {
-                wxFAIL_MSG( _T("where is the radio group start item?") );
+                // start a new radio group
+                item->SetAsRadioGroupStart();
+                item->SetRadioGroupEnd(posItem);
+
+                // ensure that we have a checked item in the radio group
+                check = true;
             }
         }
             }
         }
+        else
+        {
+            if ( item->GetId() == idMenuTitle )
+                item->GetMenu()->Enable( idMenuTitle, false );
+        }
     }
     }
-    else // not a radio item
+
+    // We also need to update the indices of radio group start and end we store
+    // in any existing radio items after this item.
+    if ( pos < GetMenuItemCount() - 1 ) // takes into account pos == -1 case
     {
     {
-        EndRadioGroup();
+        for ( wxMenuItemList::compatibility_iterator
+                node = GetMenuItems().Item(pos + 1);
+                node;
+                node = node->GetNext() )
+        {
+            wxMenuItem* const item = node->GetData();
+            if ( item->IsRadio() )
+            {
+                if ( item->IsRadioGroupStart() )
+                {
+                    // If the starting item is after the just inserted one,
+                    // then the end one must be after it too and needs to be
+                    // updated.
+                    item->SetRadioGroupEnd(item->GetRadioGroupEnd() + 1);
+                }
+                else // Not the first radio group item.
+                {
+                    // We need to update the start item index only if it is
+                    // after the just inserted item.
+                    const int groupStart = item->GetRadioGroupStart();
+                    if ( (size_t)groupStart > pos )
+                        item->SetRadioGroupStart(groupStart + 1);
+                }
+            }
+        }
     }
 
     }
 
-    if ( !wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item) )
-        return NULL;
+    // if we're already attached to the menubar, we must update it
+    if ( IsAttached() && GetMenuBar()->IsAttached() )
+        GetMenuBar()->Refresh();
 
     if ( check )
 
     if ( check )
-        // check the item initially
         item->Check(true);
 
         item->Check(true);
 
-    return item;
+    return true ;
+}
+
+wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
+{
+    if (wxMenuBase::DoAppend(item) && DoInsertOrAppend(item) )
+        return item;
+
+    return NULL;
 }
 
 wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
 }
 
 wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
@@ -224,6 +257,36 @@ wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
 
 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
 {
 
 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
 {
+    if ( item->IsRadio() )
+    {
+        // Check if we're removing the item starting the radio group
+        if ( item->IsRadioGroupStart() )
+        {
+            // Yes, we do, update the next radio group item, if any, to be the
+            // start one now.
+            const int endGroup = item->GetRadioGroupEnd();
+
+            wxMenuItemList::compatibility_iterator
+                node = GetMenuItems().Item(endGroup);
+            wxASSERT_MSG( node, wxS("Should have valid radio group end") );
+
+            while ( node->GetData() != item )
+            {
+                const wxMenuItemList::compatibility_iterator
+                    prevNode = node->GetPrevious();
+                wxMenuItem* const prevItem = prevNode->GetData();
+                if ( prevItem == item )
+                {
+                    prevItem->SetAsRadioGroupStart();
+                    prevItem->SetRadioGroupEnd(endGroup);
+                    break;
+                }
+
+                node = prevNode;
+            }
+        }
+    }
+
 /*
     // we need to find the items position in the child list
     size_t pos;
 /*
     // we need to find the items position in the child list
     size_t pos;
@@ -242,7 +305,7 @@ wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
 
     wxOSXMenuRemoveItem(m_hMenu , pos );
     */
 
     wxOSXMenuRemoveItem(m_hMenu , pos );
     */
-    m_peer->Remove( item );
+    GetPeer()->Remove( item );
     // and from internal data structures
     return wxMenuBase::DoRemove(item);
 }
     // and from internal data structures
     return wxMenuBase::DoRemove(item);
 }
@@ -250,7 +313,7 @@ wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
 void wxMenu::SetTitle(const wxString& label)
 {
     m_title = label ;
 void wxMenu::SetTitle(const wxString& label)
 {
     m_title = label ;
-    m_peer->SetTitle( wxStripMenuCodes( label ) );
+    GetPeer()->SetTitle( wxStripMenuCodes( label ) );
 }
 
 bool wxMenu::ProcessCommand(wxCommandEvent & event)
 }
 
 bool wxMenu::ProcessCommand(wxCommandEvent & event)
@@ -263,7 +326,7 @@ bool wxMenu::ProcessCommand(wxCommandEvent & event)
 
     // Try the window the menu was popped up from
     // (and up through the hierarchy)
 
     // Try the window the menu was popped up from
     // (and up through the hierarchy)
-    wxWindow *win = GetInvokingWindow();
+    wxWindow *win = GetWindow();
     if ( !processed && win )
         processed = win->HandleWindowEvent(event);
 
     if ( !processed && win )
         processed = win->HandleWindowEvent(event);
 
@@ -274,16 +337,6 @@ bool wxMenu::ProcessCommand(wxCommandEvent & event)
 // other
 // ---------------------------------------------------------------------------
 
 // other
 // ---------------------------------------------------------------------------
 
-wxWindow *wxMenu::GetWindow() const
-{
-    if ( m_invokingWindow != NULL )
-        return m_invokingWindow;
-    else if ( GetMenuBar() != NULL)
-        return (wxWindow *) GetMenuBar()->GetFrame();
-
-    return NULL;
-}
-
 // MacOS needs to know about submenus somewhere within this menu
 // before it can be displayed, also hide special menu items
 // like preferences that are handled by the OS
 // MacOS needs to know about submenus somewhere within this menu
 // before it can be displayed, also hide special menu items
 // like preferences that are handled by the OS
@@ -291,7 +344,7 @@ void wxMenu::DoRearrange()
 {
     if ( !AllowRearrange() )
         return;
 {
     if ( !AllowRearrange() )
         return;
-        
+
     wxMenuItem* previousItem = NULL ;
     size_t pos ;
     wxMenuItemList::compatibility_iterator node;
     wxMenuItem* previousItem = NULL ;
     size_t pos ;
     wxMenuItemList::compatibility_iterator node;
@@ -329,7 +382,7 @@ void wxMenu::DoRearrange()
                 {
                     // next (i.e. second as we must be first) item is
                     // the separator to hide
                 {
                     // next (i.e. second as we must be first) item is
                     // the separator to hide
-                    wxASSERT_MSG( pos == 0, _T("should be the menu start") );
+                    wxASSERT_MSG( pos == 0, wxT("should be the menu start") );
                     sepToHide = next;
                 }
                 else if ( GetMenuItems().GetCount() == pos + 1 &&
                     sepToHide = next;
                 }
                 else if ( GetMenuItems().GetCount() == pos + 1 &&
@@ -361,8 +414,8 @@ void wxMenu::DoRearrange()
 
 bool wxMenu::HandleCommandUpdateStatus( wxMenuItem* item, wxWindow* senderWindow )
 {
 
 bool wxMenu::HandleCommandUpdateStatus( wxMenuItem* item, wxWindow* senderWindow )
 {
-    int id = item ? item->GetId() : 0;
-    wxUpdateUIEvent event(id);
+    int menuid = item ? item->GetId() : 0;
+    wxUpdateUIEvent event(menuid);
     event.SetEventObject( this );
 
     bool processed = false;
     event.SetEventObject( this );
 
     bool processed = false;
@@ -378,18 +431,9 @@ bool wxMenu::HandleCommandUpdateStatus( wxMenuItem* item, wxWindow* senderWindow
     // (and up through the hierarchy)
     if ( !processed )
     {
     // (and up through the hierarchy)
     if ( !processed )
     {
-        const wxMenuBase *menu = this;
-        while ( menu )
-        {
-            wxWindow *win = menu->GetInvokingWindow();
-            if ( win )
-            {
-                processed = win->HandleWindowEvent(event);
-                break;
-            }
-
-            menu = menu->GetParent();
-        }
+        wxWindow *win = GetWindow();
+        if ( win )
+            processed = win->HandleWindowEvent(event);
     }
 
     if ( !processed && senderWindow != NULL)
     }
 
     if ( !processed && senderWindow != NULL)
@@ -401,56 +445,98 @@ bool wxMenu::HandleCommandUpdateStatus( wxMenuItem* item, wxWindow* senderWindow
     {
         // if anything changed, update the changed attribute
         if (event.GetSetText())
     {
         // if anything changed, update the changed attribute
         if (event.GetSetText())
-            SetLabel(id, event.GetText());
+            SetLabel(menuid, event.GetText());
         if (event.GetSetChecked())
         if (event.GetSetChecked())
-            Check(id, event.GetChecked());
+            Check(menuid, event.GetChecked());
         if (event.GetSetEnabled())
         if (event.GetSetEnabled())
-            Enable(id, event.GetEnabled());
+            Enable(menuid, event.GetEnabled());
     }
     }
+    else
+    {
+#if wxOSX_USE_CARBON
+        // these two items are also managed by the Carbon Menu Manager, therefore we must
+        // always reset them ourselves
+        UInt32 cmd = 0;
+
+        if ( menuid == wxApp::s_macExitMenuItemId )
+        {
+            cmd = kHICommandQuit;
+        }
+        else if (menuid == wxApp::s_macPreferencesMenuItemId )
+        {
+            cmd = kHICommandPreferences;
+        }
+
+        if ( cmd != 0 )
+        {
+            if ( !item->IsEnabled() || wxDialog::OSXHasModalDialogsOpen() )
+                DisableMenuCommand( NULL , cmd ) ;
+            else
+                EnableMenuCommand( NULL , cmd ) ;
+
+        }
+#endif
+    }
+
     return processed;
 }
 
 bool wxMenu::HandleCommandProcess( wxMenuItem* item, wxWindow* senderWindow )
 {
     return processed;
 }
 
 bool wxMenu::HandleCommandProcess( wxMenuItem* item, wxWindow* senderWindow )
 {
-    int id = item ? item->GetId() : 0;
+    int menuid = item ? item->GetId() : 0;
     bool processed = false;
     if (item->IsCheckable())
         item->Check( !item->IsChecked() ) ;
 
     bool processed = false;
     if (item->IsCheckable())
         item->Check( !item->IsChecked() ) ;
 
-    if ( SendEvent( id , item->IsCheckable() ? item->IsChecked() : -1 ) )
+    if ( SendEvent( menuid , item->IsCheckable() ? item->IsChecked() : -1 ) )
         processed = true ;
     else
     {
         if ( senderWindow != NULL )
         {
         processed = true ;
     else
     {
         if ( senderWindow != NULL )
         {
-            wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED , id);
-            event.SetEventObject(senderWindow);
+            wxCommandEvent event(wxEVT_MENU , menuid);
+            event.SetEventObject(this);
             event.SetInt(item->IsCheckable() ? item->IsChecked() : -1);
 
             if ( senderWindow->HandleWindowEvent(event) )
                 processed = true ;
         }
     }
             event.SetInt(item->IsCheckable() ? item->IsChecked() : -1);
 
             if ( senderWindow->HandleWindowEvent(event) )
                 processed = true ;
         }
     }
+
+    if(!processed && item)
+    {
+        processed = item->GetPeer()->DoDefault();  
+    }
+    
     return processed;
 }
 
 void wxMenu::HandleMenuItemHighlighted( wxMenuItem* item )
 {
     return processed;
 }
 
 void wxMenu::HandleMenuItemHighlighted( wxMenuItem* item )
 {
-    int id = item ? item->GetId() : 0;
-    wxMenuEvent wxevent(wxEVT_MENU_HIGHLIGHT, id, this);
+    int menuid = item ? item->GetId() : 0;
+    wxMenuEvent wxevent(wxEVT_MENU_HIGHLIGHT, menuid, this);
     DoHandleMenuEvent( wxevent );
 }
 
     DoHandleMenuEvent( wxevent );
 }
 
-void wxMenu::HandleMenuOpened()
+void wxMenu::DoHandleMenuOpenedOrClosed(wxEventType evtType)
 {
 {
-    wxMenuEvent wxevent(wxEVT_MENU_OPEN, 0, this);
+    // Popup menu being currently shown or NULL, defined in wincmn.cpp.
+    extern wxMenu *wxCurrentPopupMenu;
+
+    // Set the id to allow wxMenuEvent::IsPopup() to work correctly.
+    int menuid = this == wxCurrentPopupMenu ? wxID_ANY : 0;
+    wxMenuEvent wxevent(evtType, menuid, this);
     DoHandleMenuEvent( wxevent );
 }
 
     DoHandleMenuEvent( wxevent );
 }
 
+void wxMenu::HandleMenuOpened()
+{
+    DoHandleMenuOpenedOrClosed(wxEVT_MENU_OPEN);
+}
+
 void wxMenu::HandleMenuClosed()
 {
 void wxMenu::HandleMenuClosed()
 {
-    wxMenuEvent wxevent(wxEVT_MENU_CLOSE, 0, this);
-    DoHandleMenuEvent( wxevent );
+    DoHandleMenuOpenedOrClosed(wxEVT_MENU_CLOSE);
 }
 
 bool wxMenu::DoHandleMenuEvent(wxEvent& wxevent)
 }
 
 bool wxMenu::DoHandleMenuEvent(wxEvent& wxevent)
@@ -463,7 +549,7 @@ bool wxMenu::DoHandleMenuEvent(wxEvent& wxevent)
     }
     else
     {
     }
     else
     {
-        wxWindow *win = GetInvokingWindow();
+        wxWindow *win = GetWindow();
         if (win)
         {
             if ( win->HandleWindowEvent(wxevent) )
         if (win)
         {
             if ( win->HandleWindowEvent(wxevent) )
@@ -497,24 +583,82 @@ wxMenuBar* wxMenuBar::s_macCommonMenuBar = NULL ;
 bool     wxMenuBar::s_macAutoWindowMenu = true ;
 WXHMENU  wxMenuBar::s_macWindowMenuHandle = NULL ;
 
 bool     wxMenuBar::s_macAutoWindowMenu = true ;
 WXHMENU  wxMenuBar::s_macWindowMenuHandle = NULL ;
 
+
+wxMenu* emptyMenuBar = NULL;
+
+const int firstMenuPos = 1; // to account for the 0th application menu on mac
+
 void wxMenuBar::Init()
 {
 void wxMenuBar::Init()
 {
+    if ( emptyMenuBar == NULL )
+    {
+        emptyMenuBar = new wxMenu();
+        
+        wxMenu* appleMenu = new wxMenu();
+        appleMenu->SetAllowRearrange(false);
+#if !wxOSX_USE_CARBON
+        // standard menu items, handled in wxMenu::HandleCommandProcess(), see above:
+        wxString hideLabel;
+        hideLabel = wxString::Format(_("Hide %s"), wxTheApp ? wxTheApp->GetAppDisplayName() : _("Application"));
+        appleMenu->Append( wxID_OSX_HIDE, hideLabel + "\tCtrl+H" );
+        appleMenu->Append( wxID_OSX_HIDEOTHERS, _("Hide Others")+"\tAlt+Ctrl+H" );
+        appleMenu->Append( wxID_OSX_SHOWALL, _("Show All") );
+        appleMenu->AppendSeparator();
+        
+        // Do always add "Quit" item unconditionally however, it can't be disabled.
+        wxString quitLabel;
+        quitLabel = wxString::Format(_("Quit %s"), wxTheApp ? wxTheApp->GetAppDisplayName() : _("Application"));
+        appleMenu->Append( wxApp::s_macExitMenuItemId, quitLabel + "\tCtrl+Q" );
+#endif // !wxOSX_USE_CARBON
+
+        emptyMenuBar->AppendSubMenu(appleMenu, "\x14") ;
+    }
+    
     m_eventHandler = this;
     m_menuBarFrame = NULL;
     m_eventHandler = this;
     m_menuBarFrame = NULL;
-    m_invokingWindow = NULL;
     m_rootMenu = new wxMenu();
     m_rootMenu = new wxMenu();
-    wxMenu* applemenu = new wxMenu();
-    applemenu->SetAllowRearrange(false);
-    applemenu->Append( wxApp::s_macAboutMenuItemId, "About..." );
-    applemenu->AppendSeparator();
-    applemenu->Append( wxApp::s_macPreferencesMenuItemId, "Preferences..." );
-    applemenu->AppendSeparator();
+    m_rootMenu->Attach(this);
+
+    m_appleMenu = new wxMenu();
+    m_appleMenu->SetAllowRearrange(false);
+
+    // Create standard items unless the application explicitly disabled this by
+    // setting the corresponding ids to wxID_NONE: although this is not
+    // recommended, sometimes these items really don't make sense.
+    if ( wxApp::s_macAboutMenuItemId != wxID_NONE )
+    {
+        wxString aboutLabel(_("About"));
+        if ( wxTheApp )
+            aboutLabel << ' ' << wxTheApp->GetAppDisplayName();
+        else
+            aboutLabel << "...";
+        m_appleMenu->Append( wxApp::s_macAboutMenuItemId, aboutLabel);
+        m_appleMenu->AppendSeparator();
+    }
+
+#if !wxOSX_USE_CARBON
+    if ( wxApp::s_macPreferencesMenuItemId != wxID_NONE )
+    {
+        m_appleMenu->Append( wxApp::s_macPreferencesMenuItemId,
+                             _("Preferences...") + "\tCtrl+," );
+        m_appleMenu->AppendSeparator();
+    }
+
+    // standard menu items, handled in wxMenu::HandleCommandProcess(), see above:
+    wxString hideLabel;
+    hideLabel = wxString::Format(_("Hide %s"), wxTheApp ? wxTheApp->GetAppDisplayName() : _("Application"));
+    m_appleMenu->Append( wxID_OSX_HIDE, hideLabel + "\tCtrl+H" );    
+    m_appleMenu->Append( wxID_OSX_HIDEOTHERS, _("Hide Others")+"\tAlt+Ctrl+H" );    
+    m_appleMenu->Append( wxID_OSX_SHOWALL, _("Show All") );    
+    m_appleMenu->AppendSeparator();
     
     
-#if ! wxOSX_USE_CARBON
-    applemenu->Append( wxApp::s_macExitMenuItemId, "Quit\tCtrl+Q" );
-#endif
+    // Do always add "Quit" item unconditionally however, it can't be disabled.
+    wxString quitLabel;
+    quitLabel = wxString::Format(_("Quit %s"), wxTheApp ? wxTheApp->GetAppDisplayName() : _("Application"));
+    m_appleMenu->Append( wxApp::s_macExitMenuItemId, quitLabel + "\tCtrl+Q" );
+#endif // !wxOSX_USE_CARBON
 
 
-    m_rootMenu->AppendSubMenu(applemenu, "\x14") ;
+    m_rootMenu->AppendSubMenu(m_appleMenu, "\x14") ;
 }
 
 wxMenuBar::wxMenuBar()
 }
 
 wxMenuBar::wxMenuBar()
@@ -531,12 +675,9 @@ wxMenuBar::wxMenuBar(size_t count, wxMenu *menus[], const wxString titles[], lon
 {
     Init();
 
 {
     Init();
 
-    m_titles.Alloc(count);
-
     for ( size_t i = 0; i < count; i++ )
     {
         m_menus.Append(menus[i]);
     for ( size_t i = 0; i < count; i++ )
     {
         m_menus.Append(menus[i]);
-        m_titles.Add(titles[i]);
 
         menus[i]->Attach(this);
         Append( menus[i], titles[i] );
 
         menus[i]->Attach(this);
         Append( menus[i], titles[i] );
@@ -550,8 +691,16 @@ wxMenuBar::~wxMenuBar()
 
     if (s_macInstalledMenuBar == this)
     {
 
     if (s_macInstalledMenuBar == this)
     {
+        emptyMenuBar->GetPeer()->MakeRoot();
         s_macInstalledMenuBar = NULL;
     }
         s_macInstalledMenuBar = NULL;
     }
+    wxDELETE( m_rootMenu );
+    // apple menu is a submenu, therefore we don't have to delete it
+    m_appleMenu = NULL;
+
+    // deleting the root menu also removes all its wxMenu* submenus, therefore
+    // we must avoid double deleting them in the superclass destructor
+    m_menus.clear();
 }
 
 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
 }
 
 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
@@ -563,29 +712,38 @@ void wxMenuBar::MacInstallMenuBar()
 {
     if ( s_macInstalledMenuBar == this )
         return ;
 {
     if ( s_macInstalledMenuBar == this )
         return ;
-        
-    m_rootMenu->GetPeer()->MakeRoot();
-#if 0
 
 
-    MenuBarHandle menubar = NULL ;
-
-    menubar = NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
-
-    ::SetMenuBar( menubar ) ;
-    DisposeMenuBar( menubar ) ;
-    MenuHandle appleMenu = NULL ;
-
-    verify_noerr( CreateNewMenu( kwxMacAppleMenuId , 0 , &appleMenu ) ) ;
-    verify_noerr( SetMenuTitleWithCFString( appleMenu , CFSTR( "\x14" ) ) );
+    m_rootMenu->GetPeer()->MakeRoot();
+    
+    // hide items in the apple menu that don't exist in the wx menubar
+    
+    wxMenuItem* appleItem = NULL;
+    wxMenuItem* wxItem = NULL;
 
 
-    // Add About/Preferences separator only on OS X
-    // KH/RN: Separator is always present on 10.3 but not on 10.2
-    // However, the change from 10.2 to 10.3 suggests it is preferred
-    InsertMenuItemTextWithCFString( appleMenu,
-                CFSTR(""), 0, kMenuItemAttrSeparator, 0);
-    InsertMenuItemTextWithCFString( appleMenu,
-                CFSTR("About..."), 0, 0, 0);
-    MacInsertMenu( appleMenu , 0 ) ;
+    int menuid = wxApp::s_macAboutMenuItemId;
+    appleItem = m_appleMenu->FindItem(menuid);
+    wxItem = FindItem(menuid);
+    if ( appleItem != NULL )
+    {
+        if ( wxItem == NULL )
+            appleItem->GetPeer()->Hide();
+        else 
+            appleItem->SetItemLabel(wxItem->GetItemLabel());
+    }
+    
+    menuid = wxApp::s_macPreferencesMenuItemId;
+    appleItem = m_appleMenu->FindItem(menuid);
+    wxItem = FindItem(menuid);
+    if ( appleItem != NULL )
+    {
+        if ( wxItem == NULL )
+            appleItem->GetPeer()->Hide();
+        else 
+            appleItem->SetItemLabel(wxItem->GetItemLabel());
+    }
+    
+        
+#if 0
 
     // if we have a mac help menu, clean it up before adding new items
     MenuHandle helpMenuHandle ;
 
     // if we have a mac help menu, clean it up before adding new items
     MenuHandle helpMenuHandle ;
@@ -641,7 +799,9 @@ void wxMenuBar::MacInstallMenuBar()
                 subMenu = item->GetSubMenu() ;
                 if (subMenu)
                 {
                 subMenu = item->GetSubMenu() ;
                 if (subMenu)
                 {
-                    // we don't support hierarchical menus in the help menu yet
+                    UMAAppendMenuItem(mh, wxStripMenuCodes(item->GetText()) , wxFont::GetDefaultEncoding() );
+                    MenuItemIndex position = CountMenuItems(mh);
+                    ::SetMenuItemHierarchicalMenu(mh, position, MAC_WXHMENU(subMenu->GetHMenu()));
                 }
                 else
                 {
                 }
                 else
                 {
@@ -725,7 +885,7 @@ void wxMenuBar::MacInstallMenuBar()
             UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i], GetFont().GetEncoding()  ) ;
             menu->MacBeforeDisplay(false) ;
 
             UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i], GetFont().GetEncoding()  ) ;
             menu->MacBeforeDisplay(false) ;
 
-            ::InsertMenu(MAC_WXHMENU(_wxMenuAt(m_menus, i)->GetHMenu()), 0);
+            ::InsertMenu(MAC_WXHMENU(GetMenu(i)->GetHMenu()), 0);
         }
     }
 
         }
     }
 
@@ -763,12 +923,23 @@ void wxMenuBar::MacInstallMenuBar()
 void wxMenuBar::EnableTop(size_t pos, bool enable)
 {
     wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
 void wxMenuBar::EnableTop(size_t pos, bool enable)
 {
     wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
-    
-    m_rootMenu->FindItemByPosition( pos )->Enable(enable);
+
+    m_rootMenu->FindItemByPosition(pos+firstMenuPos)->Enable(enable);
 
     Refresh();
 }
 
 
     Refresh();
 }
 
+bool wxMenuBar::IsEnabledTop(size_t pos) const
+{
+    wxCHECK_MSG( IsAttached(), true,
+                 wxT("doesn't work with unattached menubars") );
+
+    wxMenuItem* const item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
+    wxCHECK_MSG( item, false, wxT("invalid menu index") );
+
+    return item->IsEnabled();
+}
+
 bool wxMenuBar::Enable(bool enable)
 {
     wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
 bool wxMenuBar::Enable(bool enable)
 {
     wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
@@ -784,12 +955,7 @@ void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label)
 {
     wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
 
 {
     wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
 
-    m_titles[pos] = label;
-
-    if ( !IsAttached() )
-        return;
-
-    _wxMenuAt(m_menus, pos)->SetTitle( label ) ;
+    GetMenu(pos)->SetTitle( label ) ;
 }
 
 wxString wxMenuBar::GetMenuLabel(size_t pos) const
 }
 
 wxString wxMenuBar::GetMenuLabel(size_t pos) const
@@ -797,45 +963,23 @@ wxString wxMenuBar::GetMenuLabel(size_t pos) const
     wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
                  wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
 
     wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
                  wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
 
-    return m_titles[pos];
-}
-
-int wxMenuBar::FindMenu(const wxString& title)
-{
-    wxString menuTitle = wxStripMenuCodes(title);
-
-    size_t count = GetMenuCount();
-    for ( size_t i = 0; i < count; i++ )
-    {
-        wxString title = wxStripMenuCodes(m_titles[i]);
-        if ( menuTitle == title )
-            return i;
-    }
-
-    return wxNOT_FOUND;
+    return GetMenu(pos)->GetTitle();
 }
 
 // ---------------------------------------------------------------------------
 // wxMenuBar construction
 // ---------------------------------------------------------------------------
 
 }
 
 // ---------------------------------------------------------------------------
 // wxMenuBar construction
 // ---------------------------------------------------------------------------
 
-const int firstMenuPos = 1; // to account for the 0th application menu on mac
-
 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
 {
     wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
     if ( !menuOld )
         return NULL;
 
 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
 {
     wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
     if ( !menuOld )
         return NULL;
 
-    m_titles[pos] = title;
-
     wxMenuItem* item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
     m_rootMenu->Remove(item);
     m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
 
     wxMenuItem* item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
     m_rootMenu->Remove(item);
     m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
 
-    if (m_invokingWindow)
-        wxMenubarSetInvokingWindow( menu, m_invokingWindow );
-
     return menuOld;
 }
 
     return menuOld;
 }
 
@@ -844,12 +988,8 @@ bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
     if ( !wxMenuBarBase::Insert(pos, menu, title) )
         return false;
 
     if ( !wxMenuBarBase::Insert(pos, menu, title) )
         return false;
 
-    m_titles.Insert(title, pos);
-    
     m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
     m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
-
-    if (m_invokingWindow)
-        wxMenubarSetInvokingWindow( menu, m_invokingWindow );
+    menu->SetTitle(title);
 
     return true;
 }
 
     return true;
 }
@@ -863,8 +1003,6 @@ wxMenu *wxMenuBar::Remove(size_t pos)
     wxMenuItem* item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
     m_rootMenu->Remove(item);
 
     wxMenuItem* item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
     m_rootMenu->Remove(item);
 
-    m_titles.RemoveAt(pos);
-
     return menu;
 }
 
     return menu;
 }
 
@@ -876,79 +1014,12 @@ bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
     if ( !wxMenuBarBase::Append(menu, title) )
         return false;
 
     if ( !wxMenuBarBase::Append(menu, title) )
         return false;
 
-    m_titles.Add(title);
-
     m_rootMenu->AppendSubMenu(menu, title);
     m_rootMenu->AppendSubMenu(menu, title);
-
-    // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
-    // adding menu later on.
-    if (m_invokingWindow)
-        wxMenubarSetInvokingWindow( menu, m_invokingWindow );
+    menu->SetTitle(title);
 
     return true;
 }
 
 
     return true;
 }
 
-static void wxMenubarUnsetInvokingWindow( wxMenu *menu )
-{
-    menu->SetInvokingWindow( NULL );
-    wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
-
-    while (node)
-    {
-        wxMenuItem *menuitem = node->GetData();
-        if (menuitem->IsSubMenu())
-            wxMenubarUnsetInvokingWindow( menuitem->GetSubMenu() );
-
-        node = node->GetNext();
-    }
-}
-
-static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win )
-{
-    menu->SetInvokingWindow( win );
-    wxMenuItem *menuitem;
-    wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
-
-    while (node)
-    {
-        menuitem = node->GetData();
-        if (menuitem->IsSubMenu())
-            wxMenubarSetInvokingWindow( menuitem->GetSubMenu() , win );
-
-        node = node->GetNext();
-    }
-}
-
-void wxMenuBar::UnsetInvokingWindow()
-{
-    m_invokingWindow = NULL;
-    wxMenu *menu;
-    wxMenuList::compatibility_iterator node = m_menus.GetFirst();
-
-    while (node)
-    {
-        menu = node->GetData();
-        wxMenubarUnsetInvokingWindow( menu );
-
-        node = node->GetNext();
-    }
-}
-
-void wxMenuBar::SetInvokingWindow(wxFrame *frame)
-{
-    m_invokingWindow = frame;
-    wxMenu *menu;
-    wxMenuList::compatibility_iterator node = m_menus.GetFirst();
-
-    while (node)
-    {
-        menu = node->GetData();
-        wxMenubarSetInvokingWindow( menu, frame );
-
-        node = node->GetNext();
-    }
-}
-
 void wxMenuBar::Detach()
 {
     wxMenuBarBase::Detach() ;
 void wxMenuBar::Detach()
 {
     wxMenuBarBase::Detach() ;
@@ -959,35 +1030,4 @@ void wxMenuBar::Attach(wxFrame *frame)
     wxMenuBarBase::Attach( frame ) ;
 }
 
     wxMenuBarBase::Attach( frame ) ;
 }
 
-// ---------------------------------------------------------------------------
-// wxMenuBar searching for menu items
-// ---------------------------------------------------------------------------
-
-// Find the itemString in menuString, and return the item id or wxNOT_FOUND
-int wxMenuBar::FindMenuItem(const wxString& menuString,
-                            const wxString& itemString) const
-{
-    wxString menuLabel = wxStripMenuCodes(menuString);
-    size_t count = GetMenuCount();
-    for ( size_t i = 0; i < count; i++ )
-    {
-        wxString title = wxStripMenuCodes(m_titles[i]);
-        if ( menuLabel == title )
-            return _wxMenuAt(m_menus, i)->FindItem(itemString);
-    }
-
-    return wxNOT_FOUND;
-}
-
-wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
-{
-    if ( itemMenu )
-        *itemMenu = NULL;
-
-    wxMenuItem *item = NULL;
-    size_t count = GetMenuCount();
-    for ( size_t i = 0; !item && (i < count); i++ )
-        item = _wxMenuAt(m_menus, i)->FindItem(id, itemMenu);
-
-    return item;
-}
+#endif // wxUSE_MENUS