From a2dc867dfa906cff66da3e804c2085b9a162a9d8 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Tue, 31 Mar 2020 14:08:12 -0700 Subject: [PATCH 01/18] first lets add back the code that crashes --- src/cascadia/TerminalCore/Terminal.hpp | 1 + src/cascadia/TerminalCore/terminalrenderdata.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index f5ca256e31a..f10bd4ba9b4 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -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" diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index e49859cb374..686b2334575 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -107,7 +107,9 @@ COLORREF Terminal::GetCursorColor() const noexcept bool Terminal::IsCursorDoubleWidth() const noexcept { - return false; + const auto position = _buffer->GetCursor().GetPosition(); + TextBufferTextIterator it(TextBufferCellIterator(*_buffer, position)); + return IsGlyphFullWidth(*it); } const std::vector Terminal::GetOverlays() const noexcept From 56392f62befa024693ec6156e4bcf042598fc12b Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Thu, 2 Apr 2020 13:41:12 -0700 Subject: [PATCH 02/18] adding a test that may or may not work --- src/cascadia/TerminalCore/Terminal.cpp | 2 + src/host/ft_host/API_OutputTests.cpp | 56 +++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index b3471ee68eb..a73436fb0e0 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -683,6 +683,8 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition) notifyScroll = true; } + proposedCursorPosition.X = base::ClampMin(proposedCursorPosition.X, ::base::ClampedNumeric(bufferSize.Width() - 1)); + // Update Cursor Position cursor.SetPosition(proposedCursorPosition); diff --git a/src/host/ft_host/API_OutputTests.cpp b/src/host/ft_host/API_OutputTests.cpp index 4912f17a597..bed09cfd605 100644 --- a/src/host/ft_host/API_OutputTests.cpp +++ b/src/host/ft_host/API_OutputTests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. #include "precomp.h" @@ -46,6 +46,8 @@ class OutputTests TEST_METHOD(WriteBackspaceTest); TEST_METHOD(WinPtyWrite); + + TEST_METHOD(WriteTwoColumnCharacterToCheckOverflow); }; bool OutputTests::TestSetup() @@ -1062,3 +1064,55 @@ void OutputTests::WinPtyWrite() break; } } + +void OutputTests::WriteTwoColumnCharacterToCheckOverflow() +{ + // Get output buffer information. + const auto consoleOutputHandle = GetStdOutputHandle(); + SetConsoleActiveScreenBuffer(consoleOutputHandle); + + CONSOLE_SCREEN_BUFFER_INFOEX sbiex{ 0 }; + sbiex.cbSize = sizeof(sbiex); + + VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(consoleOutputHandle, &sbiex)); + const auto bufferSize = sbiex.dwSize; + + // Establish a writing region that is the width of the buffer and half the height. + const SMALL_RECT region{ 0, 0, bufferSize.X - 1, 1 }; + const COORD regionDimensions{ region.Right - region.Left + 1, region.Bottom - region.Top + 1 }; + const auto regionSize = regionDimensions.X * regionDimensions.Y; + const COORD regionOrigin{ 0, 0 }; + + // Make a double width character value with lead bit and fill an array (via a vector) full of it. + // We just want the character to be in the last column of the buffer. + CHAR_INFO testValue; + testValue.Attributes = 0x0100; + testValue.Char.UnicodeChar = L'是'; + + std::vector buffer(regionSize, testValue); + + CHAR_INFO lastColumnValue; + lastColumnValue.Attributes = 0x0100; + lastColumnValue.Char.UnicodeChar = L'我'; + buffer[regionSize - 1] = lastColumnValue; + + // Call the API and confirm results. + SMALL_RECT affected = region; + VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleOutputW(consoleOutputHandle, buffer.data(), regionDimensions, regionOrigin, &affected)); + VERIFY_ARE_EQUAL(region, affected); + + // Move the cursor to the last column of the buffer + VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleCursorPosition(consoleOutputHandle, { bufferSize.X - 1, 0 })); + + // Check that the character + const auto cursorPos = sbiex.dwCursorPosition; + + // Make an array that can hold the output + std::vector singleBuf(1); + + // Call the API and confirm results + SMALL_RECT singleAffectedRegion = { 0, 0, 1, 1 }; + const COORD singleRegionDimension = { 1, 1 }; + VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputW(consoleOutputHandle, singleBuf.data(), singleRegionDimension, cursorPos, &affected)); + VERIFY_ARE_EQUAL(singleBuf[0], lastColumnValue); +} From b86d85ed72366a26ae6bef09321ee9dbb2497bcb Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Fri, 3 Apr 2020 01:59:30 -0700 Subject: [PATCH 03/18] test case --- src/cascadia/TerminalCore/Terminal.cpp | 2 +- src/host/ft_host/API_OutputTests.cpp | 36 ++++++++++++++------------ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index a73436fb0e0..37fd13c639f 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -683,7 +683,7 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition) notifyScroll = true; } - proposedCursorPosition.X = base::ClampMin(proposedCursorPosition.X, ::base::ClampedNumeric(bufferSize.Width() - 1)); + //proposedCursorPosition.X = base::ClampMin(proposedCursorPosition.X, ::base::ClampedNumeric(bufferSize.Width() - 1)); // Update Cursor Position cursor.SetPosition(proposedCursorPosition); diff --git a/src/host/ft_host/API_OutputTests.cpp b/src/host/ft_host/API_OutputTests.cpp index bed09cfd605..499eab10b7f 100644 --- a/src/host/ft_host/API_OutputTests.cpp +++ b/src/host/ft_host/API_OutputTests.cpp @@ -1078,21 +1078,20 @@ void OutputTests::WriteTwoColumnCharacterToCheckOverflow() const auto bufferSize = sbiex.dwSize; // Establish a writing region that is the width of the buffer and half the height. - const SMALL_RECT region{ 0, 0, bufferSize.X - 1, 1 }; + const SMALL_RECT region{ 0, 0, bufferSize.X - 1, 0 }; const COORD regionDimensions{ region.Right - region.Left + 1, region.Bottom - region.Top + 1 }; const auto regionSize = regionDimensions.X * regionDimensions.Y; const COORD regionOrigin{ 0, 0 }; - // Make a double width character value with lead bit and fill an array (via a vector) full of it. - // We just want the character to be in the last column of the buffer. CHAR_INFO testValue; - testValue.Attributes = 0x0100; - testValue.Char.UnicodeChar = L'是'; + testValue.Attributes = 0x3e; + testValue.Char.UnicodeChar = L'A'; std::vector buffer(regionSize, testValue); + // Place a double width character with a lead bit in the last column of the buffer. CHAR_INFO lastColumnValue; - lastColumnValue.Attributes = 0x0100; + lastColumnValue.Attributes = 0x13e; lastColumnValue.Char.UnicodeChar = L'我'; buffer[regionSize - 1] = lastColumnValue; @@ -1104,15 +1103,18 @@ void OutputTests::WriteTwoColumnCharacterToCheckOverflow() // Move the cursor to the last column of the buffer VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleCursorPosition(consoleOutputHandle, { bufferSize.X - 1, 0 })); - // Check that the character - const auto cursorPos = sbiex.dwCursorPosition; - - // Make an array that can hold the output - std::vector singleBuf(1); - - // Call the API and confirm results - SMALL_RECT singleAffectedRegion = { 0, 0, 1, 1 }; - const COORD singleRegionDimension = { 1, 1 }; - VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputW(consoleOutputHandle, singleBuf.data(), singleRegionDimension, cursorPos, &affected)); - VERIFY_ARE_EQUAL(singleBuf[0], lastColumnValue); + //// Make an array that can hold the output + //std::vector readBuffer(regionSize); + + //// Call the API and confirm results + //SMALL_RECT readRegion = region; + //VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputW(consoleOutputHandle, readBuffer.data(), regionDimensions, regionOrigin, &readRegion)); + //for (auto x : readBuffer) + //{ + // for (int i = 0; i < 1000; ++i) + // { + // VERIFY_ARE_EQUAL(x, testValue); + // } + // + //} } From 9e149cbfe56239eaed8b2a3ecb3f840f0c1b8457 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Tue, 7 Apr 2020 14:45:26 -0700 Subject: [PATCH 04/18] i just add debug for now --- src/cascadia/TerminalCore/Terminal.cpp | 22 ++++++++++++++++++++-- src/renderer/base/renderer.cpp | 4 ++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 37fd13c639f..d88487c8d1c 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -165,6 +165,12 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting [[nodiscard]] HRESULT Terminal::UserResize(const COORD viewportSize) noexcept { const auto oldDimensions = _mutableViewport.Dimensions(); + + if (!_buffer->GetSize().IsInBounds(_buffer->GetCursor().GetPosition())) + { + OutputDebugString(L"UserResize not in bounds\n"); + } + if (viewportSize == oldDimensions) { return S_FALSE; @@ -630,6 +636,12 @@ void Terminal::_WriteBuffer(const std::wstring_view& stringView) // If "wch" was a surrogate character, we just consumed 2 code units above. // -> Increment "i" by 1 in that case and thus by 2 in total in this iteration. proposedCursorPosition.X += gsl::narrow(cellDistance); + + if (!_buffer->GetSize().IsInBounds(proposedCursorPosition)) + { + OutputDebugString(L"InDist > 0 not in Bounds\n"); + } + i += inputDistance - 1; } else @@ -646,6 +658,8 @@ void Terminal::_WriteBuffer(const std::wstring_view& stringView) // Try the character again. i--; + OutputDebugString(L"Reset to 0\n"); + // If we write the last cell of the row here, TextBuffer::Write will // mark this line as wrapped for us. If the next character we // process is a newline, the Terminal::CursorLineFeed will unmark @@ -660,6 +674,11 @@ void Terminal::_WriteBuffer(const std::wstring_view& stringView) _AdjustCursorPosition(proposedCursorPosition); } + if (!_buffer->GetSize().IsInBounds(_buffer->GetCursor().GetPosition())) + { + OutputDebugString(L"Still not in Bounds\n"); + } + cursor.EndDeferDrawing(); } @@ -683,8 +702,6 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition) notifyScroll = true; } - //proposedCursorPosition.X = base::ClampMin(proposedCursorPosition.X, ::base::ClampedNumeric(bufferSize.Width() - 1)); - // Update Cursor Position cursor.SetPosition(proposedCursorPosition); @@ -800,6 +817,7 @@ CATCH_LOG() // - isVisible: whether the cursor should be visible void Terminal::SetCursorOn(const bool isOn) noexcept { + auto lock = LockForWriting(); _buffer->GetCursor().SetIsOn(isOn); } diff --git a/src/renderer/base/renderer.cpp b/src/renderer/base/renderer.cpp index dfe4bdd3a6d..ef293999c5c 100644 --- a/src/renderer/base/renderer.cpp +++ b/src/renderer/base/renderer.cpp @@ -832,6 +832,10 @@ void Renderer::_PaintCursor(_In_ IRenderEngine* const pEngine) // Draw it within the viewport LOG_IF_FAILED(pEngine->PaintCursor(options)); } + else + { + OutputDebugString(L"PaintCursor NOT In Bounds \n"); + } } } From 5fcbac7a3505240cc2d4c30e833e181a1dcf0596 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Wed, 8 Apr 2020 15:14:30 -0700 Subject: [PATCH 05/18] mAYBE --- src/buffer/out/cursor.cpp | 19 +++++++++----- src/buffer/out/cursor.h | 1 + src/cascadia/TerminalCore/Terminal.cpp | 36 ++++++++++++++------------ src/renderer/base/renderer.cpp | 11 +++++--- 4 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/buffer/out/cursor.cpp b/src/buffer/out/cursor.cpp index 46f0208f820..359a3eb43d1 100644 --- a/src/buffer/out/cursor.cpp +++ b/src/buffer/out/cursor.cpp @@ -29,7 +29,8 @@ Cursor::Cursor(const ULONG ulSize, TextBuffer& parentBuffer) noexcept : _ulSize(ulSize), _cursorType(CursorType::Legacy), _fUseColor(false), - _color(s_InvertCursorColor) + _color(s_InvertCursorColor), + _iDeferCounter{ 0 } { } @@ -166,7 +167,7 @@ void Cursor::_RedrawCursor() noexcept // (Conversion areas have cursors to mark the insertion point internally, but the user's actual cursor is the one on the primary screen buffer.) if (IsOn() && !IsConversionArea()) { - if (_fDeferCursorRedraw) + if (_iDeferCounter > 0) { _fHaveDeferredCursorRedraw = true; } @@ -281,6 +282,7 @@ void Cursor::CopyProperties(const Cursor& OtherCursor) noexcept _fDeferCursorRedraw = OtherCursor._fDeferCursorRedraw; _fHaveDeferredCursorRedraw = OtherCursor._fHaveDeferredCursorRedraw; + _iDeferCounter = OtherCursor._iDeferCounter; // Size will be handled separately in the resize operation. //_ulSize = OtherCursor._ulSize; @@ -312,17 +314,22 @@ bool Cursor::IsDelayedEOLWrap() const noexcept void Cursor::StartDeferDrawing() noexcept { - _fDeferCursorRedraw = true; + ++_iDeferCounter; } void Cursor::EndDeferDrawing() noexcept { - if (_fHaveDeferredCursorRedraw) + // Nobody has started a defer drawing. + if (_iDeferCounter == 0) { - _RedrawCursorAlways(); + return; } - _fDeferCursorRedraw = FALSE; + --_iDeferCounter; + if (_iDeferCounter == 0) + { + _RedrawCursorAlways(); + } } const CursorType Cursor::GetType() const noexcept diff --git a/src/buffer/out/cursor.h b/src/buffer/out/cursor.h index 7ac93359a49..d47cdd8825d 100644 --- a/src/buffer/out/cursor.h +++ b/src/buffer/out/cursor.h @@ -107,6 +107,7 @@ class Cursor final bool _fDelayedEolWrap; // don't wrap at EOL till the next char comes in. COORD _coordDelayedAt; // coordinate the EOL wrap was delayed at. + int _iDeferCounter; bool _fDeferCursorRedraw; // whether we should defer redrawing the cursor or not bool _fHaveDeferredCursorRedraw; // have we been asked to redraw the cursor while it was being deferred? diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 272bc4c5934..ef670f8ce87 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -166,11 +166,6 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting { const auto oldDimensions = _mutableViewport.Dimensions(); - if (!_buffer->GetSize().IsInBounds(_buffer->GetCursor().GetPosition())) - { - OutputDebugString(L"UserResize not in bounds\n"); - } - if (viewportSize == oldDimensions) { return S_FALSE; @@ -196,6 +191,23 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting // bottom in the new buffer as well. Track that case now. const bool originalOffsetWasZero = _scrollOffset == 0; + // Defer the cursor drawing here right before the Reflow call + // because we only want the renderer to redraw the cursor right + // after we swap out the old buffer with the new buffer from Reflow. + // This swap happens down below, and so we'll EndDeferDrawing right + // after the swap. + // What would happen is that at the end of Reflow, we would call + // EndDeferDrawing, causing the renderer to go and attempt to redraw + // the cursor. However there's a race condition where, sometimes it + // would check for the _buffer properties before we swap out the + // buffer with the new one. This would make it crash if the old + // buffer's cursor position was out of bounds. + // Now that StartDeferDrawing uses a counter and will only redraw + // when the counter reaches 0, this StartDeferDrawing call here will + // force the renderer to redraw at least until this particular + // deferral is met with its corresponding EndDeferral down below. + _buffer->GetCursor().StartDeferDrawing(); + // First allocate a new text buffer to take the place of the current one. std::unique_ptr newTextBuffer; try @@ -335,6 +347,8 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting _buffer.swap(newTextBuffer); + _buffer->GetCursor().EndDeferDrawing(); + // GH#3494: Maintain scrollbar position during resize // Make sure that we don't scroll past the mutableViewport at the bottom of the buffer newVisibleTop = std::min(newVisibleTop, _mutableViewport.Top()); @@ -716,11 +730,6 @@ void Terminal::_WriteBuffer(const std::wstring_view& stringView) // -> Increment "i" by 1 in that case and thus by 2 in total in this iteration. proposedCursorPosition.X += gsl::narrow(cellDistance); - if (!_buffer->GetSize().IsInBounds(proposedCursorPosition)) - { - OutputDebugString(L"InDist > 0 not in Bounds\n"); - } - i += inputDistance - 1; } else @@ -737,8 +746,6 @@ void Terminal::_WriteBuffer(const std::wstring_view& stringView) // Try the character again. i--; - OutputDebugString(L"Reset to 0\n"); - // If we write the last cell of the row here, TextBuffer::Write will // mark this line as wrapped for us. If the next character we // process is a newline, the Terminal::CursorLineFeed will unmark @@ -753,11 +760,6 @@ void Terminal::_WriteBuffer(const std::wstring_view& stringView) _AdjustCursorPosition(proposedCursorPosition); } - if (!_buffer->GetSize().IsInBounds(_buffer->GetCursor().GetPosition())) - { - OutputDebugString(L"Still not in Bounds\n"); - } - cursor.EndDeferDrawing(); } diff --git a/src/renderer/base/renderer.cpp b/src/renderer/base/renderer.cpp index ef293999c5c..88847c04bac 100644 --- a/src/renderer/base/renderer.cpp +++ b/src/renderer/base/renderer.cpp @@ -236,6 +236,13 @@ void Renderer::TriggerRedrawCursor(const COORD* const pcoord) { LOG_IF_FAILED(pEngine->InvalidateCursor(&updateCoord)); + if (!_pData->GetTextBuffer().GetSize().IsInBounds(_pData->GetTextBuffer().GetCursor().GetPosition())) + { + char buf[2000]; + sprintf_s(buf, "TriggerRedraw: bufferX: %d, cursorpos: %d, updateCoord: %d\n", gsl::narrow_cast(_pData->GetTextBuffer().GetSize().RightExclusive()), gsl::narrow_cast(_pData->GetTextBuffer().GetCursor().GetPosition().X), updateCoord.X); + OutputDebugStringA(buf); + } + // Double-wide cursors need to invalidate the right half as well. if (_pData->IsCursorDoubleWidth()) { @@ -832,10 +839,6 @@ void Renderer::_PaintCursor(_In_ IRenderEngine* const pEngine) // Draw it within the viewport LOG_IF_FAILED(pEngine->PaintCursor(options)); } - else - { - OutputDebugString(L"PaintCursor NOT In Bounds \n"); - } } } From 32af07a3847e5c31e1ff7a1b139a5f1e66610b87 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Wed, 8 Apr 2020 15:38:30 -0700 Subject: [PATCH 06/18] ridding myself of comments --- src/cascadia/TerminalCore/Terminal.cpp | 1 - src/renderer/base/renderer.cpp | 7 ------- 2 files changed, 8 deletions(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index ef670f8ce87..b319e294ac0 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -729,7 +729,6 @@ void Terminal::_WriteBuffer(const std::wstring_view& stringView) // If "wch" was a surrogate character, we just consumed 2 code units above. // -> Increment "i" by 1 in that case and thus by 2 in total in this iteration. proposedCursorPosition.X += gsl::narrow(cellDistance); - i += inputDistance - 1; } else diff --git a/src/renderer/base/renderer.cpp b/src/renderer/base/renderer.cpp index 88847c04bac..dfe4bdd3a6d 100644 --- a/src/renderer/base/renderer.cpp +++ b/src/renderer/base/renderer.cpp @@ -236,13 +236,6 @@ void Renderer::TriggerRedrawCursor(const COORD* const pcoord) { LOG_IF_FAILED(pEngine->InvalidateCursor(&updateCoord)); - if (!_pData->GetTextBuffer().GetSize().IsInBounds(_pData->GetTextBuffer().GetCursor().GetPosition())) - { - char buf[2000]; - sprintf_s(buf, "TriggerRedraw: bufferX: %d, cursorpos: %d, updateCoord: %d\n", gsl::narrow_cast(_pData->GetTextBuffer().GetSize().RightExclusive()), gsl::narrow_cast(_pData->GetTextBuffer().GetCursor().GetPosition().X), updateCoord.X); - OutputDebugStringA(buf); - } - // Double-wide cursors need to invalidate the right half as well. if (_pData->IsCursorDoubleWidth()) { From 69b0f27edacb730fb3b9a0e599ab462c3c0bd2b5 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Thu, 9 Apr 2020 12:41:37 -0700 Subject: [PATCH 07/18] y fail if it wouldn't matter hmm --- src/cascadia/TerminalCore/Terminal.cpp | 1 - src/cascadia/TerminalCore/terminalrenderdata.cpp | 15 +++++++++++++-- src/host/ft_host/API_OutputTests.cpp | 15 --------------- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index b319e294ac0..6073596dc1e 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -165,7 +165,6 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting [[nodiscard]] HRESULT Terminal::UserResize(const COORD viewportSize) noexcept { const auto oldDimensions = _mutableViewport.Dimensions(); - if (viewportSize == oldDimensions) { return S_FALSE; diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index 686b2334575..0d23d884a1e 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -108,8 +108,19 @@ COLORREF Terminal::GetCursorColor() const noexcept bool Terminal::IsCursorDoubleWidth() const noexcept { const auto position = _buffer->GetCursor().GetPosition(); - TextBufferTextIterator it(TextBufferCellIterator(*_buffer, position)); - return IsGlyphFullWidth(*it); + + if (_buffer->GetSize().IsInBounds(position)) + { + TextBufferTextIterator it(TextBufferCellIterator(*_buffer, position)); + return IsGlyphFullWidth(*it); + } + else + { + // If the cursor isn't in the bounds of the buffer for any reason, + // it won't be rendered anyway, so let's just say the cursor + // was single width. + return false; + } } const std::vector Terminal::GetOverlays() const noexcept diff --git a/src/host/ft_host/API_OutputTests.cpp b/src/host/ft_host/API_OutputTests.cpp index 499eab10b7f..22a9a2eb9ab 100644 --- a/src/host/ft_host/API_OutputTests.cpp +++ b/src/host/ft_host/API_OutputTests.cpp @@ -1102,19 +1102,4 @@ void OutputTests::WriteTwoColumnCharacterToCheckOverflow() // Move the cursor to the last column of the buffer VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleCursorPosition(consoleOutputHandle, { bufferSize.X - 1, 0 })); - - //// Make an array that can hold the output - //std::vector readBuffer(regionSize); - - //// Call the API and confirm results - //SMALL_RECT readRegion = region; - //VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputW(consoleOutputHandle, readBuffer.data(), regionDimensions, regionOrigin, &readRegion)); - //for (auto x : readBuffer) - //{ - // for (int i = 0; i < 1000; ++i) - // { - // VERIFY_ARE_EQUAL(x, testValue); - // } - // - //} } From 21fd1b3476e26763f66163282ec929473dc08693 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Thu, 9 Apr 2020 16:50:08 -0700 Subject: [PATCH 08/18] why don't we just take these calls and place them over here --- src/buffer/out/cursor.cpp | 19 ++++--------- src/buffer/out/cursor.h | 1 - src/buffer/out/textBuffer.cpp | 6 ---- src/cascadia/TerminalCore/Terminal.cpp | 28 +++++++------------ .../TerminalCore/terminalrenderdata.cpp | 15 ++-------- src/host/ft_host/API_OutputTests.cpp | 2 +- src/host/screenInfo.cpp | 8 ++++++ 7 files changed, 27 insertions(+), 52 deletions(-) diff --git a/src/buffer/out/cursor.cpp b/src/buffer/out/cursor.cpp index 359a3eb43d1..46f0208f820 100644 --- a/src/buffer/out/cursor.cpp +++ b/src/buffer/out/cursor.cpp @@ -29,8 +29,7 @@ Cursor::Cursor(const ULONG ulSize, TextBuffer& parentBuffer) noexcept : _ulSize(ulSize), _cursorType(CursorType::Legacy), _fUseColor(false), - _color(s_InvertCursorColor), - _iDeferCounter{ 0 } + _color(s_InvertCursorColor) { } @@ -167,7 +166,7 @@ void Cursor::_RedrawCursor() noexcept // (Conversion areas have cursors to mark the insertion point internally, but the user's actual cursor is the one on the primary screen buffer.) if (IsOn() && !IsConversionArea()) { - if (_iDeferCounter > 0) + if (_fDeferCursorRedraw) { _fHaveDeferredCursorRedraw = true; } @@ -282,7 +281,6 @@ void Cursor::CopyProperties(const Cursor& OtherCursor) noexcept _fDeferCursorRedraw = OtherCursor._fDeferCursorRedraw; _fHaveDeferredCursorRedraw = OtherCursor._fHaveDeferredCursorRedraw; - _iDeferCounter = OtherCursor._iDeferCounter; // Size will be handled separately in the resize operation. //_ulSize = OtherCursor._ulSize; @@ -314,22 +312,17 @@ bool Cursor::IsDelayedEOLWrap() const noexcept void Cursor::StartDeferDrawing() noexcept { - ++_iDeferCounter; + _fDeferCursorRedraw = true; } void Cursor::EndDeferDrawing() noexcept { - // Nobody has started a defer drawing. - if (_iDeferCounter == 0) - { - return; - } - - --_iDeferCounter; - if (_iDeferCounter == 0) + if (_fHaveDeferredCursorRedraw) { _RedrawCursorAlways(); } + + _fDeferCursorRedraw = FALSE; } const CursorType Cursor::GetType() const noexcept diff --git a/src/buffer/out/cursor.h b/src/buffer/out/cursor.h index d47cdd8825d..7ac93359a49 100644 --- a/src/buffer/out/cursor.h +++ b/src/buffer/out/cursor.h @@ -107,7 +107,6 @@ class Cursor final bool _fDelayedEolWrap; // don't wrap at EOL till the next char comes in. COORD _coordDelayedAt; // coordinate the EOL wrap was delayed at. - int _iDeferCounter; bool _fDeferCursorRedraw; // whether we should defer redrawing the cursor or not bool _fHaveDeferredCursorRedraw; // have we been asked to redraw the cursor while it was being deferred? diff --git a/src/buffer/out/textBuffer.cpp b/src/buffer/out/textBuffer.cpp index eaa41dc415a..eb92fe9055e 100644 --- a/src/buffer/out/textBuffer.cpp +++ b/src/buffer/out/textBuffer.cpp @@ -1969,9 +1969,6 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer, { 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 @@ -2197,8 +2194,5 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer, newCursor.SetSize(ulSize); } - newCursor.EndDeferDrawing(); - oldCursor.EndDeferDrawing(); - return hr; } diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 6073596dc1e..211aaccfd22 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -190,23 +190,6 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting // bottom in the new buffer as well. Track that case now. const bool originalOffsetWasZero = _scrollOffset == 0; - // Defer the cursor drawing here right before the Reflow call - // because we only want the renderer to redraw the cursor right - // after we swap out the old buffer with the new buffer from Reflow. - // This swap happens down below, and so we'll EndDeferDrawing right - // after the swap. - // What would happen is that at the end of Reflow, we would call - // EndDeferDrawing, causing the renderer to go and attempt to redraw - // the cursor. However there's a race condition where, sometimes it - // would check for the _buffer properties before we swap out the - // buffer with the new one. This would make it crash if the old - // buffer's cursor position was out of bounds. - // Now that StartDeferDrawing uses a counter and will only redraw - // when the counter reaches 0, this StartDeferDrawing call here will - // force the renderer to redraw at least until this particular - // deferral is met with its corresponding EndDeferral down below. - _buffer->GetCursor().StartDeferDrawing(); - // First allocate a new text buffer to take the place of the current one. std::unique_ptr newTextBuffer; try @@ -216,6 +199,10 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting 0, // temporarily set size to 0 so it won't render. _buffer->GetRenderTarget()); + // skip any drawing updates that might occur as we manipulate the new buffer, until we swap the new with the old. + _buffer->GetCursor().StartDeferDrawing(); + 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. @@ -239,7 +226,11 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting newViewportTop = oldRows.mutableViewportTop; newVisibleTop = oldRows.visibleViewportTop; } - CATCH_RETURN(); + catch (...) + { + _buffer->GetCursor().EndDeferDrawing(); + RETURN_CAUGHT_EXCEPTION(); + } // Conpty resizes a little oddly - if the height decreased, and there were // blank lines at the bottom, those lines will get trimmed. If there's not @@ -346,6 +337,7 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting _buffer.swap(newTextBuffer); + // Now that the new buffer was swapped to be Terminal's buffer, we can tell its cursor to start drawing again. _buffer->GetCursor().EndDeferDrawing(); // GH#3494: Maintain scrollbar position during resize diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index 0d23d884a1e..686b2334575 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -108,19 +108,8 @@ COLORREF Terminal::GetCursorColor() const noexcept bool Terminal::IsCursorDoubleWidth() const noexcept { const auto position = _buffer->GetCursor().GetPosition(); - - if (_buffer->GetSize().IsInBounds(position)) - { - TextBufferTextIterator it(TextBufferCellIterator(*_buffer, position)); - return IsGlyphFullWidth(*it); - } - else - { - // If the cursor isn't in the bounds of the buffer for any reason, - // it won't be rendered anyway, so let's just say the cursor - // was single width. - return false; - } + TextBufferTextIterator it(TextBufferCellIterator(*_buffer, position)); + return IsGlyphFullWidth(*it); } const std::vector Terminal::GetOverlays() const noexcept diff --git a/src/host/ft_host/API_OutputTests.cpp b/src/host/ft_host/API_OutputTests.cpp index 22a9a2eb9ab..04369896259 100644 --- a/src/host/ft_host/API_OutputTests.cpp +++ b/src/host/ft_host/API_OutputTests.cpp @@ -1077,7 +1077,7 @@ void OutputTests::WriteTwoColumnCharacterToCheckOverflow() VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(consoleOutputHandle, &sbiex)); const auto bufferSize = sbiex.dwSize; - // Establish a writing region that is the width of the buffer and half the height. + // Establish a writing region that is the width of the buffer and just one row tall. const SMALL_RECT region{ 0, 0, bufferSize.X - 1, 0 }; const COORD regionDimensions{ region.Right - region.Left + 1, region.Bottom - region.Top + 1 }; const auto regionSize = regionDimensions.X * regionDimensions.Y; diff --git a/src/host/screenInfo.cpp b/src/host/screenInfo.cpp index b893c1962cd..cfbb2dcf845 100644 --- a/src/host/screenInfo.cpp +++ b/src/host/screenInfo.cpp @@ -1403,6 +1403,10 @@ bool SCREEN_INFORMATION::IsMaximizedY() const // Save cursor's relative height versus the viewport SHORT const sCursorHeightInViewportBefore = _textBuffer->GetCursor().GetPosition().Y - _viewport.Top(); + // Tell the both the new and old buffer to not redraw its cursor as we reflow and swap them. + newTextBuffer->GetCursor().StartDeferDrawing(); + _textBuffer->GetCursor().StartDeferDrawing(); + HRESULT hr = TextBuffer::Reflow(*_textBuffer.get(), *newTextBuffer.get(), std::nullopt, std::nullopt); if (SUCCEEDED(hr)) @@ -1417,6 +1421,10 @@ bool SCREEN_INFORMATION::IsMaximizedY() const _textBuffer.swap(newTextBuffer); } + // Only tell _textBuffer to EndDefer (and not newTextBuffer) because whether or not Reflow failed, + // _textBuffer will end up being the buffer that we use after returning. + _textBuffer->GetCursor().EndDeferDrawing(); + return NTSTATUS_FROM_HRESULT(hr); } From 91e4fb80838c16fc4530ebff06e5075f0551444f Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Fri, 10 Apr 2020 14:06:47 -0700 Subject: [PATCH 09/18] added test case to idk if this is right place --- .../TerminalApiTest.cpp | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/cascadia/UnitTests_TerminalCore/TerminalApiTest.cpp b/src/cascadia/UnitTests_TerminalCore/TerminalApiTest.cpp index 3e715e44fd5..b236765bb43 100644 --- a/src/cascadia/UnitTests_TerminalCore/TerminalApiTest.cpp +++ b/src/cascadia/UnitTests_TerminalCore/TerminalApiTest.cpp @@ -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); }; }; @@ -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()); +} From 51f6cce895362f37269dcaaba19819cba285f6c2 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Fri, 10 Apr 2020 14:07:53 -0700 Subject: [PATCH 10/18] remove this --- src/host/ft_host/API_OutputTests.cpp | 41 ---------------------------- 1 file changed, 41 deletions(-) diff --git a/src/host/ft_host/API_OutputTests.cpp b/src/host/ft_host/API_OutputTests.cpp index 04369896259..0f3e88ebd47 100644 --- a/src/host/ft_host/API_OutputTests.cpp +++ b/src/host/ft_host/API_OutputTests.cpp @@ -46,8 +46,6 @@ class OutputTests TEST_METHOD(WriteBackspaceTest); TEST_METHOD(WinPtyWrite); - - TEST_METHOD(WriteTwoColumnCharacterToCheckOverflow); }; bool OutputTests::TestSetup() @@ -1064,42 +1062,3 @@ void OutputTests::WinPtyWrite() break; } } - -void OutputTests::WriteTwoColumnCharacterToCheckOverflow() -{ - // Get output buffer information. - const auto consoleOutputHandle = GetStdOutputHandle(); - SetConsoleActiveScreenBuffer(consoleOutputHandle); - - CONSOLE_SCREEN_BUFFER_INFOEX sbiex{ 0 }; - sbiex.cbSize = sizeof(sbiex); - - VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(consoleOutputHandle, &sbiex)); - const auto bufferSize = sbiex.dwSize; - - // Establish a writing region that is the width of the buffer and just one row tall. - const SMALL_RECT region{ 0, 0, bufferSize.X - 1, 0 }; - const COORD regionDimensions{ region.Right - region.Left + 1, region.Bottom - region.Top + 1 }; - const auto regionSize = regionDimensions.X * regionDimensions.Y; - const COORD regionOrigin{ 0, 0 }; - - CHAR_INFO testValue; - testValue.Attributes = 0x3e; - testValue.Char.UnicodeChar = L'A'; - - std::vector buffer(regionSize, testValue); - - // Place a double width character with a lead bit in the last column of the buffer. - CHAR_INFO lastColumnValue; - lastColumnValue.Attributes = 0x13e; - lastColumnValue.Char.UnicodeChar = L'我'; - buffer[regionSize - 1] = lastColumnValue; - - // Call the API and confirm results. - SMALL_RECT affected = region; - VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleOutputW(consoleOutputHandle, buffer.data(), regionDimensions, regionOrigin, &affected)); - VERIFY_ARE_EQUAL(region, affected); - - // Move the cursor to the last column of the buffer - VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleCursorPosition(consoleOutputHandle, { bufferSize.X - 1, 0 })); -} From 640bc695dff4558393ef0433f841a7e34bb2e26f Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Fri, 10 Apr 2020 14:13:47 -0700 Subject: [PATCH 11/18] reverting this file --- src/host/ft_host/API_OutputTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host/ft_host/API_OutputTests.cpp b/src/host/ft_host/API_OutputTests.cpp index 0f3e88ebd47..4912f17a597 100644 --- a/src/host/ft_host/API_OutputTests.cpp +++ b/src/host/ft_host/API_OutputTests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. #include "precomp.h" From ae430ce9ca6416f919961ecea6220c86d68c621a Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Fri, 10 Apr 2020 15:16:50 -0700 Subject: [PATCH 12/18] wtf --- src/buffer/out/textBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buffer/out/textBuffer.cpp b/src/buffer/out/textBuffer.cpp index eb92fe9055e..1fbf1bbea1d 100644 --- a/src/buffer/out/textBuffer.cpp +++ b/src/buffer/out/textBuffer.cpp @@ -1967,7 +1967,7 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer, const std::optional lastCharacterViewport, std::optional> positionInfo) { - Cursor& oldCursor = oldBuffer.GetCursor(); + const Cursor& oldCursor = oldBuffer.GetCursor(); Cursor& newCursor = newBuffer.GetCursor(); // We need to save the old cursor position so that we can From 3509c9f9adbe2f5be541574a6d49dcafb4094ad1 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Mon, 13 Apr 2020 14:43:20 -0700 Subject: [PATCH 13/18] build is complaining, more returns --- src/cascadia/TerminalCore/Terminal.cpp | 19 +++++++++++++------ src/cascadia/TerminalCore/Terminal.hpp | 2 +- .../TerminalCore/terminalrenderdata.cpp | 2 +- src/renderer/inc/IRenderData.hpp | 2 +- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 211aaccfd22..58de489b88b 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -190,6 +190,9 @@ 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. + _buffer->GetCursor().StartDeferDrawing(); + // First allocate a new text buffer to take the place of the current one. std::unique_ptr newTextBuffer; try @@ -199,8 +202,6 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting 0, // temporarily set size to 0 so it won't render. _buffer->GetRenderTarget()); - // skip any drawing updates that might occur as we manipulate the new buffer, until we swap the new with the old. - _buffer->GetCursor().StartDeferDrawing(); newTextBuffer->GetCursor().StartDeferDrawing(); // Build a PositionInformation to track the position of both the top of @@ -218,10 +219,16 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting oldRows.visibleViewportTop = newVisibleTop; const std::optional oldViewStart{ oldViewportTop }; - RETURN_IF_FAILED(TextBuffer::Reflow(*_buffer.get(), - *newTextBuffer.get(), - _mutableViewport, - { oldRows })); + const HRESULT reflowHR = TextBuffer::Reflow(*_buffer.get(), + *newTextBuffer.get(), + _mutableViewport, + { oldRows }); + + if (FAILED(reflowHR)) + { + _buffer->GetCursor().EndDeferDrawing(); + return reflowHR; + } newViewportTop = oldRows.mutableViewportTop; newVisibleTop = oldRows.visibleViewportTop; diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 59d0bad4d96..9c8334edbb5 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -148,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 GetOverlays() const noexcept override; const bool IsGridLineDrawingAllowed() noexcept override; diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index 686b2334575..01672a047d1 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -105,7 +105,7 @@ COLORREF Terminal::GetCursorColor() const noexcept return _buffer->GetCursor().GetColor(); } -bool Terminal::IsCursorDoubleWidth() const noexcept +bool Terminal::IsCursorDoubleWidth() const { const auto position = _buffer->GetCursor().GetPosition(); TextBufferTextIterator it(TextBufferCellIterator(*_buffer, position)); diff --git a/src/renderer/inc/IRenderData.hpp b/src/renderer/inc/IRenderData.hpp index 860537514ff..c504ae2dbb3 100644 --- a/src/renderer/inc/IRenderData.hpp +++ b/src/renderer/inc/IRenderData.hpp @@ -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; From 8e70d831c7867691d1dd0775b7787e312060a4e6 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Mon, 13 Apr 2020 15:11:15 -0700 Subject: [PATCH 14/18] what about nOW --- src/cascadia/TerminalCore/Terminal.cpp | 2 +- src/cascadia/TerminalCore/Terminal.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 58de489b88b..ea4ab3d1a6e 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -893,7 +893,7 @@ 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(); _buffer->GetCursor().SetIsOn(isOn); diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 9c8334edbb5..313f0f6b34e 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -172,7 +172,7 @@ class Microsoft::Terminal::Core::Terminal final : void SetCursorPositionChangedCallback(std::function pfn) noexcept; void SetBackgroundCallback(std::function pfn) noexcept; - void SetCursorOn(const bool isOn) noexcept; + void SetCursorOn(const bool isOn); bool IsCursorBlinkingAllowed() const noexcept; #pragma region TextSelection From 1a3a312a1ed4c656d8686f75977ff783cc414b84 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Tue, 14 Apr 2020 14:30:46 -0700 Subject: [PATCH 15/18] this is a much better thing --- src/cascadia/TerminalCore/Terminal.cpp | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 58de489b88b..f87830aae11 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -190,8 +190,9 @@ 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. + // skip any drawing updates that might occur until we swap _buffer with the new buffer or if we exit early. _buffer->GetCursor().StartDeferDrawing(); + auto endDefer = wil::scope_exit([&] { _buffer->GetCursor().EndDeferDrawing(); }); // First allocate a new text buffer to take the place of the current one. std::unique_ptr newTextBuffer; @@ -224,20 +225,10 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting _mutableViewport, { oldRows }); - if (FAILED(reflowHR)) - { - _buffer->GetCursor().EndDeferDrawing(); - return reflowHR; - } - newViewportTop = oldRows.mutableViewportTop; newVisibleTop = oldRows.visibleViewportTop; } - catch (...) - { - _buffer->GetCursor().EndDeferDrawing(); - RETURN_CAUGHT_EXCEPTION(); - } + CATCH_RETURN(); // Conpty resizes a little oddly - if the height decreased, and there were // blank lines at the bottom, those lines will get trimmed. If there's not @@ -344,9 +335,6 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting _buffer.swap(newTextBuffer); - // Now that the new buffer was swapped to be Terminal's buffer, we can tell its cursor to start drawing again. - _buffer->GetCursor().EndDeferDrawing(); - // GH#3494: Maintain scrollbar position during resize // Make sure that we don't scroll past the mutableViewport at the bottom of the buffer newVisibleTop = std::min(newVisibleTop, _mutableViewport.Top()); From 3e4252bf4a919aee2b5a223b450340f5efaf8c11 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Tue, 14 Apr 2020 14:37:13 -0700 Subject: [PATCH 16/18] conhost can also use this, and i forgot to put something back in --- src/cascadia/TerminalCore/Terminal.cpp | 8 ++++---- src/host/screenInfo.cpp | 6 +----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 0c04b75cfba..201e34a27de 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -220,10 +220,10 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting oldRows.visibleViewportTop = newVisibleTop; const std::optional oldViewStart{ oldViewportTop }; - const HRESULT reflowHR = TextBuffer::Reflow(*_buffer.get(), - *newTextBuffer.get(), - _mutableViewport, - { oldRows }); + RETURN_IF_FAILED(TextBuffer::Reflow(*_buffer.get(), + *newTextBuffer.get(), + _mutableViewport, + { oldRows })); newViewportTop = oldRows.mutableViewportTop; newVisibleTop = oldRows.visibleViewportTop; diff --git a/src/host/screenInfo.cpp b/src/host/screenInfo.cpp index cfbb2dcf845..2880d77be71 100644 --- a/src/host/screenInfo.cpp +++ b/src/host/screenInfo.cpp @@ -1403,9 +1403,9 @@ bool SCREEN_INFORMATION::IsMaximizedY() const // Save cursor's relative height versus the viewport SHORT const sCursorHeightInViewportBefore = _textBuffer->GetCursor().GetPosition().Y - _viewport.Top(); - // Tell the both the new and old buffer to not redraw its cursor as we reflow and swap them. newTextBuffer->GetCursor().StartDeferDrawing(); _textBuffer->GetCursor().StartDeferDrawing(); + auto endDefer = wil::scope_exit([&] { _textBuffer->GetCursor().EndDeferDrawing(); }); HRESULT hr = TextBuffer::Reflow(*_textBuffer.get(), *newTextBuffer.get(), std::nullopt, std::nullopt); @@ -1421,10 +1421,6 @@ bool SCREEN_INFORMATION::IsMaximizedY() const _textBuffer.swap(newTextBuffer); } - // Only tell _textBuffer to EndDefer (and not newTextBuffer) because whether or not Reflow failed, - // _textBuffer will end up being the buffer that we use after returning. - _textBuffer->GetCursor().EndDeferDrawing(); - return NTSTATUS_FROM_HRESULT(hr); } From cf32371cb915192d53d167da94100b3162ee8fe2 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Tue, 14 Apr 2020 14:53:11 -0700 Subject: [PATCH 17/18] i am getting absolutely destroyed by mr static --- src/cascadia/TerminalCore/Terminal.cpp | 2 +- src/host/screenInfo.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 201e34a27de..4991ab0c2a2 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -192,7 +192,7 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting // skip any drawing updates that might occur until we swap _buffer with the new buffer or if we exit early. _buffer->GetCursor().StartDeferDrawing(); - auto endDefer = wil::scope_exit([&] { _buffer->GetCursor().EndDeferDrawing(); }); + auto endDefer = wil::scope_exit([&]() noexcept { _buffer->GetCursor().EndDeferDrawing(); }); // First allocate a new text buffer to take the place of the current one. std::unique_ptr newTextBuffer; diff --git a/src/host/screenInfo.cpp b/src/host/screenInfo.cpp index 2880d77be71..4edd0e500b0 100644 --- a/src/host/screenInfo.cpp +++ b/src/host/screenInfo.cpp @@ -1405,7 +1405,7 @@ bool SCREEN_INFORMATION::IsMaximizedY() const newTextBuffer->GetCursor().StartDeferDrawing(); _textBuffer->GetCursor().StartDeferDrawing(); - auto endDefer = wil::scope_exit([&] { _textBuffer->GetCursor().EndDeferDrawing(); }); + auto endDefer = wil::scope_exit([&]() noexcept { _textBuffer->GetCursor().EndDeferDrawing(); }); HRESULT hr = TextBuffer::Reflow(*_textBuffer.get(), *newTextBuffer.get(), std::nullopt, std::nullopt); From 2216cb9a1052157298c5b2ae87dfa06a67dfdded Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Tue, 14 Apr 2020 15:02:43 -0700 Subject: [PATCH 18/18] comment --- src/cascadia/TerminalCore/Terminal.cpp | 1 + src/host/screenInfo.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 4991ab0c2a2..56c9c8f7c26 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -192,6 +192,7 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting // 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(); }); // First allocate a new text buffer to take the place of the current one. diff --git a/src/host/screenInfo.cpp b/src/host/screenInfo.cpp index 4edd0e500b0..eaa5185e017 100644 --- a/src/host/screenInfo.cpp +++ b/src/host/screenInfo.cpp @@ -1403,8 +1403,10 @@ 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(); }); HRESULT hr = TextBuffer::Reflow(*_textBuffer.get(), *newTextBuffer.get(), std::nullopt, std::nullopt);