diff --git a/runtime/doc/gui_mac.txt b/runtime/doc/gui_mac.txt index df2644f4e2..619c88a314 100644 --- a/runtime/doc/gui_mac.txt +++ b/runtime/doc/gui_mac.txt @@ -310,11 +310,6 @@ KEY VALUE ~ *MMScrollOneDirectionOnly* scroll along one axis only when using trackpad [bool] *MMSmoothResize* allow smooth resizing of MacVim window [bool] *MMShareFindPboard* share search text to Find Pasteboard [bool] -*MMShowAddTabButton* enable "add tab" button on tabline [bool] -*MMShowTabScrollButtons* enable tab scroll buttons on tabline [bool] -*MMTabMinWidth* minimum width of a tab [int] -*MMTabOptimumWidth* default width of a tab [int] -*MMDefaultTablineColors* use default colors instead of colorscheme for tabs [bool] *MMTextInsetBottom* text area offset in pixels [int] *MMTextInsetLeft* text area offset in pixels [int] *MMTextInsetRight* text area offset in pixels [int] @@ -327,6 +322,14 @@ KEY VALUE ~ *MMUpdaterPrereleaseChannel* opt-in to pre-release software update [bool] *MMShowWhatsNewOnStartup* show "What's New" after updating to new version [bool] +Tabs ~ +*MMTabColorsMode* use default/auto/colorscheme for tab colors [int] +*MMWindowUseTabBackgroundColor* use tabs background fill color as window color [bool] +*MMShowAddTabButton* enable "add tab" button on tabline [bool] +*MMShowTabScrollButtons* enable tab scroll buttons on tabline [bool] +*MMTabMinWidth* minimum width of a tab [int] +*MMTabOptimumWidth* default width of a tab [int] + As an example, if you have more than one mouse button and would wish to free up Ctrl-click so you can bind it to something else, then the appropriate command is: > diff --git a/runtime/doc/tags b/runtime/doc/tags index d8b5f59472..b55d15bddf 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -5645,7 +5645,6 @@ MMAllowForceClickLookUp gui_mac.txt /*MMAllowForceClickLookUp* MMAppearanceModeSelection gui_mac.txt /*MMAppearanceModeSelection* MMCellWidthMultiplier gui_mac.txt /*MMCellWidthMultiplier* MMCmdLineAlignBottom gui_mac.txt /*MMCmdLineAlignBottom* -MMDefaultTablineColors gui_mac.txt /*MMDefaultTablineColors* MMDialogsTrackPwd gui_mac.txt /*MMDialogsTrackPwd* MMDisableLaunchAnimation gui_mac.txt /*MMDisableLaunchAnimation* MMDisableTablineAnimation gui_mac.txt /*MMDisableTablineAnimation* @@ -5666,6 +5665,7 @@ MMShowAddTabButton gui_mac.txt /*MMShowAddTabButton* MMShowTabScrollButtons gui_mac.txt /*MMShowTabScrollButtons* MMShowWhatsNewOnStartup gui_mac.txt /*MMShowWhatsNewOnStartup* MMSmoothResize gui_mac.txt /*MMSmoothResize* +MMTabColorsMode gui_mac.txt /*MMTabColorsMode* MMTabMinWidth gui_mac.txt /*MMTabMinWidth* MMTabOptimumWidth gui_mac.txt /*MMTabOptimumWidth* MMTextInsetBottom gui_mac.txt /*MMTextInsetBottom* @@ -5678,6 +5678,7 @@ MMTranslateCtrlClick gui_mac.txt /*MMTranslateCtrlClick* MMUpdaterPrereleaseChannel gui_mac.txt /*MMUpdaterPrereleaseChannel* MMUseMouseTime gui_mac.txt /*MMUseMouseTime* MMVerticalSplit gui_mac.txt /*MMVerticalSplit* +MMWindowUseTabBackgroundColor gui_mac.txt /*MMWindowUseTabBackgroundColor* MMZoomBoth gui_mac.txt /*MMZoomBoth* MS-DOS os_msdos.txt /*MS-DOS* MS-Windows os_win32.txt /*MS-Windows* diff --git a/src/MacVim/Base.lproj/Preferences.xib b/src/MacVim/Base.lproj/Preferences.xib index 1aa2e8057d..893ae01353 100644 --- a/src/MacVim/Base.lproj/Preferences.xib +++ b/src/MacVim/Base.lproj/Preferences.xib @@ -280,11 +280,11 @@ - + - + @@ -345,11 +345,11 @@ - + - + @@ -358,7 +358,7 @@ + - - - - - - - - - @@ -535,7 +569,7 @@ - + @@ -622,7 +656,7 @@ - + diff --git a/src/MacVim/MMAppController.m b/src/MacVim/MMAppController.m index 1dd4ac5a4e..89d347609e 100644 --- a/src/MacVim/MMAppController.m +++ b/src/MacVim/MMAppController.m @@ -178,6 +178,9 @@ + (void)registerDefaults [NSNumber numberWithInt:210], MMTabOptimumWidthKey, [NSNumber numberWithBool:YES], MMShowAddTabButtonKey, [NSNumber numberWithBool:NO], MMShowTabScrollButtonsKey, + [NSNumber numberWithInt:MMTabColorsModeAutomatic], + MMTabColorsModeKey, + [NSNumber numberWithBool:NO], MMWindowUseTabBackgroundColorKey, [NSNumber numberWithInt:2], MMTextInsetLeftKey, [NSNumber numberWithInt:1], MMTextInsetRightKey, [NSNumber numberWithInt:1], MMTextInsetTopKey, @@ -1238,7 +1241,7 @@ - (void)refreshAllAppearances - (void)refreshAllTabProperties { for (MMVimController *vc in vimControllers) { - [vc.windowController.vimView refreshTabProperties]; + [vc.windowController refreshTabProperties]; } } diff --git a/src/MacVim/MMBackend.h b/src/MacVim/MMBackend.h index 6a730a0f3f..e8271f2ded 100644 --- a/src/MacVim/MMBackend.h +++ b/src/MacVim/MMBackend.h @@ -62,6 +62,7 @@ - (void)setBackgroundColor:(int)color; - (void)setForegroundColor:(int)color; - (void)setSpecialColor:(int)color; +- (void)setTablineColors:(int[6])colors; - (void)setDefaultColorsBackground:(int)bg foreground:(int)fg; - (NSConnection *)connection; - (NSDictionary *)actionDict; diff --git a/src/MacVim/MMBackend.m b/src/MacVim/MMBackend.m index 9f38769967..0d35f841a3 100644 --- a/src/MacVim/MMBackend.m +++ b/src/MacVim/MMBackend.m @@ -293,6 +293,17 @@ - (void)setSpecialColor:(int)color specialColor = MM_COLOR(color); } +- (void)setTablineColors:(int[6])colors +{ + unsigned tabColors[6]; + for (int i = 0; i < 6; i++) { + tabColors[i] = MM_COLOR(colors[i]); + } + NSMutableData *data = [NSMutableData data]; + [data appendBytes:&tabColors length:sizeof(tabColors)]; + [self queueMessage:SetTablineColorsMsgID data:data]; +} + - (void)setDefaultColorsBackground:(int)bg foreground:(int)fg { defaultBackgroundColor = MM_COLOR_WITH_TRANSP(bg,p_transp); diff --git a/src/MacVim/MMTabline/MMTab.m b/src/MacVim/MMTabline/MMTab.m index 1b6de407a9..235af717dc 100644 --- a/src/MacVim/MMTabline/MMTab.m +++ b/src/MacVim/MMTabline/MMTab.m @@ -3,9 +3,10 @@ #import "MMTabline.h" #import "MMHoverButton.h" -#import "MacVim.h" // for availability macros +// Only imported for AVAILABLE_MAC_OS +#import "MacVim.h" -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13 +#if !defined(MAC_OS_X_VERSION_10_13) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13 typedef NSString * NSAnimatablePropertyKey; #endif @@ -46,7 +47,7 @@ - (instancetype)initWithFrame:(NSRect)frameRect tabline:(MMTabline *)tabline [self addSubview:_closeButton]; _titleLabel = [NSTextField new]; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11 +#if defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11 if (AVAILABLE_MAC_OS(10,11)) { _titleLabel.font = [NSFont systemFontOfSize:NSFont.smallSystemFontSize weight:NSFontWeightSemibold]; } else @@ -109,27 +110,29 @@ - (void)setFillColor:(NSColor *)fillColor - (void)setState:(MMTabState)state { + const BOOL hasFocus = (self.window == nil) || [self.window isKeyWindow]; + // Transitions to and from MMTabStateSelected // DO NOT animate so that UX feels snappier. if (state == MMTabStateSelected) { _closeButton.fgColor = _tabline.tablineSelFgColor; - _titleLabel.textColor = _tabline.tablineSelFgColor; + _titleLabel.textColor = hasFocus ? _tabline.tablineSelFgColor : _tabline.tablineUnfocusedSelFgColor; self.fillColor = _tabline.tablineSelBgColor; } else if (state == MMTabStateUnselected) { if (_state == MMTabStateSelected) { _closeButton.fgColor = _tabline.tablineFgColor; - _titleLabel.textColor = _tabline.tablineFgColor; + _titleLabel.textColor = hasFocus ? _tabline.tablineFgColor : _tabline.tablineUnfocusedFgColor; self.fillColor = _tabline.tablineBgColor; } else { _closeButton.animator.fgColor = _tabline.tablineFgColor; - _titleLabel.animator.textColor = _tabline.tablineFgColor; + _titleLabel.animator.textColor = hasFocus ? _tabline.tablineFgColor : _tabline.tablineUnfocusedFgColor; self.animator.fillColor = _tabline.tablineBgColor; } } else { // state == MMTabStateUnselectedHover _closeButton.animator.fgColor = _tabline.tablineSelFgColor; - _titleLabel.animator.textColor = _tabline.tablineSelFgColor; + _titleLabel.animator.textColor = hasFocus ? _tabline.tablineSelFgColor : _tabline.tablineUnfocusedSelFgColor; self.animator.fillColor = self.unselectedHoverColor; } _state = state; @@ -164,6 +167,11 @@ - (void)drawRect:(NSRect)dirtyRect [p transformUsingAffineTransform:transform]; } [p fill]; + NSColor *strokeColor = _tabline.tablineStrokeColor; + if (strokeColor != nil) { + [strokeColor set]; + [p stroke]; + } } @end diff --git a/src/MacVim/MMTabline/MMTabline.h b/src/MacVim/MMTabline/MMTabline.h index a43be7828b..98bef13bdf 100644 --- a/src/MacVim/MMTabline/MMTabline.h +++ b/src/MacVim/MMTabline/MMTabline.h @@ -19,11 +19,18 @@ @property (nonatomic) BOOL useAnimation; @property (nonatomic, readonly) NSInteger numberOfTabs; @property (nonatomic, retain, readonly) MMHoverButton *addTabButton; + @property (nonatomic, retain) NSColor *tablineBgColor; @property (nonatomic, retain) NSColor *tablineFgColor; @property (nonatomic, retain) NSColor *tablineSelBgColor; @property (nonatomic, retain) NSColor *tablineSelFgColor; @property (nonatomic, retain) NSColor *tablineFillFgColor; + +// Derived colors that cannot be set directly +@property (nonatomic, readonly) NSColor *tablineUnfocusedFgColor; +@property (nonatomic, readonly) NSColor *tablineUnfocusedSelFgColor; +@property (nonatomic, readonly) NSColor *tablineStrokeColor; + @property (nonatomic, weak) id delegate; /// Add a tab at the end. It's not selected automatically. @@ -57,7 +64,16 @@ - (void)scrollTabToVisibleAtIndex:(NSInteger)index; - (void)scrollBackwardOneTab; - (void)scrollForwardOneTab; -- (void)setTablineSelBackground:(NSColor *)back foreground:(NSColor *)fore; + +/// Sets the colors used by this tab bar explicitly. Pass nil to use default +/// colors based on the system light/dark modes. +- (void)setColorsTabBg:(NSColor *)tabBg tabFg:(NSColor *)tabFg + selBg:(NSColor *)selBg selFg:(NSColor *)selFg + fill:(NSColor *)fill; + +/// Lets the tabline calculate best colors to use based on background and +/// foreground colors of the selected tab. The colors cannot be nil. +- (void)setAutoColorsSelBg:(NSColor *)back fg:(NSColor *)fore; @end diff --git a/src/MacVim/MMTabline/MMTabline.m b/src/MacVim/MMTabline/MMTabline.m index ff90d46d01..dd237ec239 100644 --- a/src/MacVim/MMTabline/MMTabline.m +++ b/src/MacVim/MMTabline/MMTabline.m @@ -1,6 +1,8 @@ #import #import #import "MMTabline.h" + +// Only imported for getCurrentAppearance() #import "Miscellaneous.h" typedef struct TabWidth { @@ -26,9 +28,20 @@ return button; } -static BOOL isDarkMode(NSAppearance *appearance) { - int flags = getCurrentAppearance(appearance); - return (flags == 1 || flags == 3); +static CGFloat calculateBrightness(NSColor *color) { + if (color.colorSpace.colorSpaceModel == NSColorSpaceModelRGB) { + // Calculate brightness according to a formula from + // the W3C that gives brightness as the eye perceives it. Then lighten + // or darken the default colors based on whether brightness is greater + // than 50% to achieve good visual contrast. + // www.w3.org/WAI/ER/WD-AERT/#color-contrast + CGFloat r, g, b; + [color getRed:&r green:&g blue:&b alpha:NULL]; + return r * 0.299 + g * 0.114 + b * 0.587; + } else if (color.colorSpace.colorSpaceModel == NSColorSpaceModelGray) { + return color.whiteComponent; + } + return 1; } @implementation MMTabline @@ -47,6 +60,7 @@ @implementation MMTabline MMHoverButton *_backwardScrollButton; MMHoverButton *_forwardScrollButton; id _scrollWheelEventMonitor; + AppearanceType _appearance; // cached appearance to avoid querying it every time } @synthesize tablineBgColor = _tablineBgColor; @@ -54,6 +68,8 @@ @implementation MMTabline @synthesize tablineSelBgColor = _tablineSelBgColor; @synthesize tablineSelFgColor = _tablineSelFgColor; @synthesize tablineFillFgColor = _tablineFillFgColor; +@synthesize tablineUnfocusedFgColor = _tablineUnfocusedFgColor; +@synthesize tablineUnfocusedSelFgColor = _tablineUnfocusedSelFgColor; - (instancetype)initWithFrame:(NSRect)frameRect { @@ -111,11 +127,15 @@ - (instancetype)initWithFrame:(NSRect)frameRect [self addConstraint:_addTabButtonTrailingConstraint]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didScroll:) name:NSViewBoundsDidChangeNotification object:_scrollView.contentView]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateTabStates) name:NSWindowDidBecomeKeyNotification object:self.window]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateTabStates) name:NSWindowDidResignKeyNotification object:self.window]; if ([self useRightToLeft]) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateTabsContainerBoundsForRTL:) name:NSViewFrameDidChangeNotification object:_tabsContainer]; } [self addScrollWheelMonitor]; + + _appearance = getCurrentAppearance(self.effectiveAppearance); } return self; } @@ -135,7 +155,8 @@ - (void)updateLayer - (void)viewDidChangeEffectiveAppearance { - for (MMTab *tab in _tabs) tab.state = tab.state; + _appearance = getCurrentAppearance(self.effectiveAppearance); + [self updateTabStates]; } - (void)viewDidHide @@ -217,39 +238,50 @@ - (void)setShowsTabScrollButtons:(BOOL)showsTabScrollButtons - (NSColor *)tablineBgColor { - return _tablineBgColor ?: isDarkMode(self.effectiveAppearance) - ? [NSColor colorWithWhite:0.2 alpha:1] - : [NSColor colorWithWhite:0.8 alpha:1]; + if (_tablineBgColor != nil) + return _tablineBgColor; + switch (_appearance) { + case AppearanceLight: + default: + return [NSColor colorWithWhite:0.8 alpha:1]; + case AppearanceDark: + return [NSColor colorWithWhite:0.2 alpha:1]; + case AppearanceLightHighContrast: + return [NSColor colorWithWhite:0.7 alpha:1]; + case AppearanceDarkHighContrast: + return [NSColor colorWithWhite:0.15 alpha:1]; + } } - (void)setTablineBgColor:(NSColor *)color { _tablineBgColor = color; - for (MMTab *tab in _tabs) tab.state = tab.state; + [self updateTabStates]; } - (NSColor *)tablineFgColor { - return _tablineFgColor ?: NSColor.disabledControlTextColor; + return _tablineFgColor ?: NSColor.secondaryLabelColor; } - (void)setTablineFgColor:(NSColor *)color { _tablineFgColor = color; - for (MMTab *tab in _tabs) tab.state = tab.state; + _tablineUnfocusedFgColor = nil; + [self updateTabStates]; } - (NSColor *)tablineSelBgColor { - return _tablineSelBgColor ?: isDarkMode(self.effectiveAppearance) - ? [NSColor colorWithWhite:0.4 alpha:1] - : NSColor.whiteColor; + return _tablineSelBgColor ?: (_appearance == AppearanceLight || _appearance == AppearanceLightHighContrast) + ? [NSColor colorWithWhite:0.95 alpha:1] + : [NSColor colorWithWhite:0.4 alpha:1]; } - (void)setTablineSelBgColor:(NSColor *)color { _tablineSelBgColor = color; - for (MMTab *tab in _tabs) tab.state = tab.state; + [self updateTabStates]; } - (NSColor *)tablineSelFgColor @@ -260,17 +292,18 @@ - (NSColor *)tablineSelFgColor - (void)setTablineSelFgColor:(NSColor *)color { _tablineSelFgColor = color; + _tablineUnfocusedSelFgColor = nil; _addTabButton.fgColor = color; _backwardScrollButton.fgColor = color; _forwardScrollButton.fgColor = color; - for (MMTab *tab in _tabs) tab.state = tab.state; + [self updateTabStates]; } - (NSColor *)tablineFillFgColor { - return _tablineFillFgColor ?: isDarkMode(self.effectiveAppearance) - ? [NSColor colorWithWhite:0.2 alpha:1] - : [NSColor colorWithWhite:0.8 alpha:1]; + return _tablineFillFgColor ?: (_appearance == AppearanceLight || _appearance == AppearanceLightHighContrast) + ? [NSColor colorWithWhite:0.9 alpha:1] + : [NSColor colorWithWhite:0.25 alpha:1]; } - (void)setTablineFillFgColor:(NSColor *)color @@ -279,6 +312,30 @@ - (void)setTablineFillFgColor:(NSColor *)color self.needsDisplay = YES; } +- (NSColor *)tablineUnfocusedFgColor +{ + return _tablineUnfocusedFgColor ?: _tablineFgColor ?: NSColor.tertiaryLabelColor; +} + +- (NSColor *)tablineUnfocusedSelFgColor +{ + return _tablineUnfocusedSelFgColor ?: _tablineSelFgColor ?: NSColor.tertiaryLabelColor; +} + +- (NSColor *)tablineStrokeColor +{ + if (_appearance == AppearanceLight || _appearance == AppearanceDark) + return nil; // non-high-contrast modes + + // High-contrast modes. Should stroke to make it easier to read. + NSColor *bgColor = self.tablineBgColor; + CGFloat brightness = calculateBrightness(bgColor); + if (brightness > 0.5) + return NSColor.blackColor; + else + return NSColor.whiteColor; +} + - (NSInteger)addTabAtEnd { return [self addTabAtIndex:(_tabs.count ? _tabs.count : 0)]; @@ -511,43 +568,59 @@ - (MMTab *)tabAtIndex:(NSInteger)index return _tabs[index]; } -- (void)setTablineSelBackground:(NSColor *)back foreground:(NSColor *)fore +- (void)setColorsTabBg:(NSColor *)tabBg tabFg:(NSColor *)tabFg + selBg:(NSColor *)selBg selFg:(NSColor *)selFg + fill:(NSColor *)fill { - // Reset to default tabline colors if user doesn't want auto-generated ones. - if ([NSUserDefaults.standardUserDefaults boolForKey:@"MMDefaultTablineColors"]) { - self.tablineBgColor = nil; - self.tablineFgColor = nil; - self.tablineSelBgColor = nil; - self.tablineSelFgColor = nil; - self.tablineFillFgColor = nil; - return; - } + // Don't use the property mutators as we just want to update the states in + // one go at the end. + _tablineSelBgColor = selBg; + _tablineSelFgColor = selFg; + _tablineBgColor = tabBg; + _tablineFgColor = tabFg; + _tablineFillFgColor = fill; + + _tablineUnfocusedFgColor = [_tablineFgColor blendedColorWithFraction:0.4 ofColor:_tablineBgColor]; + _tablineUnfocusedSelFgColor = [_tablineSelFgColor blendedColorWithFraction:0.38 ofColor:_tablineSelBgColor]; + + _addTabButton.fgColor = _tablineSelFgColor; + _backwardScrollButton.fgColor = _tablineSelFgColor; + _forwardScrollButton.fgColor = _tablineSelFgColor; + + [self updateTabStates]; + self.needsDisplay = YES; +} +- (void)setAutoColorsSelBg:(NSColor *)back fg:(NSColor *)fore; +{ // Set the colors for the tabline based on the default background and - // foreground colors. Calculate brightness according to a formula from - // the W3C that gives brightness as the eye perceives it. Then lighten - // or darken the default colors based on whether brightness is greater - // than 50% to achieve good visual contrast. - // www.w3.org/WAI/ER/WD-AERT/#color-contrast - CGFloat r, g, b, brightness; - [back getRed:&r green:&g blue:&b alpha:NULL]; - brightness = r * 0.299 + g * 0.114 + b * 0.587; - - self.tablineSelBgColor = back; + // foreground colors. + const CGFloat brightness = calculateBrightness(back); - self.tablineSelFgColor = (brightness > 0.5) + _tablineSelBgColor = back; + + _tablineSelFgColor = (brightness > 0.5) ? [fore blendedColorWithFraction:0.6 ofColor:NSColor.blackColor] : [fore blendedColorWithFraction:0.6 ofColor:NSColor.whiteColor]; + _addTabButton.fgColor = _tablineSelFgColor; + _backwardScrollButton.fgColor = _tablineSelFgColor; + _forwardScrollButton.fgColor = _tablineSelFgColor; - self.tablineBgColor = (brightness > 0.5) + _tablineBgColor = (brightness > 0.5) ? [back blendedColorWithFraction:0.16 ofColor:NSColor.blackColor] : [back blendedColorWithFraction:0.13 ofColor:NSColor.whiteColor]; - self.tablineFgColor = [self.tablineSelFgColor blendedColorWithFraction:0.5 ofColor:self.tablineBgColor]; + _tablineFgColor = [_tablineSelFgColor blendedColorWithFraction:0.5 ofColor:_tablineBgColor]; + + _tablineUnfocusedFgColor = [_tablineFgColor blendedColorWithFraction:0.4 ofColor:_tablineBgColor]; + _tablineUnfocusedSelFgColor = [_tablineSelFgColor blendedColorWithFraction:0.38 ofColor:_tablineSelBgColor]; - self.tablineFillFgColor = (brightness > 0.5) + _tablineFillFgColor = (brightness > 0.5) ? [back blendedColorWithFraction:0.25 ofColor:NSColor.blackColor] : [back blendedColorWithFraction:0.18 ofColor:NSColor.whiteColor]; + + [self updateTabStates]; + self.needsDisplay = YES; } #pragma mark - Helpers @@ -740,6 +813,11 @@ - (void)fixupLayoutWithAnimation:(BOOL)shouldAnimate [self fixupLayoutWithAnimation:shouldAnimate delayResize:NO]; } +- (void)updateTabStates +{ + for (MMTab *tab in _tabs) tab.state = tab.state; +} + #pragma mark - Right-to-left (RTL) support - (BOOL)useRightToLeft @@ -943,7 +1021,7 @@ - (void)scrollTabToVisibleAtIndex:(NSInteger)index // faster animations. For example, the user might hold down the tab // scrolling buttons (causing them to repeatedly fire) or they might // rapidly click them. -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12 +#if defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12 static NSTimeInterval lastTime = 0; struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); diff --git a/src/MacVim/MMVimController.m b/src/MacVim/MMVimController.m index df12bfa0f4..12fa382f12 100644 --- a/src/MacVim/MMVimController.m +++ b/src/MacVim/MMVimController.m @@ -968,6 +968,26 @@ - (void)handleMessage:(int)msgid data:(NSData *)data } } break; + case SetTablineColorsMsgID: + { + const void *bytes = [data bytes]; + unsigned argbTabBg = *((unsigned*)bytes); bytes += sizeof(unsigned); + unsigned argbTabFg = *((unsigned*)bytes); bytes += sizeof(unsigned); + unsigned argbFillBg = *((unsigned*)bytes); bytes += sizeof(unsigned); + unsigned argbFillFg = *((unsigned*)bytes); bytes += sizeof(unsigned); + unsigned argbSelBg = *((unsigned*)bytes); bytes += sizeof(unsigned); + unsigned argbSelFg = *((unsigned*)bytes); bytes += sizeof(unsigned); + + NSColor *tabBg = [NSColor colorWithRgbInt:argbTabBg]; + NSColor *tabFg = [NSColor colorWithRgbInt:argbTabFg]; + NSColor *fillBg = [NSColor colorWithRgbInt:argbFillBg]; + NSColor *fillFg = [NSColor colorWithRgbInt:argbFillFg]; + NSColor *selBg = [NSColor colorWithRgbInt:argbSelBg]; + NSColor *selFg = [NSColor colorWithRgbInt:argbSelFg]; + + [windowController setTablineColorsTabBg:tabBg tabFg:tabFg fillBg:fillBg fillFg:fillFg selBg:selBg selFg:selFg]; + } + break; case SetDefaultColorsMsgID: { const void *bytes = [data bytes]; diff --git a/src/MacVim/MMVimView.h b/src/MacVim/MMVimView.h index d29b75c63c..f1a49009b3 100644 --- a/src/MacVim/MMVimView.h +++ b/src/MacVim/MMVimView.h @@ -60,6 +60,9 @@ - (void)finishPlaceScrollbars; - (void)setDefaultColorsBackground:(NSColor *)back foreground:(NSColor *)fore; +- (void)setTablineColorsTabBg:(NSColor *)tabBg tabFg:(NSColor *)tabFg + fillBg:(NSColor *)fillBg fillFg:(NSColor *)fillFg + selBg:(NSColor *)selBg selFg:(NSColor *)selFg; - (void)viewWillStartLiveResize; - (void)viewDidEndLiveResize; diff --git a/src/MacVim/MMVimView.m b/src/MacVim/MMVimView.m index 96c6273094..9a7a5a4781 100644 --- a/src/MacVim/MMVimView.m +++ b/src/MacVim/MMVimView.m @@ -35,6 +35,15 @@ MMScrollerTypeBottom }; +typedef enum: NSInteger { + MMTabColorTypeTabBg = 0, + MMTabColorTypeTabFg, + MMTabColorTypeSelBg, + MMTabColorTypeSelFg, + MMTabColorTypeFill, + MMTabColorTypeCount +} MMTabColorType; + // TODO: Move! @interface MMScroller : NSScroller { @@ -72,6 +81,9 @@ - (void)liveResizeDidEnd; @implementation MMVimView +{ + NSColor *tabColors[MMTabColorTypeCount]; +} - (MMVimView *)initWithFrame:(NSRect)frame vimController:(MMVimController *)controller @@ -133,6 +145,9 @@ - (void)dealloc [tabline release]; [scrollbars release]; scrollbars = nil; + for (NSUInteger i = 0; i < MMTabColorTypeCount; i++) + [tabColors[i] release]; + // HACK! The text storage is the principal owner of the text system, but we // keep only a reference to the text view, so release the text storage // first (unless we are using the CoreText renderer). @@ -362,6 +377,7 @@ - (void)refreshTabProperties { NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; tabline.showsTabScrollButtons = [ud boolForKey:MMShowTabScrollButtonsKey]; + [self updateTablineColors]; } - (void)createScrollbarWithIdentifier:(int32_t)ident type:(int)type @@ -453,11 +469,36 @@ - (void)finishPlaceScrollbars } } +- (void)updateTablineColors +{ + NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; + MMTabColorsMode tabColorsMode = [ud integerForKey:MMTabColorsModeKey]; + if (tabColorsMode == MMTabColorsModeDefaultColors) { + [tabline setColorsTabBg:nil + tabFg:nil + selBg:nil + selFg:nil + fill:nil]; + } else if (tabColorsMode == MMTabColorsModeVimColorscheme) { + [tabline setColorsTabBg:tabColors[MMTabColorTypeTabBg] + tabFg:tabColors[MMTabColorTypeTabFg] + selBg:tabColors[MMTabColorTypeSelBg] + selFg:tabColors[MMTabColorTypeSelFg] + fill:tabColors[MMTabColorTypeFill]]; + } else { + // tabColorsMode == MMTabColorsModeAutomatic, but catch-all in case it's + // set to an out-of-range number. + NSColor *back = [[self textView] defaultBackgroundColor]; + NSColor *fore = [[self textView] defaultForegroundColor]; + [tabline setAutoColorsSelBg:back fg:fore]; + } + +} + - (void)setDefaultColorsBackground:(NSColor *)back foreground:(NSColor *)fore { [textView setDefaultColorsBackground:back foreground:fore]; - - [tabline setTablineSelBackground:back foreground:fore]; + [self updateTablineColors]; CALayer *backedLayer = [self layer]; if (backedLayer) { @@ -476,6 +517,21 @@ - (void)setDefaultColorsBackground:(NSColor *)back foreground:(NSColor *)fore [self setNeedsDisplay:YES]; } +- (void)setTablineColorsTabBg:(NSColor *)tabBg tabFg:(NSColor *)tabFg + fillBg:(NSColor *)fillBg fillFg:(NSColor *)fillFg + selBg:(NSColor *)selBg selFg:(NSColor *)selFg +{ + for (NSUInteger i = 0; i < MMTabColorTypeCount; i++) + [tabColors[i] release]; + tabColors[MMTabColorTypeTabBg] = [tabBg retain]; + tabColors[MMTabColorTypeTabFg] = [tabFg retain]; + tabColors[MMTabColorTypeSelBg] = [selBg retain]; + tabColors[MMTabColorTypeSelFg] = [selFg retain]; + tabColors[MMTabColorTypeFill] = [fillBg retain]; + (void)fillFg; // We don't use fillFg as we don't draw anything in the empty area + [self updateTablineColors]; +} + // -- MMTablineDelegate ---------------------------------------------- @@ -594,6 +650,19 @@ - (void)setFrame:(NSRect)frame - (void)viewDidChangeEffectiveAppearance { [vimController appearanceChanged:getCurrentAppearance(self.effectiveAppearance)]; + + NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; + if ([ud integerForKey:MMTabColorsModeKey] == MMTabColorsModeDefaultColors && + [ud boolForKey:MMWindowUseTabBackgroundColorKey]) + { + // Tab line default colors depends on system light/dark modes. We will + // need to notify the window as well if it is set up to use the tab bar + // colors. We need to schedule this for later because the tabline's + // effectAppearance gets changed *after* this method is called, so we + // need to delay the refresh or we would get stale data. + MMWindowController *winController = [vimController windowController]; + [winController performSelectorOnMainThread:@selector(refreshTabProperties) withObject:nil waitUntilDone:NO]; + } } @end // MMVimView diff --git a/src/MacVim/MMWindowController.h b/src/MacVim/MMWindowController.h index df932f0e98..544385f8c2 100644 --- a/src/MacVim/MMWindowController.h +++ b/src/MacVim/MMWindowController.h @@ -84,7 +84,10 @@ - (void)setBackgroundOption:(int)dark; - (void)refreshApperanceMode; - (void)updateResizeConstraints:(BOOL)resizeWindow; - +- (void)setTablineColorsTabBg:(NSColor *)tabBg tabFg:(NSColor *)tabFg + fillBg:(NSColor *)fillBg fillFg:(NSColor *)fillFg + selBg:(NSColor *)selBg selFg:(NSColor *)selFg; +- (void)refreshTabProperties; - (void)setDefaultColorsBackground:(NSColor *)back foreground:(NSColor *)fore; - (void)setFont:(NSFont *)font; - (void)setWideFont:(NSFont *)font; diff --git a/src/MacVim/MMWindowController.m b/src/MacVim/MMWindowController.m index e062796052..a583aa395f 100644 --- a/src/MacVim/MMWindowController.m +++ b/src/MacVim/MMWindowController.m @@ -71,6 +71,7 @@ #import "MMWindow.h" #import "MMWindowController.h" #import "Miscellaneous.h" +#import "MMTabline/MMTabline.h" // These have to be the same as in option.h @@ -672,11 +673,61 @@ - (void)refreshApperanceMode #endif } +- (void)setTablineColorsTabBg:(NSColor *)tabBg tabFg:(NSColor *)tabFg + fillBg:(NSColor *)fillBg fillFg:(NSColor *)fillFg + selBg:(NSColor *)selBg selFg:(NSColor *)selFg +{ + [vimView setTablineColorsTabBg:tabBg tabFg:tabFg fillBg:fillBg fillFg:fillFg selBg:selBg selFg:selFg]; + + if([[NSUserDefaults standardUserDefaults] boolForKey:MMWindowUseTabBackgroundColorKey]) { + if (!vimView.tabline.hidden) { + [self setWindowColorToTablineColor]; + } + } +} + +- (void)setWindowColorToTablineColor +{ + NSColor *defaultBg = vimView.textView.defaultBackgroundColor; + NSColor *tablineColor = vimView.tabline.tablineFillFgColor; + if (defaultBg.alphaComponent == 1.0) { + [self setWindowBackgroundColor:tablineColor]; + } else { + // Make sure 'transparency' Vim setting is preserved + NSColor *colorWithAlpha = [tablineColor colorWithAlphaComponent:defaultBg.alphaComponent]; + [self setWindowBackgroundColor:colorWithAlpha]; + } +} + +- (void)refreshTabProperties +{ + [vimView refreshTabProperties]; + NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; + if([ud boolForKey:MMWindowUseTabBackgroundColorKey] && !vimView.tabline.hidden) { + [self setWindowColorToTablineColor]; + } else { + [self setWindowBackgroundColor:vimView.textView.defaultBackgroundColor]; + } +} + - (void)setDefaultColorsBackground:(NSColor *)back foreground:(NSColor *)fore +{ + [vimView setDefaultColorsBackground:back foreground:fore]; + if([[NSUserDefaults standardUserDefaults] boolForKey:MMWindowUseTabBackgroundColorKey] && + !vimView.tabline.hidden) + { + [self setWindowColorToTablineColor]; + } + else { + [self setWindowBackgroundColor:back]; + } +} + +- (void)setWindowBackgroundColor:(NSColor *)back { // NOTE: This is called when the transparency changes so set the opacity // flag on the window here (should be faster if the window is opaque). - BOOL isOpaque = [back alphaComponent] == 1.0f; + const BOOL isOpaque = [back alphaComponent] == 1.0f; [decoratedWindow setOpaque:isOpaque]; if (fullScreenWindow) [fullScreenWindow setOpaque:isOpaque]; @@ -727,7 +778,7 @@ - (void)setDefaultColorsBackground:(NSColor *)back foreground:(NSColor *)fore // but if we are toggling the titlebar transparent option, we need to set // the window background color in order the title bar to be tinted correctly. if ([[NSUserDefaults standardUserDefaults] - boolForKey:MMTitlebarAppearsTransparentKey]) { + boolForKey:MMTitlebarAppearsTransparentKey]) { if ([back alphaComponent] != 0) { [decoratedWindow setBackgroundColor:back]; } else { @@ -739,8 +790,6 @@ - (void)setDefaultColorsBackground:(NSColor *)back foreground:(NSColor *)fore } } } - - [vimView setDefaultColorsBackground:back foreground:fore]; } - (void)setFont:(NSFont *)font @@ -871,6 +920,14 @@ - (void)showTabline:(BOOL)on [vimView showTabline:on]; [self updateTablineSeparator]; shouldMaximizeWindow = YES; + + if([[NSUserDefaults standardUserDefaults] boolForKey:MMWindowUseTabBackgroundColorKey]) { + if (on) { + [self setWindowColorToTablineColor]; + } else { + [self setWindowBackgroundColor:vimView.textView.defaultBackgroundColor]; + } + } } - (void)showToolbar:(BOOL)on size:(int)size mode:(int)mode diff --git a/src/MacVim/MacVim.h b/src/MacVim/MacVim.h index 515ebe8355..aa12b8c575 100644 --- a/src/MacVim/MacVim.h +++ b/src/MacVim/MacVim.h @@ -301,6 +301,7 @@ extern const char * const MMVimMsgIDStrings[]; MSG(SetWideFontMsgID) \ MSG(VimShouldCloseMsgID) \ MSG(SetDefaultColorsMsgID) \ + MSG(SetTablineColorsMsgID) \ MSG(ExecuteActionMsgID) \ MSG(DropFilesMsgID) \ MSG(DropStringMsgID) \ diff --git a/src/MacVim/Miscellaneous.h b/src/MacVim/Miscellaneous.h index 0d297dd094..a247b3f647 100644 --- a/src/MacVim/Miscellaneous.h +++ b/src/MacVim/Miscellaneous.h @@ -23,6 +23,8 @@ extern NSString *MMTabMaxWidthKey; extern NSString *MMTabOptimumWidthKey; extern NSString *MMShowAddTabButtonKey; extern NSString *MMShowTabScrollButtonsKey; +extern NSString *MMTabColorsModeKey; +extern NSString *MMWindowUseTabBackgroundColorKey; extern NSString *MMTextInsetLeftKey; extern NSString *MMTextInsetRightKey; extern NSString *MMTextInsetTopKey; @@ -104,6 +106,11 @@ enum MMAppearanceModeSelectionEnum { MMAppearanceModeSelectionBackgroundOption = 3, }; +typedef enum : NSInteger { + MMTabColorsModeDefaultColors = 0, ///< Use default colors based on macOS light/dark modes + MMTabColorsModeAutomatic, ///< Automatically derive tab colors based on foreground/background colors + MMTabColorsModeVimColorscheme, ///< Use Vim colorscheme TabLine/TabLineSel/TabLineFill colors +} MMTabColorsMode; enum { // These values are chosen so that the min text view size is not too small @@ -174,7 +181,13 @@ NSView *showHiddenFilesView(void); NSString *normalizeFilename(NSString *filename); NSArray *normalizeFilenames(NSArray *filenames); -int getCurrentAppearance(NSAppearance *appearance); +typedef enum : int { + AppearanceLight = 0, + AppearanceDark, + AppearanceLightHighContrast, + AppearanceDarkHighContrast, +} AppearanceType; +AppearanceType getCurrentAppearance(NSAppearance *appearance); // Pasteboard helpers NSPasteboardType getPasteboardFilenamesType(void); diff --git a/src/MacVim/Miscellaneous.m b/src/MacVim/Miscellaneous.m index 0b1e0523e2..17e9304238 100644 --- a/src/MacVim/Miscellaneous.m +++ b/src/MacVim/Miscellaneous.m @@ -19,6 +19,8 @@ NSString *MMTabOptimumWidthKey = @"MMTabOptimumWidth"; NSString *MMShowAddTabButtonKey = @"MMShowAddTabButton"; NSString *MMShowTabScrollButtonsKey = @"MMShowTabScrollButtons"; +NSString *MMTabColorsModeKey = @"MMTabColorsMode"; +NSString *MMWindowUseTabBackgroundColorKey = @"MMWindowUseTabBackgroundColor"; NSString *MMTextInsetLeftKey = @"MMTextInsetLeft"; NSString *MMTextInsetRightKey = @"MMTextInsetRight"; NSString *MMTextInsetTopKey = @"MMTextInsetTop"; @@ -305,9 +307,9 @@ - (NSInteger)tag -int +AppearanceType getCurrentAppearance(NSAppearance *appearance){ - int flag = 0; // for macOS 10.13 or earlier always return 0; + int flag = AppearanceLight; // for macOS 10.13 or earlier always return 0; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 if (@available(macOS 10.14, *)) { NSAppearanceName appearanceName = [appearance bestMatchFromAppearancesWithNames: @@ -316,11 +318,11 @@ - (NSInteger)tag , NSAppearanceNameAccessibilityHighContrastAqua , NSAppearanceNameAccessibilityHighContrastDarkAqua]]; if ([appearanceName isEqualToString:NSAppearanceNameDarkAqua]) { - flag = 1; + flag = AppearanceDark; } else if ([appearanceName isEqualToString:NSAppearanceNameAccessibilityHighContrastAqua]) { - flag = 2; + flag = AppearanceLightHighContrast; } else if ([appearanceName isEqualToString:NSAppearanceNameAccessibilityHighContrastDarkAqua]) { - flag = 3; + flag = AppearanceDarkHighContrast; } } #endif diff --git a/src/MacVim/gui_macvim.m b/src/MacVim/gui_macvim.m index 3538acbbae..0d030f04ca 100644 --- a/src/MacVim/gui_macvim.m +++ b/src/MacVim/gui_macvim.m @@ -633,6 +633,17 @@ ASLogDebug(@"back=%ld norm=%ld", gui.def_back_pixel, gui.def_norm_pixel); + [[MMBackend sharedInstance] + setDefaultColorsBackground:gui.def_back_pixel + foreground:gui.def_norm_pixel]; +} + +/* + * Called when any highlight has been changed in general + */ + void +gui_mch_update_highlight(void) +{ // If using a highlight group for fullscreen background color we need to // update the app when a new color scheme has been picked. This function // technically wouldn't be called if a user manually set the relevant @@ -641,9 +652,34 @@ if (fuoptions_flags & FUOPT_BGCOLOR_HLGROUP) gui_mch_fuopt_update(); - [[MMBackend sharedInstance] - setDefaultColorsBackground:gui.def_back_pixel - foreground:gui.def_norm_pixel]; + // Update the GUI with tab colors + // We can cache the tabline syn IDs because they will never change. + static int tablineSynIds[3] = { 0 }; + char *tablineSynNames[3] = {"TabLine", "TabLineFill", "TabLineSel"}; + + BOOL hasTablineColors = YES; + int tablineColors[6] = { 0 }; + for (int i = 0; i < 3; i++) { + if (tablineSynIds[i] <= 0) + tablineSynIds[i] = syn_name2id((char_u *)tablineSynNames[i]); + if (tablineSynIds[i] > 0) { + guicolor_T bg, fg; + syn_id2colors(tablineSynIds[i], &fg, &bg); + tablineColors[i*2] = (int)bg; + tablineColors[i*2+1] = (int)fg; + } else { + hasTablineColors = NO; + } + } + if (hasTablineColors) { + // Cache the old colors just so we don't spam the IPC channel if the + // colors didn't actually change. + static int oldTablineColors[6] = { 0 }; + if (memcmp(oldTablineColors, tablineColors, sizeof(oldTablineColors)) != 0) { + memcpy(oldTablineColors, tablineColors, sizeof(oldTablineColors)); + [[MMBackend sharedInstance] setTablineColors:tablineColors]; + } + } } /* @@ -1995,6 +2031,8 @@ { if (!gui.in_use) return; + if (!p_fullscreen) + return; guicolor_T fg, bg; if (fuoptions_flags & FUOPT_BGCOLOR_HLGROUP) { diff --git a/src/highlight.c b/src/highlight.c index a04f158e09..0bf781ab9b 100644 --- a/src/highlight.c +++ b/src/highlight.c @@ -4069,6 +4069,12 @@ highlight_changed(void) #endif // USER_HIGHLIGHT +#if defined(FEAT_GUI) && defined(FEAT_GUI_MACVIM) + // MacVim needs to know about the other highlight colors other than just + // the default fg/bg colors. + if (gui.in_use) + gui_mch_update_highlight(); +#endif return OK; } diff --git a/src/proto/gui_macvim.pro b/src/proto/gui_macvim.pro index 869727d044..7d27521d5d 100644 --- a/src/proto/gui_macvim.pro +++ b/src/proto/gui_macvim.pro @@ -63,6 +63,7 @@ int gui_mch_haskey(char_u *name); void gui_mch_iconify(void); void gui_mch_invert_rectangle(int r, int c, int nr, int nc, int invert); void gui_mch_new_colors(void); +void gui_mch_update_highlight(void); void gui_mch_set_bg_color(guicolor_T color); int gui_mch_is_blinking(void); int gui_mch_is_blink_off(void);