Fix racy access to _tsfTryRedrawCanvas in TermControl (#10549)
Previously `TermControl::Close` destroyed all `ThrottledFunc`s to ensure they're not scheduling any callbacks on the UI thread, as the call to `Close` signals the point at which the `TermControl` isn't part of the UI thread anymore. `_CursorPositionChanged` tried to prevent access to the potentially deallocated `_tsfTryRedrawCanvas` by checking the `std::shared_ptr` for nullability, but since the deallocation happens on the UI thread and the nullability check on a background thread, this check introduced a race condition. This commit solves the issue by not deallocating any `ThrottledFunc`s anymore and instead checking the `_closing` flag inside the `ThrottledFunc` callback on the UI thread. Additionally this commit cleans up some antipatterns around the use of `std::optional`. ## PR Checklist * [x] Closes #10479 * [x] Closes #10302 ## Validation Steps Performed * Opening and closing tabs doesn't crash ✔️ * Printing long text doesn't crash ✔️ * Manual scrolling doesn't crash ✔️ * ^G / the audible bell doesn't crash ✔️
This commit is contained in:
parent
59239e3b07
commit
83c6bce73d
|
@ -48,9 +48,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
{
|
{
|
||||||
TermControl::TermControl(IControlSettings settings,
|
TermControl::TermControl(IControlSettings settings,
|
||||||
TerminalConnection::ITerminalConnection connection) :
|
TerminalConnection::ITerminalConnection connection) :
|
||||||
_initializedTerminal{ false },
|
|
||||||
_settings{ settings },
|
_settings{ settings },
|
||||||
_closing{ false },
|
|
||||||
_isInternalScrollBarUpdate{ false },
|
_isInternalScrollBarUpdate{ false },
|
||||||
_autoScrollVelocity{ 0 },
|
_autoScrollVelocity{ 0 },
|
||||||
_autoScrollingPointerPoint{ std::nullopt },
|
_autoScrollingPointerPoint{ std::nullopt },
|
||||||
|
@ -110,11 +108,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// Core eventually won't have access to. When we get to
|
// Core eventually won't have access to. When we get to
|
||||||
// https://github.com/microsoft/terminal/projects/5#card-50760282
|
// https://github.com/microsoft/terminal/projects/5#card-50760282
|
||||||
// then we'll move the applicable ones.
|
// then we'll move the applicable ones.
|
||||||
|
//
|
||||||
|
// These four throttled functions are triggered by terminal output and interact with the UI.
|
||||||
|
// Since Close() is the point after which we are removed from the UI, but before the
|
||||||
|
// destructor has run, we MUST check control->_IsClosing() before actually doing anything.
|
||||||
_tsfTryRedrawCanvas = std::make_shared<ThrottledFuncTrailing<>>(
|
_tsfTryRedrawCanvas = std::make_shared<ThrottledFuncTrailing<>>(
|
||||||
Dispatcher(),
|
Dispatcher(),
|
||||||
TsfRedrawInterval,
|
TsfRedrawInterval,
|
||||||
[weakThis = get_weak()]() {
|
[weakThis = get_weak()]() {
|
||||||
if (auto control{ weakThis.get() })
|
if (auto control{ weakThis.get() }; !control->_IsClosing())
|
||||||
{
|
{
|
||||||
control->TSFInputControl().TryRedrawCanvas();
|
control->TSFInputControl().TryRedrawCanvas();
|
||||||
}
|
}
|
||||||
|
@ -124,7 +126,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
Dispatcher(),
|
Dispatcher(),
|
||||||
UpdatePatternLocationsInterval,
|
UpdatePatternLocationsInterval,
|
||||||
[weakThis = get_weak()]() {
|
[weakThis = get_weak()]() {
|
||||||
if (auto control{ weakThis.get() })
|
if (auto control{ weakThis.get() }; !control->_IsClosing())
|
||||||
{
|
{
|
||||||
control->_core->UpdatePatternLocations();
|
control->_core->UpdatePatternLocations();
|
||||||
}
|
}
|
||||||
|
@ -134,7 +136,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
Dispatcher(),
|
Dispatcher(),
|
||||||
TerminalWarningBellInterval,
|
TerminalWarningBellInterval,
|
||||||
[weakThis = get_weak()]() {
|
[weakThis = get_weak()]() {
|
||||||
if (auto control{ weakThis.get() })
|
if (auto control{ weakThis.get() }; !control->_IsClosing())
|
||||||
{
|
{
|
||||||
control->_WarningBellHandlers(*control, nullptr);
|
control->_WarningBellHandlers(*control, nullptr);
|
||||||
}
|
}
|
||||||
|
@ -144,14 +146,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
Dispatcher(),
|
Dispatcher(),
|
||||||
ScrollBarUpdateInterval,
|
ScrollBarUpdateInterval,
|
||||||
[weakThis = get_weak()](const auto& update) {
|
[weakThis = get_weak()](const auto& update) {
|
||||||
if (auto control{ weakThis.get() })
|
if (auto control{ weakThis.get() }; !control->_IsClosing())
|
||||||
{
|
{
|
||||||
control->_isInternalScrollBarUpdate = true;
|
control->_isInternalScrollBarUpdate = true;
|
||||||
|
|
||||||
auto scrollBar = control->ScrollBar();
|
auto scrollBar = control->ScrollBar();
|
||||||
if (update.newValue.has_value())
|
if (update.newValue)
|
||||||
{
|
{
|
||||||
scrollBar.Value(update.newValue.value());
|
scrollBar.Value(*update.newValue);
|
||||||
}
|
}
|
||||||
scrollBar.Maximum(update.newMaximum);
|
scrollBar.Maximum(update.newMaximum);
|
||||||
scrollBar.Minimum(update.newMinimum);
|
scrollBar.Minimum(update.newMinimum);
|
||||||
|
@ -205,7 +207,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
void TermControl::SearchMatch(const bool goForward)
|
void TermControl::SearchMatch(const bool goForward)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -296,7 +298,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// - newSettings: the new settings to set
|
// - newSettings: the new settings to set
|
||||||
void TermControl::_UpdateSettingsFromUIThread(IControlSettings newSettings)
|
void TermControl::_UpdateSettingsFromUIThread(IControlSettings newSettings)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -314,7 +316,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// - newAppearance: the new appearance to set
|
// - newAppearance: the new appearance to set
|
||||||
void TermControl::_UpdateAppearanceFromUIThread(IControlAppearance newAppearance)
|
void TermControl::_UpdateAppearanceFromUIThread(IControlAppearance newAppearance)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -527,7 +529,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
Windows::UI::Xaml::Automation::Peers::AutomationPeer TermControl::OnCreateAutomationPeer()
|
Windows::UI::Xaml::Automation::Peers::AutomationPeer TermControl::OnCreateAutomationPeer()
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_initializedTerminal && !_closing) // only set up the automation peer if we're ready to go live
|
if (_initializedTerminal && !_IsClosing()) // only set up the automation peer if we're ready to go live
|
||||||
{
|
{
|
||||||
// create a custom automation peer with this code pattern:
|
// create a custom automation peer with this code pattern:
|
||||||
// (https://docs.microsoft.com/en-us/windows/uwp/design/accessibility/custom-automation-peers)
|
// (https://docs.microsoft.com/en-us/windows/uwp/design/accessibility/custom-automation-peers)
|
||||||
|
@ -747,7 +749,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_CharacterHandler(winrt::Windows::Foundation::IInspectable const& /*sender*/,
|
void TermControl::_CharacterHandler(winrt::Windows::Foundation::IInspectable const& /*sender*/,
|
||||||
Input::CharacterReceivedRoutedEventArgs const& e)
|
Input::CharacterReceivedRoutedEventArgs const& e)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -845,7 +847,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// win32-input-mode, then we'll send all these keystrokes to the
|
// win32-input-mode, then we'll send all these keystrokes to the
|
||||||
// terminal - it's smart enough to ignore the keys it doesn't care
|
// terminal - it's smart enough to ignore the keys it doesn't care
|
||||||
// about.
|
// about.
|
||||||
if (_closing ||
|
if (_IsClosing() ||
|
||||||
e.OriginalKey() == VirtualKey::LeftWindows ||
|
e.OriginalKey() == VirtualKey::LeftWindows ||
|
||||||
e.OriginalKey() == VirtualKey::RightWindows)
|
e.OriginalKey() == VirtualKey::RightWindows)
|
||||||
|
|
||||||
|
@ -997,12 +999,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
keyDown) :
|
keyDown) :
|
||||||
true;
|
true;
|
||||||
|
|
||||||
if (_cursorTimer.has_value())
|
if (_cursorTimer)
|
||||||
{
|
{
|
||||||
// Manually show the cursor when a key is pressed. Restarting
|
// Manually show the cursor when a key is pressed. Restarting
|
||||||
// the timer prevents flickering.
|
// the timer prevents flickering.
|
||||||
_core->CursorOn(true);
|
_core->CursorOn(true);
|
||||||
_cursorTimer.value().Start();
|
_cursorTimer->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
|
@ -1027,7 +1029,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_PointerPressedHandler(Windows::Foundation::IInspectable const& sender,
|
void TermControl::_PointerPressedHandler(Windows::Foundation::IInspectable const& sender,
|
||||||
Input::PointerRoutedEventArgs const& args)
|
Input::PointerRoutedEventArgs const& args)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1078,7 +1080,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_PointerMovedHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
void TermControl::_PointerMovedHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||||
Input::PointerRoutedEventArgs const& args)
|
Input::PointerRoutedEventArgs const& args)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1151,7 +1153,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_PointerReleasedHandler(Windows::Foundation::IInspectable const& sender,
|
void TermControl::_PointerReleasedHandler(Windows::Foundation::IInspectable const& sender,
|
||||||
Input::PointerRoutedEventArgs const& args)
|
Input::PointerRoutedEventArgs const& args)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1193,7 +1195,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_MouseWheelHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
void TermControl::_MouseWheelHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||||
Input::PointerRoutedEventArgs const& args)
|
Input::PointerRoutedEventArgs const& args)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1295,7 +1297,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_ScrollbarChangeHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
void TermControl::_ScrollbarChangeHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||||
Controls::Primitives::RangeBaseValueChangedEventArgs const& args)
|
Controls::Primitives::RangeBaseValueChangedEventArgs const& args)
|
||||||
{
|
{
|
||||||
if (_isInternalScrollBarUpdate || _closing)
|
if (_isInternalScrollBarUpdate || _IsClosing())
|
||||||
{
|
{
|
||||||
// The update comes from ourselves, more specifically from the
|
// The update comes from ourselves, more specifically from the
|
||||||
// terminal. So we don't have to update the terminal because it
|
// terminal. So we don't have to update the terminal because it
|
||||||
|
@ -1361,15 +1363,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_TryStartAutoScroll(Windows::UI::Input::PointerPoint const& pointerPoint, const double scrollVelocity)
|
void TermControl::_TryStartAutoScroll(Windows::UI::Input::PointerPoint const& pointerPoint, const double scrollVelocity)
|
||||||
{
|
{
|
||||||
// Allow only one pointer at the time
|
// Allow only one pointer at the time
|
||||||
if (!_autoScrollingPointerPoint.has_value() ||
|
if (!_autoScrollingPointerPoint ||
|
||||||
_autoScrollingPointerPoint.value().PointerId() == pointerPoint.PointerId())
|
_autoScrollingPointerPoint->PointerId() == pointerPoint.PointerId())
|
||||||
{
|
{
|
||||||
_autoScrollingPointerPoint = pointerPoint;
|
_autoScrollingPointerPoint = pointerPoint;
|
||||||
_autoScrollVelocity = scrollVelocity;
|
_autoScrollVelocity = scrollVelocity;
|
||||||
|
|
||||||
// If this is first time the auto scroll update is about to be called,
|
// If this is first time the auto scroll update is about to be called,
|
||||||
// kick-start it by initializing its time delta as if it started now
|
// kick-start it by initializing its time delta as if it started now
|
||||||
if (!_lastAutoScrollUpdateTime.has_value())
|
if (!_lastAutoScrollUpdateTime)
|
||||||
{
|
{
|
||||||
_lastAutoScrollUpdateTime = std::chrono::high_resolution_clock::now();
|
_lastAutoScrollUpdateTime = std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
@ -1388,8 +1390,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// - pointerId: id of pointer for which to stop auto scroll
|
// - pointerId: id of pointer for which to stop auto scroll
|
||||||
void TermControl::_TryStopAutoScroll(const uint32_t pointerId)
|
void TermControl::_TryStopAutoScroll(const uint32_t pointerId)
|
||||||
{
|
{
|
||||||
if (_autoScrollingPointerPoint.has_value() &&
|
if (_autoScrollingPointerPoint &&
|
||||||
pointerId == _autoScrollingPointerPoint.value().PointerId())
|
pointerId == _autoScrollingPointerPoint->PointerId())
|
||||||
{
|
{
|
||||||
_autoScrollingPointerPoint = std::nullopt;
|
_autoScrollingPointerPoint = std::nullopt;
|
||||||
_autoScrollVelocity = 0;
|
_autoScrollVelocity = 0;
|
||||||
|
@ -1415,15 +1417,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
{
|
{
|
||||||
const auto timeNow = std::chrono::high_resolution_clock::now();
|
const auto timeNow = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
if (_lastAutoScrollUpdateTime.has_value())
|
if (_lastAutoScrollUpdateTime)
|
||||||
{
|
{
|
||||||
static constexpr double microSecPerSec = 1000000.0;
|
static constexpr double microSecPerSec = 1000000.0;
|
||||||
const double deltaTime = std::chrono::duration_cast<std::chrono::microseconds>(timeNow - _lastAutoScrollUpdateTime.value()).count() / microSecPerSec;
|
const double deltaTime = std::chrono::duration_cast<std::chrono::microseconds>(timeNow - *_lastAutoScrollUpdateTime).count() / microSecPerSec;
|
||||||
ScrollBar().Value(ScrollBar().Value() + _autoScrollVelocity * deltaTime);
|
ScrollBar().Value(ScrollBar().Value() + _autoScrollVelocity * deltaTime);
|
||||||
|
|
||||||
if (_autoScrollingPointerPoint.has_value())
|
if (_autoScrollingPointerPoint)
|
||||||
{
|
{
|
||||||
_SetEndSelectionPointAtCursor(_autoScrollingPointerPoint.value().Position());
|
_SetEndSelectionPointAtCursor(_autoScrollingPointerPoint->Position());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1439,7 +1441,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_GotFocusHandler(Windows::Foundation::IInspectable const& /* sender */,
|
void TermControl::_GotFocusHandler(Windows::Foundation::IInspectable const& /* sender */,
|
||||||
RoutedEventArgs const& /* args */)
|
RoutedEventArgs const& /* args */)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1468,16 +1470,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
TSFInputControl().NotifyFocusEnter();
|
TSFInputControl().NotifyFocusEnter();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_cursorTimer.has_value())
|
if (_cursorTimer)
|
||||||
{
|
{
|
||||||
// When the terminal focuses, show the cursor immediately
|
// When the terminal focuses, show the cursor immediately
|
||||||
_core->CursorOn(true);
|
_core->CursorOn(true);
|
||||||
_cursorTimer.value().Start();
|
_cursorTimer->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_blinkTimer.has_value())
|
if (_blinkTimer)
|
||||||
{
|
{
|
||||||
_blinkTimer.value().Start();
|
_blinkTimer->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
_interactivity->GainFocus();
|
_interactivity->GainFocus();
|
||||||
|
@ -1498,7 +1500,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_LostFocusHandler(Windows::Foundation::IInspectable const& /* sender */,
|
void TermControl::_LostFocusHandler(Windows::Foundation::IInspectable const& /* sender */,
|
||||||
RoutedEventArgs const& /* args */)
|
RoutedEventArgs const& /* args */)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1517,15 +1519,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
TSFInputControl().NotifyFocusLeave();
|
TSFInputControl().NotifyFocusLeave();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_cursorTimer.has_value())
|
if (_cursorTimer)
|
||||||
{
|
{
|
||||||
_cursorTimer.value().Stop();
|
_cursorTimer->Stop();
|
||||||
_core->CursorOn(false);
|
_core->CursorOn(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_blinkTimer.has_value())
|
if (_blinkTimer)
|
||||||
{
|
{
|
||||||
_blinkTimer.value().Stop();
|
_blinkTimer->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there is an unfocused config we should set the appearance to
|
// Check if there is an unfocused config we should set the appearance to
|
||||||
|
@ -1544,7 +1546,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_SwapChainSizeChanged(winrt::Windows::Foundation::IInspectable const& /*sender*/,
|
void TermControl::_SwapChainSizeChanged(winrt::Windows::Foundation::IInspectable const& /*sender*/,
|
||||||
SizeChangedEventArgs const& e)
|
SizeChangedEventArgs const& e)
|
||||||
{
|
{
|
||||||
if (!_initializedTerminal || _closing)
|
if (!_initializedTerminal || _IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1596,7 +1598,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_CursorTimerTick(Windows::Foundation::IInspectable const& /* sender */,
|
void TermControl::_CursorTimerTick(Windows::Foundation::IInspectable const& /* sender */,
|
||||||
Windows::Foundation::IInspectable const& /* e */)
|
Windows::Foundation::IInspectable const& /* e */)
|
||||||
{
|
{
|
||||||
if (!_closing)
|
if (!_IsClosing())
|
||||||
{
|
{
|
||||||
_core->BlinkCursor();
|
_core->BlinkCursor();
|
||||||
}
|
}
|
||||||
|
@ -1610,7 +1612,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_BlinkTimerTick(Windows::Foundation::IInspectable const& /* sender */,
|
void TermControl::_BlinkTimerTick(Windows::Foundation::IInspectable const& /* sender */,
|
||||||
Windows::Foundation::IInspectable const& /* e */)
|
Windows::Foundation::IInspectable const& /* e */)
|
||||||
{
|
{
|
||||||
if (!_closing)
|
if (!_IsClosing())
|
||||||
{
|
{
|
||||||
_core->BlinkAttributeTick();
|
_core->BlinkAttributeTick();
|
||||||
}
|
}
|
||||||
|
@ -1638,13 +1640,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_ScrollPositionChanged(const IInspectable& /*sender*/,
|
void TermControl::_ScrollPositionChanged(const IInspectable& /*sender*/,
|
||||||
const Control::ScrollPositionChangedArgs& args)
|
const Control::ScrollPositionChangedArgs& args)
|
||||||
{
|
{
|
||||||
// Since this callback fires from non-UI thread, we might be already
|
|
||||||
// closed/closing.
|
|
||||||
if (_closing.load())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollBarUpdate update;
|
ScrollBarUpdate update;
|
||||||
const auto hiddenContent = args.BufferSize() - args.ViewHeight();
|
const auto hiddenContent = args.BufferSize() - args.ViewHeight();
|
||||||
update.newMaximum = hiddenContent;
|
update.newMaximum = hiddenContent;
|
||||||
|
@ -1664,10 +1659,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_CursorPositionChanged(const IInspectable& /*sender*/,
|
void TermControl::_CursorPositionChanged(const IInspectable& /*sender*/,
|
||||||
const IInspectable& /*args*/)
|
const IInspectable& /*args*/)
|
||||||
{
|
{
|
||||||
if (_tsfTryRedrawCanvas)
|
_tsfTryRedrawCanvas->Run();
|
||||||
{
|
|
||||||
_tsfTryRedrawCanvas->Run();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hstring TermControl::Title()
|
hstring TermControl::Title()
|
||||||
|
@ -1700,7 +1692,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// if we should defer which formats are copied to the global setting
|
// if we should defer which formats are copied to the global setting
|
||||||
bool TermControl::CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats)
|
bool TermControl::CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1717,21 +1709,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
void TermControl::Close()
|
void TermControl::Close()
|
||||||
{
|
{
|
||||||
if (!_closing.exchange(true))
|
if (!_IsClosing())
|
||||||
{
|
{
|
||||||
|
_closing = true;
|
||||||
|
|
||||||
_core->ReceivedOutput(_coreOutputEventToken);
|
_core->ReceivedOutput(_coreOutputEventToken);
|
||||||
|
|
||||||
_RestorePointerCursorHandlers(*this, nullptr);
|
_RestorePointerCursorHandlers(*this, nullptr);
|
||||||
|
|
||||||
// These four throttled functions are triggered by terminal output and interact with the UI.
|
|
||||||
// Since Close() is the point after which we are removed from the UI, but before the destructor
|
|
||||||
// has run, we should disconnect them *right now*. If we don't, they may fire between the
|
|
||||||
// throttle delay (from the final output) and the dtor.
|
|
||||||
_tsfTryRedrawCanvas.reset();
|
|
||||||
_updatePatternLocations.reset();
|
|
||||||
_updateScrollBar.reset();
|
|
||||||
_playWarningBell.reset();
|
|
||||||
|
|
||||||
// Disconnect the TSF input control so it doesn't receive EditContext events.
|
// Disconnect the TSF input control so it doesn't receive EditContext events.
|
||||||
TSFInputControl().Close();
|
TSFInputControl().Close();
|
||||||
_autoScrollTimer.Stop();
|
_autoScrollTimer.Stop();
|
||||||
|
@ -2097,7 +2080,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// - <none>
|
// - <none>
|
||||||
void TermControl::_CompositionCompleted(winrt::hstring text)
|
void TermControl::_CompositionCompleted(winrt::hstring text)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2174,7 +2157,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
winrt::fire_and_forget TermControl::_DragDropHandler(Windows::Foundation::IInspectable /*sender*/,
|
winrt::fire_and_forget TermControl::_DragDropHandler(Windows::Foundation::IInspectable /*sender*/,
|
||||||
DragEventArgs e)
|
DragEventArgs e)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2261,7 +2244,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void TermControl::_DragOverHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
void TermControl::_DragOverHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||||
DragEventArgs const& e)
|
DragEventArgs const& e)
|
||||||
{
|
{
|
||||||
if (_closing)
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2422,7 +2405,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// Stop the timer and switch off the light
|
// Stop the timer and switch off the light
|
||||||
_bellLightTimer.Stop();
|
_bellLightTimer.Stop();
|
||||||
|
|
||||||
if (!_closing)
|
if (!_IsClosing())
|
||||||
{
|
{
|
||||||
VisualBellLight::SetIsTarget(RootGrid(), false);
|
VisualBellLight::SetIsTarget(RootGrid(), false);
|
||||||
}
|
}
|
||||||
|
@ -2465,7 +2448,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
if (auto self{ weakThis.get() })
|
if (auto self{ weakThis.get() })
|
||||||
{
|
{
|
||||||
auto lastHoveredCell = _core->GetHoveredCell();
|
auto lastHoveredCell = _core->GetHoveredCell();
|
||||||
if (lastHoveredCell.has_value())
|
if (lastHoveredCell)
|
||||||
{
|
{
|
||||||
const auto uriText = _core->GetHoveredUriText();
|
const auto uriText = _core->GetHoveredUriText();
|
||||||
if (!uriText.empty())
|
if (!uriText.empty())
|
||||||
|
|
|
@ -149,9 +149,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
winrt::com_ptr<SearchBoxControl> _searchBox;
|
winrt::com_ptr<SearchBoxControl> _searchBox;
|
||||||
|
|
||||||
IControlSettings _settings;
|
IControlSettings _settings;
|
||||||
std::atomic<bool> _closing;
|
bool _closing{ false };
|
||||||
bool _focused;
|
bool _focused{ false };
|
||||||
bool _initializedTerminal;
|
bool _initializedTerminal{ false };
|
||||||
|
|
||||||
std::shared_ptr<ThrottledFuncTrailing<>> _tsfTryRedrawCanvas;
|
std::shared_ptr<ThrottledFuncTrailing<>> _tsfTryRedrawCanvas;
|
||||||
std::shared_ptr<ThrottledFuncTrailing<>> _updatePatternLocations;
|
std::shared_ptr<ThrottledFuncTrailing<>> _updatePatternLocations;
|
||||||
|
@ -183,6 +183,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||||
|
|
||||||
|
inline bool _IsClosing() const noexcept
|
||||||
|
{
|
||||||
|
// _closing isn't atomic and may only be accessed from the main thread.
|
||||||
|
assert(Dispatcher().HasThreadAccess());
|
||||||
|
return _closing;
|
||||||
|
}
|
||||||
|
|
||||||
void _UpdateSettingsFromUIThread(IControlSettings newSettings);
|
void _UpdateSettingsFromUIThread(IControlSettings newSettings);
|
||||||
void _UpdateAppearanceFromUIThread(IControlAppearance newAppearance);
|
void _UpdateAppearanceFromUIThread(IControlAppearance newAppearance);
|
||||||
void _ApplyUISettings(const IControlSettings&);
|
void _ApplyUISettings(const IControlSettings&);
|
||||||
|
|
Loading…
Reference in New Issue