diff --git a/src/MacVim/Base.lproj/Preferences.xib b/src/MacVim/Base.lproj/Preferences.xib index 893ae01353..6d70bccb9f 100644 --- a/src/MacVim/Base.lproj/Preferences.xib +++ b/src/MacVim/Base.lproj/Preferences.xib @@ -507,6 +507,7 @@ + diff --git a/src/MacVim/MMAppController.h b/src/MacVim/MMAppController.h index f97c028c76..a7ceeba1b5 100644 --- a/src/MacVim/MMAppController.h +++ b/src/MacVim/MMAppController.h @@ -83,11 +83,13 @@ - (NSArray *)filterOpenFiles:(NSArray *)filenames; - (BOOL)openFiles:(NSArray *)filenames withArguments:(NSDictionary *)args; +// Refresh functions are used by preference pane to push through settings changes - (void)refreshAllAppearances; - (void)refreshAllTabProperties; - (void)refreshAllFonts; - (void)refreshAllResizeConstraints; - (void)refreshAllTextViews; +- (void)refreshAllFullScreenPresentationOptions; - (void)openNewWindow:(enum NewWindowMode)mode activate:(BOOL)activate extraArgs:(NSArray *)args; - (void)openNewWindow:(enum NewWindowMode)mode activate:(BOOL)activate; diff --git a/src/MacVim/MMAppController.m b/src/MacVim/MMAppController.m index 89d347609e..393ddd502e 100644 --- a/src/MacVim/MMAppController.m +++ b/src/MacVim/MMAppController.m @@ -38,6 +38,7 @@ */ #import "MMAppController.h" +#import "MMFullScreenWindow.h" #import "MMPreferenceController.h" #import "MMVimController.h" #import "MMVimView.h" @@ -1272,6 +1273,19 @@ - (void)refreshAllTextViews } } +/// Refresh all non-native full screen windows to update their presentation +/// options (show/hide menu and dock). +- (void)refreshAllFullScreenPresentationOptions +{ + for (MMVimController *vc in vimControllers) { + MMFullScreenWindow *fullScreenWindow = vc.windowController.fullScreenWindow; + if (fullScreenWindow != nil) { + [fullScreenWindow updatePresentationOptions]; + [vc.windowController resizeVimView]; + } + } +} + - (BOOL)validateMenuItem:(NSMenuItem *)item { if ([item action] == @selector(showWhatsNew:)) { diff --git a/src/MacVim/MMFullScreenWindow.h b/src/MacVim/MMFullScreenWindow.h index 34519dbc7e..b432011aae 100644 --- a/src/MacVim/MMFullScreenWindow.h +++ b/src/MacVim/MMFullScreenWindow.h @@ -35,6 +35,7 @@ - (MMFullScreenWindow *)initWithWindow:(NSWindow *)t view:(MMVimView *)v backgroundColor:(NSColor *)back; - (void)setOptions:(int)opt; +- (void)updatePresentationOptions; - (void)enterFullScreen; - (void)leaveFullScreen; - (NSRect)getDesiredFrame; diff --git a/src/MacVim/MMFullScreenWindow.m b/src/MacVim/MMFullScreenWindow.m index 78bfeb1ec3..c4cbb23c48 100644 --- a/src/MacVim/MMFullScreenWindow.m +++ b/src/MacVim/MMFullScreenWindow.m @@ -134,6 +134,22 @@ - (void)setOptions:(int)opt options = opt; } +- (void)updatePresentationOptions +{ + // Hide Dock and menu bar when going to full screen. Only do so if the current screen + // has a menu bar and dock. + if ([self screenHasDockAndMenu]) { + const bool showMenu = [[NSUserDefaults standardUserDefaults] + boolForKey:MMNonNativeFullScreenShowMenuKey]; + + [NSApplication sharedApplication].presentationOptions = showMenu ? + NSApplicationPresentationAutoHideDock : + NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar; + } else { + [NSApplication sharedApplication].presentationOptions = NSApplicationPresentationDefault; + } +} + - (void)enterFullScreen { ASLogDebug(@"Enter full-screen now"); @@ -147,16 +163,7 @@ - (void)enterFullScreen [winController setWindow:nil]; [target setDelegate:nil]; - // Hide Dock and menu bar when going to full screen. Only do so if the current screen - // has a menu bar and dock. - if ([self screenHasDockAndMenu]) { - const bool showMenu = [[NSUserDefaults standardUserDefaults] - boolForKey:MMNonNativeFullScreenShowMenuKey]; - - [NSApplication sharedApplication].presentationOptions = showMenu ? - NSApplicationPresentationAutoHideDock : - NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar; - } + [self updatePresentationOptions]; // fade to black Boolean didBlend = NO; @@ -376,6 +383,10 @@ - (void)applicationDidChangeScreenParameters:(NSNotification *)notification - (NSEdgeInsets) viewOffset { NSEdgeInsets offset = NSEdgeInsetsMake(0, 0, 0, 0); + NSScreen *screen = [self screen]; + if (screen == nil) + return offset; + NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; const BOOL showMenu = [ud boolForKey:MMNonNativeFullScreenShowMenuKey]; @@ -390,29 +401,28 @@ - (NSEdgeInsets) viewOffset { // In the future there may be more. E.g. we can draw tabs in the safe area. // If menu is shown, we ignore this because this doesn't make sense. if (safeAreaBehavior == 0 || showMenu) { - offset = [self screen].safeAreaInsets; + offset = screen.safeAreaInsets; } } #endif if (showMenu) { - // Offset by menu height - if (offset.top == 0) { - const CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; - if (menuBarHeight > offset.top) { - offset.top = menuBarHeight; - } - } else { - // Unfortunately, if there is a notch (safe area != 0), menuBarHeight does *not* return - // the menu height shown in the main screen, so we need to calculate it otherwise. - // visibleArea is supposed to give us this information but it's oddly off by one, leading - // to a one-pixel black line, so we need to manually increment it by one. Yes, it sucks. - NSRect visibleFrame = [self screen].visibleFrame; - visibleFrame.size.height += 1; - const CGFloat menuBarHeight = [self screen].frame.size.height - NSMaxY(visibleFrame); - if (menuBarHeight > offset.top) { - offset.top = menuBarHeight; - } + // Offset by menu height. We use NSScreen's visibleFrame which is the + // most reliable way to do so, as NSApp.mainMenu.menuBarHeight could + // give us the wrong height if one screen is a laptop screen with + // notch, or the user has configured to use single Space for all + // screens and we're in a screen without the menu bar. + // + // Quirks of visibleFrame API: + // - It oddly leaves a one pixel gap between menu bar and screen, + // leading to a black bar. We manually adjust for it. + // - It will sometimes leave room for the Dock even when it's + // auto-hidden (depends on screen configuration and OS version). As + // such we just use the max Y component (where the menu is) and + // ignore the rest. + const CGFloat menuBarHeight = NSMaxY(screen.frame) - NSMaxY(screen.visibleFrame) - 1; + if (menuBarHeight > offset.top) { + offset.top = menuBarHeight; } } @@ -514,14 +524,7 @@ - (BOOL)screenHasDockAndMenu - (void)windowDidBecomeMain:(NSNotification *)notification { // Hide menu and dock when this window gets focus. - if ([self screenHasDockAndMenu]) { - const bool showMenu = [[NSUserDefaults standardUserDefaults] - boolForKey:MMNonNativeFullScreenShowMenuKey]; - - [NSApplication sharedApplication].presentationOptions = showMenu ? - NSApplicationPresentationAutoHideDock : - NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar; - } + [self updatePresentationOptions]; } @@ -530,9 +533,7 @@ - (void)windowDidResignMain:(NSNotification *)notification // Un-hide menu/dock when we lose focus. This makes sure if we have multiple // windows opened, when the non-fullscreen windows get focus they will have the // dock and menu showing (since presentationOptions is per-app, not per-window). - if ([self screenHasDockAndMenu]) { - [NSApplication sharedApplication].presentationOptions = NSApplicationPresentationDefault; - } + [NSApplication sharedApplication].presentationOptions = NSApplicationPresentationDefault; } - (void)windowDidMove:(NSNotification *)notification @@ -558,6 +559,10 @@ - (void)windowDidMove:(NSNotification *)notification // Ensure the full-screen window is still covering the entire screen and // then resize view according to 'fuopt'. [self setFrame:[screen frame] display:NO]; + + if ([self isMainWindow]) { + [self updatePresentationOptions]; + } } @end // MMFullScreenWindow (Private) diff --git a/src/MacVim/MMPreferenceController.h b/src/MacVim/MMPreferenceController.h index e705f4e3a2..5cc152616a 100644 --- a/src/MacVim/MMPreferenceController.h +++ b/src/MacVim/MMPreferenceController.h @@ -40,5 +40,6 @@ // Appearance pane - (IBAction)fontPropertiesChanged:(id)sender; - (IBAction)tabsPropertiesChanged:(id)sender; +- (IBAction)nonNativeFullScreenShowMenuChanged:(id)sender; @end diff --git a/src/MacVim/MMPreferenceController.m b/src/MacVim/MMPreferenceController.m index 4a615da45b..32f19ee84f 100644 --- a/src/MacVim/MMPreferenceController.m +++ b/src/MacVim/MMPreferenceController.m @@ -182,4 +182,9 @@ - (IBAction)cmdlineAlignBottomChanged:(id)sender [[MMAppController sharedInstance] refreshAllTextViews]; } +- (IBAction)nonNativeFullScreenShowMenuChanged:(id)sender +{ + [[MMAppController sharedInstance] refreshAllFullScreenPresentationOptions]; +} + @end diff --git a/src/MacVim/MMVimController.h b/src/MacVim/MMVimController.h index fc35589118..3656ea22be 100644 --- a/src/MacVim/MMVimController.h +++ b/src/MacVim/MMVimController.h @@ -60,6 +60,8 @@ /// E.g. ".AppleSystemUIFontMonospaced-Medium" -> "-monospace-Medium" @property (nonatomic, readonly) NSMutableDictionary* systemFontNamesToAlias; +@property (nonatomic, readonly) BOOL isHandlingInputQueue; + - (id)initWithBackend:(id)backend pid:(int)processIdentifier; - (void)uninitialize; - (unsigned long)vimControllerId; diff --git a/src/MacVim/MMVimController.m b/src/MacVim/MMVimController.m index bff551ac1d..de6b9d0964 100644 --- a/src/MacVim/MMVimController.m +++ b/src/MacVim/MMVimController.m @@ -557,6 +557,8 @@ - (void)processInputQueue:(NSArray *)queue { if (!isInitialized) return; + _isHandlingInputQueue = YES; + // NOTE: This method must not raise any exceptions (see comment in the // calling method). @try { @@ -566,6 +568,7 @@ - (void)processInputQueue:(NSArray *)queue @catch (NSException *ex) { ASLogDebug(@"Exception: pid=%d id=%lu reason=%@", pid, identifier, ex); } + _isHandlingInputQueue = NO; } - (NSToolbarItem *)toolbar:(NSToolbar *)theToolbar diff --git a/src/MacVim/MMWindowController.h b/src/MacVim/MMWindowController.h index 4b8a0a2278..4f9d324c8a 100644 --- a/src/MacVim/MMWindowController.h +++ b/src/MacVim/MMWindowController.h @@ -62,6 +62,7 @@ - (id)initWithVimController:(MMVimController *)controller; - (MMVimController *)vimController; - (MMVimView *)vimView; +- (MMFullScreenWindow*)fullScreenWindow; - (NSString *)windowAutosaveKey; - (void)setWindowAutosaveKey:(NSString *)key; - (void)cleanup; diff --git a/src/MacVim/MMWindowController.m b/src/MacVim/MMWindowController.m index 05890bcedf..a3f8354e60 100644 --- a/src/MacVim/MMWindowController.m +++ b/src/MacVim/MMWindowController.m @@ -290,6 +290,11 @@ - (MMVimView *)vimView return vimView; } +- (MMFullScreenWindow *)fullScreenWindow +{ + return fullScreenWindow; +} + - (NSString *)windowAutosaveKey { return windowAutosaveKey; @@ -468,6 +473,8 @@ - (void)resizeVimViewAndWindow if (setupDone) { shouldResizeVimView = YES; + if (!vimController.isHandlingInputQueue) + [self processInputQueueDidFinish]; } } @@ -480,6 +487,8 @@ - (void)resizeVimView { shouldResizeVimView = YES; shouldKeepGUISize = YES; + if (!vimController.isHandlingInputQueue) + [self processInputQueueDidFinish]; } } @@ -492,9 +501,13 @@ - (void)resizeVimView /// or shows the tab bar. - (void)resizeVimViewBlockRender { - [self resizeVimView]; - if (shouldResizeVimView) { + if (setupDone) + { + shouldResizeVimView = YES; + shouldKeepGUISize = YES; blockRenderUntilResize = YES; + if (!vimController.isHandlingInputQueue) + [self processInputQueueDidFinish]; } }