@@ -299,7 +299,7 @@ - (id)init
299299 ASLogCrit (@" Failed to register connection with name '%@ '" , name);
300300 [connection release ]; connection = nil ;
301301 }
302-
302+
303303#if !DISABLE_SPARKLE
304304 // Sparkle is enabled (this is the default). Initialize it. It will
305305 // automatically check for update.
@@ -321,6 +321,7 @@ - (void)dealloc
321321 [openSelectionString release ]; openSelectionString = nil ;
322322 [recentFilesMenuItem release ]; recentFilesMenuItem = nil ;
323323 [defaultMainMenu release ]; defaultMainMenu = nil ;
324+ currentMainMenu = nil ;
324325 [appMenuItemTemplate release ]; appMenuItemTemplate = nil ;
325326 [updater release ]; updater = nil ;
326327
@@ -329,6 +330,11 @@ - (void)dealloc
329330
330331- (void )applicationWillFinishLaunching : (NSNotification *)notification
331332{
333+ // This prevents macOS from injecting "Enter Full Screen" menu item.
334+ // MacVim already has a separate menu item to do that.
335+ // See https://developer.apple.com/library/archive/releasenotes/AppKit/RN-AppKitOlderNotes/index.html#10_11FullScreen
336+ [[NSUserDefaults standardUserDefaults ] setBool: NO forKey: @" NSFullScreenMenuItemEverywhere" ];
337+
332338 // Remember the default menu so that it can be restored if the user closes
333339 // all editor windows.
334340 defaultMainMenu = [[NSApp mainMenu ] retain ];
@@ -862,7 +868,42 @@ - (void)windowControllerWillOpen:(MMWindowController *)windowController
862868
863869- (void )setMainMenu : (NSMenu *)mainMenu
864870{
865- if ([NSApp mainMenu ] == mainMenu) return ;
871+ if (currentMainMenu == mainMenu) {
872+ return ;
873+ }
874+ currentMainMenu = mainMenu;
875+ [self refreshMainMenu ];
876+ }
877+
878+ // Refresh the currently active main menu. This call is necessary when any
879+ // modification was made to the menu, because refreshMainMenu makes a copy of
880+ // the main menu, meaning that modifications to the original menu wouldn't be
881+ // reflected until refreshMainMenu is invoked.
882+ - (void )markMainMenuDirty : (NSMenu *)mainMenu
883+ {
884+ if (currentMainMenu != mainMenu) {
885+ // The menu being updated is not the currently set menu, so just ignore,
886+ // as this is likely a background Vim window.
887+ return ;
888+ }
889+ if (!mainMenuDirty) {
890+ // Mark the main menu as dirty and queue up a refresh. We don't immediately
891+ // execute the refresh so that multiple calls would get batched up in one go.
892+ mainMenuDirty = YES ;
893+ [self performSelectorOnMainThread: @selector (refreshMainMenu ) withObject: nil waitUntilDone: NO ];
894+ }
895+ }
896+
897+ - (void )refreshMainMenu
898+ {
899+ mainMenuDirty = NO ;
900+
901+ // Make a copy of the menu before we pass to AppKit. The main reason is
902+ // that setWindowsMenu: below will inject items like "Tile Window to Left
903+ // of Screen" to the Window menu, and on repeated calls it will keep adding
904+ // the same item over and over again, without resolving for duplicates. Using
905+ // copies help keep the source menu clean.
906+ NSMenu *mainMenu = [currentMainMenu copy ];
866907
867908 // If the new menu has a "Recent Files" dummy item, then swap the real item
868909 // for the dummy. We are forced to do this since Cocoa initializes the
@@ -871,7 +912,7 @@ - (void)setMainMenu:(NSMenu *)mainMenu
871912 NSMenu *fileMenu = [mainMenu findFileMenu ];
872913 if (recentFilesMenuItem && fileMenu) {
873914 int dummyIdx =
874- [fileMenu indexOfItemWithAction: @selector (recentFilesDummy: )];
915+ [fileMenu indexOfItemWithAction: @selector (recentFilesDummy: )];
875916 if (dummyIdx >= 0 ) {
876917 NSMenuItem *dummyItem = [[fileMenu itemAtIndex: dummyIdx] retain ];
877918 [fileMenu removeItemAtIndex: dummyIdx];
@@ -889,45 +930,26 @@ - (void)setMainMenu:(NSMenu *)mainMenu
889930 }
890931 }
891932
892- // Now set the new menu. Notice that we keep one menu for each editor
893- // window since each editor can have its own set of menus. When swapping
894- // menus we have to tell Cocoa where the new "MacVim", "Windows", and
895- // "Services" menu are.
896- [NSApp setMainMenu: mainMenu];
897-
898- // Setting the "MacVim" (or "Application") menu ensures that it is typeset
899- // in boldface. (The setAppleMenu: method used to be public but is now
900- // private so this will have to be considered a bit of a hack!)
901- NSMenu *appMenu = [mainMenu findApplicationMenu ];
902- [NSApp performSelector: @selector (setAppleMenu: ) withObject: appMenu];
903-
904933#if DISABLE_SPARKLE
934+ NSMenu *appMenu = [mainMenu findApplicationMenu ];
935+
905936 // If Sparkle is disabled, we want to remove the "Check for Updates" menu
906937 // item since it's no longer useful.
907938 NSMenuItem *checkForUpdatesItem = [appMenu itemAtIndex:
908939 [appMenu indexOfItemWithAction: @selector (checkForUpdates: )]];
909940 checkForUpdatesItem.hidden = true ;
910941#endif
911942
943+ // Now set the new menu. Notice that we keep one menu for each editor
944+ // window since each editor can have its own set of menus. When swapping
945+ // menus we have to tell Cocoa where the new "MacVim", "Windows", and
946+ // "Services" menu are.
947+ [NSApp setMainMenu: mainMenu];
948+
912949 NSMenu *servicesMenu = [mainMenu findServicesMenu ];
913950 [NSApp setServicesMenu: servicesMenu];
914951
915952 NSMenu *windowsMenu = [mainMenu findWindowsMenu ];
916- if (windowsMenu) {
917- // Cocoa isn't clever enough to get rid of items it has added to the
918- // "Windows" menu so we have to do it ourselves otherwise there will be
919- // multiple menu items for each window in the "Windows" menu.
920- // This code assumes that the only items Cocoa add are ones which
921- // send off the action makeKeyAndOrderFront:. (Cocoa will not add
922- // another separator item if the last item on the "Windows" menu
923- // already is a separator, so we needen't worry about separators.)
924- int i, count = [windowsMenu numberOfItems ];
925- for (i = count-1 ; i >= 0 ; --i) {
926- NSMenuItem *item = [windowsMenu itemAtIndex: i];
927- if ([item action ] == @selector (makeKeyAndOrderFront: ))
928- [windowsMenu removeItem: item];
929- }
930- }
931953 [NSApp setWindowsMenu: windowsMenu];
932954}
933955
@@ -1220,7 +1242,7 @@ - (IBAction)showVimHelp:(id)sender
12201242 @" -c" , @" :h gui_mac" , @" -c" , @" :res" , nil ]
12211243 workingDirectory: nil ];
12221244}
1223-
1245+
12241246- (IBAction )checkForUpdates:(id )sender
12251247{
12261248#if !DISABLE_SPARKLE
@@ -1816,7 +1838,7 @@ - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
18161838 // Only opens files that already exist.
18171839 if ([[NSFileManager defaultManager ] fileExistsAtPath: filePath]) {
18181840 NSArray *filenames = [NSArray arrayWithObject: filePath];
1819-
1841+
18201842 // Look for the line and column options.
18211843 NSDictionary *args = nil ;
18221844 NSString *line = [dict objectForKey: @" line" ];
@@ -1831,7 +1853,7 @@ - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
18311853 args = [NSDictionary dictionaryWithObject: line
18321854 forKey: @" cursorLine" ];
18331855 }
1834-
1856+
18351857 [self openFiles: filenames withArguments: args];
18361858 } else {
18371859 NSAlert *alert = [[NSAlert alloc ] init ];
@@ -2198,7 +2220,7 @@ - (void)startWatchingVimDir
21982220
21992221 NSString *path = [@" ~/.vim" stringByExpandingTildeInPath ];
22002222 NSArray *pathsToWatch = [NSArray arrayWithObject: path];
2201-
2223+
22022224 fsEventStream = FSEventStreamCreate (NULL , &fsEventCallback, NULL ,
22032225 (CFArrayRef)pathsToWatch, kFSEventStreamEventIdSinceNow ,
22042226 MMEventStreamLatency, kFSEventStreamCreateFlagNone );
0 commit comments