Repository: microsoft/terminal
File: src/host/VtIo.cpp (C++)

Code before:
//   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()
{
    if (_pPtySignalInputThread)
    {
        _pPtySignalInputThread->CreatePseudoWindow();
    }
    else
    {
        ServiceLocator::LocatePseudoWindow();
    }
}

void VtIo::SetWindowVisibility(bool showOrHide) noexcept
{
    // MSFT:40853556 Grab the shutdown lock here, so that another
    // thread can't trigger a CloseOutput and release the
    // _pVtRenderEngine out from underneath us.
    std::lock_guard<std::mutex> lk(_shutdownLock);

    if (!_pVtRenderEngine)
    {
        return;
    }

    auto& gci = ::Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().getConsoleInformation();

    gci.LockConsole();
    auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });

    LOG_IF_FAILED(_pVtRenderEngine->SetWindowVisibility(showOrHide));
}

// 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
//      attaching to the console. We need to create it first and foremost,
//      because it's possible that a terminal application could
//      CreatePseudoConsole, then ClosePseudoConsole without ever attaching a
//      client. Should that happen, we still need to exit.
// Arguments:
// - <none>
// Return Value:

Review comment (bug):
Actually, i am suddenly worried this is a deadlock factory. We call `SetWindowVisibility` off the I/O thread when Terminal says "I got focus." The PseudoWindow itself may also take the console lock to send Terminal messages. Is there a condition that will result in Terminal receiving and processing a message while the console lock is held, and then trying to dump a focus message back into the VtIo pipe?

Code after:
// Method Description:
// - Create our pseudo window. 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()
{
    if (_pPtySignalInputThread)
    {
        _pPtySignalInputThread->CreatePseudoWindow();
    }
    else
    {
        ServiceLocator::LocatePseudoWindow();
    }
}

void VtIo::SetWindowVisibility(bool showOrHide) noexcept
{
    auto& gci = ::Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().getConsoleInformation();

    gci.LockConsole();
    auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });

    // ConsoleInputThreadProcWin32 calls VtIo::CreatePseudoWindow,
    // which calls CreateWindowExW, which causes a WM_SIZE message.
    // In short, this function might be called before _pVtRenderEngine exists.
    // See PtySignalInputThread::CreatePseudoWindow().
    if (!_pVtRenderEngine)
    {
        return;
    }

    LOG_IF_FAILED(_pVtRenderEngine->SetWindowVisibility(showOrHide));
}

// 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
//      attaching to the console. We need to create it first and foremost,
//      because it's possible that a terminal application could
//      CreatePseudoConsole, then ClosePseudoConsole without ever attaching a
//      client. Should that happen, we still need to exit.
// Arguments:
// - <none>