Skip to content

Commit 4eb06fe

Browse files
authored
Restore contents when a screen info is closed (#17853)
1 parent d2c3cfd commit 4eb06fe

File tree

4 files changed

+63
-43
lines changed

4 files changed

+63
-43
lines changed

src/host/VtIo.cpp

+49
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <til/unicode.h>
88

9+
#include "directio.h"
910
#include "handle.h" // LockConsole
1011
#include "output.h" // CloseConsoleProcessState
1112
#include "../interactivity/inc/ServiceLocator.hpp"
@@ -790,3 +791,51 @@ void VtIo::Writer::WriteInfos(til::point target, std::span<const CHAR_INFO> info
790791
} while (--repeat);
791792
}
792793
}
794+
795+
void VtIo::Writer::WriteScreenInfo(SCREEN_INFORMATION& newContext, til::size oldSize) const
796+
{
797+
const auto area = static_cast<size_t>(oldSize.width * oldSize.height);
798+
799+
auto& main = newContext.GetMainBuffer();
800+
auto& alt = newContext.GetActiveBuffer();
801+
const auto hasAltBuffer = &alt != &main;
802+
803+
// TODO GH#5094: This could use xterm's XTWINOPS "\e[8;<height>;<width>t" escape sequence here.
804+
if (oldSize != main.GetBufferSize().Dimensions())
805+
{
806+
THROW_IF_NTSTATUS_FAILED(main.ResizeTraditional(oldSize));
807+
main.SetViewportSize(&oldSize);
808+
}
809+
if (hasAltBuffer && oldSize != alt.GetBufferSize().Dimensions())
810+
{
811+
THROW_IF_NTSTATUS_FAILED(alt.ResizeTraditional(oldSize));
812+
alt.SetViewportSize(&oldSize);
813+
}
814+
815+
const auto request = Viewport::FromDimensions({}, oldSize);
816+
Viewport read;
817+
til::small_vector<CHAR_INFO, 1024> infos;
818+
infos.resize(area, CHAR_INFO{ L' ', FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED });
819+
820+
const auto dumpScreenInfo = [&](SCREEN_INFORMATION& screenInfo) {
821+
THROW_IF_FAILED(ReadConsoleOutputWImplHelper(screenInfo, infos, request, read));
822+
for (til::CoordType i = 0; i < oldSize.height; i++)
823+
{
824+
WriteInfos({ 0, i }, { infos.begin() + i * oldSize.width, static_cast<size_t>(oldSize.width) });
825+
}
826+
827+
WriteCUP(screenInfo.GetTextBuffer().GetCursor().GetPosition());
828+
WriteAttributes(screenInfo.GetAttributes());
829+
WriteDECTCEM(screenInfo.GetTextBuffer().GetCursor().IsVisible());
830+
WriteDECAWM(WI_IsFlagSet(screenInfo.OutputMode, ENABLE_WRAP_AT_EOL_OUTPUT));
831+
};
832+
833+
WriteASB(false);
834+
dumpScreenInfo(main);
835+
836+
if (hasAltBuffer)
837+
{
838+
WriteASB(true);
839+
dumpScreenInfo(alt);
840+
}
841+
}

src/host/VtIo.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ namespace Microsoft::Console::VirtualTerminal
4444
void WriteWindowTitle(std::wstring_view title) const;
4545
void WriteAttributes(const TextAttribute& attributes) const;
4646
void WriteInfos(til::point target, std::span<const CHAR_INFO> infos) const;
47+
void WriteScreenInfo(SCREEN_INFORMATION& newContext, til::size oldSize) const;
4748

4849
private:
4950
VtIo* _io = nullptr;

src/host/getset.cpp

+2-43
Original file line numberDiff line numberDiff line change
@@ -487,49 +487,8 @@ void ApiRoutines::SetConsoleActiveScreenBufferImpl(SCREEN_INFORMATION& newContex
487487

488488
if (auto writer = gci.GetVtWriter())
489489
{
490-
const auto viewport = gci.GetActiveOutputBuffer().GetBufferSize();
491-
const auto size = viewport.Dimensions();
492-
const auto area = static_cast<size_t>(viewport.Width() * viewport.Height());
493-
494-
auto& main = newContext.GetMainBuffer();
495-
auto& alt = newContext.GetActiveBuffer();
496-
const auto hasAltBuffer = &alt != &main;
497-
498-
// TODO GH#5094: This could use xterm's XTWINOPS "\e[8;<height>;<width>t" escape sequence here.
499-
THROW_IF_NTSTATUS_FAILED(main.ResizeTraditional(size));
500-
main.SetViewportSize(&size);
501-
if (hasAltBuffer)
502-
{
503-
THROW_IF_NTSTATUS_FAILED(alt.ResizeTraditional(size));
504-
alt.SetViewportSize(&size);
505-
}
506-
507-
Viewport read;
508-
til::small_vector<CHAR_INFO, 1024> infos;
509-
infos.resize(area, CHAR_INFO{ L' ', FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED });
510-
511-
const auto dumpScreenInfo = [&](SCREEN_INFORMATION& screenInfo) {
512-
THROW_IF_FAILED(ReadConsoleOutputWImpl(screenInfo, infos, viewport, read));
513-
for (til::CoordType i = 0; i < size.height; i++)
514-
{
515-
writer.WriteInfos({ 0, i }, { infos.begin() + i * size.width, static_cast<size_t>(size.width) });
516-
}
517-
518-
writer.WriteCUP(screenInfo.GetTextBuffer().GetCursor().GetPosition());
519-
writer.WriteAttributes(screenInfo.GetAttributes());
520-
writer.WriteDECTCEM(screenInfo.GetTextBuffer().GetCursor().IsVisible());
521-
writer.WriteDECAWM(WI_IsFlagSet(screenInfo.OutputMode, ENABLE_WRAP_AT_EOL_OUTPUT));
522-
};
523-
524-
writer.WriteASB(false);
525-
dumpScreenInfo(main);
526-
527-
if (hasAltBuffer)
528-
{
529-
writer.WriteASB(true);
530-
dumpScreenInfo(alt);
531-
}
532-
490+
const auto oldSize = gci.GetActiveOutputBuffer().GetBufferSize().Dimensions();
491+
writer.WriteScreenInfo(newContext, oldSize);
533492
writer.Submit();
534493
}
535494

src/server/ObjectHandle.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,18 @@ INPUT_READ_HANDLE_DATA* ConsoleHandleData::GetClientInput() const
273273
LOG_IF_FAILED(pScreenInfo->FreeIoHandle(this));
274274
if (!pScreenInfo->HasAnyOpenHandles())
275275
{
276+
auto& gci = Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().getConsoleInformation();
277+
const auto oldSize = gci.GetActiveOutputBuffer().GetBufferSize().Dimensions();
278+
auto writer = gci.GetVtWriter();
279+
276280
SCREEN_INFORMATION::s_RemoveScreenBuffer(pScreenInfo);
281+
282+
if (writer && gci.HasActiveOutputBuffer())
283+
{
284+
auto& newContext = gci.GetActiveOutputBuffer();
285+
writer.WriteScreenInfo(newContext, oldSize);
286+
writer.Submit();
287+
}
277288
}
278289

279290
return S_OK;

0 commit comments

Comments
 (0)