diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 0b58ffd730a..8b0e90a69f2 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -1555,32 +1555,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation _RendererWarningHandlers(*this, winrt::make(hr)); } - winrt::fire_and_forget ControlCore::_renderEngineSwapChainChanged(const HANDLE sourceHandle) + void ControlCore::_renderEngineSwapChainChanged(const HANDLE handle) { - // `sourceHandle` is a weak ref to a HANDLE that's ultimately owned by the + // `handle` is a weak ref to a HANDLE that's ultimately owned by the // render engine's own unique_handle. We'll add another ref to it here. // This will make sure that we always have a valid HANDLE to give to // callers of our own SwapChainHandle method, even if the renderer is // currently in the process of discarding this value and creating a new // one. Callers should have already set up the SwapChainChanged // callback, so this all works out. + _lastSwapChainHandle.attach(handle); - winrt::handle duplicatedHandle; - const auto processHandle = GetCurrentProcess(); - THROW_IF_WIN32_BOOL_FALSE(DuplicateHandle(processHandle, sourceHandle, processHandle, duplicatedHandle.put(), 0, FALSE, DUPLICATE_SAME_ACCESS)); - - const auto weakThis{ get_weak() }; - - co_await wil::resume_foreground(_dispatcher); - - if (auto core{ weakThis.get() }) - { - // `this` is safe to use now - - _lastSwapChainHandle = (std::move(duplicatedHandle)); - // Now bubble the event up to the control. - _SwapChainChangedHandlers(*this, winrt::box_value(reinterpret_cast(_lastSwapChainHandle.get()))); - } + // Now bubble the event up to the control. + _SwapChainChangedHandlers(*this, winrt::box_value(reinterpret_cast(handle))); } void ControlCore::_rendererBackgroundColorChanged() diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index 8f7e40e6242..fa263b65888 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -328,7 +328,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation #pragma region RendererCallbacks void _rendererWarning(const HRESULT hr); - winrt::fire_and_forget _renderEngineSwapChainChanged(const HANDLE handle); + void _renderEngineSwapChainChanged(const HANDLE handle); void _rendererBackgroundColorChanged(); void _rendererTabColorChanged(); #pragma endregion diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 841b72a9cd4..c0e84977943 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -866,11 +866,28 @@ namespace winrt::Microsoft::Terminal::Control::implementation return _core.ConnectionState(); } - void TermControl::RenderEngineSwapChainChanged(IInspectable /*sender*/, IInspectable args) + winrt::fire_and_forget TermControl::RenderEngineSwapChainChanged(IInspectable /*sender*/, IInspectable args) { - // This event comes in on the UI thread - HANDLE h = reinterpret_cast(winrt::unbox_value(args)); - _AttachDxgiSwapChainToXaml(h); + // This event comes in on the render thread, not the UI thread. + + const auto weakThis{ get_weak() }; + + winrt::handle handle; + + // Add a ref to the handle passed to us, so that the HANDLE will remain + // valid to the other side of the co_await. + handle.attach(reinterpret_cast(winrt::unbox_value(args))); + + co_await wil::resume_foreground(Dispatcher()); + + if (auto control{ weakThis.get() }) + { + _AttachDxgiSwapChainToXaml(handle.get()); + } + // Detach from the handle. If you don't do this, we'll CloseHandle() on + // the handle when `handle` goes out of scope, resulting in the swap + // chain being closed. + handle.detach(); } // Method Description: @@ -1801,11 +1818,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // GH#5421: Enable the UiaEngine before checking for the SearchBox // That way, new selections are notified to automation clients. // The _uiaEngine lives in _interactivity, so call into there to enable it. - - if (_interactivity) - { - _interactivity.GotFocus(); - } + _interactivity.GotFocus(); // If the searchbox is focused, we don't want TSFInputControl to think // it has focus so it doesn't intercept IME input. We also don't want the @@ -1860,10 +1873,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // This will disable the accessibility notifications, because the // UiaEngine lives in ControlInteractivity - if (_interactivity) - { - _interactivity.LostFocus(); - } + _interactivity.LostFocus(); if (TSFInputControl() != nullptr) { diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index f06a50f3373..56767936fb2 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -95,7 +95,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation void ToggleShaderEffects(); - void RenderEngineSwapChainChanged(IInspectable sender, IInspectable args); + winrt::fire_and_forget RenderEngineSwapChainChanged(IInspectable sender, IInspectable args); void _AttachDxgiSwapChainToXaml(HANDLE swapChainHandle); winrt::fire_and_forget _RendererEnteredErrorState(IInspectable sender, IInspectable args);