diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index 07e584c6ba7..319e0bae7a8 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -1401,7 +1401,8 @@ "properties": { "acrylicOpacity": { "default": 0.5, - "description": "When useAcrylic is set to true, it sets the transparency of the window for the profile. Accepts floating point values from 0-1 (default 0.5).", + "description": "[deprecated] Please use `opacity` instead.", + "deprecated": true, "maximum": 1, "minimum": 0, "type": "number" @@ -1614,6 +1615,13 @@ "minLength": 1, "type": "string" }, + "opacity": { + "default": 100, + "description": "Sets the opacity of the window for the profile. Accepts values from 0-100. Defaults to 50 when useAcrylic is set to true.", + "maximum": 100, + "minimum": 0, + "type": "number" + }, "padding": { "default": "8, 8, 8, 8", "description": "Sets the padding around the text within the window. Can have three different formats:\n -\"#\" sets the same padding for all sides \n -\"#, #\" sets the same padding for left-right and top-bottom\n -\"#, #, #, #\" sets the padding individually for left, top, right, and bottom.", diff --git a/scratch/ScratchIslandApp/SampleApp/MySettings.h b/scratch/ScratchIslandApp/SampleApp/MySettings.h index 34643f7fe87..4d34b86241c 100644 --- a/scratch/ScratchIslandApp/SampleApp/MySettings.h +++ b/scratch/ScratchIslandApp/SampleApp/MySettings.h @@ -45,7 +45,7 @@ namespace winrt::SampleApp::implementation WINRT_PROPERTY(winrt::hstring, ProfileName); WINRT_PROPERTY(bool, UseAcrylic, false); - WINRT_PROPERTY(double, TintOpacity, 0.5); + WINRT_PROPERTY(double, Opacity, .5); WINRT_PROPERTY(winrt::hstring, Padding, DEFAULT_PADDING); WINRT_PROPERTY(winrt::hstring, FontFace, L"Consolas"); WINRT_PROPERTY(int32_t, FontSize, DEFAULT_FONT_SIZE); diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index f3940e56345..0c5705a7bb2 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -53,10 +53,6 @@ Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFo _SetupResources(); } - // Use the unfocused border color as the pane background, so an actual color - // appears behind panes as we animate them sliding in. - _root.Background(s_unfocusedBorderBrush); - // Register an event with the control to have it inform us when it gains focus. _gotFocusRevoker = _control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler }); _lostFocusRevoker = _control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler }); @@ -1616,6 +1612,8 @@ winrt::fire_and_forget Pane::_CloseChildRoutine(const bool closeFirst) // Create the dummy grid. This grid will be the one we actually animate, // in the place of the closed pane. Controls::Grid dummyGrid; + // GH#603 - we can safely add a BG here, as the control is gone right + // away, to fill the space as the rest of the pane expands. dummyGrid.Background(s_unfocusedBorderBrush); // It should be the size of the closed pane. dummyGrid.Width(removedOriginalSize.Width); @@ -1871,6 +1869,19 @@ void Pane::_SetupEntranceAnimation() return; } + // Use the unfocused border color as the pane background, so an actual color + // appears behind panes as we animate them sliding in. + // + // GH#603 - We set only the background of the new pane, while it animates + // in. Once the animation is done, we'll remove that background, so if the + // user wants vintage opacity, they'll be able to see what's under the + // window. + // * If we don't give it a background, then the BG will be entirely transparent. + // * If we give the parent (us) root BG a color, then a transparent pane + // will flash opaque during the animation, then back to transparent, which + // looks bad. + _secondChild->_root.Background(s_unfocusedBorderBrush); + const auto [firstSize, secondSize] = _CalcChildrenSizes(::base::saturated_cast(totalSize)); // This is safe to capture this, because it's only being called in the @@ -1938,11 +1949,12 @@ void Pane::_SetupEntranceAnimation() // When the animation is completed, undo the trickiness from before, to // restore the controls to the behavior they'd usually have. - animation.Completed([childGrid, control](auto&&, auto&&) { + animation.Completed([childGrid, control, root = _secondChild->_root](auto&&, auto&&) { control.Width(NAN); childGrid.Width(NAN); childGrid.HorizontalAlignment(HorizontalAlignment::Stretch); control.HorizontalAlignment(HorizontalAlignment::Stretch); + root.Background(nullptr); }); } else @@ -1956,11 +1968,12 @@ void Pane::_SetupEntranceAnimation() // When the animation is completed, undo the trickiness from before, to // restore the controls to the behavior they'd usually have. - animation.Completed([childGrid, control](auto&&, auto&&) { + animation.Completed([childGrid, control, root = _secondChild->_root](auto&&, auto&&) { control.Height(NAN); childGrid.Height(NAN); childGrid.VerticalAlignment(VerticalAlignment::Stretch); control.VerticalAlignment(VerticalAlignment::Stretch); + root.Background(nullptr); }); } diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index 3730f7ac7bd..f57e3fe9bf3 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -87,7 +87,7 @@ namespace winrt::TerminalApp::implementation TraceLoggingBool(usedManualProfile, "ProfileSpecified", "Whether the new tab specified a profile explicitly"), TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The GUID of the profile spawned in the new tab"), TraceLoggingBool(settings.DefaultSettings().UseAcrylic(), "UseAcrylic", "The acrylic preference from the settings"), - TraceLoggingFloat64(settings.DefaultSettings().TintOpacity(), "TintOpacity", "Opacity preference from the settings"), + TraceLoggingFloat64(settings.DefaultSettings().Opacity(), "TintOpacity", "Opacity preference from the settings"), TraceLoggingWideString(settings.DefaultSettings().FontFace().c_str(), "FontFace", "Font face chosen in the settings"), TraceLoggingWideString(schemeName.data(), "SchemeName", "Color scheme set in the settings"), TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), diff --git a/src/cascadia/TerminalApp/TerminalPage.xaml b/src/cascadia/TerminalApp/TerminalPage.xaml index eea2039f614..b6a4676dd19 100644 --- a/src/cascadia/TerminalApp/TerminalPage.xaml +++ b/src/cascadia/TerminalApp/TerminalPage.xaml @@ -9,10 +9,11 @@ xmlns:local="using:TerminalApp" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mux="using:Microsoft.UI.Xaml.Controls" + Background="Transparent" mc:Ignorable="d"> + Background="Transparent"> diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index eac350c2ac3..0231c1acbf7 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -276,7 +276,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // GH#5098: Inform the engine of the opacity of the default text background. if (_settings.UseAcrylic()) { - _renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast(_settings.TintOpacity())); + _renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast(_settings.Opacity())); } THROW_IF_FAILED(_renderEngine->Enable()); @@ -425,41 +425,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation return; } - auto newOpacity = std::clamp(_settings.TintOpacity() + adjustment, + auto newOpacity = std::clamp(_settings.Opacity() + adjustment, 0.0, 1.0); - if (_settings.UseAcrylic()) - { - try - { - _settings.TintOpacity(newOpacity); - if (newOpacity >= 1.0) - { - _settings.UseAcrylic(false); - } - else - { - // GH#5098: Inform the engine of the new opacity of the default text background. - SetBackgroundOpacity(::base::saturated_cast(newOpacity)); - } + // GH#5098: Inform the engine of the new opacity of the default text background. + SetBackgroundOpacity(::base::saturated_cast(newOpacity)); - auto eventArgs = winrt::make_self(newOpacity); - _TransparencyChangedHandlers(*this, *eventArgs); - } - CATCH_LOG(); - } - else if (adjustment < 0) - { - _settings.UseAcrylic(true); + _settings.Opacity(newOpacity); - //Setting initial opacity set to 1 to ensure smooth transition to acrylic during mouse scroll - newOpacity = std::clamp(1.0 + adjustment, 0.0, 1.0); - _settings.TintOpacity(newOpacity); - - auto eventArgs = winrt::make_self(newOpacity); - _TransparencyChangedHandlers(*this, *eventArgs); - } + auto eventArgs = winrt::make_self(newOpacity); + _TransparencyChangedHandlers(*this, *eventArgs); } void ControlCore::ToggleShaderEffects() diff --git a/src/cascadia/TerminalControl/IControlAppearance.idl b/src/cascadia/TerminalControl/IControlAppearance.idl index a0fa0a0ad8f..fd06bc853c3 100644 --- a/src/cascadia/TerminalControl/IControlAppearance.idl +++ b/src/cascadia/TerminalControl/IControlAppearance.idl @@ -13,6 +13,7 @@ namespace Microsoft.Terminal.Control Windows.UI.Xaml.VerticalAlignment BackgroundImageVerticalAlignment; Boolean IntenseIsBold; // IntenseIsBright is in Core Appearance + Double Opacity; // Experimental settings Boolean RetroTerminalEffect; diff --git a/src/cascadia/TerminalControl/IControlSettings.idl b/src/cascadia/TerminalControl/IControlSettings.idl index 56aab7395cc..1b67df91f0e 100644 --- a/src/cascadia/TerminalControl/IControlSettings.idl +++ b/src/cascadia/TerminalControl/IControlSettings.idl @@ -29,7 +29,6 @@ namespace Microsoft.Terminal.Control String ProfileName; Boolean UseAcrylic; - Double TintOpacity; ScrollbarState ScrollState; String FontFace; diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 115f9afc580..fc74dd0a945 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -428,6 +428,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - void TermControl::_InitializeBackgroundBrush() { + auto appearance = _settings.try_as(); if (_settings.UseAcrylic()) { // See if we've already got an acrylic background brush @@ -449,7 +450,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation acrylic.TintColor(bgColor); // Apply brush settings - acrylic.TintOpacity(_settings.TintOpacity()); + acrylic.TintOpacity(appearance.Opacity()); // Apply brush to control if it's not already there if (RootGrid().Background() != acrylic) @@ -458,15 +459,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation } // GH#5098: Inform the engine of the new opacity of the default text background. - _core.SetBackgroundOpacity(::base::saturated_cast(_settings.TintOpacity())); + _core.SetBackgroundOpacity(::base::saturated_cast(appearance.Opacity())); } else { Media::SolidColorBrush solidColor{}; + solidColor.Opacity(_settings.Opacity()); RootGrid().Background(solidColor); // GH#5098: Inform the engine of the new opacity of the default text background. - _core.SetBackgroundOpacity(1.0f); + _core.SetBackgroundOpacity(appearance.Opacity()); } } @@ -497,7 +499,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation } else if (auto solidColor = RootGrid().Background().try_as()) { + const auto originalOpacity = solidColor.Opacity(); solidColor.Color(bg); + solidColor.Opacity(originalOpacity); } } } diff --git a/src/cascadia/TerminalControl/TermControl.xaml b/src/cascadia/TerminalControl/TermControl.xaml index 94aa92c5fa0..663ccf7ce1a 100644 --- a/src/cascadia/TerminalControl/TermControl.xaml +++ b/src/cascadia/TerminalControl/TermControl.xaml @@ -14,6 +14,7 @@ d:DesignWidth="1024" AllowDrop="True" AllowFocusOnInteraction="True" + Background="Transparent" CharacterReceived="_CharacterHandler" DragOver="_DragOverHandler" Drop="_DragDropHandler" diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.xaml b/src/cascadia/TerminalSettingsEditor/MainPage.xaml index 9576102a118..9d24ac10926 100644 --- a/src/cascadia/TerminalSettingsEditor/MainPage.xaml +++ b/src/cascadia/TerminalSettingsEditor/MainPage.xaml @@ -8,6 +8,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:muxc="using:Microsoft.UI.Xaml.Controls" + Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" mc:Ignorable="d"> diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.h b/src/cascadia/TerminalSettingsEditor/Profiles.h index e1ceba5d0b6..54d7d410849 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles.h +++ b/src/cascadia/TerminalSettingsEditor/Profiles.h @@ -22,7 +22,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void SetAcrylicOpacityPercentageValue(double value) { - AcrylicOpacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(value)); + _profile.DefaultAppearance().Opacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(value)); }; void SetPadding(double value) @@ -66,7 +66,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation OBSERVABLE_PROJECTED_SETTING(_profile, TabColor); OBSERVABLE_PROJECTED_SETTING(_profile, SuppressApplicationTitle); OBSERVABLE_PROJECTED_SETTING(_profile, UseAcrylic); - OBSERVABLE_PROJECTED_SETTING(_profile, AcrylicOpacity); OBSERVABLE_PROJECTED_SETTING(_profile, ScrollState); OBSERVABLE_PROJECTED_SETTING(_profile, Padding); OBSERVABLE_PROJECTED_SETTING(_profile, Commandline); @@ -78,6 +77,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Background); OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), SelectionBackground); OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), CursorColor); + OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Opacity); OBSERVABLE_PROJECTED_SETTING(_profile, HistorySize); OBSERVABLE_PROJECTED_SETTING(_profile, SnapOnInput); OBSERVABLE_PROJECTED_SETTING(_profile, AltGrAliasing); diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.idl b/src/cascadia/TerminalSettingsEditor/Profiles.idl index 4ecc488995c..482a1967174 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles.idl +++ b/src/cascadia/TerminalSettingsEditor/Profiles.idl @@ -47,7 +47,7 @@ namespace Microsoft.Terminal.Settings.Editor OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference, TabColor); OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SuppressApplicationTitle); OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAcrylic); - OBSERVABLE_PROJECTED_PROFILE_SETTING(Double, AcrylicOpacity); + OBSERVABLE_PROJECTED_PROFILE_SETTING(Double, Opacity); OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.ScrollbarState, ScrollState); OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Padding); OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Commandline); @@ -109,6 +109,6 @@ namespace Microsoft.Terminal.Settings.Editor IInspectable CurrentScrollState; Windows.Foundation.Collections.IObservableVector ScrollStateList { get; }; - Windows.UI.Xaml.Controls.Slider AcrylicOpacitySlider { get; }; + Windows.UI.Xaml.Controls.Slider OpacitySlider { get; }; } } diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.xaml b/src/cascadia/TerminalSettingsEditor/Profiles.xaml index 5e11e2450f3..24e6a7fe187 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles.xaml +++ b/src/cascadia/TerminalSettingsEditor/Profiles.xaml @@ -238,43 +238,43 @@ - + - - - - - - - - - + + + - + Value="{x:Bind local:Converters.PercentageToPercentageValue(State.Profile.Opacity), BindBack=State.Profile.SetAcrylicOpacityPercentageValue, Mode=TwoWay}" /> + Text="{x:Bind local:Converters.AppendPercentageSign(OpacitySlider.Value), Mode=OneWay}" /> + + + + + + diff --git a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw index 4c39ba4d1aa..a21ae08e3be 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw @@ -495,6 +495,14 @@ Sets the transparency of the window. A description for what the "acrylic opacity" setting does. Presented near "Profile_AcrylicOpacity.Header". + + Background Opacity + Header for a control to determine the level of opacity for the background of the control. The user can choose to make the background of the app more or less opaque. + + + Sets the transparency of the window. + A description for what the "opacity" setting does. Presented near "Profile_Opacity.Header". + Advanced Header for a sub-page of profile settings focused on more advanced scenarios. @@ -986,6 +994,10 @@ Acrylic Header for a group of settings related to the acrylic texture rendering on the background of the app. + + Transparency + Header for a group of settings related to transparency, including the acrylic texture rendering on the background of the app. + Background image Header for a group of settings that control the image presented on the background of the app. Presented near "Profile_BackgroundImage" and other keys starting with "Profile_BackgroundImage". diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp b/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp index 67eb279eaa6..1f8c88758f6 100644 --- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp +++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp @@ -26,6 +26,8 @@ static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageA static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" }; static constexpr std::string_view PixelShaderPathKey{ "experimental.pixelShaderPath" }; static constexpr std::string_view IntenseTextStyleKey{ "intenseTextStyle" }; +static constexpr std::string_view LegacyAcrylicTransparencyKey{ "acrylicOpacity" }; +static constexpr std::string_view OpacityKey{ "opacity" }; winrt::Microsoft::Terminal::Settings::Model::implementation::AppearanceConfig::AppearanceConfig(const winrt::weak_ref sourceProfile) : _sourceProfile(sourceProfile) @@ -50,6 +52,7 @@ winrt::com_ptr AppearanceConfig::CopyAppearance(const winrt::c appearance->_RetroTerminalEffect = sourceAppearance->_RetroTerminalEffect; appearance->_PixelShaderPath = sourceAppearance->_PixelShaderPath; appearance->_IntenseTextStyle = sourceAppearance->_IntenseTextStyle; + appearance->_Opacity = sourceAppearance->_Opacity; return appearance; } @@ -71,6 +74,7 @@ Json::Value AppearanceConfig::ToJson() const JsonUtils::SetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect); JsonUtils::SetValueForKey(json, PixelShaderPathKey, _PixelShaderPath); JsonUtils::SetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle); + JsonUtils::SetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter{}); return json; } @@ -102,6 +106,8 @@ void AppearanceConfig::LayerJson(const Json::Value& json) JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect); JsonUtils::GetValueForKey(json, PixelShaderPathKey, _PixelShaderPath); JsonUtils::GetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle); + JsonUtils::GetValueForKey(json, LegacyAcrylicTransparencyKey, _Opacity); + JsonUtils::GetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter{}); } winrt::Microsoft::Terminal::Settings::Model::Profile AppearanceConfig::SourceProfile() diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h index 7a0c47985d0..d28b9a92ce2 100644 --- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h +++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h @@ -53,6 +53,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::IAppearanceConfig, bool, RetroTerminalEffect, false); INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, PixelShaderPath, L""); INHERITABLE_SETTING(Model::IAppearanceConfig, Model::IntenseStyle, IntenseTextStyle, Model::IntenseStyle::Bright); + INHERITABLE_SETTING(Model::IAppearanceConfig, double, Opacity, 1.0); private: winrt::weak_ref _sourceProfile; diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp index e98592ce449..c2b2fceb279 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp @@ -307,7 +307,6 @@ winrt::Microsoft::Terminal::Settings::Model::Profile CascadiaSettings::Duplicate DUPLICATE_SETTING_MACRO(TabColor); DUPLICATE_SETTING_MACRO(SuppressApplicationTitle); DUPLICATE_SETTING_MACRO(UseAcrylic); - DUPLICATE_SETTING_MACRO(AcrylicOpacity); DUPLICATE_SETTING_MACRO(ScrollState); DUPLICATE_SETTING_MACRO(Padding); DUPLICATE_SETTING_MACRO(Commandline); @@ -347,6 +346,7 @@ winrt::Microsoft::Terminal::Settings::Model::Profile CascadiaSettings::Duplicate DUPLICATE_SETTING_MACRO_SUB(appearance, target, RetroTerminalEffect); DUPLICATE_SETTING_MACRO_SUB(appearance, target, CursorShape); DUPLICATE_SETTING_MACRO_SUB(appearance, target, CursorHeight); + DUPLICATE_SETTING_MACRO_SUB(appearance, target, Opacity); } // UnfocusedAppearance is treated as a single setting, diff --git a/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl b/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl index b33cf23e7dc..af89f55e8a6 100644 --- a/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl +++ b/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl @@ -51,5 +51,6 @@ namespace Microsoft.Terminal.Settings.Model INHERITABLE_APPEARANCE_SETTING(Boolean, RetroTerminalEffect); INHERITABLE_APPEARANCE_SETTING(String, PixelShaderPath); INHERITABLE_APPEARANCE_SETTING(IntenseStyle, IntenseTextStyle); + INHERITABLE_APPEARANCE_SETTING(Double, Opacity); }; } diff --git a/src/cascadia/TerminalSettingsModel/Profile.cpp b/src/cascadia/TerminalSettingsModel/Profile.cpp index 338de21ac04..c76247a9fee 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.cpp +++ b/src/cascadia/TerminalSettingsModel/Profile.cpp @@ -36,7 +36,6 @@ static constexpr std::string_view AltGrAliasingKey{ "altGrAliasing" }; static constexpr std::string_view ConnectionTypeKey{ "connectionType" }; static constexpr std::string_view CommandlineKey{ "commandline" }; static constexpr std::string_view FontInfoKey{ "font" }; -static constexpr std::string_view AcrylicTransparencyKey{ "acrylicOpacity" }; static constexpr std::string_view UseAcrylicKey{ "useAcrylic" }; static constexpr std::string_view ScrollbarStateKey{ "scrollbarState" }; static constexpr std::string_view CloseOnExitKey{ "closeOnExit" }; @@ -95,7 +94,6 @@ winrt::com_ptr Profile::CopySettings(winrt::com_ptr source) profile->_TabColor = source->_TabColor; profile->_SuppressApplicationTitle = source->_SuppressApplicationTitle; profile->_UseAcrylic = source->_UseAcrylic; - profile->_AcrylicOpacity = source->_AcrylicOpacity; profile->_ScrollState = source->_ScrollState; profile->_Padding = source->_Padding; profile->_Commandline = source->_Commandline; @@ -356,7 +354,6 @@ void Profile::LayerJson(const Json::Value& json) // Control Settings JsonUtils::GetValueForKey(json, ConnectionTypeKey, _ConnectionType); JsonUtils::GetValueForKey(json, CommandlineKey, _Commandline); - JsonUtils::GetValueForKey(json, AcrylicTransparencyKey, _AcrylicOpacity); JsonUtils::GetValueForKey(json, UseAcrylicKey, _UseAcrylic); JsonUtils::GetValueForKey(json, SuppressApplicationTitleKey, _SuppressApplicationTitle); JsonUtils::GetValueForKey(json, CloseOnExitKey, _CloseOnExit); @@ -548,7 +545,6 @@ Json::Value Profile::ToJson() const // Control Settings JsonUtils::SetValueForKey(json, ConnectionTypeKey, _ConnectionType); JsonUtils::SetValueForKey(json, CommandlineKey, _Commandline); - JsonUtils::SetValueForKey(json, AcrylicTransparencyKey, _AcrylicOpacity); JsonUtils::SetValueForKey(json, UseAcrylicKey, _UseAcrylic); JsonUtils::SetValueForKey(json, SuppressApplicationTitleKey, _SuppressApplicationTitle); JsonUtils::SetValueForKey(json, CloseOnExitKey, _CloseOnExit); diff --git a/src/cascadia/TerminalSettingsModel/Profile.idl b/src/cascadia/TerminalSettingsModel/Profile.idl index 5ad1ae93314..c69d57280db 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.idl +++ b/src/cascadia/TerminalSettingsModel/Profile.idl @@ -67,7 +67,6 @@ namespace Microsoft.Terminal.Settings.Model INHERITABLE_PROFILE_SETTING(Windows.Foundation.IReference, TabColor); INHERITABLE_PROFILE_SETTING(Boolean, SuppressApplicationTitle); INHERITABLE_PROFILE_SETTING(Boolean, UseAcrylic); - INHERITABLE_PROFILE_SETTING(Double, AcrylicOpacity); INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.ScrollbarState, ScrollState); INHERITABLE_PROFILE_SETTING(String, Padding); INHERITABLE_PROFILE_SETTING(String, Commandline); diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp index ff46d81b64c..3d7b2f11efe 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp @@ -201,6 +201,16 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation _IntenseIsBold = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bold); _IntenseIsBright = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bright); + + // If the user set an opacity, then just use that. Otherwise, change the + // default value based off of whether useAcrylic was set or not. If they + // want acrylic, then default to 50%. Otherwise, default to 100% (fully + // opaque) + _Opacity = appearance.HasOpacity() ? + appearance.Opacity() : + UseAcrylic() ? + .5 : + 1.0; } // Method Description: @@ -273,7 +283,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation // Fill in the remaining properties from the profile _ProfileName = profile.Name(); _UseAcrylic = profile.UseAcrylic(); - _TintOpacity = profile.AcrylicOpacity(); _FontFace = profile.FontInfo().FontFace(); _FontSize = profile.FontInfo().FontSize(); diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.h b/src/cascadia/TerminalSettingsModel/TerminalSettings.h index 8525668ab6e..1c27f689ea8 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.h @@ -118,7 +118,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileName); INHERITABLE_SETTING(Model::TerminalSettings, bool, UseAcrylic, false); - INHERITABLE_SETTING(Model::TerminalSettings, double, TintOpacity, 0.5); + INHERITABLE_SETTING(Model::TerminalSettings, double, Opacity, UseAcrylic() ? 0.5 : 1.0); INHERITABLE_SETTING(Model::TerminalSettings, hstring, Padding, DEFAULT_PADDING); INHERITABLE_SETTING(Model::TerminalSettings, hstring, FontFace, DEFAULT_FONT_FACE); INHERITABLE_SETTING(Model::TerminalSettings, int32_t, FontSize, DEFAULT_FONT_SIZE); diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h index 83c791f95ed..a4503efb7d9 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h @@ -342,6 +342,34 @@ struct ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<::winr } }; +struct IntAsFloatPercentConversionTrait : ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait +{ + double FromJson(const Json::Value& json) + { + return ::base::saturated_cast(json.asUInt()) / 100.0; + } + + bool CanConvert(const Json::Value& json) + { + if (!json.isUInt()) + { + return false; + } + const auto value = json.asUInt(); + return value >= 0 && value <= 100; + } + + Json::Value ToJson(const double& val) + { + return std::clamp(::base::saturated_cast(std::round(val * 100.0)), 0u, 100u); + } + + std::string TypeDescription() const + { + return "number (>= 0, <=100)"; + } +}; + // Possible FocusDirection values JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::FocusDirection) { diff --git a/src/cascadia/UnitTests_Control/ControlCoreTests.cpp b/src/cascadia/UnitTests_Control/ControlCoreTests.cpp index 9e8599032bd..9e4a19e7b50 100644 --- a/src/cascadia/UnitTests_Control/ControlCoreTests.cpp +++ b/src/cascadia/UnitTests_Control/ControlCoreTests.cpp @@ -119,7 +119,7 @@ namespace ControlUnitTests auto [settings, conn] = _createSettingsAndConnection(); settings->UseAcrylic(true); - settings->TintOpacity(0.5f); + settings->Opacity(0.5f); auto core = createCore(*settings, *conn); VERIFY_IS_NOT_NULL(core); @@ -128,16 +128,19 @@ namespace ControlUnitTests double expectedOpacity = 0.5; auto opacityCallback = [&](auto&&, Control::TransparencyChangedEventArgs args) mutable { VERIFY_ARE_EQUAL(expectedOpacity, args.Opacity()); - VERIFY_ARE_EQUAL(expectedOpacity, settings->TintOpacity()); - VERIFY_ARE_EQUAL(expectedOpacity, core->_settings.TintOpacity()); + VERIFY_ARE_EQUAL(expectedOpacity, settings->Opacity()); + VERIFY_ARE_EQUAL(expectedOpacity, core->_settings.Opacity()); if (expectedOpacity < 1.0) { VERIFY_IS_TRUE(settings->UseAcrylic()); VERIFY_IS_TRUE(core->_settings.UseAcrylic()); } - VERIFY_ARE_EQUAL(expectedOpacity < 1.0, settings->UseAcrylic()); - VERIFY_ARE_EQUAL(expectedOpacity < 1.0, core->_settings.UseAcrylic()); + + // GH#603: Adjusting opacity shouldn't change whether or not we + // requested acrylic. + VERIFY_IS_TRUE(settings->UseAcrylic()); + VERIFY_IS_TRUE(core->_settings.UseAcrylic()); }; core->TransparencyChanged(opacityCallback); @@ -220,7 +223,7 @@ namespace ControlUnitTests { auto [settings, conn] = _createSettingsAndConnection(); Log::Comment(L"Create ControlCore object"); - auto core = winrt::make_self(*settings, *conn); + auto core = createCore(*settings, *conn); VERIFY_IS_NOT_NULL(core); _standardInit(core); @@ -259,7 +262,7 @@ namespace ControlUnitTests { auto [settings, conn] = _createSettingsAndConnection(); Log::Comment(L"Create ControlCore object"); - auto core = winrt::make_self(*settings, *conn); + auto core = createCore(*settings, *conn); VERIFY_IS_NOT_NULL(core); _standardInit(core); @@ -298,7 +301,7 @@ namespace ControlUnitTests { auto [settings, conn] = _createSettingsAndConnection(); Log::Comment(L"Create ControlCore object"); - auto core = winrt::make_self(*settings, *conn); + auto core = createCore(*settings, *conn); VERIFY_IS_NOT_NULL(core); _standardInit(core); diff --git a/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp b/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp index dba09c9e439..3cffb107c12 100644 --- a/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp +++ b/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp @@ -99,10 +99,16 @@ namespace ControlUnitTests WEX::TestExecution::SetVerifyOutput verifyOutputScope{ WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures }; + BEGIN_TEST_METHOD_PROPERTIES() + TEST_METHOD_PROPERTY(L"Data:useAcrylic", L"{true, false}") + END_TEST_METHOD_PROPERTIES() + bool useAcrylic; + VERIFY_SUCCEEDED(TestData::TryGetValue(L"useAcrylic", useAcrylic), L"whether or not we should enable acrylic"); + auto [settings, conn] = _createSettingsAndConnection(); - settings->UseAcrylic(true); - settings->TintOpacity(0.5f); + settings->UseAcrylic(useAcrylic); + settings->Opacity(0.5f); auto [core, interactivity] = _createCoreAndInteractivity(*settings, *conn); @@ -110,16 +116,11 @@ namespace ControlUnitTests double expectedOpacity = 0.5; auto opacityCallback = [&](auto&&, Control::TransparencyChangedEventArgs args) mutable { VERIFY_ARE_EQUAL(expectedOpacity, args.Opacity()); - VERIFY_ARE_EQUAL(expectedOpacity, settings->TintOpacity()); - VERIFY_ARE_EQUAL(expectedOpacity, core->_settings.TintOpacity()); + VERIFY_ARE_EQUAL(expectedOpacity, settings->Opacity()); + VERIFY_ARE_EQUAL(expectedOpacity, core->_settings.Opacity()); - if (expectedOpacity < 1.0) - { - VERIFY_IS_TRUE(settings->UseAcrylic()); - VERIFY_IS_TRUE(core->_settings.UseAcrylic()); - } - VERIFY_ARE_EQUAL(expectedOpacity < 1.0, settings->UseAcrylic()); - VERIFY_ARE_EQUAL(expectedOpacity < 1.0, core->_settings.UseAcrylic()); + VERIFY_ARE_EQUAL(useAcrylic, settings->UseAcrylic()); + VERIFY_ARE_EQUAL(useAcrylic, core->_settings.UseAcrylic()); }; core->TransparencyChanged(opacityCallback); @@ -157,7 +158,7 @@ namespace ControlUnitTests // The mouse location and buttons don't matter here. interactivity->MouseWheel(modifiers, - 30, + -30, til::point{ 0, 0 }, buttonState); } diff --git a/src/cascadia/UnitTests_Control/MockControlSettings.h b/src/cascadia/UnitTests_Control/MockControlSettings.h index d8400658988..c2e6db9ae84 100644 --- a/src/cascadia/UnitTests_Control/MockControlSettings.h +++ b/src/cascadia/UnitTests_Control/MockControlSettings.h @@ -51,7 +51,7 @@ namespace ControlUnitTests WINRT_PROPERTY(winrt::hstring, ProfileName); WINRT_PROPERTY(bool, UseAcrylic, false); - WINRT_PROPERTY(double, TintOpacity, 0.5); + WINRT_PROPERTY(double, Opacity, .5); WINRT_PROPERTY(winrt::hstring, Padding, DEFAULT_PADDING); WINRT_PROPERTY(winrt::hstring, FontFace, L"Consolas"); WINRT_PROPERTY(int32_t, FontSize, DEFAULT_FONT_SIZE); diff --git a/src/cascadia/WindowsTerminal/IslandWindow.cpp b/src/cascadia/WindowsTerminal/IslandWindow.cpp index 0fa5654c45d..8fc7e78d33b 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/IslandWindow.cpp @@ -7,6 +7,8 @@ #include "resource.h" #include "icon.h" #include "NotificationIcon.h" +#include +#include extern "C" IMAGE_DOS_HEADER __ImageBase; @@ -59,7 +61,14 @@ void IslandWindow::MakeWindow() noexcept // Create the window with the default size here - During the creation of the // window, the system will give us a chance to set its size in WM_CREATE. // WM_CREATE will be handled synchronously, before CreateWindow returns. - WINRT_VERIFY(CreateWindowEx(_alwaysOnTop ? WS_EX_TOPMOST : 0, + // + // We need WS_EX_NOREDIRECTIONBITMAP for vintage style opacity, GH#603 + // + // WS_EX_LAYERED acts REAL WEIRD with TerminalTrySetTransparentBackground, + // but it works just fine when the window is in the TOPMOST group. But if + // you enable it always, activating the window will remove our DWM frame + // entirely. Weird. + WINRT_VERIFY(CreateWindowEx(WS_EX_NOREDIRECTIONBITMAP | (_alwaysOnTop ? WS_EX_TOPMOST : 0), wc.lpszClassName, L"Windows Terminal", WS_OVERLAPPEDWINDOW, @@ -311,6 +320,10 @@ void IslandWindow::Initialize() _taskbar = std::move(taskbar); } } + + // Enable vintage opacity by removing the XAML emergency backstop, GH#603. + // We don't really care if this failed or not. + TerminalTrySetTransparentBackground(true); } void IslandWindow::OnSize(const UINT width, const UINT height) @@ -424,6 +437,7 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize { _WindowActivatedHandlers(); } + break; } @@ -828,7 +842,7 @@ void IslandWindow::SetTaskbarProgress(const size_t state, const size_t progress) } // From GdiEngine::s_SetWindowLongWHelper -void _SetWindowLongWHelper(const HWND hWnd, const int nIndex, const LONG dwNewLong) noexcept +void SetWindowLongWHelper(const HWND hWnd, const int nIndex, const LONG dwNewLong) noexcept { // SetWindowLong has strange error handling. On success, it returns the // previous Window Long value and doesn't modify the Last Error state. To @@ -919,14 +933,14 @@ void IslandWindow::_SetIsBorderless(const bool borderlessEnabled) // First, modify regular window styles as appropriate auto windowStyle = _getDesiredWindowStyle(); - _SetWindowLongWHelper(hWnd, GWL_STYLE, windowStyle); + SetWindowLongWHelper(hWnd, GWL_STYLE, windowStyle); // Now modify extended window styles as appropriate // When moving to fullscreen, remove the window edge style to avoid an // ugly border when not focused. auto exWindowStyle = GetWindowLongW(hWnd, GWL_EXSTYLE); WI_UpdateFlag(exWindowStyle, WS_EX_WINDOWEDGE, !_fullscreen); - _SetWindowLongWHelper(hWnd, GWL_EXSTYLE, exWindowStyle); + SetWindowLongWHelper(hWnd, GWL_EXSTYLE, exWindowStyle); // Resize the window, with SWP_FRAMECHANGED, to trigger user32 to // recalculate the non/client areas @@ -1064,14 +1078,14 @@ void IslandWindow::_SetIsFullscreen(const bool fullscreenEnabled) // First, modify regular window styles as appropriate auto windowStyle = _getDesiredWindowStyle(); - _SetWindowLongWHelper(hWnd, GWL_STYLE, windowStyle); + SetWindowLongWHelper(hWnd, GWL_STYLE, windowStyle); // Now modify extended window styles as appropriate // When moving to fullscreen, remove the window edge style to avoid an // ugly border when not focused. auto exWindowStyle = GetWindowLongW(hWnd, GWL_EXSTYLE); WI_UpdateFlag(exWindowStyle, WS_EX_WINDOWEDGE, !_fullscreen); - _SetWindowLongWHelper(hWnd, GWL_EXSTYLE, exWindowStyle); + SetWindowLongWHelper(hWnd, GWL_EXSTYLE, exWindowStyle); // Only change the window position if changing fullscreen state. if (fChangingFullscreen) diff --git a/src/cascadia/WindowsTerminal/IslandWindow.h b/src/cascadia/WindowsTerminal/IslandWindow.h index b15f63a23f0..8f6b283c12a 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.h +++ b/src/cascadia/WindowsTerminal/IslandWindow.h @@ -6,6 +6,8 @@ #include #include "../../cascadia/inc/cppwinrt_utils.h" +void SetWindowLongWHelper(const HWND hWnd, const int nIndex, const LONG dwNewLong) noexcept; + class IslandWindow : public BaseWindow { diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index c00347708cb..b4f0683fa3f 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -685,9 +685,18 @@ SIZE NonClientIslandWindow::GetTotalNonClientExclusiveSize(UINT dpi) const noexc // - the HRESULT returned by DwmExtendFrameIntoClientArea. void NonClientIslandWindow::_UpdateFrameMargins() const noexcept { - MARGINS margins = {}; + MARGINS margins = { 0, 0, 0, 0 }; - if (_GetTopBorderHeight() != 0) + // GH#603: When we're in Focus Mode, hide the titlebar, by setting it to a single + // pixel tall. Otherwise, the titlebar will be visible underneath controls with + // vintage opacity set. + // + // We can't set it to all 0's unfortunately. + if (_borderless) + { + margins.cyTopHeight = 1; + } + else if (_GetTopBorderHeight() != 0) { RECT frame = {}; winrt::check_bool(::AdjustWindowRectExForDpi(&frame, GetWindowStyle(_window.get()), FALSE, 0, _currentDpi)); @@ -896,6 +905,10 @@ void NonClientIslandWindow::_SetIsBorderless(const bool borderlessEnabled) _titlebar.Visibility(_IsTitlebarVisible() ? Visibility::Visible : Visibility::Collapsed); } + // Update the margins when entering/leaving focus mode, so we can prevent + // the titlebar from showing through transparent terminal controls + _UpdateFrameMargins(); + // GH#4224 - When the auto-hide taskbar setting is enabled, then we don't // always get another window message to trigger us to remove the drag bar. // So, make sure to update the size of the drag region here, so that it diff --git a/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj b/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj index 07ba6658f0e..e0e6ae06ab4 100644 --- a/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj +++ b/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj @@ -128,7 +128,7 @@ - + - - \ No newline at end of file + + diff --git a/src/cascadia/WindowsTerminal/packages.config b/src/cascadia/WindowsTerminal/packages.config index f2f5c3f58dc..db58384dcc7 100644 --- a/src/cascadia/WindowsTerminal/packages.config +++ b/src/cascadia/WindowsTerminal/packages.config @@ -3,6 +3,6 @@ - - + + diff --git a/src/cascadia/WindowsTerminal/pch.h b/src/cascadia/WindowsTerminal/pch.h index 01d2f04a76d..59f24e94997 100644 --- a/src/cascadia/WindowsTerminal/pch.h +++ b/src/cascadia/WindowsTerminal/pch.h @@ -67,6 +67,7 @@ Module Name: #include #include #include +#include #include #include