Skip to content

Commit

Permalink
Add support for resetting the color scheme with RIS (#17879)
Browse files Browse the repository at this point in the history
## Summary of the Pull Request

This improves our `RIS` (hard reset) implementation, so it now also
resets any changes that are made to the color table and color aliases,
which is one of the things it's supposed to be doing.

## References and Relevant Issues

This is also a small step towards implementing the `OSC` sequences that
reset individual color table entries (issue #3719).

## Detailed Description of the Pull Request / Additional comments

The way this works is by having a second copy of the color table and
alias indices to hold the default values in the `RenderSettings` class.
This default set is initially populated at startup with the user's
chosen color scheme, but can also potentially be updated if the user
changes their settings while a session is already in progress.

When we receive an `RIS` request, we just copy the default values back
over the active settings, and refresh the renderer.

## Validation Steps Performed

I've manually tested both OpenConsole and Windows Terminal by changing
my color scheme programmatically, and then confirming that the original
colors are restored when an `RIS` sequence is received.

I've also added some basic unit tests that check both the color aliases
and color table are restored by `RIS`.

## PR Checklist
- [x] Tests added/passed
  • Loading branch information
j4james committed Sep 16, 2024
1 parent bc6f3e2 commit 5e8e10f
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/cascadia/TerminalControl/HwndTerminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,9 @@ void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR font
renderSettings.SetColorTableEntry(tableIndex, gsl::at(theme.ColorTable, tableIndex));
}

// Save these values as the new default render settings.
renderSettings.SaveDefaultSettings();

publicTerminal->_terminal->SetCursorStyle(static_cast<Microsoft::Console::VirtualTerminal::DispatchTypes::CursorStyle>(theme.CursorStyle));

publicTerminal->_desiredFont = { fontFamily, 0, DEFAULT_FONT_WEIGHT, static_cast<float>(fontSize), CP_UTF8 };
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/TerminalCore/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ void Terminal::UpdateSettings(ICoreSettings settings)
GetRenderSettings().SetColorTableEntry(TextColor::FRAME_BACKGROUND, til::color{ settings.TabColor().Value() });
}

// Save the changes made above and in UpdateAppearance as the new default render settings.
GetRenderSettings().SaveDefaultSettings();

if (!_startingTabColor && settings.StartingTabColor())
{
_startingTabColor = settings.StartingTabColor().Value();
Expand Down
7 changes: 7 additions & 0 deletions src/host/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ void Settings::Validate()
TextAttribute::SetLegacyDefaultAttributes(_wFillAttribute);
// And calculate the position of the default colors in the color table.
CalculateDefaultColorIndices();
// We can also then save these values as the default render settings.
SaveDefaultRenderSettings();

FAIL_FAST_IF(!(_dwWindowSize.X > 0));
FAIL_FAST_IF(!(_dwWindowSize.Y > 0));
Expand Down Expand Up @@ -755,6 +757,11 @@ void Settings::CalculateDefaultColorIndices() noexcept
_renderSettings.SetColorAliasIndex(ColorAlias::DefaultBackground, backgroundAlias);
}

void Settings::SaveDefaultRenderSettings() noexcept
{
_renderSettings.SaveDefaultSettings();
}

bool Settings::IsTerminalScrolling() const noexcept
{
return _TerminalScrolling;
Expand Down
1 change: 1 addition & 0 deletions src/host/settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ class Settings
void SetInterceptCopyPaste(const bool interceptCopyPaste) noexcept;

void CalculateDefaultColorIndices() noexcept;
void SaveDefaultRenderSettings() noexcept;

bool IsTerminalScrolling() const noexcept;
void SetTerminalScrolling(const bool terminalScrollingEnabled) noexcept;
Expand Down
17 changes: 17 additions & 0 deletions src/host/ut_host/ScreenBufferTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "../interactivity/inc/ServiceLocator.hpp"
#include "../../inc/conattrs.hpp"
#include "../../types/inc/colorTable.hpp"
#include "../../types/inc/Viewport.hpp"

#include "../../inc/TestUtils.h"
Expand Down Expand Up @@ -2070,6 +2071,15 @@ void ScreenBufferTests::VtRestoreColorTableReport()
// Blue component is clamped at 100%, so 150% interpreted as 100%
stateMachine.ProcessString(L"\033P2$p14;2;0;0;150\033\\");
VERIFY_ARE_EQUAL(RGB(0, 0, 255), gci.GetColorTableEntry(14));

Log::Comment(L"RIS restores initial Campbell color scheme");

stateMachine.ProcessString(L"\033c");
for (auto i = 0; i < 16; i++)
{
const COLORREF expectedColor = Microsoft::Console::Utils::CampbellColorTable()[i];
VERIFY_ARE_EQUAL(expectedColor, gci.GetColorTableEntry(i));
}
}

void ScreenBufferTests::ResizeTraditionalDoesNotDoubleFreeAttrRows()
Expand Down Expand Up @@ -3352,6 +3362,13 @@ void ScreenBufferTests::AssignColorAliases()
stateMachine.ProcessString(L"\033[2;34;56,|");
VERIFY_ARE_EQUAL(34u, renderSettings.GetColorAliasIndex(ColorAlias::FrameForeground));
VERIFY_ARE_EQUAL(56u, renderSettings.GetColorAliasIndex(ColorAlias::FrameBackground));

Log::Comment(L"Test RIS restores initial color assignments");
stateMachine.ProcessString(L"\033c");
VERIFY_ARE_EQUAL(defaultFg, renderSettings.GetColorAliasIndex(ColorAlias::DefaultForeground));
VERIFY_ARE_EQUAL(defaultBg, renderSettings.GetColorAliasIndex(ColorAlias::DefaultBackground));
VERIFY_ARE_EQUAL(frameFg, renderSettings.GetColorAliasIndex(ColorAlias::FrameForeground));
VERIFY_ARE_EQUAL(frameBg, renderSettings.GetColorAliasIndex(ColorAlias::FrameBackground));
}

void ScreenBufferTests::DeleteCharsNearEndOfLine()
Expand Down
2 changes: 2 additions & 0 deletions src/interactivity/win32/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,8 @@ void Menu::s_PropertiesUpdate(PCONSOLE_STATE_INFO pStateInfo)
TextAttribute::SetLegacyDefaultAttributes(pStateInfo->ScreenAttributes);
// And recalculate the position of the default colors in the color table.
gci.CalculateDefaultColorIndices();
// Then save these values as the new default render settings.
gci.SaveDefaultRenderSettings();

// Set the screen info's default text attributes to defaults -
ScreenInfo.SetDefaultAttributes({}, TextAttribute{ gci.GetPopupFillAttribute() });
Expand Down
23 changes: 23 additions & 0 deletions src/renderer/base/RenderSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,29 @@ RenderSettings::RenderSettings() noexcept
SetColorAliasIndex(ColorAlias::DefaultBackground, TextColor::DARK_BLACK);
SetColorAliasIndex(ColorAlias::FrameForeground, TextColor::FRAME_FOREGROUND);
SetColorAliasIndex(ColorAlias::FrameBackground, TextColor::FRAME_BACKGROUND);

SaveDefaultSettings();
}

// Routine Description:
// - Saves the current color table and color aliases as the default values, so
// we can later restore them when a hard reset (RIS) is requested.
void RenderSettings::SaveDefaultSettings() noexcept
{
_defaultColorTable = _colorTable;
_defaultColorAliasIndices = _colorAliasIndices;
}

// Routine Description:
// - Resets the render settings to their default values. which is typically
// what they were set to at startup.
void RenderSettings::RestoreDefaultSettings() noexcept
{
_colorTable = _defaultColorTable;
_colorAliasIndices = _defaultColorAliasIndices;
// For now, DECSCNM is the only render mode we need to reset. The others are
// all user preferences that can't be changed programmatically.
_renderMode.reset(Mode::ScreenReversed);
}

// Routine Description:
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/inc/RenderSettings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ namespace Microsoft::Console::Render
};

RenderSettings() noexcept;
void SaveDefaultSettings() noexcept;
void RestoreDefaultSettings() noexcept;
void SetRenderMode(const Mode mode, const bool enabled) noexcept;
bool GetRenderMode(const Mode mode) const noexcept;
const std::array<COLORREF, TextColor::TABLE_SIZE>& GetColorTable() const noexcept;
Expand All @@ -48,6 +50,8 @@ namespace Microsoft::Console::Render
til::enumset<Mode> _renderMode{ Mode::BlinkAllowed, Mode::IntenseIsBright };
std::array<COLORREF, TextColor::TABLE_SIZE> _colorTable;
std::array<size_t, static_cast<size_t>(ColorAlias::ENUM_COUNT)> _colorAliasIndices;
std::array<COLORREF, TextColor::TABLE_SIZE> _defaultColorTable;
std::array<size_t, static_cast<size_t>(ColorAlias::ENUM_COUNT)> _defaultColorAliasIndices;
size_t _blinkCycle = 0;
mutable bool _blinkIsInUse = false;
bool _blinkShouldBeFaint = false;
Expand Down
9 changes: 7 additions & 2 deletions src/terminal/adapter/adaptDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3019,8 +3019,13 @@ void AdaptDispatch::HardReset()
EraseInDisplay(DispatchTypes::EraseType::All);
EraseInDisplay(DispatchTypes::EraseType::Scrollback);

// Set the DECSCNM screen mode back to normal.
_renderSettings.SetRenderMode(RenderSettings::Mode::ScreenReversed, false);
// Set the color table and render modes back to their initial startup values.
_renderSettings.RestoreDefaultSettings();
// Let the renderer know that the background and frame colors may have changed.
if (_renderer)
{
_renderer->TriggerRedrawAll(true, true);
}

// Cursor to 1,1 - the Soft Reset guarantees this is absolute
CursorPosition(1, 1);
Expand Down

0 comments on commit 5e8e10f

Please sign in to comment.