diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 925ee3dd207..30fcab0cc5b 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -2430,11 +2430,11 @@ namespace winrt::TerminalApp::implementation // TermControl will copy the settings out of the settings passed to it. TermControl term{ settings.DefaultSettings(), settings.UnfocusedSettings(), connection }; - // // GH#12515: ConPTY assumes it's hidden at the start. If we're not, let it know now. - // if (_visible) - // { - // term.WindowVisibilityChanged(_visible); - // } + // GH#12515: ConPTY assumes it's hidden at the start. If we're not, let it know now. + if (_visible) + { + term.WindowVisibilityChanged(_visible); + } if (_hostingHwnd.has_value()) { diff --git a/src/cascadia/TerminalConnection/ConptyConnection.cpp b/src/cascadia/TerminalConnection/ConptyConnection.cpp index 2867e27fbbb..3a5996b763a 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.cpp +++ b/src/cascadia/TerminalConnection/ConptyConnection.cpp @@ -317,10 +317,10 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation } // GH#12515: The conpty assumes it's hidden at the start. If we're visible, let it know now. - // if (_initialVisibility) - // { - // THROW_IF_FAILED(ConptyShowHidePseudoConsole(_hPC.get(), _initialVisibility)); - // } + if (_initialVisibility) + { + THROW_IF_FAILED(ConptyShowHidePseudoConsole(_hPC.get(), _initialVisibility)); + } // THROW_IF_FAILED(ConptyShowHidePseudoConsole(_hPC.get(), _initialVisibility)); THROW_IF_FAILED(_LaunchAttachedClient()); diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 7fe8a689cf8..0f648fd0a49 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -1706,10 +1706,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - void ControlCore::WindowVisibilityChanged(const bool showOrHide) { - // show is true, hide is false - if (auto conpty{ _connection.try_as() }) + if (_initializedTerminal) { - conpty.ShowHide(showOrHide); + // show is true, hide is false + if (auto conpty{ _connection.try_as() }) + { + conpty.ShowHide(showOrHide); + } } } diff --git a/src/host/PtySignalInputThread.cpp b/src/host/PtySignalInputThread.cpp index 9f3bd98c2cc..544a7e06239 100644 --- a/src/host/PtySignalInputThread.cpp +++ b/src/host/PtySignalInputThread.cpp @@ -74,12 +74,19 @@ void PtySignalInputThread::ConnectConsole() noexcept { _DoShowHide(_initialShowHide->show); } +} - // If we were given a owner HWND, then manually start the pseudo window now. - if (_earlyReparent) - { - _DoSetWindowParent(*_earlyReparent); - } +// Method Description: +// - Create our pseudowindow. We're doing this here, instead of in +// ConnectConsole, because the window is created in +// ConsoleInputThreadProcWin32, before ConnectConsole is first called. Doing +// this here ensures that the window is first created with the initial owner +// set up (if so specified). +// - Refer to GH#13066 for details. +void PtySignalInputThread::CreatePseudoWindow() +{ + HWND owner = _earlyReparent.has_value() ? reinterpret_cast((*_earlyReparent).handle) : HWND_DESKTOP; + ServiceLocator::LocatePseudoWindow(owner); } // Method Description: diff --git a/src/host/PtySignalInputThread.hpp b/src/host/PtySignalInputThread.hpp index 1ac12f44f33..f9f4268bb9c 100644 --- a/src/host/PtySignalInputThread.hpp +++ b/src/host/PtySignalInputThread.hpp @@ -33,6 +33,7 @@ namespace Microsoft::Console PtySignalInputThread& operator=(const PtySignalInputThread&) = delete; void ConnectConsole() noexcept; + void CreatePseudoWindow(); private: enum class PtySignal : unsigned short diff --git a/src/host/VtIo.cpp b/src/host/VtIo.cpp index a01f5680bf9..03d8240a62b 100644 --- a/src/host/VtIo.cpp +++ b/src/host/VtIo.cpp @@ -300,18 +300,34 @@ bool VtIo::IsUsingVt() const if (_pPtySignalInputThread) { - // IMPORTANT! Start the pseudo window on this thread. This thread has a - // message pump. If you DON'T, then a DPI change in the owning hwnd will - // cause us to get a dpi change as well, which we'll never deque and - // handle, effectively HANGING THE OWNER HWND. + // Let the signal thread know that the console is connected. // - // Let the signal thread know that the console is connected + // By this point, the pseudo window should have already been created, by + // ConsoleInputThreadProcWin32. That thread has a message pump, which is + // needed to ensure that DPI change messages to the owning terminal + // window don't end up hanging because the pty didn't also process it. _pPtySignalInputThread->ConnectConsole(); } return S_OK; } +// Method Description: +// - Create our pseudowindow. This is exclusively called by +// ConsoleInputThreadProcWin32 on the console input thread. +// * It needs to be called on that thread, before any other calls to +// LocatePseudoWindow, to make sure that the input thread is the HWND's +// message thread. +// * It needs to be plumbed through the signal thread, because the signal +// thread knows if someone should be marked as the window's owner. It's +// VERY IMPORTANT that any initial owners are set up when the window is +// first created. +// - Refer to GH#13066 for details. +void VtIo::CreatePseudoWindow() +{ + _pPtySignalInputThread->CreatePseudoWindow(); +} + // Method Description: // - Create and start the signal thread. The signal thread can be created // independent of the i/o threads, and doesn't require a client first diff --git a/src/host/VtIo.hpp b/src/host/VtIo.hpp index 3abba39c184..39af4466bb3 100644 --- a/src/host/VtIo.hpp +++ b/src/host/VtIo.hpp @@ -52,6 +52,8 @@ namespace Microsoft::Console::VirtualTerminal [[nodiscard]] HRESULT ManuallyClearScrollback() const noexcept; + void CreatePseudoWindow(); + private: // After CreateIoHandlers is called, these will be invalid. wil::unique_hfile _hInput; diff --git a/src/interactivity/win32/windowio.cpp b/src/interactivity/win32/windowio.cpp index 86a51e09ca6..7816d8ff398 100644 --- a/src/interactivity/win32/windowio.cpp +++ b/src/interactivity/win32/windowio.cpp @@ -1036,9 +1036,18 @@ DWORD WINAPI ConsoleInputThreadProcWin32(LPVOID /*lpParameter*/) // If we are headless (because we're a pseudo console), we // will still need a window handle in the win32 environment // in case anyone sends messages at that HWND (vim.exe is an example.) - // We have to CreateWindow on the same thread that will pump the messages - // which is this thread. - ServiceLocator::LocatePseudoWindow(); + // + // IMPORTANT! We have to CreateWindow on the same thread that will pump + // the messages, which is this thread. If you DON'T, then a DPI change + // in the owning hwnd will cause us to get a dpi change as well, which + // we'll never deque and handle, effectively HANGING THE OWNER HWND. + // ServiceLocator::LocatePseudoWindow(); + // + // Instead of just calling LocatePseudoWindow, make sure to go through + // VtIo's CreatePseudoWindow, which will make sure that the window is + // successfully created with the owner configured when the window is + // first created. See GH#13066 for details. + ServiceLocator::LocateGlobals().getConsoleInformation().GetVtIo()->CreatePseudoWindow(); } UnlockConsole();