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

Show a double width cursor for double width characters #5319

Merged
21 commits merged into from
Apr 15, 2020
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
8 changes: 1 addition & 7 deletions src/buffer/out/textBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1967,11 +1967,8 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
const std::optional<Viewport> lastCharacterViewport,
std::optional<std::reference_wrapper<PositionInformation>> positionInfo)
{
Cursor& oldCursor = oldBuffer.GetCursor();
const Cursor& oldCursor = oldBuffer.GetCursor();
Cursor& newCursor = newBuffer.GetCursor();
// skip any drawing updates that might occur as we manipulate the new buffer
oldCursor.StartDeferDrawing();
newCursor.StartDeferDrawing();

// We need to save the old cursor position so that we can
// place the new cursor back on the equivalent character in
Expand Down Expand Up @@ -2197,8 +2194,5 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
newCursor.SetSize(ulSize);
}

newCursor.EndDeferDrawing();
oldCursor.EndDeferDrawing();

return hr;
}
10 changes: 9 additions & 1 deletion src/cascadia/TerminalCore/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting
// bottom in the new buffer as well. Track that case now.
const bool originalOffsetWasZero = _scrollOffset == 0;

// skip any drawing updates that might occur until we swap _buffer with the new buffer or if we exit early.
_buffer->GetCursor().StartDeferDrawing();
// we're capturing _buffer by reference here because when we exit, we want to EndDefer on the current active buffer.
auto endDefer = wil::scope_exit([&]() noexcept { _buffer->GetCursor().EndDeferDrawing(); });
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: might be worth a comment that we're capturing _buffer by reference because either way, when we exit, we want to undefer the current active one


// First allocate a new text buffer to take the place of the current one.
std::unique_ptr<TextBuffer> newTextBuffer;
try
Expand All @@ -199,6 +204,8 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting
0, // temporarily set size to 0 so it won't render.
_buffer->GetRenderTarget());

newTextBuffer->GetCursor().StartDeferDrawing();

// Build a PositionInformation to track the position of both the top of
// the mutable viewport and the top of the visible viewport in the new
// buffer.
Expand Down Expand Up @@ -875,8 +882,9 @@ CATCH_LOG()
// Visible, then it will immediately become visible.
// Arguments:
// - isVisible: whether the cursor should be visible
void Terminal::SetCursorOn(const bool isOn) noexcept
void Terminal::SetCursorOn(const bool isOn)
{
auto lock = LockForWriting();
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved
_buffer->GetCursor().SetIsOn(isOn);
}

Expand Down
5 changes: 3 additions & 2 deletions src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "../../terminal/input/terminalInput.hpp"

#include "../../types/inc/Viewport.hpp"
#include "../../types/inc/GlyphWidth.hpp"
#include "../../types/IUiaData.h"
#include "../../cascadia/terminalcore/ITerminalApi.hpp"
#include "../../cascadia/terminalcore/ITerminalInput.hpp"
Expand Down Expand Up @@ -147,7 +148,7 @@ class Microsoft::Terminal::Core::Terminal final :
ULONG GetCursorPixelWidth() const noexcept override;
CursorType GetCursorStyle() const noexcept override;
COLORREF GetCursorColor() const noexcept override;
bool IsCursorDoubleWidth() const noexcept override;
bool IsCursorDoubleWidth() const override;
bool IsScreenReversed() const noexcept override;
const std::vector<Microsoft::Console::Render::RenderOverlay> GetOverlays() const noexcept override;
const bool IsGridLineDrawingAllowed() noexcept override;
Expand All @@ -171,7 +172,7 @@ class Microsoft::Terminal::Core::Terminal final :
void SetCursorPositionChangedCallback(std::function<void()> pfn) noexcept;
void SetBackgroundCallback(std::function<void(const uint32_t)> pfn) noexcept;

void SetCursorOn(const bool isOn) noexcept;
void SetCursorOn(const bool isOn);
bool IsCursorBlinkingAllowed() const noexcept;

#pragma region TextSelection
Expand Down
6 changes: 4 additions & 2 deletions src/cascadia/TerminalCore/terminalrenderdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,11 @@ COLORREF Terminal::GetCursorColor() const noexcept
return _buffer->GetCursor().GetColor();
}

bool Terminal::IsCursorDoubleWidth() const noexcept
bool Terminal::IsCursorDoubleWidth() const
{
return false;
const auto position = _buffer->GetCursor().GetPosition();
TextBufferTextIterator it(TextBufferCellIterator(*_buffer, position));
return IsGlyphFullWidth(*it);
}

const std::vector<RenderOverlay> Terminal::GetOverlays() const noexcept
Expand Down
43 changes: 43 additions & 0 deletions src/cascadia/UnitTests_TerminalCore/TerminalApiTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace TerminalCoreUnitTests
// This test ensures that Terminal::_WriteBuffer doesn't get stuck when
// PrintString() is called with more code units than the buffer width.
TEST_METHOD(PrintStringOfSurrogatePairs);
TEST_METHOD(CheckDoubleWidthCursor);
};
};

Expand Down Expand Up @@ -208,3 +209,45 @@ void TerminalApiTest::CursorVisibilityViaStateMachine()
VERIFY_IS_FALSE(cursor.IsBlinkingAllowed());
VERIFY_IS_FALSE(cursor.IsVisible());
}

void TerminalApiTest::CheckDoubleWidthCursor()
{
DummyRenderTarget renderTarget;
Terminal term;
term.Create({ 100, 100 }, 0, renderTarget);

auto& tbi = *(term._buffer);
auto& stateMachine = *(term._stateMachine);
auto& cursor = tbi.GetCursor();

// Lets stuff the buffer with single width characters,
// but leave the last two columns empty for double width.
std::wstring singleWidthText;
singleWidthText.reserve(98);
for (size_t i = 0; i < 98; ++i)
{
singleWidthText.append(L"A");
}
stateMachine.ProcessString(singleWidthText);
VERIFY_IS_TRUE(cursor.GetPosition().X == 98);

// Stuff two double width characters.
std::wstring doubleWidthText{ L"我愛" };
stateMachine.ProcessString(doubleWidthText);

// The last 'A'
term.SetCursorPosition(97, 0);
VERIFY_IS_FALSE(term.IsCursorDoubleWidth());

// This and the next CursorPos are taken up by '我‘
term.SetCursorPosition(98, 0);
VERIFY_IS_TRUE(term.IsCursorDoubleWidth());
term.SetCursorPosition(99, 0);
VERIFY_IS_TRUE(term.IsCursorDoubleWidth());

// This and the next CursorPos are taken up by ’愛‘
term.SetCursorPosition(0, 1);
VERIFY_IS_TRUE(term.IsCursorDoubleWidth());
term.SetCursorPosition(1, 1);
VERIFY_IS_TRUE(term.IsCursorDoubleWidth());
}
6 changes: 6 additions & 0 deletions src/host/screenInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1403,6 +1403,12 @@ bool SCREEN_INFORMATION::IsMaximizedY() const
// Save cursor's relative height versus the viewport
SHORT const sCursorHeightInViewportBefore = _textBuffer->GetCursor().GetPosition().Y - _viewport.Top();

// skip any drawing updates that might occur until we swap _textBuffer with the new buffer or we exit early.
newTextBuffer->GetCursor().StartDeferDrawing();
_textBuffer->GetCursor().StartDeferDrawing();
// we're capturing _textBuffer by reference here because when we exit, we want to EndDefer on the current active buffer.
auto endDefer = wil::scope_exit([&]() noexcept { _textBuffer->GetCursor().EndDeferDrawing(); });
Copy link
Contributor

Choose a reason for hiding this comment

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

same comment as above :)


HRESULT hr = TextBuffer::Reflow(*_textBuffer.get(), *newTextBuffer.get(), std::nullopt, std::nullopt);

if (SUCCEEDED(hr))
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/inc/IRenderData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ namespace Microsoft::Console::Render
virtual CursorType GetCursorStyle() const noexcept = 0;
virtual ULONG GetCursorPixelWidth() const noexcept = 0;
virtual COLORREF GetCursorColor() const noexcept = 0;
virtual bool IsCursorDoubleWidth() const noexcept = 0;
virtual bool IsCursorDoubleWidth() const = 0;

virtual bool IsScreenReversed() const noexcept = 0;

Expand Down