From f6ab5cbc0377c8e635c79cf971e7f2fd730c5d32 Mon Sep 17 00:00:00 2001 From: Bjorn Winckler Date: Tue, 3 Jun 2008 23:15:18 +0200 Subject: [PATCH] Use default menu when no window open, fix 'Recent Files' menu --- .../English.lproj/MainMenu.nib/classes.nib | 10 + .../English.lproj/MainMenu.nib/info.nib | 4 +- .../MainMenu.nib/keyedobjects.nib | Bin 9287 -> 7688 bytes src/MacVim/MMAppController.h | 5 +- src/MacVim/MMAppController.m | 216 +++++++++++++++--- src/MacVim/MMVimController.h | 7 +- src/MacVim/MMVimController.m | 185 +++------------ src/MacVim/MMWindowController.m | 4 +- 8 files changed, 245 insertions(+), 186 deletions(-) diff --git a/src/MacVim/English.lproj/MainMenu.nib/classes.nib b/src/MacVim/English.lproj/MainMenu.nib/classes.nib index 1dbd06362c..4a0573b97d 100644 --- a/src/MacVim/English.lproj/MainMenu.nib/classes.nib +++ b/src/MacVim/English.lproj/MainMenu.nib/classes.nib @@ -15,6 +15,8 @@ id newWindow id + openWebsite + id orderFrontPreferencePanel id selectNextWindow @@ -29,6 +31,14 @@ SUPERCLASS NSObject + + CLASS + NSMenu + LANGUAGE + ObjC + SUPERCLASS + NSObject + ACTIONS diff --git a/src/MacVim/English.lproj/MainMenu.nib/info.nib b/src/MacVim/English.lproj/MainMenu.nib/info.nib index 0fe119084e..fb4d19ea6e 100644 --- a/src/MacVim/English.lproj/MainMenu.nib/info.nib +++ b/src/MacVim/English.lproj/MainMenu.nib/info.nib @@ -10,10 +10,10 @@ 5 IBOpenObjects - 57 + 218 IBSystem Version - 9B18 + 9D34 targetFramework IBCocoaFramework diff --git a/src/MacVim/English.lproj/MainMenu.nib/keyedobjects.nib b/src/MacVim/English.lproj/MainMenu.nib/keyedobjects.nib index f58db777c012b9552a5310329c93c38c2a075b1a..241ca9cbc215547607056ff4caabc65d29f516f0 100644 GIT binary patch literal 7688 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 diff --git a/src/MacVim/MMAppController.h b/src/MacVim/MMAppController.h index db3d61af48..0236eaaed9 100644 --- a/src/MacVim/MMAppController.h +++ b/src/MacVim/MMAppController.h @@ -21,12 +21,15 @@ NSString *openSelectionString; ATSFontContainerRef fontContainerRef; NSMutableDictionary *pidArguments; - + NSMenu *defaultMainMenu; NSMenuItem *recentFilesMenuItem; } ++ (MMAppController *)sharedInstance; +- (NSMenu *)defaultMainMenu; - (void)removeVimController:(id)controller; - (void)windowControllerWillOpen:(MMWindowController *)windowController; +- (void)setMainMenu:(NSMenu *)mainMenu; - (IBAction)newWindow:(id)sender; - (IBAction)fileOpen:(id)sender; - (IBAction)selectNextWindow:(id)sender; diff --git a/src/MacVim/MMAppController.m b/src/MacVim/MMAppController.m index 3ad8e2e493..0a978d6d53 100644 --- a/src/MacVim/MMAppController.m +++ b/src/MacVim/MMAppController.m @@ -92,6 +92,18 @@ static int executeInLoginShell(NSString *path, NSArray *args); @end +@interface NSMenu (MMExtras) +- (int)indexOfItemWithAction:(SEL)action; +- (NSMenuItem *)itemWithAction:(SEL)action; +- (NSMenu *)findMenuContainingItemWithAction:(SEL)action; +- (NSMenu *)findWindowsMenu; +- (NSMenu *)findApplicationMenu; +- (NSMenu *)findServicesMenu; +- (NSMenu *)findFileMenu; +@end + + + @implementation MMAppController @@ -177,39 +189,42 @@ static int executeInLoginShell(NSString *path, NSArray *args); [vimControllers release]; vimControllers = nil; [openSelectionString release]; openSelectionString = nil; [recentFilesMenuItem release]; recentFilesMenuItem = nil; + [defaultMainMenu release]; defaultMainMenu = nil; [super dealloc]; } - (void)applicationWillFinishLaunching:(NSNotification *)notification { - // Create the "Open Recent" menu. See - // http://lapcatsoftware.com/blog/2007/07/10/working-without-a-nib-part-5-open-recent-menu/ - // and http://www.cocoabuilder.com/archive/message/cocoa/2007/8/15/187793 + // Remember the default menu so that it can be restored if the user closes + // all editor windows. + defaultMainMenu = [[NSApp mainMenu] retain]; + + // Set up the "Open Recent" menu. See + // http://lapcatsoftware.com/blog/2007/07/10/ + // working-without-a-nib-part-5-open-recent-menu/ + // and + // http://www.cocoabuilder.com/archive/message/cocoa/2007/8/15/187793 // for more information. - // - // The menu needs to be created and be added to a toplevel menu in - // applicationWillFinishLaunching at the latest, otherwise it doesn't work. + // + // The menu itself is created in MainMenu.nib but we still seem to have to + // hack around a bit to get it to work. (This has to be done in + // applicationWillFinishLaunching at the latest, otherwise it doesn't + // work.) + NSMenu *fileMenu = [defaultMainMenu findFileMenu]; + if (fileMenu) { + int idx = [fileMenu indexOfItemWithAction:@selector(fileOpen:)]; + if (idx >= 0 && idx+1 < [fileMenu numberOfItems]) - recentFilesMenuItem = [[NSMenuItem alloc] - initWithTitle:NSLocalizedString(@"Open Recent", @"Open Recent menu") - action:nil keyEquivalent:@""]; + recentFilesMenuItem = [fileMenu itemWithTitle:@"Open Recent"]; + [[recentFilesMenuItem submenu] performSelector:@selector(_setMenuName:) + withObject:@"NSRecentDocumentsMenu"]; - NSMenu *recentFilesMenu = [[NSMenu alloc] - initWithTitle:NSLocalizedString(@"Open Recent", @"Open Recent menu")]; - [recentFilesMenu performSelector:@selector(_setMenuName:) - withObject:@"NSRecentDocumentsMenu"]; - - [recentFilesMenu addItemWithTitle:NSLocalizedString(@"Clear Menu", - @"Open Recent menu") - action:@selector(clearRecentDocuments:) - keyEquivalent:@""]; - [recentFilesMenuItem setSubmenu:recentFilesMenu]; - [recentFilesMenu release]; // the menu is retained by recentFilesMenuItem - [recentFilesMenuItem setTag:-1]; // must not be 0 - - // TODO: this will not work in a localized MacVim - [[[[NSApp mainMenu] itemWithTitle:@"File"] submenu] addItem:recentFilesMenuItem]; + // Note: The "Recent Files" menu must be moved around since there is no + // -[NSApp setRecentFilesMenu:] method. We keep a reference to it to + // facilitate this move (see setMainMenu: below). + [recentFilesMenuItem retain]; + } #if MM_HANDLE_XCODE_MOD_EVENT [[NSAppleEventManager sharedAppleEventManager] @@ -504,6 +519,19 @@ static int executeInLoginShell(NSString *path, NSArray *args); [NSApp setDelegate:nil]; } ++ (MMAppController *)sharedInstance +{ + // Note: The app controller is a singleton which is instantiated in + // MainMenu.nib where it is also connected as the delegate of NSApp. + id delegate = [NSApp delegate]; + return [delegate isKindOfClass:self] ? (MMAppController*)delegate : nil; +} + +- (NSMenu *)defaultMainMenu +{ + return defaultMainMenu; +} + - (void)removeVimController:(id)controller { //NSLog(@"%s%@", _cmd, controller); @@ -513,7 +541,9 @@ static int executeInLoginShell(NSString *path, NSArray *args); [vimControllers removeObject:controller]; if (![vimControllers count]) { - // TODO: change menu to default state + // The last editor window just closed so restore the main menu back to + // its default state (which is defined in MainMenu.nib). + [self setMainMenu:defaultMainMenu]; } } @@ -556,6 +586,68 @@ static int executeInLoginShell(NSString *path, NSArray *args); } } +- (void)setMainMenu:(NSMenu *)mainMenu +{ + if ([NSApp mainMenu] == mainMenu) return; + + // If the new menu has a "Recent Files" dummy item, then swap the real item + // for the dummy. We are forced to do this since Cocoa initializes the + // "Recent Files" menu and there is no way to simply point Cocoa to a new + // item each time the menus are swapped. + NSMenu *fileMenu = [mainMenu findFileMenu]; + int dummyIdx = + [fileMenu indexOfItemWithAction:@selector(recentFilesDummy:)]; + if (dummyIdx >= 0 && recentFilesMenuItem) { + NSMenuItem *dummyItem = [[fileMenu itemAtIndex:dummyIdx] retain]; + [fileMenu removeItemAtIndex:dummyIdx]; + + NSMenu *recentFilesParentMenu = [recentFilesMenuItem menu]; + int idx = [recentFilesParentMenu indexOfItem:recentFilesMenuItem]; + if (idx >= 0) { + [[recentFilesMenuItem retain] autorelease]; + [recentFilesParentMenu removeItemAtIndex:idx]; + [recentFilesParentMenu insertItem:dummyItem atIndex:idx]; + } + + [fileMenu insertItem:recentFilesMenuItem atIndex:dummyIdx]; + [dummyItem release]; + } + + // Now set the new menu. Notice that we keep one menu for each editor + // window since each editor can have its own set of menus. When swapping + // menus we have to tell Cocoa where the new "MacVim", "Windows", and + // "Services" menu are. + [NSApp setMainMenu:mainMenu]; + + // Setting the "MacVim" (or "Application") menu ensures that it is typeset + // in boldface. (The setAppleMenu: method used to be public but is now + // private so this will have to be considered a bit of a hack!) + NSMenu *appMenu = [mainMenu findApplicationMenu]; + [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; + + NSMenu *servicesMenu = [mainMenu findServicesMenu]; + [NSApp setServicesMenu:servicesMenu]; + + NSMenu *windowsMenu = [mainMenu findWindowsMenu]; + if (windowsMenu) { + // Cocoa isn't clever enough to get rid of items it has added to the + // "Windows" menu so we have to do it ourselves otherwise there will be + // multiple menu items for each window in the "Windows" menu. + // This code assumes that the only items Cocoa add are ones which + // send off the action makeKeyAndOrderFront:. (Cocoa will not add + // another separator item if the last item on the "Windows" menu + // already is a separator, so we needen't worry about separators.) + int i, count = [windowsMenu numberOfItems]; + for (i = count-1; i >= 0; --i) { + NSMenuItem *item = [windowsMenu itemAtIndex:i]; + if ([item action] == @selector(makeKeyAndOrderFront:)) + [windowsMenu removeItem:item]; + } + + [NSApp setWindowsMenu:windowsMenu]; + } +} + - (IBAction)newWindow:(id)sender { [self launchVimProcessWithArguments:nil]; @@ -657,7 +749,7 @@ static int executeInLoginShell(NSString *path, NSArray *args); setProtocolForProxy:@protocol(MMBackendProtocol)]; vc = [[[MMVimController alloc] - initWithBackend:backend pid:pid recentFiles:recentFilesMenuItem] + initWithBackend:backend pid:pid] autorelease]; if (![vimControllers count]) { @@ -1144,6 +1236,77 @@ static int executeInLoginShell(NSString *path, NSArray *args); +@implementation NSMenu (MMExtras) + +- (int)indexOfItemWithAction:(SEL)action +{ + int i, count = [self numberOfItems]; + for (i = 0; i < count; ++i) { + NSMenuItem *item = [self itemAtIndex:i]; + if ([item action] == action) + return i; + } + + return -1; +} + +- (NSMenuItem *)itemWithAction:(SEL)action +{ + int idx = [self indexOfItemWithAction:action]; + return idx >= 0 ? [self itemAtIndex:idx] : nil; +} + +- (NSMenu *)findMenuContainingItemWithAction:(SEL)action +{ + // NOTE: We only look for the action in the submenus of 'self' + int i, count = [self numberOfItems]; + for (i = 0; i < count; ++i) { + NSMenu *menu = [[self itemAtIndex:i] submenu]; + NSMenuItem *item = [menu itemWithAction:action]; + if (item) return menu; + } + + return nil; +} + +- (NSMenu *)findWindowsMenu +{ + return [self findMenuContainingItemWithAction: + @selector(performMiniaturize:)]; +} + +- (NSMenu *)findApplicationMenu +{ + // TODO: Just return [self itemAtIndex:0]? + return [self findMenuContainingItemWithAction:@selector(terminate:)]; +} + +- (NSMenu *)findServicesMenu +{ + // NOTE! Our heuristic for finding the "Services" menu is to look for the + // second item before the "Hide MacVim" menu item on the "MacVim" menu. + // (The item before "Hide MacVim" should be a separator, but this is not + // important as long as the item before that is the "Services" menu.) + + NSMenu *appMenu = [self findApplicationMenu]; + if (!appMenu) return nil; + + int idx = [appMenu indexOfItemWithAction: @selector(hide:)]; + if (idx-2 < 0) return nil; // idx == -1, if selector not found + + return [[appMenu itemAtIndex:idx-2] submenu]; +} + +- (NSMenu *)findFileMenu +{ + return [self findMenuContainingItemWithAction:@selector(performClose:)]; +} + +@end // NSMenu (MMExtras) + + + + static int executeInLoginShell(NSString *path, NSArray *args) { @@ -1237,4 +1400,3 @@ executeInLoginShell(NSString *path, NSArray *args) return pid; } - diff --git a/src/MacVim/MMVimController.h b/src/MacVim/MMVimController.h index 56fb6d16b9..a48ae7429a 100644 --- a/src/MacVim/MMVimController.h +++ b/src/MacVim/MMVimController.h @@ -38,19 +38,17 @@ int resendMsgid; NSData *resendData; #endif - NSMenuItem *recentFilesMenuItem; - NSMenuItem *recentFilesDummy; NSDictionary *vimState; } -- (id)initWithBackend:(id)backend pid:(int)processIdentifier - recentFiles:(NSMenuItem*)menu; +- (id)initWithBackend:(id)backend pid:(int)processIdentifier; - (id)backendProxy; - (int)pid; - (void)setServerName:(NSString *)name; - (NSString *)serverName; - (MMWindowController *)windowController; - (NSDictionary *)vimState; +- (NSMenu *)mainMenu; - (void)cleanup; - (void)dropFiles:(NSArray *)filenames forceOpen:(BOOL)force; - (void)dropString:(NSString *)string; @@ -61,5 +59,4 @@ timeout:(NSTimeInterval)timeout; - (void)addVimInput:(NSString *)string; - (NSString *)evaluateVimExpression:(NSString *)expr; -- (void)updateMainMenu; @end diff --git a/src/MacVim/MMVimController.m b/src/MacVim/MMVimController.m index be74f1dcd0..53d8daf371 100644 --- a/src/MacVim/MMVimController.m +++ b/src/MacVim/MMVimController.m @@ -84,11 +84,6 @@ static NSTimeInterval MMResendInterval = 0.5; #if MM_RESEND_LAST_FAILURE - (void)resendTimerFired:(NSTimer *)timer; #endif -- (void)replaceMenuItem:(NSMenuItem*)old with:(NSMenuItem*)new; -- (NSMenu *)findMenuContainingItemWithAction:(SEL)action; -- (NSMenu *)findWindowsMenu; -- (NSMenu *)findApplicationMenu; -- (NSMenu *)findServicesMenu; @end @@ -99,22 +94,13 @@ static NSTimeInterval MMResendInterval = 0.5; @end -@interface NSMenu (MMExtras) -- (int)indexOfItemWithAction:(SEL)action; -- (NSMenuItem *)itemWithAction:(SEL)action; -@end - - @implementation MMVimController - (id)initWithBackend:(id)backend pid:(int)processIdentifier - recentFiles:(NSMenuItem*)menu; { if ((self = [super init])) { - recentFilesMenuItem = [menu retain]; - windowController = [[MMWindowController alloc] initWithVimController:self]; backendProxy = [backend retain]; @@ -133,15 +119,21 @@ static NSTimeInterval MMResendInterval = 0.5; selector:@selector(connectionDidDie:) name:NSConnectionDidDieNotification object:connection]; - // Copy the "MacVim menu" from the current main menu. + // Copy the "MacVim menu" from the default main menu (we assume that it + // is the first item on the default main menu). mainMenu = [[NSMenu alloc] initWithTitle:@"MainMenu"]; - NSMenuItem *appMenuItem = [[NSApp mainMenu] itemAtIndex:0]; + NSMenuItem *appMenuItem = [[[MMAppController sharedInstance] + defaultMainMenu] itemAtIndex:0]; appMenuItem = [[appMenuItem copy] autorelease]; - // Note: If the title of the application menu is anything but "MacVim", - // then the application menu will not be typeset in boldface for some - // reason. - [appMenuItem setTitle:@"MacVim"]; + // Note: If the title of the application menu is anything but what + // CFBundleName says then the application menu will not be typeset in + // boldface for some reason. (It should already be set when we copy + // from the default main menu, but this is not the case for some + // reason.) + NSString *appName = [[NSBundle mainBundle] + objectForInfoDictionaryKey:@"CFBundleName"]; + [appMenuItem setTitle:appName]; [mainMenu addItem:appMenuItem]; @@ -169,9 +161,6 @@ static NSTimeInterval MMResendInterval = 0.5; [popupMenuItems release]; popupMenuItems = nil; [windowController release]; windowController = nil; - [recentFilesMenuItem release]; recentFilesMenuItem = nil; - [recentFilesDummy release]; recentFilesDummy = nil; - [vimState release]; vimState = nil; [mainMenu release]; mainMenu = nil; @@ -188,6 +177,11 @@ static NSTimeInterval MMResendInterval = 0.5; return vimState; } +- (NSMenu *)mainMenu +{ + return mainMenu; +} + - (void)setServerName:(NSString *)name { if (name != serverName) { @@ -588,42 +582,6 @@ static NSTimeInterval MMResendInterval = 0.5; return nil; } -- (void)updateMainMenu -{ - if ([NSApp mainMenu] == mainMenu) return; - - [NSApp setMainMenu:mainMenu]; - - NSMenu *appMenu = [self findApplicationMenu]; - [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; - - NSMenu *servicesMenu = [self findServicesMenu]; - [NSApp setServicesMenu:servicesMenu]; - - NSMenu *windowsMenu = [self findWindowsMenu]; - if (windowsMenu) { - // Remove all items that are added when setWindowsMenu: is called. - int i, count = [windowsMenu numberOfItems]; - for (i = count-1; i >= 0; --i) { - NSMenuItem *item = [windowsMenu itemAtIndex:i]; - if ([item action] == @selector(makeKeyAndOrderFront:)) - [windowsMenu removeItem:item]; - } - - [NSApp setWindowsMenu:windowsMenu]; - } - -#if 0 - // Replace real Recent Files menu in the old menu with the dummy, then - // remove dummy from new menu and put Recent Files menu there - NSMenuItem *oldItem = (NSMenuItem*)[recentFilesMenuItem representedObject]; - if (oldItem) - [self replaceMenuItem:recentFilesMenuItem with:oldItem]; - [recentFilesMenuItem setRepresentedObject:recentFilesDummy]; - [self replaceMenuItem:recentFilesDummy with:recentFilesMenuItem]; -#endif -} - @end // MMVimController @@ -1064,28 +1022,25 @@ static NSTimeInterval MMResendInterval = 0.5; item = [[[NSMenuItem alloc] init] autorelease]; [item setTitle:title]; - if ([action isEqualToString:@"recentFilesDummy:"]) { - // Remove the recent files menu item from its current menu - // and put it in the current file menu. See -[MMAppController - // applicationWillFinishLaunching for more information. - //[[recentFilesMenuItem menu] removeItem:recentFilesMenuItem]; - //item = recentFilesMenuItem; - recentFilesDummy = [item retain]; - } else { - // TODO: Check that 'action' is a valid action (nothing will - // happen if it isn't, but it would be nice with a warning). - if ([action length] > 0) - [item setAction:NSSelectorFromString(action)]; - else - [item setAction:@selector(vimMenuItemAction:)]; - if ([tip length] > 0) [item setToolTip:tip]; - if ([keyEquivalent length] > 0) { - [item setKeyEquivalent:keyEquivalent]; - [item setKeyEquivalentModifierMask:modifierMask]; - } - [item setAlternate:isAlternate]; - [item setTag:1]; // 'tag != 0' means item is enabled + // Note: It is possible to set the action to a message that "doesn't + // exist" without problems. We take advantage of this when adding + // "dummy items" e.g. when dealing with the "Recent Files" menu (in + // which case a recentFilesDummy: action is set, although it is never + // used). + if ([action length] > 0) + [item setAction:NSSelectorFromString(action)]; + else + [item setAction:@selector(vimMenuItemAction:)]; + if ([tip length] > 0) [item setToolTip:tip]; + if ([keyEquivalent length] > 0) { + [item setKeyEquivalent:keyEquivalent]; + [item setKeyEquivalentModifierMask:modifierMask]; } + [item setAlternate:isAlternate]; + + // The tag is used to indicate whether Vim thinks a menu item should be + // enabled or disabled. By default Vim thinks menu items are enabled. + [item setTag:1]; } if ([parent numberOfItems] <= idx) { @@ -1228,7 +1183,7 @@ static NSTimeInterval MMResendInterval = 0.5; [self cleanup]; // NOTE! This causes the call to removeVimController: to be delayed. - [[NSApp delegate] + [[MMAppController sharedInstance] performSelectorOnMainThread:@selector(removeVimController:) withObject:self waitUntilDone:NO]; } @@ -1258,53 +1213,6 @@ static NSTimeInterval MMResendInterval = 0.5; } #endif -- (void)replaceMenuItem:(NSMenuItem*)old with:(NSMenuItem*)new -{ - NSMenu *menu = [old menu]; - int index = [menu indexOfItem:old]; - [menu removeItemAtIndex:index]; - [menu insertItem:new atIndex:index]; -} - -- (NSMenu *)findMenuContainingItemWithAction:(SEL)action -{ - int i, count = [mainMenu numberOfItems]; - for (i = 0; i < count; ++i) { - NSMenu *menu = [[mainMenu itemAtIndex:i] submenu]; - NSMenuItem *item = [menu itemWithAction:action]; - if (item) return menu; - } - - return nil; -} - -- (NSMenu *)findWindowsMenu -{ - return [self findMenuContainingItemWithAction: - @selector(performMiniaturize:)]; -} - -- (NSMenu *)findApplicationMenu -{ - return [self findMenuContainingItemWithAction:@selector(terminate:)]; -} - -- (NSMenu *)findServicesMenu -{ - // NOTE! Our heuristic for finding the "Services" menu is to look for the - // second item before the "Hide MacVim" menu item on the "MacVim" menu. - // (The item before "Hide MacVim" should be a separator, but this is not - // important as long as the item before that is the "Services" menu.) - - NSMenu *appMenu = [self findApplicationMenu]; - if (!appMenu) return nil; - - int idx = [appMenu indexOfItemWithAction: @selector(hide:)]; - if (idx-2 < 0) return nil; // idx == -1, if selector not found - - return [[appMenu itemAtIndex:idx-2] submenu]; -} - @end // MMVimController (Private) @@ -1342,27 +1250,6 @@ static NSTimeInterval MMResendInterval = 0.5; @end // NSToolbar (MMExtras) -@implementation NSMenu (MMExtras) - -- (int)indexOfItemWithAction:(SEL)action -{ - int i, count = [self numberOfItems]; - for (i = 0; i < count; ++i) { - NSMenuItem *item = [self itemAtIndex:i]; - if ([item action] == action) - return i; - } - - return -1; -} - -- (NSMenuItem *)itemWithAction:(SEL)action -{ - int idx = [self indexOfItemWithAction:action]; - return idx >= 0 ? [self itemAtIndex:idx] : nil; -} - -@end // NSMenu (MMExtras) diff --git a/src/MacVim/MMWindowController.m b/src/MacVim/MMWindowController.m index ede1a753a6..2a78cae3d4 100644 --- a/src/MacVim/MMWindowController.m +++ b/src/MacVim/MMWindowController.m @@ -263,7 +263,7 @@ - (void)openWindow { - [[NSApp delegate] windowControllerWillOpen:self]; + [[MMAppController sharedInstance] windowControllerWillOpen:self]; [self addNewTabViewItem]; @@ -649,7 +649,7 @@ - (void)windowDidBecomeMain:(NSNotification *)notification { - [vimController updateMainMenu]; + [[MMAppController sharedInstance] setMainMenu:[vimController mainMenu]]; [vimController sendMessage:GotFocusMsgID data:nil]; if ([vimView textView]) {