From 28d4aac4dfac0d86d65e15bfeb8274a4a376b675 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Tue, 24 Mar 2020 17:51:10 -0700 Subject: [PATCH 1/8] consolidate redraw into its own function --- .../TerminalControl/TSFInputControl.cpp | 59 +++++++++++-------- .../TerminalControl/TSFInputControl.h | 1 + .../TerminalControl/TSFInputControl.idl | 1 + 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/cascadia/TerminalControl/TSFInputControl.cpp b/src/cascadia/TerminalControl/TSFInputControl.cpp index 2c14cb3a6d7..1157002f821 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.cpp +++ b/src/cascadia/TerminalControl/TSFInputControl.cpp @@ -113,21 +113,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation } } - // Method Description: - // - Handler for LayoutRequested event by CoreEditContext responsible - // for returning the current position the IME should be placed - // in screen coordinates on the screen. TSFInputControls internal - // XAML controls (TextBlock/Canvas) are also positioned and updated. - // NOTE: documentation says application should handle this event - // Arguments: - // - sender: CoreTextEditContext sending the request. - // - args: CoreTextLayoutRequestedEventArgs to be updated with position information. - // Return Value: - // - - void TSFInputControl::_layoutRequestedHandler(CoreTextEditContext sender, CoreTextLayoutRequestedEventArgs const& args) + winrt::Windows::Foundation::Rect TSFInputControl::RedrawCanvas() { - auto request = args.Request(); - // Get window in screen coordinates, this is the entire window including tabs const auto windowBounds = CoreWindow::GetForCurrentThread().Bounds(); @@ -160,9 +147,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation screenCursorPos.X = ::base::ClampAdd(screenCursorPos.X, ::base::ClampedNumeric(offsetPoint.X)); screenCursorPos.Y = ::base::ClampAdd(screenCursorPos.Y, ::base::ClampedNumeric(offsetPoint.Y)); - // Get scale factor for view - const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); - // position textblock to cursor position Canvas().SetLeft(TextBlock(), clientCursorPos.X); Canvas().SetTop(TextBlock(), ::base::ClampedNumeric(clientCursorPos.Y)); @@ -172,18 +156,45 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation TextBlock().FontSize(fontSizePx); TextBlock().FontFamily(Media::FontFamily(fontArgs->FontFace())); - const auto widthToTerminalEnd = Canvas().ActualWidth() - ::base::ClampedNumeric(clientCursorPos.X); - TextBlock().MaxWidth(widthToTerminalEnd); + const auto canvasActualWidth = Canvas().ActualWidth(); + const auto widthToTerminalEnd = canvasActualWidth - ::base::ClampedNumeric(clientCursorPos.X); + // Make sure that we're setting the MaxWidth to a positive number - a + // negative number here will crash us in mysterious ways with a useless + // stack trace + const auto newMaxWidth = std::max(0.0, widthToTerminalEnd); + TextBlock().MaxWidth(newMaxWidth); - // Set the text block bounds + // Get scale factor for view + const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); const auto yOffset = ::base::ClampedNumeric(TextBlock().ActualHeight()) - fontHeight; const auto textBottom = ::base::ClampedNumeric(screenCursorPos.Y) + yOffset; Rect selectionRect = Rect(screenCursorPos.X, textBottom, 0, fontHeight); - request.LayoutBounds().TextBounds(ScaleRect(selectionRect, scaleFactor)); + + return ScaleRect(selectionRect, scaleFactor); + } + + // Method Description: + // - Handler for LayoutRequested event by CoreEditContext responsible + // for returning the current position the IME should be placed + // in screen coordinates on the screen. TSFInputControls internal + // XAML controls (TextBlock/Canvas) are also positioned and updated. + // NOTE: documentation says application should handle this event + // Arguments: + // - sender: CoreTextEditContext sending the request. + // - args: CoreTextLayoutRequestedEventArgs to be updated with position information. + // Return Value: + // - + void TSFInputControl::_layoutRequestedHandler(CoreTextEditContext sender, CoreTextLayoutRequestedEventArgs const& args) + { + auto request = args.Request(); + + const auto scaledRect = RedrawCanvas(); + + // Set the text block bounds + request.LayoutBounds().TextBounds(scaledRect); // Set the control bounds of the whole control - Rect controlRect = Rect(screenCursorPos.X, screenCursorPos.Y, 0, fontHeight); - request.LayoutBounds().ControlBounds(ScaleRect(controlRect, scaleFactor)); + request.LayoutBounds().ControlBounds(scaledRect); } // Method Description: @@ -216,6 +227,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation { _SendAndClearText(); } + + RedrawCanvas(); } // Method Description: diff --git a/src/cascadia/TerminalControl/TSFInputControl.h b/src/cascadia/TerminalControl/TSFInputControl.h index f57925b2c07..9c34989c87a 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.h +++ b/src/cascadia/TerminalControl/TSFInputControl.h @@ -37,6 +37,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation void NotifyFocusEnter(); void NotifyFocusLeave(); void ClearBuffer(); + winrt::Windows::Foundation::Rect RedrawCanvas(); void Close(); diff --git a/src/cascadia/TerminalControl/TSFInputControl.idl b/src/cascadia/TerminalControl/TSFInputControl.idl index 0722f6d5a0b..33c1606d179 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.idl +++ b/src/cascadia/TerminalControl/TSFInputControl.idl @@ -28,6 +28,7 @@ namespace Microsoft.Terminal.TerminalControl void NotifyFocusEnter(); void NotifyFocusLeave(); void ClearBuffer(); + void RedrawCanvas(); void Close(); } From 8012a9bec9995db3991bf30ef5396dae66f92538 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Wed, 25 Mar 2020 11:45:55 -0700 Subject: [PATCH 2/8] so it works but im not convinced i wont crash everything --- .../TerminalControl/TSFInputControl.cpp | 13 +++++++-- .../TerminalControl/TSFInputControl.h | 1 + src/cascadia/TerminalControl/TermControl.cpp | 28 +++++++++++++++++++ src/cascadia/TerminalControl/TermControl.h | 1 + src/cascadia/TerminalCore/Terminal.cpp | 15 ++++++++++ src/cascadia/TerminalCore/Terminal.hpp | 4 +++ 6 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalControl/TSFInputControl.cpp b/src/cascadia/TerminalControl/TSFInputControl.cpp index 1157002f821..7137fa7087d 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.cpp +++ b/src/cascadia/TerminalControl/TSFInputControl.cpp @@ -19,7 +19,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation TSFInputControl::TSFInputControl() : _editContext{ nullptr }, _inComposition{ false }, - _activeTextStart{ 0 } + _activeTextStart{ 0 }, + _focused{ false } { InitializeComponent(); @@ -59,6 +60,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation // Explicitly disconnect the LayoutRequested handler -- it can cause problems during application teardown. // See GH#4159 for more info. _layoutRequestedRevoker.revoke(); + _focused = false; } // Method Description: @@ -73,6 +75,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation if (_editContext != nullptr) { _editContext.NotifyFocusEnter(); + _focused = true; } } @@ -88,6 +91,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation if (_editContext != nullptr) { _editContext.NotifyFocusLeave(); + _focused = false; } } @@ -115,6 +119,11 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation winrt::Windows::Foundation::Rect TSFInputControl::RedrawCanvas() { + if (!_focused) + { + return { 0, 0, 0, 0 }; + } + // Get window in screen coordinates, this is the entire window including tabs const auto windowBounds = CoreWindow::GetForCurrentThread().Bounds(); @@ -227,8 +236,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation { _SendAndClearText(); } - - RedrawCanvas(); } // Method Description: diff --git a/src/cascadia/TerminalControl/TSFInputControl.h b/src/cascadia/TerminalControl/TSFInputControl.h index 9c34989c87a..420f7623773 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.h +++ b/src/cascadia/TerminalControl/TSFInputControl.h @@ -74,6 +74,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation bool _inComposition; size_t _activeTextStart; void _SendAndClearText(); + bool _focused; }; } namespace winrt::Microsoft::Terminal::TerminalControl::factory_implementation diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 47d93ca8591..aadacd195af 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -612,6 +612,9 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation auto pfnScrollPositionChanged = std::bind(&TermControl::_TerminalScrollPositionChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); _terminal->SetScrollPositionChangedCallback(pfnScrollPositionChanged); + auto pfnCursorPositionChanged = std::bind(&TermControl::_TerminalCursorPositionChanged, this); + _terminal->SetCursorPositionChangedCallback(pfnCursorPositionChanged); + static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast(1.0 / 30.0 * 1000000)); _autoScrollTimer.Interval(AutoScrollUpdateInterval); _autoScrollTimer.Tick({ get_weak(), &TermControl::_UpdateAutoScroll }); @@ -1772,6 +1775,31 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation } } + + // Method Description: + // - Tells TSFInputControl to redraw the Canvas/TextBlock so it'll update + // to be where the current cursor position is. + // Arguments: + // - N/A + winrt::fire_and_forget TermControl::_TerminalCursorPositionChanged() + { + if (_closing.load()) + { + return; + } + + auto weakThis{ get_weak() }; + co_await winrt::resume_foreground(Dispatcher()); + + if (auto control{ weakThis.get() }) + { + if (!_closing.load()) + { + TSFInputControl().RedrawCanvas(); + } + } + } + hstring TermControl::Title() { if (!_initializedTerminal) diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index 57606506bee..e825c24a4cd 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -194,6 +194,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation void _DoResize(const double newWidth, const double newHeight); void _TerminalTitleChanged(const std::wstring_view& wstr); winrt::fire_and_forget _TerminalScrollPositionChanged(const int viewTop, const int viewHeight, const int bufferSize); + winrt::fire_and_forget _TerminalCursorPositionChanged(); void _MouseScrollHandler(const double delta, Windows::UI::Input::PointerPoint const& pointerPoint); void _MouseZoomHandler(const double delta); diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 36daae54fce..4031297ad97 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -703,6 +703,8 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition) } } + _NotifyTerminalCursorPositionChanged(); + if (notifyScroll) { _buffer->GetRenderTarget().TriggerRedrawAll(); @@ -740,6 +742,14 @@ try } CATCH_LOG() +void Terminal::_NotifyTerminalCursorPositionChanged() noexcept +{ + if (_pfnCursorPositionChanged) + { + _pfnCursorPositionChanged(); + } +} + void Terminal::SetWriteInputCallback(std::function pfn) noexcept { _pfnWriteInput.swap(pfn); @@ -755,6 +765,11 @@ void Terminal::SetScrollPositionChangedCallback(std::function pfn) noexcept +{ + _pfnCursorPositionChanged.swap(pfn); +} + // Method Description: // - Allows setting a callback for when the background color is changed // Arguments: diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 8498efa1aff..a796a2382de 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -168,6 +168,7 @@ class Microsoft::Terminal::Core::Terminal final : void SetWriteInputCallback(std::function pfn) noexcept; void SetTitleChangedCallback(std::function pfn) noexcept; void SetScrollPositionChangedCallback(std::function pfn) noexcept; + void SetCursorPositionChangedCallback(std::function pfn) noexcept; void SetBackgroundCallback(std::function pfn) noexcept; void SetCursorOn(const bool isOn) noexcept; @@ -195,6 +196,7 @@ class Microsoft::Terminal::Core::Terminal final : std::function _pfnTitleChanged; std::function _pfnScrollPositionChanged; std::function _pfnBackgroundColorChanged; + std::function _pfnCursorPositionChanged; std::unique_ptr<::Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine; std::unique_ptr<::Microsoft::Console::VirtualTerminal::TerminalInput> _terminalInput; @@ -269,6 +271,8 @@ class Microsoft::Terminal::Core::Terminal final : void _NotifyScrollEvent() noexcept; + void _NotifyTerminalCursorPositionChanged() noexcept; + #pragma region TextSelection // These methods are defined in TerminalSelection.cpp std::vector _GetSelectionRects() const noexcept; From 7ff587e7e57597bc88726058bb8043cb4c94e619 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Wed, 25 Mar 2020 13:45:31 -0700 Subject: [PATCH 3/8] explicitly revoke some handlers bc it would crash --- src/cascadia/TerminalControl/TSFInputControl.cpp | 15 +++++---------- src/cascadia/TerminalControl/TSFInputControl.h | 1 - src/cascadia/TerminalCore/Terminal.hpp | 2 +- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/cascadia/TerminalControl/TSFInputControl.cpp b/src/cascadia/TerminalControl/TSFInputControl.cpp index 7137fa7087d..27287ac5fc3 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.cpp +++ b/src/cascadia/TerminalControl/TSFInputControl.cpp @@ -19,8 +19,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation TSFInputControl::TSFInputControl() : _editContext{ nullptr }, _inComposition{ false }, - _activeTextStart{ 0 }, - _focused{ false } + _activeTextStart{ 0 } { InitializeComponent(); @@ -59,8 +58,11 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation { // Explicitly disconnect the LayoutRequested handler -- it can cause problems during application teardown. // See GH#4159 for more info. + // Also disconnect compositionCompleted and textUpdating explicitly. It seems to occasionally cause problems if + // a composition is active during application teardown. _layoutRequestedRevoker.revoke(); - _focused = false; + _compositionCompletedRevoker.revoke(); + _textUpdatingRevoker.revoke(); } // Method Description: @@ -75,7 +77,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation if (_editContext != nullptr) { _editContext.NotifyFocusEnter(); - _focused = true; } } @@ -91,7 +92,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation if (_editContext != nullptr) { _editContext.NotifyFocusLeave(); - _focused = false; } } @@ -119,11 +119,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation winrt::Windows::Foundation::Rect TSFInputControl::RedrawCanvas() { - if (!_focused) - { - return { 0, 0, 0, 0 }; - } - // Get window in screen coordinates, this is the entire window including tabs const auto windowBounds = CoreWindow::GetForCurrentThread().Bounds(); diff --git a/src/cascadia/TerminalControl/TSFInputControl.h b/src/cascadia/TerminalControl/TSFInputControl.h index 420f7623773..9c34989c87a 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.h +++ b/src/cascadia/TerminalControl/TSFInputControl.h @@ -74,7 +74,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation bool _inComposition; size_t _activeTextStart; void _SendAndClearText(); - bool _focused; }; } namespace winrt::Microsoft::Terminal::TerminalControl::factory_implementation diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index a796a2382de..929de64caeb 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -170,7 +170,7 @@ class Microsoft::Terminal::Core::Terminal final : void SetScrollPositionChangedCallback(std::function pfn) noexcept; void SetCursorPositionChangedCallback(std::function pfn) noexcept; void SetBackgroundCallback(std::function pfn) noexcept; - + void SetCursorOn(const bool isOn) noexcept; bool IsCursorBlinkingAllowed() const noexcept; From 7b812d432fcd334121fda40d3805cd4c51e6d724 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Thu, 26 Mar 2020 11:42:25 -0700 Subject: [PATCH 4/8] ok now it works for real --- .../TerminalControl/TSFInputControl.cpp | 102 +++++++++++++----- .../TerminalControl/TSFInputControl.h | 10 +- .../TerminalControl/TSFInputControl.idl | 2 +- src/cascadia/TerminalControl/TermControl.cpp | 7 +- src/cascadia/TerminalCore/Terminal.cpp | 4 +- 5 files changed, 91 insertions(+), 34 deletions(-) diff --git a/src/cascadia/TerminalControl/TSFInputControl.cpp b/src/cascadia/TerminalControl/TSFInputControl.cpp index 27287ac5fc3..c56f7439eb1 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.cpp +++ b/src/cascadia/TerminalControl/TSFInputControl.cpp @@ -19,7 +19,13 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation TSFInputControl::TSFInputControl() : _editContext{ nullptr }, _inComposition{ false }, - _activeTextStart{ 0 } + _activeTextStart{ 0 }, + _focused{ false }, + _currentTerminalCursorPos{ 0, 0 }, + _currentCanvasWidth{ 0.0 }, + _currentTextBlockHeight{ 0.0 }, + _currentTextBounds{ 0, 0, 0, 0 }, + _currentControlBounds{ 0, 0, 0, 0 } { InitializeComponent(); @@ -77,6 +83,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation if (_editContext != nullptr) { _editContext.NotifyFocusEnter(); + _focused = true; } } @@ -92,6 +99,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation if (_editContext != nullptr) { _editContext.NotifyFocusLeave(); + _focused = false; } } @@ -117,16 +125,54 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation } } - winrt::Windows::Foundation::Rect TSFInputControl::RedrawCanvas() + // Method Description: + // - Redraw the canvas and update our dimensions if certain dimensions have changed since the last + // redraw. This includes the Terminal cursor position, the actual Canvas width, + // and the actual TextBlock height. + // Arguments: + // - + // Return Value: + // - + void TSFInputControl::TryRedrawCanvas() { - // Get window in screen coordinates, this is the entire window including tabs - const auto windowBounds = CoreWindow::GetForCurrentThread().Bounds(); + if (!_focused) + { + return; + } // Get the cursor position in text buffer position auto cursorArgs = winrt::make_self(); _CurrentCursorPositionHandlers(*this, *cursorArgs); const COORD cursorPos = { ::base::ClampedNumeric(cursorArgs->CurrentPosition().X), ::base::ClampedNumeric(cursorArgs->CurrentPosition().Y) }; + const double actualCanvasWidth = Canvas().ActualWidth(); + + const double actualTextBlockHeight = TextBlock().ActualHeight(); + + if (_currentTerminalCursorPos.X == cursorPos.X && + _currentTerminalCursorPos.Y == cursorPos.Y && + _currentCanvasWidth == actualCanvasWidth && + _currentTextBlockHeight == actualTextBlockHeight) + { + return; + } + + _currentTerminalCursorPos = cursorPos; + _currentCanvasWidth = actualCanvasWidth; + _currentTextBlockHeight = actualTextBlockHeight; + + _RedrawCanvas(); + } + + // Method Description: + // - Redraw the Canvas and update the current Text Bounds and Control Bounds for + // the CoreTextEditContext. + // Arguments: + // - + // Return Value: + // - + void TSFInputControl::_RedrawCanvas() + { // Get Font Info as we use this is the pixel size for characters in the display auto fontArgs = winrt::make_self(); _CurrentFontInfoHandlers(*this, *fontArgs); @@ -136,45 +182,47 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation // Convert text buffer cursor position to client coordinate position within the window COORD clientCursorPos; - clientCursorPos.X = ::base::ClampMul(cursorPos.X, ::base::ClampedNumeric(fontWidth)); - clientCursorPos.Y = ::base::ClampMul(cursorPos.Y, ::base::ClampedNumeric(fontHeight)); - - // Convert from client coordinate to screen coordinate by adding window position - COORD screenCursorPos; - screenCursorPos.X = ::base::ClampAdd(clientCursorPos.X, ::base::ClampedNumeric(windowBounds.X)); - screenCursorPos.Y = ::base::ClampAdd(clientCursorPos.Y, ::base::ClampedNumeric(windowBounds.Y)); - - // get any offset (margin + tabs, etc..) of the control within the window - const auto offsetPoint = this->TransformToVisual(nullptr).TransformPoint(winrt::Windows::Foundation::Point(0, 0)); - - // add the margin offsets if any - screenCursorPos.X = ::base::ClampAdd(screenCursorPos.X, ::base::ClampedNumeric(offsetPoint.X)); - screenCursorPos.Y = ::base::ClampAdd(screenCursorPos.Y, ::base::ClampedNumeric(offsetPoint.Y)); + clientCursorPos.X = ::base::ClampMul(_currentTerminalCursorPos.X, ::base::ClampedNumeric(fontWidth)); + clientCursorPos.Y = ::base::ClampMul(_currentTerminalCursorPos.Y, ::base::ClampedNumeric(fontHeight)); // position textblock to cursor position Canvas().SetLeft(TextBlock(), clientCursorPos.X); Canvas().SetTop(TextBlock(), ::base::ClampedNumeric(clientCursorPos.Y)); - // calculate FontSize in pixels from DIPs + // calculate FontSize in pixels from DPIs const double fontSizePx = (fontHeight * 72) / USER_DEFAULT_SCREEN_DPI; TextBlock().FontSize(fontSizePx); TextBlock().FontFamily(Media::FontFamily(fontArgs->FontFace())); - const auto canvasActualWidth = Canvas().ActualWidth(); - const auto widthToTerminalEnd = canvasActualWidth - ::base::ClampedNumeric(clientCursorPos.X); + const auto widthToTerminalEnd = _currentCanvasWidth - ::base::ClampedNumeric(clientCursorPos.X); // Make sure that we're setting the MaxWidth to a positive number - a // negative number here will crash us in mysterious ways with a useless // stack trace const auto newMaxWidth = std::max(0.0, widthToTerminalEnd); TextBlock().MaxWidth(newMaxWidth); + // Get window in screen coordinates, this is the entire window including tabs + const auto windowBounds = CoreWindow::GetForCurrentThread().Bounds(); + + // Convert from client coordinate to screen coordinate by adding window position + COORD screenCursorPos; + screenCursorPos.X = ::base::ClampAdd(clientCursorPos.X, ::base::ClampedNumeric(windowBounds.X)); + screenCursorPos.Y = ::base::ClampAdd(clientCursorPos.Y, ::base::ClampedNumeric(windowBounds.Y)); + + // get any offset (margin + tabs, etc..) of the control within the window + const auto offsetPoint = this->TransformToVisual(nullptr).TransformPoint(winrt::Windows::Foundation::Point(0, 0)); + + // add the margin offsets if any + screenCursorPos.X = ::base::ClampAdd(screenCursorPos.X, ::base::ClampedNumeric(offsetPoint.X)); + screenCursorPos.Y = ::base::ClampAdd(screenCursorPos.Y, ::base::ClampedNumeric(offsetPoint.Y)); + // Get scale factor for view const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); - const auto yOffset = ::base::ClampedNumeric(TextBlock().ActualHeight()) - fontHeight; + const auto yOffset = ::base::ClampedNumeric(_currentTextBlockHeight) - fontHeight; const auto textBottom = ::base::ClampedNumeric(screenCursorPos.Y) + yOffset; - Rect selectionRect = Rect(screenCursorPos.X, textBottom, 0, fontHeight); - return ScaleRect(selectionRect, scaleFactor); + _currentTextBounds = ScaleRect(Rect(screenCursorPos.X, textBottom, 0, fontHeight), scaleFactor); + _currentControlBounds = ScaleRect(Rect(screenCursorPos.X, screenCursorPos.Y, 0, fontHeight), scaleFactor); } // Method Description: @@ -192,13 +240,13 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation { auto request = args.Request(); - const auto scaledRect = RedrawCanvas(); + TryRedrawCanvas(); // Set the text block bounds - request.LayoutBounds().TextBounds(scaledRect); + request.LayoutBounds().TextBounds(_currentTextBounds); // Set the control bounds of the whole control - request.LayoutBounds().ControlBounds(scaledRect); + request.LayoutBounds().ControlBounds(_currentControlBounds); } // Method Description: diff --git a/src/cascadia/TerminalControl/TSFInputControl.h b/src/cascadia/TerminalControl/TSFInputControl.h index 9c34989c87a..bd0fe1b18ce 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.h +++ b/src/cascadia/TerminalControl/TSFInputControl.h @@ -37,7 +37,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation void NotifyFocusEnter(); void NotifyFocusLeave(); void ClearBuffer(); - winrt::Windows::Foundation::Rect RedrawCanvas(); + void TryRedrawCanvas(); void Close(); @@ -74,6 +74,14 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation bool _inComposition; size_t _activeTextStart; void _SendAndClearText(); + void _RedrawCanvas(); + bool _focused; + + COORD _currentTerminalCursorPos; + double _currentCanvasWidth; + double _currentTextBlockHeight; + winrt::Windows::Foundation::Rect _currentControlBounds; + winrt::Windows::Foundation::Rect _currentTextBounds; }; } namespace winrt::Microsoft::Terminal::TerminalControl::factory_implementation diff --git a/src/cascadia/TerminalControl/TSFInputControl.idl b/src/cascadia/TerminalControl/TSFInputControl.idl index 33c1606d179..04ee78bb95e 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.idl +++ b/src/cascadia/TerminalControl/TSFInputControl.idl @@ -28,7 +28,7 @@ namespace Microsoft.Terminal.TerminalControl void NotifyFocusEnter(); void NotifyFocusLeave(); void ClearBuffer(); - void RedrawCanvas(); + void TryRedrawCanvas(); void Close(); } diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index aadacd195af..6e45c0a6541 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -612,8 +612,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation auto pfnScrollPositionChanged = std::bind(&TermControl::_TerminalScrollPositionChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); _terminal->SetScrollPositionChangedCallback(pfnScrollPositionChanged); - auto pfnCursorPositionChanged = std::bind(&TermControl::_TerminalCursorPositionChanged, this); - _terminal->SetCursorPositionChangedCallback(pfnCursorPositionChanged); + auto pfnTerminalCursorPositionChanged = std::bind(&TermControl::_TerminalCursorPositionChanged, this); + _terminal->SetCursorPositionChangedCallback(pfnTerminalCursorPositionChanged); static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast(1.0 / 30.0 * 1000000)); _autoScrollTimer.Interval(AutoScrollUpdateInterval); @@ -1789,13 +1789,14 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation } auto weakThis{ get_weak() }; + co_await winrt::resume_foreground(Dispatcher()); if (auto control{ weakThis.get() }) { if (!_closing.load()) { - TSFInputControl().RedrawCanvas(); + TSFInputControl().TryRedrawCanvas(); } } } diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 4031297ad97..082b39b6af7 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -703,13 +703,13 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition) } } - _NotifyTerminalCursorPositionChanged(); - if (notifyScroll) { _buffer->GetRenderTarget().TriggerRedrawAll(); _NotifyScrollEvent(); } + + _NotifyTerminalCursorPositionChanged(); } void Terminal::UserScrollViewport(const int viewTop) From 2a9e6a0c661d21b92f445bf097b405265ef726a2 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Thu, 26 Mar 2020 13:54:16 -0700 Subject: [PATCH 5/8] comment update --- src/cascadia/TerminalControl/TSFInputControl.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalControl/TSFInputControl.cpp b/src/cascadia/TerminalControl/TSFInputControl.cpp index c56f7439eb1..54b3c7719f9 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.cpp +++ b/src/cascadia/TerminalControl/TSFInputControl.cpp @@ -126,9 +126,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation } // Method Description: - // - Redraw the canvas and update our dimensions if certain dimensions have changed since the last - // redraw. This includes the Terminal cursor position, the actual Canvas width, - // and the actual TextBlock height. + // - Redraw the canvas if certain dimensions have changed since the last + // redraw. This includes the Terminal cursor position, the Canvas width, and the TextBlock height. // Arguments: // - // Return Value: From 0139ba54f1361001ea0771b5b26e08acb76a870f Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Thu, 26 Mar 2020 14:08:13 -0700 Subject: [PATCH 6/8] formatting --- src/cascadia/TerminalControl/TermControl.cpp | 1 - src/cascadia/TerminalCore/Terminal.hpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 44e29306ef9..813c9697a8f 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -1777,7 +1777,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation } } - // Method Description: // - Tells TSFInputControl to redraw the Canvas/TextBlock so it'll update // to be where the current cursor position is. diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 9ba2a80d87b..f5ca256e31a 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -170,7 +170,7 @@ class Microsoft::Terminal::Core::Terminal final : void SetScrollPositionChangedCallback(std::function pfn) noexcept; void SetCursorPositionChangedCallback(std::function pfn) noexcept; void SetBackgroundCallback(std::function pfn) noexcept; - + void SetCursorOn(const bool isOn) noexcept; bool IsCursorBlinkingAllowed() const noexcept; From 76d0c2482a9c4916f058a1fea133b5b51ced2e85 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Mon, 30 Mar 2020 10:24:02 -0700 Subject: [PATCH 7/8] changing currentTerminalCursorPos to tilPoint --- src/cascadia/TerminalControl/TSFInputControl.cpp | 8 ++++---- src/cascadia/TerminalControl/TSFInputControl.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cascadia/TerminalControl/TSFInputControl.cpp b/src/cascadia/TerminalControl/TSFInputControl.cpp index 54b3c7719f9..a299662ca23 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.cpp +++ b/src/cascadia/TerminalControl/TSFInputControl.cpp @@ -148,8 +148,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation const double actualTextBlockHeight = TextBlock().ActualHeight(); - if (_currentTerminalCursorPos.X == cursorPos.X && - _currentTerminalCursorPos.Y == cursorPos.Y && + if (_currentTerminalCursorPos.x() == cursorPos.X && + _currentTerminalCursorPos.y() == cursorPos.Y && _currentCanvasWidth == actualCanvasWidth && _currentTextBlockHeight == actualTextBlockHeight) { @@ -181,8 +181,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation // Convert text buffer cursor position to client coordinate position within the window COORD clientCursorPos; - clientCursorPos.X = ::base::ClampMul(_currentTerminalCursorPos.X, ::base::ClampedNumeric(fontWidth)); - clientCursorPos.Y = ::base::ClampMul(_currentTerminalCursorPos.Y, ::base::ClampedNumeric(fontHeight)); + clientCursorPos.X = ::base::ClampMul(_currentTerminalCursorPos.x(), ::base::ClampedNumeric(fontWidth)); + clientCursorPos.Y = ::base::ClampMul(_currentTerminalCursorPos.y(), ::base::ClampedNumeric(fontHeight)); // position textblock to cursor position Canvas().SetLeft(TextBlock(), clientCursorPos.X); diff --git a/src/cascadia/TerminalControl/TSFInputControl.h b/src/cascadia/TerminalControl/TSFInputControl.h index bd0fe1b18ce..536bed5df59 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.h +++ b/src/cascadia/TerminalControl/TSFInputControl.h @@ -77,7 +77,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation void _RedrawCanvas(); bool _focused; - COORD _currentTerminalCursorPos; + til::point _currentTerminalCursorPos; double _currentCanvasWidth; double _currentTextBlockHeight; winrt::Windows::Foundation::Rect _currentControlBounds; From c33f483c216e8c89f37391e8b6059d382b5c84b9 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Mon, 30 Mar 2020 11:13:10 -0700 Subject: [PATCH 8/8] formatting grrrrrrrr --- src/cascadia/TerminalControl/TSFInputControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalControl/TSFInputControl.cpp b/src/cascadia/TerminalControl/TSFInputControl.cpp index c156f3f7f6f..477a565733a 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.cpp +++ b/src/cascadia/TerminalControl/TSFInputControl.cpp @@ -142,7 +142,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation // Get the cursor position in text buffer position auto cursorArgs = winrt::make_self(); _CurrentCursorPositionHandlers(*this, *cursorArgs); - const til::point cursorPos { gsl::narrow_cast(cursorArgs->CurrentPosition().X), gsl::narrow_cast(cursorArgs->CurrentPosition().Y) }; + const til::point cursorPos{ gsl::narrow_cast(cursorArgs->CurrentPosition().X), gsl::narrow_cast(cursorArgs->CurrentPosition().Y) }; const double actualCanvasWidth = Canvas().ActualWidth();