Skip to content
Open
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
1 change: 1 addition & 0 deletions .github/actions/spelling/expect/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1765,6 +1765,7 @@ UINTs
uld
uldash
uldb
ULONGLONG
ulwave
Unadvise
unattend
Expand Down
266 changes: 92 additions & 174 deletions src/buffer/out/cursor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,214 +13,157 @@
// - ulSize - The height of the cursor within this buffer
Cursor::Cursor(const ULONG ulSize, TextBuffer& parentBuffer) noexcept :
_parentBuffer{ parentBuffer },
_fIsVisible(true),
_fIsOn(true),
_fIsDouble(false),
_fBlinkingAllowed(true),
_fDelay(false),
_fIsConversionArea(false),
_fDelayedEolWrap(false),
_fDeferCursorRedraw(false),
_fHaveDeferredCursorRedraw(false),
_ulSize(ulSize),
_cursorType(CursorType::Legacy)
_ulSize(ulSize)
{
}

Cursor::~Cursor() = default;

til::point Cursor::GetPosition() const noexcept
{
return _cPosition;
}

bool Cursor::IsVisible() const noexcept
uint64_t Cursor::GetLastMutationId() const noexcept
{
return _fIsVisible;
return _mutationId;
}

bool Cursor::IsOn() const noexcept
bool Cursor::IsVisible() const noexcept
{
return _fIsOn;
return _isVisible;
}

bool Cursor::IsBlinkingAllowed() const noexcept
bool Cursor::IsBlinking() const noexcept
{
return _fBlinkingAllowed;
return _isBlinking;
}

bool Cursor::IsDouble() const noexcept
{
return _fIsDouble;
}

bool Cursor::IsConversionArea() const noexcept
{
return _fIsConversionArea;
}

bool Cursor::GetDelay() const noexcept
{
return _fDelay;
}

ULONG Cursor::GetSize() const noexcept
{
return _ulSize;
}

void Cursor::SetIsVisible(const bool fIsVisible) noexcept
{
_fIsVisible = fIsVisible;
_RedrawCursor();
}

void Cursor::SetIsOn(const bool fIsOn) noexcept
void Cursor::SetIsVisible(bool enable)
{
_fIsOn = fIsOn;
_RedrawCursorAlways();
if (_isVisible != enable)
{
_isVisible = enable;
_redrawIfVisible();
}
}

void Cursor::SetBlinkingAllowed(const bool fBlinkingAllowed) noexcept
void Cursor::SetIsBlinking(bool enable)
{
_fBlinkingAllowed = fBlinkingAllowed;
// GH#2642 - From what we've gathered from other terminals, when blinking is
// disabled, the cursor should remain On always, and have the visibility
// controlled by the IsVisible property. So when you do a printf "\e[?12l"
// to disable blinking, the cursor stays stuck On. At this point, only the
// cursor visibility property controls whether the user can see it or not.
// (Yes, the cursor can be On and NOT Visible)
_fIsOn = true;
_RedrawCursorAlways();
if (_isBlinking != enable)
{
_isBlinking = enable;
_redrawIfVisible();
}
}

void Cursor::SetIsDouble(const bool fIsDouble) noexcept
{
_fIsDouble = fIsDouble;
_RedrawCursor();
}

void Cursor::SetIsConversionArea(const bool fIsConversionArea) noexcept
{
// Functionally the same as "Hide cursor"
// Never called with TRUE, it's only used in the creation of a
// ConversionAreaInfo, and never changed after that.
_fIsConversionArea = fIsConversionArea;
_RedrawCursorAlways();
}

void Cursor::SetDelay(const bool fDelay) noexcept
{
_fDelay = fDelay;
if (_fIsDouble != fIsDouble)
{
_fIsDouble = fIsDouble;
_redrawIfVisible();
}
}

void Cursor::SetSize(const ULONG ulSize) noexcept
{
_ulSize = ulSize;
_RedrawCursor();
if (_ulSize != ulSize)
{
_ulSize = ulSize;
_redrawIfVisible();
}
}

void Cursor::SetStyle(const ULONG ulSize, const CursorType type) noexcept
{
_ulSize = ulSize;
_cursorType = type;

_RedrawCursor();
}

// Routine Description:
// - Sends a redraw message to the renderer only if the cursor is currently on.
// - NOTE: For use with most methods in this class.
// Arguments:
// - <none>
// Return Value:
// - <none>
void Cursor::_RedrawCursor() noexcept
{
// Only trigger the redraw if we're on.
// Don't draw the cursor if this was triggered from a conversion area.
// (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 (_ulSize != ulSize || _cursorType != type)
{
if (_fDeferCursorRedraw)
{
_fHaveDeferredCursorRedraw = true;
}
else
{
_RedrawCursorAlways();
}
_ulSize = ulSize;
_cursorType = type;
_redrawIfVisible();
}
}

// Routine Description:
// - Sends a redraw message to the renderer no matter what.
// - NOTE: For use with the method that turns the cursor on and off to force a refresh
// and clear the ON cursor from the screen. Not for use with other methods.
// They should use the other method so refreshes are suppressed while the cursor is off.
// Arguments:
// - <none>
// Return Value:
// - <none>
void Cursor::_RedrawCursorAlways() noexcept
{
_parentBuffer.NotifyPaintFrame();
}

void Cursor::SetPosition(const til::point cPosition) noexcept
{
_RedrawCursor();
_cPosition = cPosition;
_RedrawCursor();
// The VT code assumes that moving the cursor implicitly resets the delayed EOL wrap,
// so we call ResetDelayEOLWrap() independent of _cPosition != cPosition.
// You can see the effect of this with "`e[1;9999Ha`e[1;9999Hb", which should print just "b".
ResetDelayEOLWrap();
if (_cPosition != cPosition)
{
_cPosition = cPosition;
_redrawIfVisible();
}
}

void Cursor::SetXPosition(const til::CoordType NewX) noexcept
{
_RedrawCursor();
_cPosition.x = NewX;
_RedrawCursor();
ResetDelayEOLWrap();
if (_cPosition.x != NewX)
{
_cPosition.x = NewX;
_redrawIfVisible();
}
}

void Cursor::SetYPosition(const til::CoordType NewY) noexcept
{
_RedrawCursor();
_cPosition.y = NewY;
_RedrawCursor();
ResetDelayEOLWrap();
if (_cPosition.y != NewY)
{
_cPosition.y = NewY;
_redrawIfVisible();
}
}

void Cursor::IncrementXPosition(const til::CoordType DeltaX) noexcept
{
_RedrawCursor();
_cPosition.x += DeltaX;
_RedrawCursor();
ResetDelayEOLWrap();
if (DeltaX != 0)
{
_cPosition.x = _cPosition.x + DeltaX;
_redrawIfVisible();
}
}

void Cursor::IncrementYPosition(const til::CoordType DeltaY) noexcept
{
_RedrawCursor();
_cPosition.y += DeltaY;
_RedrawCursor();
ResetDelayEOLWrap();
if (DeltaY != 0)
{
_cPosition.y = _cPosition.y + DeltaY;
_redrawIfVisible();
}
}

void Cursor::DecrementXPosition(const til::CoordType DeltaX) noexcept
{
_RedrawCursor();
_cPosition.x -= DeltaX;
_RedrawCursor();
ResetDelayEOLWrap();
if (DeltaX != 0)
{
_cPosition.x = _cPosition.x - DeltaX;
_redrawIfVisible();
}
}

void Cursor::DecrementYPosition(const til::CoordType DeltaY) noexcept
{
_RedrawCursor();
_cPosition.y -= DeltaY;
_RedrawCursor();
ResetDelayEOLWrap();
if (DeltaY != 0)
{
_cPosition.y = _cPosition.y - DeltaY;
_redrawIfVisible();
}
}

///////////////////////////////////////////////////////////////////////////////
Expand All @@ -233,78 +176,53 @@ void Cursor::DecrementYPosition(const til::CoordType DeltaY) noexcept
// - OtherCursor - The cursor to copy properties from
// Return Value:
// - <none>
void Cursor::CopyProperties(const Cursor& OtherCursor) noexcept
void Cursor::CopyProperties(const Cursor& other) noexcept
{
// We shouldn't copy the position as it will be already rearranged by the resize operation.
//_cPosition = pOtherCursor->_cPosition;

_fIsVisible = OtherCursor._fIsVisible;
_fIsOn = OtherCursor._fIsOn;
_fIsDouble = OtherCursor._fIsDouble;
_fBlinkingAllowed = OtherCursor._fBlinkingAllowed;
_fDelay = OtherCursor._fDelay;
_fIsConversionArea = OtherCursor._fIsConversionArea;

// A resize operation should invalidate the delayed end of line status, so do not copy.
//_fDelayedEolWrap = OtherCursor._fDelayedEolWrap;
//_coordDelayedAt = OtherCursor._coordDelayedAt;

_fDeferCursorRedraw = OtherCursor._fDeferCursorRedraw;
_fHaveDeferredCursorRedraw = OtherCursor._fHaveDeferredCursorRedraw;

// Size will be handled separately in the resize operation.
//_ulSize = OtherCursor._ulSize;
_cursorType = OtherCursor._cursorType;
_cPosition = other._cPosition;
_coordDelayedAt = other._coordDelayedAt;
_ulSize = other._ulSize;
_cursorType = other._cursorType;
_isVisible = other._isVisible;
_isBlinking = other._isBlinking;
_fIsDouble = other._fIsDouble;
}

void Cursor::DelayEOLWrap() noexcept
{
_coordDelayedAt = _cPosition;
_fDelayedEolWrap = true;
}

void Cursor::ResetDelayEOLWrap() noexcept
{
_coordDelayedAt = {};
_fDelayedEolWrap = false;
_coordDelayedAt.reset();
}

til::point Cursor::GetDelayedAtPosition() const noexcept
const std::optional<til::point>& Cursor::GetDelayEOLWrap() const noexcept
{
return _coordDelayedAt;
}

bool Cursor::IsDelayedEOLWrap() const noexcept
CursorType Cursor::GetType() const noexcept
{
return _fDelayedEolWrap;
}

void Cursor::StartDeferDrawing() noexcept
{
_fDeferCursorRedraw = true;
return _cursorType;
}

bool Cursor::IsDeferDrawing() noexcept
void Cursor::SetType(const CursorType type) noexcept
{
return _fDeferCursorRedraw;
_cursorType = type;
}

void Cursor::EndDeferDrawing() noexcept
void Cursor::_redrawIfVisible() noexcept
{
if (_fHaveDeferredCursorRedraw)
_mutationId++;
if (_isVisible)
{
_RedrawCursorAlways();
_parentBuffer.NotifyPaintFrame();
}

_fDeferCursorRedraw = FALSE;
}

const CursorType Cursor::GetType() const noexcept
void Cursor::_redraw() noexcept
{
return _cursorType;
}

void Cursor::SetType(const CursorType type) noexcept
{
_cursorType = type;
_mutationId++;
_parentBuffer.NotifyPaintFrame();
}
Loading
Loading