Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the DECAC escape sequence #13058

Merged
8 commits merged into from
May 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/buffer/out/TextColor.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ enum class ColorAlias : size_t
{
DefaultForeground,
DefaultBackground,
FrameForeground,
FrameBackground,
ENUM_COUNT // must be the last element in the enum class
};

Expand All @@ -72,10 +74,13 @@ struct TextColor
static constexpr BYTE BRIGHT_CYAN = 14;
static constexpr BYTE BRIGHT_WHITE = 15;

static constexpr size_t DEFAULT_FOREGROUND = 256;
static constexpr size_t DEFAULT_BACKGROUND = 257;
static constexpr size_t CURSOR_COLOR = 258;
static constexpr size_t TABLE_SIZE = 259;
// Entries 256 to 260 are reserved for XTerm compatibility.
static constexpr size_t DEFAULT_FOREGROUND = 261;
static constexpr size_t DEFAULT_BACKGROUND = 262;
static constexpr size_t FRAME_FOREGROUND = 263;
static constexpr size_t FRAME_BACKGROUND = 264;
static constexpr size_t CURSOR_COLOR = 265;
static constexpr size_t TABLE_SIZE = 266;

constexpr TextColor() noexcept :
_meta{ ColorType::IsDefault },
Expand Down
27 changes: 9 additions & 18 deletions src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto pfnTitleChanged = std::bind(&ControlCore::_terminalTitleChanged, this, std::placeholders::_1);
_terminal->SetTitleChangedCallback(pfnTitleChanged);

auto pfnTabColorChanged = std::bind(&ControlCore::_terminalTabColorChanged, this, std::placeholders::_1);
_terminal->SetTabColorChangedCallback(pfnTabColorChanged);

auto pfnScrollPositionChanged = std::bind(&ControlCore::_terminalScrollPositionChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
_terminal->SetScrollPositionChangedCallback(pfnScrollPositionChanged);

Expand Down Expand Up @@ -126,6 +123,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(renderSettings, _terminal.get(), nullptr, 0, std::move(renderThread));

_renderer->SetBackgroundColorChangedCallback([this]() { _rendererBackgroundColorChanged(); });
_renderer->SetFrameColorChangedCallback([this]() { _rendererTabColorChanged(); });

_renderer->SetRendererEnteredErrorStateCallback([weakThis = get_weak()]() {
if (auto strongThis{ weakThis.get() })
Expand Down Expand Up @@ -647,6 +645,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Inform the renderer of our opacity
_renderEngine->EnableTransparentBackground(_isBackgroundTransparent());

// Trigger a redraw to repaint the window background and tab colors.
_renderer->TriggerRedrawAll(true, true);

_updateAntiAliasingMode();

if (sizeChanged)
Expand Down Expand Up @@ -1144,21 +1145,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_TitleChangedHandlers(*this, winrt::make<TitleChangedEventArgs>(winrt::hstring{ wstr }));
}

// Method Description:
// - Called for the Terminal's TabColorChanged callback. This will re-raise
// a new winrt TypedEvent that can be listened to.
// - The listeners to this event will re-query the control for the current
// value of TabColor().
// Arguments:
// - <unused>
// Return Value:
// - <none>
void ControlCore::_terminalTabColorChanged(const std::optional<til::color> /*color*/)
{
// Raise a TabColorChanged event
_TabColorChangedHandlers(*this, nullptr);
}

// Method Description:
// - Update the position and size of the scrollbar to match the given
// viewport top, viewport height, and buffer size.
Expand Down Expand Up @@ -1356,6 +1342,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_BackgroundColorChangedHandlers(*this, nullptr);
}

void ControlCore::_rendererTabColorChanged()
{
_TabColorChangedHandlers(*this, nullptr);
}

void ControlCore::BlinkAttributeTick()
{
auto lock = _terminal->LockForWriting();
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _terminalCopyToClipboard(std::wstring_view wstr);
void _terminalWarningBell();
void _terminalTitleChanged(std::wstring_view wstr);
void _terminalTabColorChanged(const std::optional<til::color> color);
void _terminalScrollPositionChanged(const int viewTop,
const int viewHeight,
const int bufferSize);
Expand All @@ -278,6 +277,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _rendererWarning(const HRESULT hr);
void _renderEngineSwapChainChanged();
void _rendererBackgroundColorChanged();
void _rendererTabColorChanged();
#pragma endregion

void _raiseReadOnlyWarning();
Expand Down
26 changes: 12 additions & 14 deletions src/cascadia/TerminalCore/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,23 +125,18 @@ void Terminal::UpdateSettings(ICoreSettings settings)

if (settings.TabColor() == nullptr)
{
_tabColor = std::nullopt;
_renderSettings.SetColorTableEntry(TextColor::FRAME_BACKGROUND, INVALID_COLOR);
}
else
{
_tabColor = settings.TabColor().Value();
_renderSettings.SetColorTableEntry(TextColor::FRAME_BACKGROUND, til::color{ settings.TabColor().Value() });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't 100% understand the color table vs alias thing right now, but should this use SetColorAlias to both (1) point FrameBackground at FRAME_BACKGROUND and (2) set FRAME_BACKGROUND to the new tab color?

Or is the intent that once redirected via DECAC, user-specified tab color cannot override application-specified tab color?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(And keeping with my (potential mis-)understanding of color aliases:) If that is the intent, then updating only the FRAME_BACKGROUND color but not re-pointing FrameBackground back to it is in line with that intent (?)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm glad you raised this, because I had meant to bring it up myself. I'm open to changing this, but I did it this way because it lets you map the frame background alias to the default background color table (using DECAC 2;261;262), and then switch your color scheme in the settings and still have both remain in sync. If we reset the frame alias here then we lose that ability.

But further down the line I'm assuming you might add an option for users to explicitly request that behavior (to support #702), and then the decision as to what should happen here would probably be controlled by that setting.

Does that make sense?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that make sense?

100%. We can refine this if/when we add this part of 702. For now, I like how it is. Thanks!

Mike may be changing the default s.t. Terminal always acts like DECAC 2;261;262 over in #12992, or shortly after. /cc @zadjii-msft for this discussion.

}

if (!_startingTabColor && settings.StartingTabColor())
{
_startingTabColor = settings.StartingTabColor().Value();
}

if (_pfnTabColorChanged)
{
_pfnTabColorChanged(GetTabColor());
}

// TODO:MSFT:21327402 - if HistorySize has changed, resize the buffer so we
// have a smaller scrollback. We should do this carefully - if the new buffer
// size is smaller than where the mutable viewport currently is, we'll want
Expand Down Expand Up @@ -1272,11 +1267,6 @@ void Terminal::SetTitleChangedCallback(std::function<void(std::wstring_view)> pf
_pfnTitleChanged.swap(pfn);
}

void Terminal::SetTabColorChangedCallback(std::function<void(const std::optional<til::color>)> pfn) noexcept
{
_pfnTabColorChanged.swap(pfn);
}

void Terminal::SetCopyToClipboardCallback(std::function<void(std::wstring_view)> pfn) noexcept
{
_pfnCopyToClipboard.swap(pfn);
Expand Down Expand Up @@ -1357,10 +1347,18 @@ void Terminal::ClearPatternTree() noexcept

// Method Description:
// - Returns the tab color
// If the starting color exits, it's value is preferred
// If the starting color exists, its value is preferred
const std::optional<til::color> Terminal::GetTabColor() const noexcept
{
return _startingTabColor.has_value() ? _startingTabColor : _tabColor;
if (_startingTabColor.has_value())
{
return _startingTabColor;
}
else
{
const auto tabColor = _renderSettings.GetColorAlias(ColorAlias::FrameBackground);
return tabColor == INVALID_COLOR ? std::nullopt : std::optional<til::color>{ tabColor };
}
}

// Method Description:
Expand Down
3 changes: 0 additions & 3 deletions src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ class Microsoft::Terminal::Core::Terminal final :
void SetWriteInputCallback(std::function<void(std::wstring_view)> pfn) noexcept;
void SetWarningBellCallback(std::function<void()> pfn) noexcept;
void SetTitleChangedCallback(std::function<void(std::wstring_view)> pfn) noexcept;
void SetTabColorChangedCallback(std::function<void(const std::optional<til::color>)> pfn) noexcept;
void SetCopyToClipboardCallback(std::function<void(std::wstring_view)> pfn) noexcept;
void SetScrollPositionChangedCallback(std::function<void(const int, const int, const int)> pfn) noexcept;
void SetCursorPositionChangedCallback(std::function<void()> pfn) noexcept;
Expand Down Expand Up @@ -267,7 +266,6 @@ class Microsoft::Terminal::Core::Terminal final :

std::function<void(const int, const int, const int)> _pfnScrollPositionChanged;
std::function<void()> _pfnCursorPositionChanged;
std::function<void(const std::optional<til::color>)> _pfnTabColorChanged;
std::function<void()> _pfnTaskbarProgressChanged;
std::function<void(bool)> _pfnShowWindowChanged;

Expand All @@ -277,7 +275,6 @@ class Microsoft::Terminal::Core::Terminal final :

std::optional<std::wstring> _title;
std::wstring _startingTitle;
std::optional<til::color> _tabColor;
std::optional<til::color> _startingTabColor;

CursorType _defaultCursorShape;
Expand Down
38 changes: 38 additions & 0 deletions src/host/ut_host/ScreenBufferTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ class ScreenBufferTests

TEST_METHOD(SetDefaultBackgroundColor);

TEST_METHOD(AssignColorAliases);

TEST_METHOD(DeleteCharsNearEndOfLine);
TEST_METHOD(DeleteCharsNearEndOfLineSimpleFirstCase);
TEST_METHOD(DeleteCharsNearEndOfLineSimpleSecondCase);
Expand Down Expand Up @@ -3004,6 +3006,42 @@ void ScreenBufferTests::SetDefaultBackgroundColor()
VERIFY_ARE_EQUAL(originalColor, newColor);
}

void ScreenBufferTests::AssignColorAliases()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto& stateMachine = gci.GetActiveOutputBuffer().GetStateMachine();
auto& renderSettings = gci.GetRenderSettings();

const auto defaultFg = renderSettings.GetColorAliasIndex(ColorAlias::DefaultForeground);
const auto defaultBg = renderSettings.GetColorAliasIndex(ColorAlias::DefaultBackground);
const auto frameFg = renderSettings.GetColorAliasIndex(ColorAlias::FrameForeground);
const auto frameBg = renderSettings.GetColorAliasIndex(ColorAlias::FrameBackground);

auto resetAliases = wil::scope_exit([&] {
renderSettings.SetColorAliasIndex(ColorAlias::DefaultForeground, defaultFg);
renderSettings.SetColorAliasIndex(ColorAlias::DefaultBackground, defaultBg);
renderSettings.SetColorAliasIndex(ColorAlias::FrameForeground, frameFg);
renderSettings.SetColorAliasIndex(ColorAlias::FrameBackground, frameBg);
});

Log::Comment(L"Test invalid item color assignment");
stateMachine.ProcessString(L"\033[0;12;34,|");
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));

Log::Comment(L"Test normal text color assignment");
stateMachine.ProcessString(L"\033[1;23;45,|");
VERIFY_ARE_EQUAL(23u, renderSettings.GetColorAliasIndex(ColorAlias::DefaultForeground));
VERIFY_ARE_EQUAL(45u, renderSettings.GetColorAliasIndex(ColorAlias::DefaultBackground));

Log::Comment(L"Test window frame color assignment");
stateMachine.ProcessString(L"\033[2;34;56,|");
VERIFY_ARE_EQUAL(34u, renderSettings.GetColorAliasIndex(ColorAlias::FrameForeground));
VERIFY_ARE_EQUAL(56u, renderSettings.GetColorAliasIndex(ColorAlias::FrameBackground));
}

void ScreenBufferTests::DeleteCharsNearEndOfLine()
{
// Created for MSFT:19888564.
Expand Down
9 changes: 8 additions & 1 deletion src/renderer/base/RenderSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ RenderSettings::RenderSettings() noexcept

SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, INVALID_COLOR);
SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, INVALID_COLOR);
SetColorTableEntry(TextColor::FRAME_FOREGROUND, INVALID_COLOR);
SetColorTableEntry(TextColor::FRAME_BACKGROUND, INVALID_COLOR);
SetColorTableEntry(TextColor::CURSOR_COLOR, INVALID_COLOR);

SetColorAliasIndex(ColorAlias::DefaultForeground, TextColor::DARK_WHITE);
SetColorAliasIndex(ColorAlias::DefaultBackground, TextColor::DARK_BLACK);
SetColorAliasIndex(ColorAlias::FrameForeground, TextColor::FRAME_FOREGROUND);
SetColorAliasIndex(ColorAlias::FrameBackground, TextColor::FRAME_BACKGROUND);
}

// Routine Description:
Expand Down Expand Up @@ -149,7 +153,10 @@ COLORREF RenderSettings::GetColorAlias(const ColorAlias alias) const
// - tableIndex - The new position of the alias in the color table.
void RenderSettings::SetColorAliasIndex(const ColorAlias alias, const size_t tableIndex) noexcept
{
gsl::at(_colorAliasIndices, static_cast<size_t>(alias)) = tableIndex;
if (tableIndex < TextColor::TABLE_SIZE)
{
gsl::at(_colorAliasIndices, static_cast<size_t>(alias)) = tableIndex;
}
}

// Routine Description:
Expand Down
19 changes: 18 additions & 1 deletion src/renderer/base/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,10 @@ void Renderer::TriggerRedrawCursor(const COORD* const pcoord)
// - NOTE: Use sparingly. Try to reduce the refresh region where possible. Only use when a global state change has occurred.
// Arguments:
// - backgroundChanged - Set to true if the background color has changed.
// - frameChanged - Set to true if the frame colors have changed.
// Return Value:
// - <none>
void Renderer::TriggerRedrawAll(const bool backgroundChanged)
void Renderer::TriggerRedrawAll(const bool backgroundChanged, const bool frameChanged)
{
FOREACH_ENGINE(pEngine)
{
Expand All @@ -314,6 +315,11 @@ void Renderer::TriggerRedrawAll(const bool backgroundChanged)
{
_pfnBackgroundColorChanged();
}

if (frameChanged && _pfnFrameColorChanged)
{
_pfnFrameColorChanged();
}
}

// Method Description:
Expand Down Expand Up @@ -1348,6 +1354,17 @@ void Renderer::SetBackgroundColorChangedCallback(std::function<void()> pfn)
_pfnBackgroundColorChanged = std::move(pfn);
}

// Method Description:
// - Registers a callback for when the frame colors have changed
// Arguments:
// - pfn: the callback
// Return Value:
// - <none>
void Renderer::SetFrameColorChangedCallback(std::function<void()> pfn)
{
_pfnFrameColorChanged = std::move(pfn);
}

// Method Description:
// - Registers a callback that will be called when this renderer gives up.
// An application consuming a renderer can use this to display auxiliary Retry UI
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/base/renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ namespace Microsoft::Console::Render
void TriggerRedraw(const Microsoft::Console::Types::Viewport& region);
void TriggerRedraw(const COORD* const pcoord);
void TriggerRedrawCursor(const COORD* const pcoord);
void TriggerRedrawAll(const bool backgroundChanged = false);
void TriggerRedrawAll(const bool backgroundChanged = false, const bool frameChanged = false);
void TriggerTeardown() noexcept;

void TriggerSelection();
Expand Down Expand Up @@ -85,6 +85,7 @@ namespace Microsoft::Console::Render
void AddRenderEngine(_In_ IRenderEngine* const pEngine);

void SetBackgroundColorChangedCallback(std::function<void()> pfn);
void SetFrameColorChangedCallback(std::function<void()> pfn);
void SetRendererEnteredErrorStateCallback(std::function<void()> pfn);
void ResetErrorStateAndResume();

Expand Down Expand Up @@ -123,6 +124,7 @@ namespace Microsoft::Console::Render
std::vector<Cluster> _clusterBuffer;
std::vector<SMALL_RECT> _previousSelection;
std::function<void()> _pfnBackgroundColorChanged;
std::function<void()> _pfnFrameColorChanged;
std::function<void()> _pfnRendererEnteredErrorState;
bool _destructing = false;
bool _forceUpdateViewport = true;
Expand Down
6 changes: 6 additions & 0 deletions src/terminal/adapter/DispatchTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ namespace Microsoft::Console::VirtualTerminal

namespace Microsoft::Console::VirtualTerminal::DispatchTypes
{
enum class ColorItem : VTInt
{
NormalText = 1,
WindowFrame = 2,
};

enum class EraseType : VTInt
{
ToEnd = 0,
Expand Down
1 change: 1 addition & 0 deletions src/terminal/adapter/ITermDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch
virtual bool SetColorTableEntry(const size_t tableIndex, const DWORD color) = 0; // OSCColorTable
virtual bool SetDefaultForeground(const DWORD color) = 0; // OSCDefaultForeground
virtual bool SetDefaultBackground(const DWORD color) = 0; // OSCDefaultBackground
virtual bool AssignColor(const DispatchTypes::ColorItem item, const VTInt fgIndex, const VTInt bgIndex) = 0; // DECAC

virtual bool EraseInDisplay(const DispatchTypes::EraseType eraseType) = 0; // ED
virtual bool EraseInLine(const DispatchTypes::EraseType eraseType) = 0; // EL
Expand Down
Loading