X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8ded703ddca4c6657625af80afa66a2dddd13dae..eea4d01c65f9b29baa1193db762b4c6b8144af24:/src/cocoa/mbarman.mm diff --git a/src/cocoa/mbarman.mm b/src/cocoa/mbarman.mm index e672517182..1f0e5c71f8 100644 --- a/src/cocoa/mbarman.mm +++ b/src/cocoa/mbarman.mm @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: cocoa/mbarman.cpp +// Name: src/cocoa/mbarman.mm // Purpose: wxMenuBarManager implementation // Author: David Elliott // Modified by: @@ -20,6 +20,7 @@ #include "wx/cocoa/mbarman.h" #include "wx/cocoa/autorelease.h" +#include "wx/cocoa/objc/objc_uniquifying.h" #import #import @@ -27,6 +28,20 @@ #import #import +#ifndef wxUSE_FSCRIPT +#define wxUSE_FSCRIPT 0 +#endif + +#if wxUSE_FSCRIPT + #import +#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 // ============================================================================ @@ -45,11 +60,12 @@ - (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; } @@ -94,19 +110,37 @@ #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::UpdateWindowMenuBar(wxTopLevelWindowNative *win) +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