Direct mode: invalidate m_bufferData on resize

Also, for efficieny in direct mode, only output the lines that have
changed, rather than reprinting all of the lines after the first changed
line.

Fixes https://github.com/rprichard/winpty/issues/112
This commit is contained in:
Ryan Prichard 2017-04-22 22:05:16 -07:00
parent d636a1de86
commit ac33b66172
2 changed files with 27 additions and 22 deletions

View File

@ -55,7 +55,7 @@ Scraper::Scraper(
{
m_consoleBuffer = &buffer;
resetConsoleTracking(Terminal::OmitClear, buffer.windowRect());
resetConsoleTracking(Terminal::OmitClear, buffer.windowRect().top());
m_bufferData.resize(BUFFER_LINE_COUNT);
@ -114,13 +114,13 @@ void Scraper::scrapeBuffer(Win32ConsoleBuffer &buffer,
}
void Scraper::resetConsoleTracking(
Terminal::SendClearFlag sendClear, const SmallRect &windowRect)
Terminal::SendClearFlag sendClear, int64_t scrapedLineCount)
{
for (ConsoleLine &line : m_bufferData) {
line.reset();
}
m_syncRow = -1;
m_scrapedLineCount = windowRect.top();
m_scrapedLineCount = scrapedLineCount;
m_scrolledCount = 0;
m_maxBufferedLine = -1;
m_dirtyWindowTop = -1;
@ -205,7 +205,11 @@ void Scraper::resizeImpl(const ConsoleScreenBufferInfo &origInfo)
const Coord origBufferSize = origInfo.bufferSize();
const SmallRect origWindowRect = origInfo.windowRect();
if (!m_directMode) {
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) {
@ -343,7 +347,8 @@ void Scraper::syncConsoleContentAndSize(
const bool newDirectMode = (info.bufferSize().Y != BUFFER_LINE_COUNT);
if (newDirectMode != m_directMode) {
trace("Entering %s mode", newDirectMode ? "direct" : "scrolling");
resetConsoleTracking(Terminal::SendClear, info.windowRect());
resetConsoleTracking(Terminal::SendClear,
newDirectMode ? 0 : info.windowRect().top());
m_directMode = newDirectMode;
// When we switch from direct->scrolling mode, make sure the console is
@ -355,6 +360,11 @@ void Scraper::syncConsoleContentAndSize(
}
if (m_directMode) {
// In direct-mode, resizing the console redraws the terminal, so do it
// before scraping.
if (forceResize) {
resizeImpl(info);
}
directScrapeOutput(info, cursorVisible);
} else {
if (!m_console.frozen()) {
@ -365,14 +375,15 @@ void Scraper::syncConsoleContentAndSize(
if (m_console.frozen()) {
scrollingScrapeOutput(info, cursorVisible, false);
}
// In scrolling mode, we want to scrape before resizing, because we'll
// erase everything in the console buffer up to the top of the console
// window.
if (forceResize) {
resizeImpl(info);
}
}
if (forceResize) {
resizeImpl(info);
finalInfoOut = m_consoleBuffer->bufferInfo();
} else {
finalInfoOut = info;
}
finalInfoOut = forceResize ? m_consoleBuffer->bufferInfo() : info;
}
// Try to match Windows' behavior w.r.t. to the LVB attribute flags. In some
@ -445,17 +456,11 @@ void Scraper::directScrapeOutput(const ConsoleScreenBufferInfo &info,
largeConsoleRead(m_readBuffer, *m_consoleBuffer, scrapeRect, attributesMask());
bool sawModifiedLine = false;
for (int line = 0; line < h; ++line) {
const CHAR_INFO *curLine =
const CHAR_INFO *const curLine =
m_readBuffer.lineData(scrapeRect.top() + line);
ConsoleLine &bufLine = m_bufferData[line];
if (sawModifiedLine) {
bufLine.setLine(curLine, w);
} else {
sawModifiedLine = bufLine.detectChangeAndSetLine(curLine, w);
}
if (sawModifiedLine) {
if (bufLine.detectChangeAndSetLine(curLine, w)) {
const int lineCursorColumn =
line == cursorLine ? cursorColumn : -1;
m_terminal->sendLine(line, curLine, w, lineCursorColumn);
@ -488,7 +493,7 @@ bool Scraper::scrollingScrapeOutput(const ConsoleScreenBufferInfo &info,
trace("Sync marker has disappeared -- resetting the terminal"
" (m_syncCounter=%u)",
m_syncCounter);
resetConsoleTracking(Terminal::SendClear, windowRect);
resetConsoleTracking(Terminal::SendClear, windowRect.top());
} else if (markerRow != m_syncRow) {
ASSERT(markerRow < m_syncRow);
m_scrolledCount += (m_syncRow - markerRow);
@ -531,7 +536,7 @@ bool Scraper::scrollingScrapeOutput(const ConsoleScreenBufferInfo &info,
trace("Window moved upward -- resetting the terminal"
" (m_syncCounter=%u)",
m_syncCounter);
resetConsoleTracking(Terminal::SendClear, windowRect);
resetConsoleTracking(Terminal::SendClear, windowRect.top());
}
}
m_dirtyWindowTop = windowRect.top();

View File

@ -64,7 +64,7 @@ public:
private:
void resetConsoleTracking(
Terminal::SendClearFlag sendClear, const SmallRect &windowRect);
Terminal::SendClearFlag sendClear, int64_t scrapedLineCount);
void markEntireWindowDirty(const SmallRect &windowRect);
void scanForDirtyLines(const SmallRect &windowRect);
void clearBufferLines(int firstRow, int count);