diff --git a/src/cascadia/TerminalControl/TSFInputControl.cpp b/src/cascadia/TerminalControl/TSFInputControl.cpp index 154ccbb7b4d..2e97e546201 100644 --- a/src/cascadia/TerminalControl/TSFInputControl.cpp +++ b/src/cascadia/TerminalControl/TSFInputControl.cpp @@ -134,8 +134,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation // Return Value: // - void TSFInputControl::TryRedrawCanvas() + try { - if (!_focused) + if (!_focused || !Canvas()) { return; } @@ -164,6 +165,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation _RedrawCanvas(); } + CATCH_LOG() // Method Description: // - Redraw the Canvas and update the current Text Bounds and Control Bounds for diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 14c181c8af9..c6e77635a3f 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -535,7 +535,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation _uiaEngine = std::make_unique<::Microsoft::Console::Render::UiaEngine>(autoPeer.get()); _core->AttachUiaEngine(_uiaEngine.get()); - return *autoPeer; + _automationPeer = *autoPeer; + return _automationPeer; } return nullptr; } @@ -1719,6 +1720,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation _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. TSFInputControl().Close(); _autoScrollTimer.Stop(); diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index 8169cc5c49a..715356ee236 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -138,6 +138,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation // in order to safely resolve this unsafe pointer dependency. Otherwise a deallocated // IRenderEngine is accessed when ControlCore calls Renderer::TriggerTeardown. // (C++ class members are destroyed in reverse order.) + // Further, the TermControlAutomationPeer must be destructed after _uiaEngine! + winrt::Windows::UI::Xaml::Automation::Peers::AutomationPeer _automationPeer{ nullptr }; std::unique_ptr<::Microsoft::Console::Render::UiaEngine> _uiaEngine; winrt::com_ptr _core; diff --git a/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp b/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp index 6df09f3022d..69af0750f9a 100644 --- a/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp +++ b/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp @@ -46,9 +46,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation void TermControlAutomationPeer::SignalSelectionChanged() { UiaTracing::Signal::SelectionChanged(); - Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [&]() { - // The event that is raised when the text selection is modified. - RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged); + auto dispatcher{ Dispatcher() }; + if (!dispatcher) + { + return; + } + dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }]() { + if (auto strongThis{ weakThis.get() }) + { + // The event that is raised when the text selection is modified. + strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged); + } }); } @@ -61,9 +69,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation void TermControlAutomationPeer::SignalTextChanged() { UiaTracing::Signal::TextChanged(); - Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [&]() { - // The event that is raised when textual content is modified. - RaiseAutomationEvent(AutomationEvents::TextPatternOnTextChanged); + auto dispatcher{ Dispatcher() }; + if (!dispatcher) + { + return; + } + dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }]() { + if (auto strongThis{ weakThis.get() }) + { + // The event that is raised when textual content is modified. + strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextChanged); + } }); } @@ -76,14 +92,22 @@ namespace winrt::Microsoft::Terminal::Control::implementation void TermControlAutomationPeer::SignalCursorChanged() { UiaTracing::Signal::CursorChanged(); - Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [&]() { - // The event that is raised when the text was changed in an edit control. - // Do NOT fire a TextEditTextChanged. Generally, an app on the other side - // will expect more information. Though you can dispatch that event - // on its own, it may result in a nullptr exception on the other side - // because no additional information was provided. Crashing the screen - // reader. - RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged); + auto dispatcher{ Dispatcher() }; + if (!dispatcher) + { + return; + } + dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }]() { + if (auto strongThis{ weakThis.get() }) + { + // The event that is raised when the text was changed in an edit control. + // Do NOT fire a TextEditTextChanged. Generally, an app on the other side + // will expect more information. Though you can dispatch that event + // on its own, it may result in a nullptr exception on the other side + // because no additional information was provided. Crashing the screen + // reader. + strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged); + } }); }