]> git.saurik.com Git - wxWidgets.git/blobdiff - src/mac/carbon/menu.cpp
#include "wx/settings.h" wxSystemSettings is needed by non-OSX code.
[wxWidgets.git] / src / mac / carbon / menu.cpp
index 476a45c477f354316e11c3257768ff918f98587b..841f2815ec45a1de14744a36fb4bc227c860fd37 100644 (file)
@@ -41,12 +41,42 @@ IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
 #endif
 
 // the (popup) menu title has this special id
-static const int idMenuTitle = -2;
+static const int idMenuTitle = -3;
 static MenuItemIndex firstUserHelpMenuItem = 0 ;
 
 const short kwxMacMenuBarResource = 1 ;
 const short kwxMacAppleMenuId = 1 ;
 
+
+// Find an item given the Macintosh Menu Reference
+
+wxList wxWinMacMenuList(wxKEY_INTEGER);
+wxMenu *wxFindMenuFromMacMenu(MenuRef inMenuRef)
+{
+    wxNode *node = wxWinMacMenuList.Find((long)inMenuRef);
+    if (!node)
+        return NULL;
+    return (wxMenu *)node->GetData();
+}
+
+void wxAssociateMenuWithMacMenu(MenuRef inMenuRef, wxMenu *menu) ;
+void wxAssociateMenuWithMacMenu(MenuRef inMenuRef, wxMenu *menu)
+{
+    // adding NULL MenuRef is (first) surely a result of an error and
+    // (secondly) breaks menu command processing
+    wxCHECK_RET( inMenuRef != (MenuRef) NULL, wxT("attempt to add a NULL MenuRef to menu list") );
+
+    if ( !wxWinMacMenuList.Find((long)inMenuRef) )
+        wxWinMacMenuList.Append((long)inMenuRef, menu);
+}
+
+void wxRemoveMacMenuAssociation(wxMenu *menu) ;
+void wxRemoveMacMenuAssociation(wxMenu *menu)
+{
+    wxWinMacMenuList.DeleteObject(menu);
+}
+
+
 // ============================================================================
 // implementation
 // ============================================================================
@@ -77,6 +107,8 @@ void wxMenu::Init()
         wxLogLastError(wxT("UMANewMenu failed"));
     }
 
+    wxAssociateMenuWithMacMenu( (MenuRef)m_hMenu , this ) ;
+
     // if we have a title, insert it in the beginning of the menu
     if ( !!m_title )
     {
@@ -87,6 +119,7 @@ void wxMenu::Init()
 
 wxMenu::~wxMenu()
 {
+    wxRemoveMacMenuAssociation( this ) ;
     if (MAC_WXHMENU(m_hMenu))
         ::DisposeMenu(MAC_WXHMENU(m_hMenu));
 }
@@ -153,6 +186,7 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
             }
 
             SetMenuItemCommandID( MAC_WXHMENU(m_hMenu) , pos , pItem->GetId() ) ;
+            SetMenuItemRefCon( MAC_WXHMENU(m_hMenu) , pos , (UInt32) pItem ) ;
             pItem->UpdateItemText() ;
             pItem->UpdateItemBitmap() ;
             pItem->UpdateItemStatus() ;
@@ -372,23 +406,64 @@ void wxMenu::MacBeforeDisplay( bool isSubMenu )
         {
             subMenu->MacBeforeDisplay( true ) ;
         }
-        else
+        else // normal item
         {
             #if TARGET_CARBON
             if ( UMAGetSystemVersion() >= 0x1000 )
             {
-                if ( item->GetId() == wxApp::s_macPreferencesMenuItemId || item->GetId() == wxApp::s_macExitMenuItemId)
+                // what we do here is to hide the special items which are
+                // shown in the application menu anyhow -- it doesn't make
+                // sense to show them in their normal place as well
+                if ( item->GetId() == wxApp::s_macPreferencesMenuItemId ||
+                        item->GetId() == wxApp::s_macExitMenuItemId )
                 {
-                    ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ) , pos + 1, kMenuItemAttrHidden, 0 );
-                    if ( GetMenuItems().GetCount() == pos + 1 &&
-                            previousItem != NULL &&
-                                previousItem->IsSeparator() )
+                    ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
+                                              pos + 1, kMenuItemAttrHidden, 0 );
+
+                    // also check for a separator which was used just to
+                    // separate this item from the others, so don't leave
+                    // separator at the menu start or end nor 2 consecutive
+                    // separators
+                    wxMenuItemList::Node *nextNode = node->GetNext();
+                    wxMenuItem *next = nextNode ? nextNode->GetData() : NULL;
+
+                    size_t posSeptoHide;
+                    if ( !previousItem && next && next->IsSeparator() )
                     {
-                        ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ) , pos , kMenuItemAttrHidden, 0 );
+                        // 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") );
+                        posSeptoHide = 2;
+                    }
+                    else if ( GetMenuItems().GetCount() == pos + 1 &&
+                                previousItem != NULL &&
+                                    previousItem->IsSeparator() )
+                    {
+                        // prev item is a trailing separator we want to hide
+                        posSeptoHide = pos;
+                    }
+                    else if ( previousItem && previousItem->IsSeparator() &&
+                                next && next->IsSeparator() )
+                    {
+                        // two consecutive separators, this is one too many
+                        posSeptoHide = pos;
+                    }
+                    else // no separators to hide
+                    {
+                        posSeptoHide = 0;
+                    }
+
+                    if ( posSeptoHide )
+                    {
+                        // hide the separator as well
+                        ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ),
+                                                  posSeptoHide,
+                                                  kMenuItemAttrHidden,
+                                                  0 );
                     }
                 }
             }
-            #endif
+            #endif // TARGET_CARBON
         }
         previousItem = item ;
     }
@@ -502,8 +577,6 @@ void wxMenuBar::MacInstallMenuBar()
     if ( s_macInstalledMenuBar == this )
         return ;
 
-    wxStAppResource resload ;
-
     MenuBarHandle menubar = NULL ;
 #if TARGET_API_MAC_OSX
     menubar = NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
@@ -518,6 +591,14 @@ void wxMenuBar::MacInstallMenuBar()
 
     verify_noerr( CreateNewMenu( kwxMacAppleMenuId , 0 , &appleMenu ) ) ;
     verify_noerr( SetMenuTitle( appleMenu , (ConstStr255Param) appleMenuTitle ) );
+
+    // 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
+#if TARGET_API_MAC_OSX
+    MacInsertMenuItem( appleMenu , "\p-" , 0 ) ;
+#endif
+
     MacInsertMenuItem( appleMenu , "\pAbout..." , 0 ) ;
     MacInsertMenu( appleMenu , 0 ) ;
 
@@ -582,6 +663,7 @@ void wxMenuBar::MacInstallMenuBar()
                                 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetText() , wxFont::GetDefaultEncoding() );
                                 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
                                 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetId() ) ;
+                                SetMenuItemRefCon(GetMenuHandle( kwxMacAppleMenuId ) , 1 , (UInt32)item ) ;
                                 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
                          }
                         else
@@ -590,6 +672,7 @@ void wxMenuBar::MacInstallMenuBar()
                             {
                                 UMAAppendMenuItem(mh, item->GetText()  , wxFont::GetDefaultEncoding(), entry);
                                 SetMenuItemCommandID( mh , CountMenuItems(mh) , item->GetId() ) ;
+                                SetMenuItemRefCon( mh , CountMenuItems(mh) , (UInt32)item ) ;
                             }
                         }
 
@@ -708,6 +791,8 @@ wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
 
         Refresh();
     }
+    if (m_invokingWindow)
+        wxMenubarSetInvokingWindow( menu, m_invokingWindow );
 
     return menuOld;
 }
@@ -737,6 +822,8 @@ bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
         }
         Refresh();
     }
+    if (m_invokingWindow)
+        wxMenubarSetInvokingWindow( menu, m_invokingWindow );
 
     return TRUE;
 }
@@ -784,7 +871,7 @@ bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
         Refresh();
     }
 
-   // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
+    // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
     // adding menu later on.
     if (m_invokingWindow)
         wxMenubarSetInvokingWindow( menu, m_invokingWindow );