diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index 3cef5d1946e..e20f8545681 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -82,7 +82,14 @@ "properties": { "colorScheme": { "description": "The name of a color scheme to use when unfocused.", - "type": "string" + "oneOf": [ + { + "$ref": "#/$defs/SchemePair" + }, + { + "type": "string" + } + ] }, "foreground": { "$ref": "#/$defs/Color", @@ -233,6 +240,21 @@ }, "type": "object" }, + "SchemePair": { + "description": "Contains both a light and dark color scheme for the Terminal to use, depending on the theme of the application.", + "properties": { + "light": { + "default": "Campbell", + "description": "Name of the scheme to use when the app is using light theme", + "type": "string" + }, + "dark": { + "default": "Campbell", + "description": "Name of the scheme to use when the app is using dark theme", + "type": "string" + }, + } + }, "FontConfig": { "properties": { "face": { @@ -2170,7 +2192,14 @@ "colorScheme": { "default": "Campbell", "description": "Name of the terminal color scheme to use. Color schemes are defined under \"schemes\".", - "type": "string" + "oneOf": [ + { + "$ref": "#/$defs/SchemePair" + }, + { + "type": "string" + } + ] }, "commandline": { "description": "Executable used in the profile.", diff --git a/src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp b/src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp index 721e426761b..b266064977a 100644 --- a/src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp @@ -217,6 +217,30 @@ namespace SettingsModelLocalTests { "name": "Different reference", "colorScheme": "One Half Dark" + }, + { + "name": "rename neither", + "colorScheme": + { + "dark": "One Half Dark", + "light": "One Half Light" + } + }, + { + "name": "rename only light", + "colorScheme": + { + "dark": "One Half Dark", + "light": "Campbell" + } + }, + { + "name": "rename only dark", + "colorScheme": + { + "dark": "Campbell", + "light": "One Half Light" + } } ] }, @@ -289,6 +313,28 @@ namespace SettingsModelLocalTests "selectionBackground": "#FFFFFF", "white": "#DCDFE4", "yellow": "#E5C07B" + }, + { + "name": "One Half Light", + "foreground": "#383A42", + "background": "#FAFAFA", + "cursorColor": "#4F525D", + "black": "#383A42", + "red": "#E45649", + "green": "#50A14F", + "yellow": "#C18301", + "blue": "#0184BC", + "purple": "#A626A4", + "cyan": "#0997B3", + "white": "#FAFAFA", + "brightBlack": "#4F525D", + "brightRed": "#DF6C75", + "brightGreen": "#98C379", + "brightYellow": "#E4C07A", + "brightBlue": "#61AFEF", + "brightPurple": "#C577DD", + "brightCyan": "#56B5C1", + "brightWhite": "#FFFFFF" } ] })json" }; @@ -296,31 +342,63 @@ namespace SettingsModelLocalTests const auto settings{ winrt::make_self(settingsString) }; const auto newName{ L"Campbell (renamed)" }; + settings->UpdateColorSchemeReferences(L"Campbell", newName); - VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().DefaultAppearance().ColorSchemeName()); - VERIFY_IS_TRUE(settings->ProfileDefaults().DefaultAppearance().HasColorSchemeName()); + VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().DefaultAppearance().DarkColorSchemeName()); + VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().DefaultAppearance().LightColorSchemeName()); + VERIFY_IS_TRUE(settings->ProfileDefaults().DefaultAppearance().HasDarkColorSchemeName()); + VERIFY_IS_TRUE(settings->ProfileDefaults().DefaultAppearance().HasLightColorSchemeName()); const auto& profiles{ settings->AllProfiles() }; { const auto& prof{ profiles.GetAt(0) }; - VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName()); - VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName()); + VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().DarkColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName()); + VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().LightColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName()); } { const auto& prof{ profiles.GetAt(1) }; - VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName()); - VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName()); + VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().DarkColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName()); + VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().LightColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName()); } { const auto& prof{ profiles.GetAt(2) }; - VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName()); - VERIFY_IS_FALSE(prof.DefaultAppearance().HasColorSchemeName()); + VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().DarkColorSchemeName()); + VERIFY_IS_FALSE(prof.DefaultAppearance().HasDarkColorSchemeName()); + VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().LightColorSchemeName()); + VERIFY_IS_FALSE(prof.DefaultAppearance().HasLightColorSchemeName()); } { const auto& prof{ profiles.GetAt(3) }; - VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().ColorSchemeName()); - VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName()); + VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().DarkColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName()); + VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().LightColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName()); + } + { + const auto& prof{ profiles.GetAt(4) }; + VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().DarkColorSchemeName()); + VERIFY_ARE_EQUAL(L"One Half Light", prof.DefaultAppearance().LightColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName()); + } + { + const auto& prof{ profiles.GetAt(5) }; + VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().DarkColorSchemeName()); + VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().LightColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName()); + } + { + const auto& prof{ profiles.GetAt(6) }; + VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().DarkColorSchemeName()); + VERIFY_ARE_EQUAL(L"One Half Light", prof.DefaultAppearance().LightColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName()); } } } diff --git a/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp b/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp index 7008feed586..b2eaed29014 100644 --- a/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp @@ -744,7 +744,8 @@ namespace SettingsModelLocalTests VERIFY_ARE_EQUAL(3u, settings->AllProfiles().Size()); for (const auto& profile : settings->AllProfiles()) { - VERIFY_ARE_EQUAL(L"Campbell", profile.DefaultAppearance().ColorSchemeName()); + VERIFY_ARE_EQUAL(L"Campbell", profile.DefaultAppearance().DarkColorSchemeName()); + VERIFY_ARE_EQUAL(L"Campbell", profile.DefaultAppearance().LightColorSchemeName()); } } @@ -959,6 +960,10 @@ namespace SettingsModelLocalTests }, { "name": "profile3", + "closeOnExit": "automatic" + }, + { + "name": "profile4", "closeOnExit": null } ] @@ -968,9 +973,10 @@ namespace SettingsModelLocalTests VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings->AllProfiles().GetAt(0).CloseOnExit()); VERIFY_ARE_EQUAL(CloseOnExitMode::Always, settings->AllProfiles().GetAt(1).CloseOnExit()); VERIFY_ARE_EQUAL(CloseOnExitMode::Never, settings->AllProfiles().GetAt(2).CloseOnExit()); + VERIFY_ARE_EQUAL(CloseOnExitMode::Automatic, settings->AllProfiles().GetAt(3).CloseOnExit()); - // Unknown modes parse as "Graceful" - VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings->AllProfiles().GetAt(3).CloseOnExit()); + // Unknown modes parse as "Automatic" + VERIFY_ARE_EQUAL(CloseOnExitMode::Automatic, settings->AllProfiles().GetAt(4).CloseOnExit()); } void DeserializationTests::TestCloseOnExitCompatibilityShim() diff --git a/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp b/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp index f0a3ed3d02a..4f9fb528f99 100644 --- a/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp @@ -134,7 +134,7 @@ namespace SettingsModelLocalTests "font": { "face": "Cascadia Mono", - "size": 12, + "size": 12.0, "weight": "normal" }, "padding": "8, 8, 8, 8", @@ -250,8 +250,8 @@ namespace SettingsModelLocalTests // complex command with key chords static constexpr std::string_view actionsString4A{ R"([ - { "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+c" }, - { "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+d" } + { "command": { "action": "adjustFontSize", "delta": 1.0 }, "keys": "ctrl+c" }, + { "command": { "action": "adjustFontSize", "delta": 1.0 }, "keys": "ctrl+d" } ])" }; // GH#13323 - these can be fragile. In the past, the order these get // re-serialized as has been not entirely stable. We don't really care @@ -260,7 +260,7 @@ namespace SettingsModelLocalTests // itself. Feel free to change as needed. static constexpr std::string_view actionsString4B{ R"([ { "command": { "action": "findMatch", "direction": "prev" }, "keys": "ctrl+shift+r" }, - { "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+d" } + { "command": { "action": "adjustFontSize", "delta": 1.0 }, "keys": "ctrl+d" } ])" }; // command with name and icon and multiple key chords @@ -284,8 +284,8 @@ namespace SettingsModelLocalTests { "name": "Change font size...", "commands": [ - { "command": { "action": "adjustFontSize", "delta": 1 } }, - { "command": { "action": "adjustFontSize", "delta": -1 } }, + { "command": { "action": "adjustFontSize", "delta": 1.0 } }, + { "command": { "action": "adjustFontSize", "delta": -1.0 } }, { "command": "resetFontSize" }, ] } @@ -478,7 +478,7 @@ namespace SettingsModelLocalTests "name": "Profile with legacy font settings", "fontFace": "Cascadia Mono", - "fontSize": 12, + "fontSize": 12.0, "fontWeight": "normal" })" }; @@ -488,7 +488,7 @@ namespace SettingsModelLocalTests "font": { "face": "Cascadia Mono", - "size": 12, + "size": 12.0, "weight": "normal" } })" }; diff --git a/src/cascadia/LocalTests_SettingsModel/TerminalSettingsTests.cpp b/src/cascadia/LocalTests_SettingsModel/TerminalSettingsTests.cpp index 8680e7f9cd2..0ae0bcc164e 100644 --- a/src/cascadia/LocalTests_SettingsModel/TerminalSettingsTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/TerminalSettingsTests.cpp @@ -779,21 +779,22 @@ namespace SettingsModelLocalTests VERIFY_ARE_EQUAL(6u, settings->ActiveProfiles().Size()); VERIFY_ARE_EQUAL(2u, settings->GlobalSettings().ColorSchemes().Size()); - auto createTerminalSettings = [&](const auto& profile, const auto& schemes) { + auto createTerminalSettings = [&](const auto& profile, const auto& schemes, const auto& Theme) { auto terminalSettings{ winrt::make_self() }; terminalSettings->_ApplyProfileSettings(profile); - terminalSettings->_ApplyAppearanceSettings(profile.DefaultAppearance(), schemes); + terminalSettings->_ApplyAppearanceSettings(profile.DefaultAppearance(), schemes, Theme); return terminalSettings; }; const auto activeProfiles = settings->ActiveProfiles(); const auto colorSchemes = settings->GlobalSettings().ColorSchemes(); - const auto terminalSettings0 = createTerminalSettings(activeProfiles.GetAt(0), colorSchemes); - const auto terminalSettings1 = createTerminalSettings(activeProfiles.GetAt(1), colorSchemes); - const auto terminalSettings2 = createTerminalSettings(activeProfiles.GetAt(2), colorSchemes); - const auto terminalSettings3 = createTerminalSettings(activeProfiles.GetAt(3), colorSchemes); - const auto terminalSettings4 = createTerminalSettings(activeProfiles.GetAt(4), colorSchemes); - const auto terminalSettings5 = createTerminalSettings(activeProfiles.GetAt(5), colorSchemes); + const auto currentTheme = settings->GlobalSettings().CurrentTheme(); + const auto terminalSettings0 = createTerminalSettings(activeProfiles.GetAt(0), colorSchemes, currentTheme); + const auto terminalSettings1 = createTerminalSettings(activeProfiles.GetAt(1), colorSchemes, currentTheme); + const auto terminalSettings2 = createTerminalSettings(activeProfiles.GetAt(2), colorSchemes, currentTheme); + const auto terminalSettings3 = createTerminalSettings(activeProfiles.GetAt(3), colorSchemes, currentTheme); + const auto terminalSettings4 = createTerminalSettings(activeProfiles.GetAt(4), colorSchemes, currentTheme); + const auto terminalSettings5 = createTerminalSettings(activeProfiles.GetAt(5), colorSchemes, currentTheme); VERIFY_ARE_EQUAL(til::color(0x12, 0x34, 0x56), terminalSettings0->CursorColor()); // from color scheme VERIFY_ARE_EQUAL(DEFAULT_CURSOR_COLOR, terminalSettings1->CursorColor()); // default diff --git a/src/cascadia/LocalTests_SettingsModel/pch.h b/src/cascadia/LocalTests_SettingsModel/pch.h index b018bdaa4a6..b2e15b5a7b1 100644 --- a/src/cascadia/LocalTests_SettingsModel/pch.h +++ b/src/cascadia/LocalTests_SettingsModel/pch.h @@ -44,6 +44,7 @@ Author(s): #include #include #include +#include #include #include #include diff --git a/src/cascadia/TerminalApp/App.cpp b/src/cascadia/TerminalApp/App.cpp index c143f2eceda..4d7e5f93763 100644 --- a/src/cascadia/TerminalApp/App.cpp +++ b/src/cascadia/TerminalApp/App.cpp @@ -54,7 +54,7 @@ namespace winrt::TerminalApp::implementation { auto logic = Logic(); logic.RunAsUwp(); // Must set UWP status first, settings might change based on it. - logic.LoadSettings(); + logic.ReloadSettings(); logic.Create(); auto page = logic.GetRoot().as(); diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp index 7062bfd73a9..040c39d29d1 100644 --- a/src/cascadia/TerminalApp/AppLogic.cpp +++ b/src/cascadia/TerminalApp/AppLogic.cpp @@ -191,7 +191,7 @@ namespace winrt::TerminalApp::implementation _reloadSettings = std::make_shared>(winrt::Windows::System::DispatcherQueue::GetForCurrentThread(), std::chrono::milliseconds(100), [weakSelf = get_weak()]() { if (auto self{ weakSelf.get() }) { - self->_ReloadSettings(); + self->ReloadSettings(); } }); @@ -615,7 +615,7 @@ namespace winrt::TerminalApp::implementation if (!_loadedInitialSettings) { // Load settings if we haven't already - LoadSettings(); + ReloadSettings(); } winrt::Windows::Foundation::Size proposedSize{}; @@ -696,7 +696,7 @@ namespace winrt::TerminalApp::implementation if (!_loadedInitialSettings) { // Load settings if we haven't already - LoadSettings(); + ReloadSettings(); } // GH#4620/#5801 - If the user passed --maximized or --fullscreen on the @@ -730,7 +730,7 @@ namespace winrt::TerminalApp::implementation if (!_loadedInitialSettings) { // Load settings if we haven't already - LoadSettings(); + ReloadSettings(); } auto initialPosition{ _settings.GlobalSettings().InitialPosition() }; @@ -760,7 +760,7 @@ namespace winrt::TerminalApp::implementation if (!_loadedInitialSettings) { // Load settings if we haven't already - LoadSettings(); + ReloadSettings(); } // If the position has been specified on the commandline, don't center on launch return _settings.GlobalSettings().CenterOnLaunch() && !_appArgs.GetPosition().has_value(); @@ -776,7 +776,7 @@ namespace winrt::TerminalApp::implementation if (!_loadedInitialSettings) { // Load settings if we haven't already - LoadSettings(); + ReloadSettings(); } return _settings.GlobalSettings().ShowTabsInTitlebar(); @@ -787,7 +787,7 @@ namespace winrt::TerminalApp::implementation if (!_loadedInitialSettings) { // Load settings if we haven't already - LoadSettings(); + ReloadSettings(); } return _settings.GlobalSettings().AlwaysOnTop(); @@ -867,36 +867,6 @@ namespace winrt::TerminalApp::implementation return hr; } - // Method Description: - // - Initialized our settings. See CascadiaSettings for more details. - // Additionally hooks up our callbacks for keybinding events to the - // keybindings object. - // NOTE: This must be called from a MTA if we're running as a packaged - // application. The Windows.Storage APIs require a MTA. If this isn't - // happening during startup, it'll need to happen on a background thread. - void AppLogic::LoadSettings() - { - // Attempt to load the settings. - // If it fails, - // - use Default settings, - // - don't persist them (LoadAll won't save them in this case). - // - _settingsLoadedResult will be set to an error, indicating that - // we should display the loading error. - // * We can't display the error now, because we might not have a - // UI yet. We'll display the error in _OnLoaded. - _settingsLoadedResult = _TryLoadSettings(); - - if (FAILED(_settingsLoadedResult)) - { - _settings = CascadiaSettings::LoadDefaults(); - } - - _loadedInitialSettings = true; - - // Register for directory change notification. - _RegisterSettingsChange(); - } - // Call this function after loading your _settings. // It handles any CPU intensive settings updates (like updating the Jumplist) // which should thus only occur if the settings file actually changed. @@ -920,7 +890,7 @@ namespace winrt::TerminalApp::implementation // Method Description: // - Registers for changes to the settings folder and upon a updated settings - // profile calls _ReloadSettings(). + // profile calls ReloadSettings(). // Arguments: // - // Return Value: @@ -1055,7 +1025,14 @@ namespace winrt::TerminalApp::implementation // Method Description: // - Reloads the settings from the settings.json file. - void AppLogic::_ReloadSettings() + // - When this is called the first time, this initializes our settings. See + // CascadiaSettings for more details. Additionally hooks up our callbacks + // for keybinding events to the keybindings object. + // - NOTE: when called initially, this must be called from a MTA if we're + // running as a packaged application. The Windows.Storage APIs require a + // MTA. If this isn't happening during startup, it'll need to happen on + // a background thread. + void AppLogic::ReloadSettings() { // Attempt to load our settings. // If it fails, @@ -1064,11 +1041,28 @@ namespace winrt::TerminalApp::implementation // - display a loading error _settingsLoadedResult = _TryLoadSettings(); + const auto initialLoad = !_loadedInitialSettings; + _loadedInitialSettings = true; + if (FAILED(_settingsLoadedResult)) { - const winrt::hstring titleKey = USES_RESOURCE(L"ReloadJsonParseErrorTitle"); - const winrt::hstring textKey = USES_RESOURCE(L"ReloadJsonParseErrorText"); - _ShowLoadErrorsDialog(titleKey, textKey, _settingsLoadedResult); + if (initialLoad) + { + _settings = CascadiaSettings::LoadDefaults(); + } + else + { + const winrt::hstring titleKey = USES_RESOURCE(L"ReloadJsonParseErrorTitle"); + const winrt::hstring textKey = USES_RESOURCE(L"ReloadJsonParseErrorText"); + _ShowLoadErrorsDialog(titleKey, textKey, _settingsLoadedResult); + return; + } + } + + if (initialLoad) + { + // Register for directory change notification. + _RegisterSettingsChange(); return; } @@ -1375,7 +1369,7 @@ namespace winrt::TerminalApp::implementation if (!_loadedInitialSettings) { // Load settings if we haven't already - LoadSettings(); + ReloadSettings(); } return AppLogic::_doFindTargetWindow(args, _settings.GlobalSettings().WindowingBehavior()); @@ -1532,7 +1526,7 @@ namespace winrt::TerminalApp::implementation if (!_loadedInitialSettings) { // Load settings if we haven't already - LoadSettings(); + ReloadSettings(); } return _settings.GlobalSettings().AutoHideWindow(); @@ -1553,7 +1547,7 @@ namespace winrt::TerminalApp::implementation if (!_loadedInitialSettings) { // Load settings if we haven't already - LoadSettings(); + ReloadSettings(); } return _root != nullptr ? _root->ShouldImmediatelyHandoffToElevated(_settings) : false; @@ -1666,7 +1660,7 @@ namespace winrt::TerminalApp::implementation if (!_loadedInitialSettings) { // Load settings if we haven't already - LoadSettings(); + ReloadSettings(); } return _settings.GlobalSettings().MinimizeToNotificationArea(); @@ -1677,7 +1671,7 @@ namespace winrt::TerminalApp::implementation if (!_loadedInitialSettings) { // Load settings if we haven't already - LoadSettings(); + ReloadSettings(); } return _settings.GlobalSettings().AlwaysShowNotificationIcon(); @@ -1693,7 +1687,7 @@ namespace winrt::TerminalApp::implementation if (!_loadedInitialSettings) { // Load settings if we haven't already - LoadSettings(); + ReloadSettings(); } return _settings.GlobalSettings().CurrentTheme(); } diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h index f4abe8254f2..5534979b973 100644 --- a/src/cascadia/TerminalApp/AppLogic.h +++ b/src/cascadia/TerminalApp/AppLogic.h @@ -62,7 +62,8 @@ namespace winrt::TerminalApp::implementation bool IsUwp() const noexcept; void RunAsUwp(); bool IsElevated() const noexcept; - void LoadSettings(); + void ReloadSettings(); + [[nodiscard]] Microsoft::Terminal::Settings::Model::CascadiaSettings GetSettings() const noexcept; void Quit(); @@ -195,7 +196,6 @@ namespace winrt::TerminalApp::implementation void _ProcessLazySettingsChanges(); void _RegisterSettingsChange(); fire_and_forget _DispatchReloadSettings(); - void _ReloadSettings(); void _OpenSettingsUI(); bool _hasCommandLineArguments{ false }; diff --git a/src/cascadia/TerminalApp/AppLogic.idl b/src/cascadia/TerminalApp/AppLogic.idl index 0f77af0c8cd..b7a92ea1103 100644 --- a/src/cascadia/TerminalApp/AppLogic.idl +++ b/src/cascadia/TerminalApp/AppLogic.idl @@ -59,7 +59,7 @@ namespace TerminalApp void Quit(); - void LoadSettings(); + void ReloadSettings(); Windows.UI.Xaml.UIElement GetRoot(); void SetInboundListener(); diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.cpp b/src/cascadia/TerminalSettingsEditor/Appearances.cpp index 4b4b5a5a361..ef77b5f6f73 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.cpp +++ b/src/cascadia/TerminalSettingsEditor/Appearances.cpp @@ -243,7 +243,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation _PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentCursorShape" }); _PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsVintageCursor" }); } - else if (settingName == L"ColorSchemeName") + else if (settingName == L"DarkColorSchemeName" || settingName == L"LightColorSchemeName") { _PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentColorScheme" }); } @@ -355,7 +355,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation ColorScheme Appearances::CurrentColorScheme() { - const auto schemeName{ Appearance().ColorSchemeName() }; + const auto schemeName{ Appearance().DarkColorSchemeName() }; if (const auto scheme{ Appearance().Schemes().TryLookup(schemeName) }) { return scheme; @@ -370,7 +370,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void Appearances::CurrentColorScheme(const ColorScheme& val) { - Appearance().ColorSchemeName(val.Name()); + Appearance().DarkColorSchemeName(val.Name()); + Appearance().LightColorSchemeName(val.Name()); } bool Appearances::IsVintageCursor() const diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.h b/src/cascadia/TerminalSettingsEditor/Appearances.h index 207a1f8846a..2f67b03a9b2 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.h +++ b/src/cascadia/TerminalSettingsEditor/Appearances.h @@ -87,7 +87,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation OBSERVABLE_PROJECTED_SETTING(_appearance, RetroTerminalEffect); OBSERVABLE_PROJECTED_SETTING(_appearance, CursorShape); OBSERVABLE_PROJECTED_SETTING(_appearance, CursorHeight); - OBSERVABLE_PROJECTED_SETTING(_appearance, ColorSchemeName); + OBSERVABLE_PROJECTED_SETTING(_appearance, DarkColorSchemeName); + OBSERVABLE_PROJECTED_SETTING(_appearance, LightColorSchemeName); OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImagePath); OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageOpacity); OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageStretchMode); diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.idl b/src/cascadia/TerminalSettingsEditor/Appearances.idl index 303e94b0d4a..e31f7e41703 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.idl +++ b/src/cascadia/TerminalSettingsEditor/Appearances.idl @@ -37,7 +37,8 @@ namespace Microsoft.Terminal.Settings.Editor OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Single, FontSize); OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Text.FontWeight, FontWeight); - OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, ColorSchemeName); + OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, DarkColorSchemeName); + OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, LightColorSchemeName); OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Boolean, RetroTerminalEffect); OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Core.CursorStyle, CursorShape); OBSERVABLE_PROJECTED_APPEARANCE_SETTING(UInt32, CursorHeight); diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.xaml b/src/cascadia/TerminalSettingsEditor/Appearances.xaml index 8a6a5d45aa9..9bed48c7ef5 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.xaml +++ b/src/cascadia/TerminalSettingsEditor/Appearances.xaml @@ -39,10 +39,11 @@ Style="{StaticResource TextBlockSubHeaderStyle}" /> + + ClearSettingValue="{x:Bind Appearance.ClearDarkColorSchemeName}" + HasSettingValue="{x:Bind Appearance.HasDarkColorSchemeName, Mode=OneWay}" + SettingOverrideSource="{x:Bind Appearance.DarkColorSchemeNameOverrideSource, Mode=OneWay}"> diff --git a/src/cascadia/TerminalSettingsEditor/ColorSchemeViewModel.cpp b/src/cascadia/TerminalSettingsEditor/ColorSchemeViewModel.cpp index 62491f7418d..160f5a3839b 100644 --- a/src/cascadia/TerminalSettingsEditor/ColorSchemeViewModel.cpp +++ b/src/cascadia/TerminalSettingsEditor/ColorSchemeViewModel.cpp @@ -52,7 +52,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation bool ColorSchemeViewModel::IsDefaultScheme() { - return _Name == _settings.ProfileDefaults().DefaultAppearance().ColorSchemeName(); + const auto defaultAppearance = _settings.ProfileDefaults().DefaultAppearance(); + return defaultAppearance.LightColorSchemeName() == defaultAppearance.DarkColorSchemeName() && + _Name == defaultAppearance.LightColorSchemeName(); } void ColorSchemeViewModel::RefreshIsDefault() diff --git a/src/cascadia/TerminalSettingsEditor/ColorSchemesPageViewModel.cpp b/src/cascadia/TerminalSettingsEditor/ColorSchemesPageViewModel.cpp index d5c1280f437..badc52b4ac3 100644 --- a/src/cascadia/TerminalSettingsEditor/ColorSchemesPageViewModel.cpp +++ b/src/cascadia/TerminalSettingsEditor/ColorSchemesPageViewModel.cpp @@ -189,7 +189,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { if (_CurrentScheme) { - _settings.ProfileDefaults().DefaultAppearance().ColorSchemeName(_CurrentScheme.Name()); + _settings.ProfileDefaults().DefaultAppearance().LightColorSchemeName(_CurrentScheme.Name()); + _settings.ProfileDefaults().DefaultAppearance().DarkColorSchemeName(_CurrentScheme.Name()); for (const auto scheme : _AllColorSchemes) { auto schemeImpl{ get_self(scheme) }; diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp b/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp index d48763eca1c..90513b146ca 100644 --- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp +++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp @@ -18,6 +18,7 @@ static constexpr std::string_view SelectionBackgroundKey{ "selectionBackground" static constexpr std::string_view CursorColorKey{ "cursorColor" }; static constexpr std::string_view LegacyAcrylicTransparencyKey{ "acrylicOpacity" }; static constexpr std::string_view OpacityKey{ "opacity" }; +static constexpr std::string_view ColorSchemeKey{ "colorScheme" }; AppearanceConfig::AppearanceConfig(winrt::weak_ref sourceProfile) : _sourceProfile(std::move(sourceProfile)) @@ -33,6 +34,9 @@ winrt::com_ptr AppearanceConfig::CopyAppearance(const Appearan appearance->_CursorColor = source->_CursorColor; appearance->_Opacity = source->_Opacity; + appearance->_DarkColorSchemeName = source->_DarkColorSchemeName; + appearance->_LightColorSchemeName = source->_LightColorSchemeName; + #define APPEARANCE_SETTINGS_COPY(type, name, jsonKey, ...) \ appearance->_##name = source->_##name; MTSM_APPEARANCE_SETTINGS(APPEARANCE_SETTINGS_COPY) @@ -50,6 +54,19 @@ Json::Value AppearanceConfig::ToJson() const JsonUtils::SetValueForKey(json, SelectionBackgroundKey, _SelectionBackground); JsonUtils::SetValueForKey(json, CursorColorKey, _CursorColor); JsonUtils::SetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter{}); + if (HasDarkColorSchemeName() || HasLightColorSchemeName()) + { + // check if the setting is coming from the UI, if so grab the ColorSchemeName until the settings UI is fixed. + if (_LightColorSchemeName != _DarkColorSchemeName) + { + JsonUtils::SetValueForKey(json["colorScheme"], "dark", _DarkColorSchemeName); + JsonUtils::SetValueForKey(json["colorScheme"], "light", _LightColorSchemeName); + } + else + { + JsonUtils::SetValueForKey(json, "colorScheme", _DarkColorSchemeName); + } + } #define APPEARANCE_SETTINGS_TO_JSON(type, name, jsonKey, ...) \ JsonUtils::SetValueForKey(json, jsonKey, _##name); @@ -79,6 +96,18 @@ void AppearanceConfig::LayerJson(const Json::Value& json) JsonUtils::GetValueForKey(json, LegacyAcrylicTransparencyKey, _Opacity); JsonUtils::GetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter{}); + if (json["colorScheme"].isString()) + { + // to make the UI happy, set ColorSchemeName. + JsonUtils::GetValueForKey(json, ColorSchemeKey, _DarkColorSchemeName); + _LightColorSchemeName = _DarkColorSchemeName; + } + else if (json["colorScheme"].isObject()) + { + // to make the UI happy, set ColorSchemeName to whatever the dark value is. + JsonUtils::GetValueForKey(json["colorScheme"], "dark", _DarkColorSchemeName); + JsonUtils::GetValueForKey(json["colorScheme"], "light", _LightColorSchemeName); + } #define APPEARANCE_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \ JsonUtils::GetValueForKey(json, jsonKey, _##name); diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h index bbc30927eb7..7e8f35e6633 100644 --- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h +++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h @@ -42,6 +42,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, CursorColor, nullptr); INHERITABLE_SETTING(Model::IAppearanceConfig, double, Opacity, 1.0); + INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, DarkColorSchemeName, L"Campbell"); + INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, LightColorSchemeName, L"Campbell"); + #define APPEARANCE_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \ INHERITABLE_SETTING(Model::IAppearanceConfig, type, name, ##__VA_ARGS__) MTSM_APPEARANCE_SETTINGS(APPEARANCE_SETTINGS_INITIALIZE) diff --git a/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.cpp b/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.cpp index a69f44eaecf..948b1822f8c 100644 --- a/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.cpp +++ b/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.cpp @@ -31,7 +31,8 @@ void AzureCloudShellGenerator::GenerateProfiles(std::vectorStartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY }); - azureCloudShellProfile->DefaultAppearance().ColorSchemeName(L"Vintage"); + azureCloudShellProfile->DefaultAppearance().DarkColorSchemeName(L"Vintage"); + azureCloudShellProfile->DefaultAppearance().LightColorSchemeName(L"Vintage"); azureCloudShellProfile->ConnectionType(AzureConnection::ConnectionType()); profiles.emplace_back(std::move(azureCloudShellProfile)); } diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp index 9712c6e51cf..c9aa9ff8e81 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp @@ -326,6 +326,8 @@ Model::Profile CascadiaSettings::DuplicateProfile(const Model::Profile& source) DUPLICATE_SETTING_MACRO_SUB(appearance, target, SelectionBackground); DUPLICATE_SETTING_MACRO_SUB(appearance, target, CursorColor); DUPLICATE_SETTING_MACRO_SUB(appearance, target, Opacity); + DUPLICATE_SETTING_MACRO_SUB(appearance, target, DarkColorSchemeName); + DUPLICATE_SETTING_MACRO_SUB(appearance, target, LightColorSchemeName); } // UnfocusedAppearance is treated as a single setting, @@ -430,22 +432,29 @@ void CascadiaSettings::_validateSettings() void CascadiaSettings::_validateAllSchemesExist() { const auto colorSchemes = _globals->ColorSchemes(); - auto foundInvalidScheme = false; + auto foundInvalidDarkScheme = false; + auto foundInvalidLightScheme = false; for (const auto& profile : _allProfiles) { for (const auto& appearance : std::array{ profile.DefaultAppearance(), profile.UnfocusedAppearance() }) { - if (appearance && !colorSchemes.HasKey(appearance.ColorSchemeName())) + if (appearance && !colorSchemes.HasKey(appearance.DarkColorSchemeName())) { - // Clear the user set color scheme. We'll just fallback instead. - appearance.ClearColorSchemeName(); - foundInvalidScheme = true; + // Clear the user set dark color scheme. We'll just fallback instead. + appearance.ClearDarkColorSchemeName(); + foundInvalidDarkScheme = true; + } + if (appearance && !colorSchemes.HasKey(appearance.LightColorSchemeName())) + { + // Clear the user set light color scheme. We'll just fallback instead. + appearance.ClearLightColorSchemeName(); + foundInvalidLightScheme = true; } } } - if (foundInvalidScheme) + if (foundInvalidDarkScheme || foundInvalidLightScheme) { _warnings.Append(SettingsLoadWarnings::UnknownColorScheme); } @@ -937,24 +946,6 @@ bool CascadiaSettings::_hasInvalidColorScheme(const Model::Command& command) con return invalid; } -// Method Description: -// - Lookup the color scheme for a given profile. If the profile doesn't exist, -// or the scheme name listed in the profile doesn't correspond to a scheme, -// this will return `nullptr`. -// Arguments: -// - profileGuid: the GUID of the profile to find the scheme for. -// Return Value: -// - a non-owning pointer to the scheme. -Model::ColorScheme CascadiaSettings::GetColorSchemeForProfile(const Model::Profile& profile) const -{ - if (!profile) - { - return nullptr; - } - const auto schemeName = profile.DefaultAppearance().ColorSchemeName(); - return _globals->ColorSchemes().TryLookup(schemeName); -} - // Method Description: // - updates all references to that color scheme with the new name // Arguments: @@ -966,26 +957,41 @@ void CascadiaSettings::UpdateColorSchemeReferences(const winrt::hstring& oldName { // update profiles.defaults, if necessary if (_baseLayerProfile && - _baseLayerProfile->DefaultAppearance().HasColorSchemeName() && - _baseLayerProfile->DefaultAppearance().ColorSchemeName() == oldName) + _baseLayerProfile->DefaultAppearance().HasDarkColorSchemeName() && + _baseLayerProfile->DefaultAppearance().DarkColorSchemeName() == oldName) + { + _baseLayerProfile->DefaultAppearance().DarkColorSchemeName(newName); + } + // NOT else-if, because both could match + if (_baseLayerProfile && + _baseLayerProfile->DefaultAppearance().HasLightColorSchemeName() && + _baseLayerProfile->DefaultAppearance().LightColorSchemeName() == oldName) { - _baseLayerProfile->DefaultAppearance().ColorSchemeName(newName); + _baseLayerProfile->DefaultAppearance().LightColorSchemeName(newName); } // update all profiles referencing this color scheme for (const auto& profile : _allProfiles) { const auto defaultAppearance = profile.DefaultAppearance(); - if (defaultAppearance.HasColorSchemeName() && defaultAppearance.ColorSchemeName() == oldName) + if (defaultAppearance.HasLightColorSchemeName() && defaultAppearance.LightColorSchemeName() == oldName) { - defaultAppearance.ColorSchemeName(newName); + defaultAppearance.LightColorSchemeName(newName); + } + if (defaultAppearance.HasDarkColorSchemeName() && defaultAppearance.DarkColorSchemeName() == oldName) + { + defaultAppearance.DarkColorSchemeName(newName); } - if (profile.UnfocusedAppearance()) + if (auto unfocused{ profile.UnfocusedAppearance() }) { - if (profile.UnfocusedAppearance().HasColorSchemeName() && profile.UnfocusedAppearance().ColorSchemeName() == oldName) + if (unfocused.HasLightColorSchemeName() && unfocused.LightColorSchemeName() == oldName) + { + unfocused.LightColorSchemeName(newName); + } + if (unfocused.HasDarkColorSchemeName() && unfocused.DarkColorSchemeName() == oldName) { - profile.UnfocusedAppearance().ColorSchemeName(newName); + unfocused.DarkColorSchemeName(newName); } } } diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.h b/src/cascadia/TerminalSettingsModel/CascadiaSettings.h index dead1629ff2..d8543e74b5a 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.h +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.h @@ -124,7 +124,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation Model::Profile ProfileDefaults() const; Model::Profile CreateNewProfile(); Model::Profile FindProfile(const winrt::guid& guid) const noexcept; - Model::ColorScheme GetColorSchemeForProfile(const Model::Profile& profile) const; void UpdateColorSchemeReferences(const winrt::hstring& oldName, const winrt::hstring& newName); Model::Profile GetProfileForArgs(const Model::NewTerminalArgs& newTerminalArgs) const; Model::Profile GetProfileByName(const winrt::hstring& name) const; diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.idl b/src/cascadia/TerminalSettingsModel/CascadiaSettings.idl index fb69e58ffc8..5a1987dcf3e 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.idl +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.idl @@ -45,7 +45,6 @@ namespace Microsoft.Terminal.Settings.Model Profile CreateNewProfile(); Profile FindProfile(Guid profileGuid); - ColorScheme GetColorSchemeForProfile(Profile profile); void UpdateColorSchemeReferences(String oldName, String newName); Profile GetProfileForArgs(NewTerminalArgs newTerminalArgs); diff --git a/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl b/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl index 2cfa305dec4..6352de64b08 100644 --- a/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl +++ b/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl @@ -5,7 +5,7 @@ import "Profile.idl"; #include "IInheritable.idl.h" #define INHERITABLE_APPEARANCE_SETTING(Type, Name) \ - _BASE_INHERITABLE_SETTING(Type, Name); \ + _BASE_INHERITABLE_SETTING(Type, Name); \ Microsoft.Terminal.Settings.Model.IAppearanceConfig Name##OverrideSource { get; } namespace Microsoft.Terminal.Settings.Model @@ -22,9 +22,7 @@ namespace Microsoft.Terminal.Settings.Model Vertical_Bottom = 0x20 }; - [flags] - enum IntenseStyle - { + [flags] enum IntenseStyle { Bold = 0x1, Bright = 0x2, All = 0xffffffff @@ -33,7 +31,10 @@ namespace Microsoft.Terminal.Settings.Model interface IAppearanceConfig { Microsoft.Terminal.Settings.Model.Profile SourceProfile { get; }; - INHERITABLE_APPEARANCE_SETTING(String, ColorSchemeName); + + INHERITABLE_APPEARANCE_SETTING(String, DarkColorSchemeName); + INHERITABLE_APPEARANCE_SETTING(String, LightColorSchemeName); + INHERITABLE_APPEARANCE_SETTING(Windows.Foundation.IReference, Foreground); INHERITABLE_APPEARANCE_SETTING(Windows.Foundation.IReference, Background); INHERITABLE_APPEARANCE_SETTING(Windows.Foundation.IReference, SelectionBackground); diff --git a/src/cascadia/TerminalSettingsModel/MTSMSettings.h b/src/cascadia/TerminalSettingsModel/MTSMSettings.h index 3cae1919883..91ff1b068a4 100644 --- a/src/cascadia/TerminalSettingsModel/MTSMSettings.h +++ b/src/cascadia/TerminalSettingsModel/MTSMSettings.h @@ -109,7 +109,6 @@ Author(s): X(bool, RetroTerminalEffect, "experimental.retroTerminalEffect", false) \ X(hstring, PixelShaderPath, "experimental.pixelShaderPath") \ X(ConvergedAlignment, BackgroundImageAlignment, "backgroundImageAlignment", ConvergedAlignment::Horizontal_Center | ConvergedAlignment::Vertical_Center) \ - X(hstring, ColorSchemeName, "colorScheme", L"Campbell") \ X(hstring, BackgroundImagePath, "backgroundImage") \ X(Model::IntenseStyle, IntenseTextStyle, "intenseTextStyle", Model::IntenseStyle::Bright) \ X(Core::AdjustTextMode, AdjustIndistinguishableColors, "adjustIndistinguishableColors", Core::AdjustTextMode::Never) diff --git a/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.cpp b/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.cpp index 5db52c810b6..ae04753a73c 100644 --- a/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.cpp +++ b/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.cpp @@ -319,7 +319,8 @@ void PowershellCoreProfileGenerator::GenerateProfiles(std::vectorCommandline(winrt::hstring{ quotedCommandline }); profile->StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY }); - profile->DefaultAppearance().ColorSchemeName(L"Campbell"); + profile->DefaultAppearance().DarkColorSchemeName(L"Campbell"); + profile->DefaultAppearance().LightColorSchemeName(L"Campbell"); profile->Icon(winrt::hstring{ WI_IsFlagSet(psI.flags, PowerShellFlags::Preview) ? POWERSHELL_PREVIEW_ICON : POWERSHELL_ICON }); if (first) diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp index 0ba57857303..39510e1b951 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp @@ -57,7 +57,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation const auto globals = appSettings.GlobalSettings(); settings->_ApplyProfileSettings(profile); settings->_ApplyGlobalSettings(globals); - settings->_ApplyAppearanceSettings(profile.DefaultAppearance(), globals.ColorSchemes()); + settings->_ApplyAppearanceSettings(profile.DefaultAppearance(), globals.ColorSchemes(), globals.CurrentTheme()); return settings; } @@ -91,7 +91,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { const auto globals = appSettings.GlobalSettings(); auto childImpl = settings->CreateChild(); - childImpl->_ApplyAppearanceSettings(unfocusedAppearance, globals.ColorSchemes()); + childImpl->_ApplyAppearanceSettings(unfocusedAppearance, globals.ColorSchemes(), globals.CurrentTheme()); child = *childImpl; } @@ -183,17 +183,50 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation return settingsPair; } - void TerminalSettings::_ApplyAppearanceSettings(const IAppearanceConfig& appearance, const Windows::Foundation::Collections::IMapView& schemes) + // I'm not even joking, this is the recommended way to do this: + // https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/apply-windows-themes#know-when-dark-mode-is-enabled + bool _isSystemInDarkTheme() + { + static auto isColorLight = [](const Windows::UI::Color& clr) -> bool { + return (((5 * clr.G) + (2 * clr.R) + clr.B) > (8 * 128)); + }; + return isColorLight(Windows::UI::ViewManagement::UISettings().GetColorValue(Windows::UI::ViewManagement::UIColorType::Foreground)); + } + + void TerminalSettings::_ApplyAppearanceSettings(const IAppearanceConfig& appearance, + const Windows::Foundation::Collections::IMapView& schemes, + const winrt::Microsoft::Terminal::Settings::Model::Theme currentTheme) { _CursorShape = appearance.CursorShape(); _CursorHeight = appearance.CursorHeight(); - if (!appearance.ColorSchemeName().empty()) + + auto requestedTheme = currentTheme.RequestedTheme(); + if (requestedTheme == winrt::Windows::UI::Xaml::ElementTheme::Default) + { + requestedTheme = _isSystemInDarkTheme() ? + winrt::Windows::UI::Xaml::ElementTheme::Dark : + winrt::Windows::UI::Xaml::ElementTheme::Light; + } + + switch (requestedTheme) { - if (const auto scheme = schemes.TryLookup(appearance.ColorSchemeName())) + case winrt::Windows::UI::Xaml::ElementTheme::Light: + if (const auto scheme = schemes.TryLookup(appearance.LightColorSchemeName())) { ApplyColorScheme(scheme); } + break; + case winrt::Windows::UI::Xaml::ElementTheme::Dark: + if (const auto scheme = schemes.TryLookup(appearance.DarkColorSchemeName())) + { + ApplyColorScheme(scheme); + } + break; + case winrt::Windows::UI::Xaml::ElementTheme::Default: + // This shouldn't happen! + break; } + if (appearance.Foreground()) { _DefaultForeground = til::color{ appearance.Foreground().Value() }; diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.h b/src/cascadia/TerminalSettingsModel/TerminalSettings.h index 0dd65cdfbb7..e92ce3aeed9 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.h @@ -170,7 +170,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation void _ApplyGlobalSettings(const Model::GlobalAppSettings& globalSettings) noexcept; void _ApplyAppearanceSettings(const Microsoft::Terminal::Settings::Model::IAppearanceConfig& appearance, - const Windows::Foundation::Collections::IMapView& schemes); + const Windows::Foundation::Collections::IMapView& schemes, + const winrt::Microsoft::Terminal::Settings::Model::Theme currentTheme); friend class SettingsModelLocalTests::TerminalSettingsTests; }; diff --git a/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp b/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp index 840835cf1f3..373282866a6 100644 --- a/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp +++ b/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp @@ -53,7 +53,8 @@ static winrt::com_ptr makeProfile(const std::wstring& d std::wstring command{}; THROW_IF_FAILED(wil::GetSystemDirectoryW(command)); WSLDistro->Commandline(winrt::hstring{ command + L"\\wsl.exe -d " + distName }); - WSLDistro->DefaultAppearance().ColorSchemeName(L"Campbell"); + WSLDistro->DefaultAppearance().DarkColorSchemeName(L"Campbell"); + WSLDistro->DefaultAppearance().LightColorSchemeName(L"Campbell"); if (isWslDashDashCdAvailableForLinuxPaths()) { WSLDistro->StartingDirectory(winrt::hstring{ WslHomeDirectory }); diff --git a/src/cascadia/TerminalSettingsModel/pch.h b/src/cascadia/TerminalSettingsModel/pch.h index f8266b66fd1..75b789ed581 100644 --- a/src/cascadia/TerminalSettingsModel/pch.h +++ b/src/cascadia/TerminalSettingsModel/pch.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index 90524d9a148..4ab2d0031bd 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -390,6 +390,7 @@ void AppHost::Initialize() _window->DragRegionClicked([this]() { _logic.TitlebarClicked(); }); _window->WindowVisibilityChanged([this](bool showOrHide) { _logic.WindowVisibilityChanged(showOrHide); }); + _window->UpdateSettingsRequested([this]() { _logic.ReloadSettings(); }); _revokers.RequestedThemeChanged = _logic.RequestedThemeChanged(winrt::auto_revoke, { this, &AppHost::_UpdateTheme }); _revokers.FullscreenChanged = _logic.FullscreenChanged(winrt::auto_revoke, { this, &AppHost::_FullscreenChanged }); diff --git a/src/cascadia/WindowsTerminal/IslandWindow.cpp b/src/cascadia/WindowsTerminal/IslandWindow.cpp index f42212912d2..446d1b46506 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/IslandWindow.cpp @@ -658,6 +658,18 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize } break; } + case WM_SETTINGCHANGE: + { + const std::wstring param{ (wchar_t*)lparam }; + // ImmersiveColorSet seems to be the notification that the OS theme + // changed. If that happens, let the app know, so it can hot-reload + // themes, color schemes that might depend on the OS theme + if (param == L"ImmersiveColorSet") + { + _UpdateSettingsRequestedHandlers(); + } + break; + } case WM_ENDSESSION: { // For WM_QUERYENDSESSION and WM_ENDSESSION, refer to: diff --git a/src/cascadia/WindowsTerminal/IslandWindow.h b/src/cascadia/WindowsTerminal/IslandWindow.h index 368e5321e8b..b0d3efff5c5 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.h +++ b/src/cascadia/WindowsTerminal/IslandWindow.h @@ -81,6 +81,7 @@ class IslandWindow : WINRT_CALLBACK(WindowMoved, winrt::delegate); WINRT_CALLBACK(WindowVisibilityChanged, winrt::delegate); + WINRT_CALLBACK(UpdateSettingsRequested, winrt::delegate); protected: void ForceResize() diff --git a/src/cascadia/inc/ControlProperties.h b/src/cascadia/inc/ControlProperties.h index 5911fa26183..8132d579e59 100644 --- a/src/cascadia/inc/ControlProperties.h +++ b/src/cascadia/inc/ControlProperties.h @@ -16,7 +16,7 @@ X(winrt::Microsoft::Terminal::Core::AdjustTextMode, AdjustIndistinguishableColors, winrt::Microsoft::Terminal::Core::AdjustTextMode::Never) // --------------------------- Control Appearance --------------------------- -// All of these settings are defined in IControlSettings. +// All of these settings are defined in IControlAppearance. #define CONTROL_APPEARANCE_SETTINGS(X) \ X(til::color, SelectionBackground, DEFAULT_FOREGROUND) \ X(double, Opacity, 1.0) \