diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 0fcf0e05d..07317bf90 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -188,7 +188,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation _autoScrollTimer.Interval(AutoScrollUpdateInterval); _autoScrollTimer.Tick({ this, &TermControl::_UpdateAutoScroll }); - _ApplyUISettings(); + _ApplyUISettings(_settings); } // Method Description: @@ -274,6 +274,73 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation this->Focus(FocusState::Programmatic); } + // Method Description: + // - Given new settings for this profile, applies the settings to the current terminal. + // - This method is separate from UpdateSettings because there is an apparent optimizer + // issue that causes one of our hstring -> wstring_view conversions to result in garbage, + // but only from a coroutine context. See GH#8723. + // - INVARIANT: This method must be called from the UI thread. + // Arguments: + // - newSettings: New settings values for the profile in this terminal. + // Return Value: + // - + void TermControl::_UpdateSettingsOnUIThread(const IControlSettings& newSettings) + { + if (_closing) + { + return; + } + + auto lock = _terminal->LockForWriting(); + + // First, store the new settings in the instance. + _settings = newSettings; + + // Update our control settings + _ApplyUISettings(_settings); + + // Update the terminal core with its new Core settings + _terminal->UpdateSettings(_settings); + + if (!_initializedTerminal) + { + // If we haven't initialized, there's no point in continuing. + // Initialization will handle the renderer settings. + return; + } + + // Update DxEngine settings under the lock + _renderEngine->SetSelectionBackground(_settings.SelectionBackground()); + + _renderEngine->SetRetroTerminalEffect(_settings.RetroTerminalEffect()); + _renderEngine->SetPixelShaderPath(_settings.PixelShaderPath()); + _renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering()); + _renderEngine->SetSoftwareRendering(_settings.SoftwareRendering()); + + switch (_settings.AntialiasingMode()) + { + case TextAntialiasingMode::Cleartype: + _renderEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE); + break; + case TextAntialiasingMode::Aliased: + _renderEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED); + break; + case TextAntialiasingMode::Grayscale: + default: + _renderEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE); + break; + } + + // Refresh our font with the renderer + const auto actualFontOldSize = _actualFont.GetSize(); + _UpdateFont(); + const auto actualFontNewSize = _actualFont.GetSize(); + if (actualFontNewSize != actualFontOldSize) + { + _RefreshSizeUnderLock(); + } + } + // Method Description: // - Given new settings for this profile, applies the settings to the current terminal. // Arguments: @@ -282,7 +349,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation // - winrt::fire_and_forget TermControl::UpdateSettings(IControlSettings newSettings) { - _settings = newSettings; auto weakThis{ get_weak() }; // Dispatch a call to the UI thread to apply the new settings to the @@ -292,49 +358,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation // If 'weakThis' is locked, then we can safely work with 'this' if (auto control{ weakThis.get() }) { - if (_closing) - { - co_return; - } - - // Update our control settings - _ApplyUISettings(); - - // Update the terminal core with its new Core settings - _terminal->UpdateSettings(_settings); - - auto lock = _terminal->LockForWriting(); - - // Update DxEngine settings under the lock - _renderEngine->SetSelectionBackground(_settings.SelectionBackground()); - - _renderEngine->SetRetroTerminalEffect(_settings.RetroTerminalEffect()); - _renderEngine->SetPixelShaderPath(_settings.PixelShaderPath()); - _renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering()); - _renderEngine->SetSoftwareRendering(_settings.SoftwareRendering()); - - switch (_settings.AntialiasingMode()) - { - case TextAntialiasingMode::Cleartype: - _renderEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE); - break; - case TextAntialiasingMode::Aliased: - _renderEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED); - break; - case TextAntialiasingMode::Grayscale: - default: - _renderEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE); - break; - } - - // Refresh our font with the renderer - const auto actualFontOldSize = _actualFont.GetSize(); - _UpdateFont(); - const auto actualFontNewSize = _actualFont.GetSize(); - if (actualFontNewSize != actualFontOldSize) - { - _RefreshSizeUnderLock(); - } + _UpdateSettingsOnUIThread(newSettings); } } @@ -384,21 +408,21 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation // - // Return Value: // - - void TermControl::_ApplyUISettings() + void TermControl::_ApplyUISettings(const IControlSettings& newSettings) { _InitializeBackgroundBrush(); - COLORREF bg = _settings.DefaultBackground(); + COLORREF bg = newSettings.DefaultBackground(); _BackgroundColorChanged(bg); // Apply padding as swapChainPanel's margin - auto newMargin = _ParseThicknessFromPadding(_settings.Padding()); + auto newMargin = _ParseThicknessFromPadding(newSettings.Padding()); SwapChainPanel().Margin(newMargin); // Initialize our font information. - const auto fontFace = _settings.FontFace(); - const short fontHeight = gsl::narrow_cast(_settings.FontSize()); - const auto fontWeight = _settings.FontWeight(); + const auto fontFace = newSettings.FontFace(); + const short fontHeight = gsl::narrow_cast(newSettings.FontSize()); + const auto fontWeight = newSettings.FontWeight(); // The font width doesn't terribly matter, we'll only be using the // height to look it up // The other params here also largely don't matter. @@ -410,12 +434,12 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation // set TSF Foreground Media::SolidColorBrush foregroundBrush{}; - foregroundBrush.Color(static_cast(_settings.DefaultForeground())); + foregroundBrush.Color(static_cast(newSettings.DefaultForeground())); TSFInputControl().Foreground(foregroundBrush); TSFInputControl().Margin(newMargin); // Apply settings for scrollbar - if (_settings.ScrollState() == ScrollbarState::Hidden) + if (newSettings.ScrollState() == ScrollbarState::Hidden) { // In the scenario where the user has turned off the OS setting to automatically hide scrollbars, the // Terminal scrollbar would still be visible; so, we need to set the control's visibility accordingly to diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index 804f0a3e4..1efcc4c91 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -263,7 +263,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker; - void _ApplyUISettings(); + void _ApplyUISettings(const IControlSettings&); + void _UpdateSettingsOnUIThread(const IControlSettings& newSettings); void _UpdateSystemParameterSettings() noexcept; void _InitializeBackgroundBrush(); winrt::fire_and_forget _BackgroundColorChanged(const COLORREF color);