in src/agent/Scraper.cc [186:317]
void Scraper::resizeImpl(const ConsoleScreenBufferInfo &origInfo)
{
ASSERT(m_console.frozen());
const int cols = m_ptySize.X;
const int rows = m_ptySize.Y;
Coord finalBufferSize;
{
//
// To accommodate Windows 10, erase all lines up to the top of the
// visible window. It's hard to tell whether this is strictly
// necessary. It ensures that the sync marker won't move downward,
// and it ensures that we won't repeat lines that have already scrolled
// up into the scrollback.
//
// It *is* possible for these blank lines to reappear in the visible
// window (e.g. if the window is made taller), but because we blanked
// the lines in the line buffer, we still don't output them again.
//
const Coord origBufferSize = origInfo.bufferSize();
const SmallRect origWindowRect = origInfo.windowRect();
if (m_directMode) {
for (ConsoleLine &line : m_bufferData) {
line.reset();
}
} else {
m_consoleBuffer->clearLines(0, origWindowRect.Top, origInfo);
clearBufferLines(0, origWindowRect.Top);
if (m_syncRow != -1) {
createSyncMarker(std::min(
m_syncRow,
BUFFER_LINE_COUNT - rows
- SYNC_MARKER_LEN
- SYNC_MARKER_MARGIN));
}
}
finalBufferSize = Coord(
cols,
// If there was previously no scrollback (e.g. a full-screen app
// in direct mode) and we're reducing the window height, then
// reduce the console buffer's height too.
(origWindowRect.height() == origBufferSize.Y)
? rows
: std::max<int>(rows, origBufferSize.Y));
// Reset the console font size. We need to do this before shrinking
// the window, because we might need to make the font bigger to permit
// a smaller window width. Making the font smaller could expand the
// screen buffer, which would hang the conhost process in the
// Windows 10 (10240 build) if the console selection is in progress, so
// unfreeze it first.
m_console.setFrozen(false);
setSmallFont(m_consoleBuffer->conout(), cols, m_console.isNewW10());
}
// We try to make the font small enough so that the entire screen buffer
// fits on the monitor, but it can't be guaranteed.
const auto largest =
GetLargestConsoleWindowSize(m_consoleBuffer->conout());
const short visibleCols = std::min<short>(cols, largest.X);
const short visibleRows = std::min<short>(rows, largest.Y);
{
// Make the window small enough. We want the console frozen during
// this step so we don't accidentally move the window above the cursor.
m_console.setFrozen(true);
const auto info = m_consoleBuffer->bufferInfo();
const auto &bufferSize = info.dwSize;
const int tmpWindowWidth = std::min(bufferSize.X, visibleCols);
const int tmpWindowHeight = std::min(bufferSize.Y, visibleRows);
SmallRect tmpWindowRect(
0,
std::min<int>(bufferSize.Y - tmpWindowHeight,
info.windowRect().Top),
tmpWindowWidth,
tmpWindowHeight);
if (cursorInWindow(info)) {
tmpWindowRect = tmpWindowRect.ensureLineIncluded(
info.cursorPosition().Y);
}
m_consoleBuffer->moveWindow(tmpWindowRect);
}
{
// Resize the buffer to the final desired size.
m_console.setFrozen(false);
m_consoleBuffer->resizeBufferRange(finalBufferSize);
}
{
// Expand the window to its full size.
m_console.setFrozen(true);
const ConsoleScreenBufferInfo info = m_consoleBuffer->bufferInfo();
SmallRect finalWindowRect(
0,
std::min<int>(info.bufferSize().Y - visibleRows,
info.windowRect().Top),
visibleCols,
visibleRows);
//
// Once a line in the screen buffer is "dirty", it should stay visible
// in the console window, so that we continue to update its content in
// the terminal. This code is particularly (only?) necessary on
// Windows 10, where making the buffer wider can rewrap lines and move
// the console window upward.
//
if (!m_directMode && m_dirtyLineCount > finalWindowRect.Bottom + 1) {
// In theory, we avoid ensureLineIncluded, because, a massive
// amount of output could have occurred while the console was
// unfrozen, so that the *top* of the window is now below the
// dirtiest tracked line.
finalWindowRect = SmallRect(
0, m_dirtyLineCount - visibleRows,
visibleCols, visibleRows);
}
// Highest priority constraint: ensure that the cursor remains visible.
if (cursorInWindow(info)) {
finalWindowRect = finalWindowRect.ensureLineIncluded(
info.cursorPosition().Y);
}
m_consoleBuffer->moveWindow(finalWindowRect);
m_dirtyWindowTop = finalWindowRect.Top;
}
ASSERT(m_console.frozen());
}