]> git.saurik.com Git - wxWidgets.git/blobdiff - src/cocoa/mbarman.mm
implement wxListCtrl::GetSubItemRect() for generic version and fix bug in it in wxMSW...
[wxWidgets.git] / src / cocoa / mbarman.mm
index c6cf916e646cdf001e7fb582310cb9068c179cc5..4a1cdec7fbf850b49552a83ae78ab8975a200984 100644 (file)
@@ -6,7 +6,7 @@
 // Created:     2003/09/04
 // RCS-ID:      $Id$
 // Copyright:   (c) 2003 David Elliott
-// Licence:     wxWindows licence
+// Licence:     wxWidgets licence
 /////////////////////////////////////////////////////////////////////////////
 
 #include "wx/wxprec.h"
@@ -20,6 +20,7 @@
 
 #include "wx/cocoa/mbarman.h"
 #include "wx/cocoa/autorelease.h"
+#include "wx/cocoa/objc/objc_uniquifying.h"
 
 #import <Foundation/NSString.h>
 #import <Foundation/NSNotification.h>
 #import <AppKit/NSApplication.h>
 #import <AppKit/NSWindow.h>
 
+#ifndef wxUSE_FSCRIPT
+#define wxUSE_FSCRIPT 0
+#endif
+
+#if wxUSE_FSCRIPT
+    #import <FScript/FScriptMenuItem.h>
+#endif
+
+// Declare setAppleMenu: in an NSApplication category since Tiger and later
+// releases support it but don't declare it as it's considered deprecated.
+@interface NSApplication(wxDeprecatedMethodsWeWantToUse)
+- (void)setAppleMenu:(NSMenu *)menu;
+@end
+
 // ============================================================================
 // wxMenuBarManagerObserver
 // ============================================================================
 - (void)windowWillClose: (NSNotification *)notification;
 #endif // 0
 @end // interface wxMenuBarManagerObserver : NSObject
+WX_DECLARE_GET_OBJC_CLASS(wxMenuBarManagerObserver,NSObject)
 
 @implementation wxMenuBarManagerObserver : NSObject
 - (id)init
 {
-    wxFAIL_MSG("[wxMenuBarManagerObserver -init] should never be called!");
+    wxFAIL_MSG(wxT("[wxMenuBarManagerObserver -init] should never be called!"));
     m_mbarman = NULL;
     return self;
 }
 #endif // 0
 
 @end // implementation wxMenuBarManagerObserver : NSObject
+WX_IMPLEMENT_GET_OBJC_CLASS(wxMenuBarManagerObserver,NSObject)
 
 // ============================================================================
 // wxMenuBarManager
 // ============================================================================
 wxMenuBarManager *wxMenuBarManager::sm_mbarmanInstance = NULL;
 
+static void AddFScriptItem(NSMenu *menu)
+#if wxUSE_FSCRIPT
+{
+    NSMenuItem *item = [[FScriptMenuItem alloc] init];
+    [menu addItem: item];
+    [item release];
+}
+#else
+{}
+#endif
+
 wxMenuBarManager::wxMenuBarManager()
 {
-    m_observer = [[wxMenuBarManagerObserver alloc]
+    m_observer = [[WX_GET_OBJC_CLASS(wxMenuBarManagerObserver) alloc]
             initWithWxMenuBarManager:this];
     [[NSNotificationCenter defaultCenter] addObserver:m_observer
             selector:@selector(windowDidBecomeKey:)
             name:NSWindowDidBecomeKeyNotification object:nil];
+
+    // HACK: Reuse the same selector and eventual C++ method and make it
+    // check for whether the notification is to become key or main.
+    [[NSNotificationCenter defaultCenter] addObserver:m_observer
+            selector:@selector(windowDidBecomeKey:)
+            name:NSWindowDidBecomeMainNotification object:nil];
 #if 0
     [[NSNotificationCenter defaultCenter] addObserver:m_observer
             selector:@selector(windowDidResignKey:)
@@ -127,7 +161,7 @@ wxMenuBarManager::wxMenuBarManager()
     m_menuMain = nil;
     m_mainMenuBarInstalled = true;
     m_mainMenuBar = NULL;
-    m_windowCurrent = NULL;
+    m_currentNSWindow = nil;
 
     NSApplication *theNSApplication = wxTheApp->GetNSApplication();
     // Create the services menu.
@@ -140,6 +174,7 @@ wxMenuBarManager::wxMenuBarManager()
 
 /**/[m_menuApp addItemWithTitle:@"Preferences..." action:nil keyEquivalent:@""];
 /**/[m_menuApp addItem: [NSMenuItem separatorItem]];
+/**/AddFScriptItem(m_menuApp);
 /**/menuitem = [[NSMenuItem alloc] initWithTitle: @"Services" action:nil keyEquivalent:@""];
     [menuitem setSubmenu:m_menuServices];
     [m_menuApp addItem: menuitem];
@@ -243,7 +278,82 @@ void wxMenuBarManager::InstallMainMenu()
 
 void wxMenuBarManager::WindowDidBecomeKey(NSNotification *notification)
 {
-    wxCocoaNSWindow *win = wxCocoaNSWindow::GetFromCocoa([notification object]);
+    /* NOTE: m_currentNSWindow might be destroyed but we only ever use it
+       to look it up in the hash table.  Do not send messages to it. */
+
+    /*  Update m_currentNSWindow only if we really should.  For instance,
+        if a non-wx window is becoming key but a wx window remains main
+        then don't change out the menubar.  However, if a non-wx window
+        (whether the same window or not) is main, then switch to the
+        generic menubar so the wx window that last installed a menubar
+        doesn't get menu events it doesn't expect.
+
+        If a wx window is becoming main then check to see if the key
+        window is a wx window and if so do nothing because that
+        is what would have been done before.
+
+        If a non-wx window is becoming main and 
+     */
+    NSString *notificationName = [notification name];
+    if(NULL == notificationName)
+        return;
+    else if([NSWindowDidBecomeKeyNotification isEqualTo:notificationName])
+    {   // This is the only one that was handled in 2.8 as shipped
+        // Generally the key window can change without the main window changing.
+        // The user can do this simply by clicking on something in a palette window
+        // that needs to become key.
+        NSWindow *newKeyWindow = [notification object];
+        wxCocoaNSWindow *theWxKeyWindow = wxCocoaNSWindow::GetFromCocoa(newKeyWindow);
+        if(theWxKeyWindow != NULL)
+        {   // If the new key window is a wx window, handle it as before
+            // even if it has not actually changed.
+            m_currentNSWindow = newKeyWindow;
+        }
+        else
+        {   // If the new key window is not wx then check the main window.
+            NSWindow *mainWindow = [[NSApplication sharedApplication] mainWindow];
+            if(m_currentNSWindow == mainWindow)
+                // Don't reset if the menubar doesn't need to change.
+                return;
+            else
+                // This is strange because theoretically we should have picked this up
+                // already in the main window notification but it's possible that
+                // we simply haven't gotten it yet and will about as soon as we return.
+                // We already know that the key window isn't wx so fall back to this
+                // one and let the code go ahead and set the wx menubar if it is
+                // a wx window and set the generic one if it isn't.
+                m_currentNSWindow = mainWindow;
+        }
+    }
+    else if([NSWindowDidBecomeMainNotification isEqualTo:notificationName])
+    {   // Handling this is new
+        // Generally the main window cannot change without the key window changing
+        // because if the user clicks on a window that can become main then the
+        // window will also become key.
+        // However, it's possible that when it becomes main it automatically makes
+        // some palette the key window.
+        NSWindow *newMainWindow = [notification object];
+        // If we already know about the window, bail.
+        if(newMainWindow == m_currentNSWindow)
+            return;
+        else
+        {
+            NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
+            if(keyWindow == m_currentNSWindow)
+                // if we already know about the key window, bail
+                return;
+            else
+            {   // As above, sort of strange.  Neither one is current.  Prefer key over main.
+                wxCocoaNSWindow *theWxMainWindow = wxCocoaNSWindow::GetFromCocoa(keyWindow);
+                if(theWxMainWindow != NULL)
+                    m_currentNSWindow = keyWindow;
+                else
+                    m_currentNSWindow = newMainWindow;
+            }
+        }
+    }
+    m_currentNSWindow = [notification object];
+    wxCocoaNSWindow *win = wxCocoaNSWindow::GetFromCocoa(m_currentNSWindow);
     if(win)
         InstallMenuBarForWindow(win);
     else
@@ -271,16 +381,19 @@ void wxMenuBarManager::WindowWillClose(NSNotification *notification)
 void wxMenuBarManager::InstallMenuBarForWindow(wxCocoaNSWindow *win)
 {
     wxASSERT(win);
-    m_windowCurrent = win;
     wxMenuBar *menubar = win->GetAppMenuBar(win);
-    wxLogDebug("Found menubar=%p for window=%p.",menubar,win);
+    wxLogTrace(wxTRACE_COCOA,wxT("Found menubar=%p for window=%p."),menubar,win);
     SetMenuBar(menubar);
 }
 
 void wxMenuBarManager::UpdateMenuBar()
 {
-    if(m_windowCurrent)
-        InstallMenuBarForWindow(m_windowCurrent);
+    if(m_currentNSWindow)
+    {
+        wxCocoaNSWindow *win = wxCocoaNSWindow::GetFromCocoa(m_currentNSWindow);
+        if(win)
+            InstallMenuBarForWindow(win);
+    }
 }
 
 #endif // wxUSE_MENUS