# HG changeset patch # User Christian Brabandt # Date 1441132204 -7200 # Node ID 383d6f39669b4f8344aef8f710b8d833bf029b27 # Parent 2f26e5950851ed932320e23c86f069d956880574 commit https://github.com/vim/vim/commit/615942452eb74eee7d8386fd3d76a1534181fa06 Author: Bram Moolenaar Date: Tue Sep 1 20:23:37 2015 +0200 patch 7.4.851 Problem: Saving and restoring the console buffer does not work properly. Solution: Instead of ReadConsoleOutputA/WriteConsoleOutputA use CreateConsoleScreenBuffer and SetConsoleActiveScreenBuffer. (Ken Takata) diff --git a/src/os_win32.c b/src/os_win32.c --- a/src/os_win32.c +++ b/src/os_win32.c @@ -2192,8 +2192,7 @@ typedef struct ConsoleBufferStruct { BOOL IsValid; CONSOLE_SCREEN_BUFFER_INFO Info; - PCHAR_INFO Buffer; - COORD BufferSize; + HANDLE handle; } ConsoleBuffer; /* @@ -2210,77 +2209,81 @@ typedef struct ConsoleBufferStruct SaveConsoleBuffer( ConsoleBuffer *cb) { - DWORD NumCells; - COORD BufferCoord; - SMALL_RECT ReadRegion; - WORD Y, Y_incr; - if (cb == NULL) return FALSE; - if (!GetConsoleScreenBufferInfo(g_hConOut, &cb->Info)) + if (!GetConsoleScreenBufferInfo(cb->handle, &cb->Info)) { cb->IsValid = FALSE; return FALSE; } cb->IsValid = TRUE; - /* - * Allocate a buffer large enough to hold the entire console screen - * buffer. If this ConsoleBuffer structure has already been initialized - * with a buffer of the correct size, then just use that one. - */ - if (!cb->IsValid || cb->Buffer == NULL || - cb->BufferSize.X != cb->Info.dwSize.X || - cb->BufferSize.Y != cb->Info.dwSize.Y) - { - cb->BufferSize.X = cb->Info.dwSize.X; - cb->BufferSize.Y = cb->Info.dwSize.Y; - NumCells = cb->BufferSize.X * cb->BufferSize.Y; - vim_free(cb->Buffer); - cb->Buffer = (PCHAR_INFO)alloc(NumCells * sizeof(CHAR_INFO)); - if (cb->Buffer == NULL) - return FALSE; - } + return TRUE; +} + +/* + * CopyOldConsoleBuffer() + * Description: + * Copies the old console buffer contents to the current console buffer. + * This is used when 'restorescreen' is off. + * Returns: + * TRUE on success + */ + static BOOL +CopyOldConsoleBuffer( + ConsoleBuffer *cb, + HANDLE hConOld) +{ + COORD BufferCoord; + COORD BufferSize; + PCHAR_INFO Buffer; + DWORD NumCells; + SMALL_RECT ReadRegion; /* - * We will now copy the console screen buffer into our buffer. - * ReadConsoleOutput() seems to be limited as far as how much you - * can read at a time. Empirically, this number seems to be about - * 12000 cells (rows * columns). Start at position (0, 0) and copy - * in chunks until it is all copied. The chunks will all have the - * same horizontal characteristics, so initialize them now. The - * height of each chunk will be (12000 / width). + * Before copying the buffer contents, clear the current buffer, and + * restore the window information. Doing this now prevents old buffer + * contents from "flashing" onto the screen. */ - BufferCoord.X = 0; + ClearConsoleBuffer(cb->Info.wAttributes); + + /* We only need to copy the window area, not whole buffer. */ + BufferSize.X = cb->Info.srWindow.Right - cb->Info.srWindow.Left + 1; + BufferSize.Y = cb->Info.srWindow.Bottom - cb->Info.srWindow.Top + 1; ReadRegion.Left = 0; - ReadRegion.Right = cb->Info.dwSize.X - 1; - Y_incr = 12000 / cb->Info.dwSize.X; - for (Y = 0; Y < cb->BufferSize.Y; Y += Y_incr) + ReadRegion.Right = BufferSize.X - 1; + ReadRegion.Top = 0; + ReadRegion.Bottom = BufferSize.Y - 1; + + NumCells = BufferSize.X * BufferSize.Y; + Buffer = (PCHAR_INFO)alloc(NumCells * sizeof(CHAR_INFO)); + if (Buffer == NULL) + return FALSE; + + BufferCoord.X = 0; + BufferCoord.Y = 0; + + if (!ReadConsoleOutputW(hConOld, /* output handle */ + Buffer, /* our buffer */ + BufferSize, /* dimensions of our buffer */ + BufferCoord, /* offset in our buffer */ + &ReadRegion)) /* region to save */ { - /* - * Read into position (0, Y) in our buffer. - */ - BufferCoord.Y = Y; - /* - * Read the region whose top left corner is (0, Y) and whose bottom - * right corner is (width - 1, Y + Y_incr - 1). This should define - * a region of size width by Y_incr. Don't worry if this region is - * too large for the remaining buffer; it will be cropped. - */ - ReadRegion.Top = Y; - ReadRegion.Bottom = Y + Y_incr - 1; - if (!ReadConsoleOutput(g_hConOut, /* output handle */ - cb->Buffer, /* our buffer */ - cb->BufferSize, /* dimensions of our buffer */ - BufferCoord, /* offset in our buffer */ - &ReadRegion)) /* region to save */ - { - vim_free(cb->Buffer); - cb->Buffer = NULL; - return FALSE; - } + vim_free(Buffer); + return FALSE; } + if (!WriteConsoleOutputW(g_hConOut, /* output handle */ + Buffer, /* our buffer */ + BufferSize, /* dimensions of our buffer */ + BufferCoord, /* offset in our buffer */ + &ReadRegion)) /* region to restore */ + { + vim_free(Buffer); + return FALSE; + } + vim_free(Buffer); + SetConsoleWindowInfo(g_hConOut, TRUE, &ReadRegion); return TRUE; } @@ -2299,67 +2302,20 @@ RestoreConsoleBuffer( ConsoleBuffer *cb, BOOL RestoreScreen) { - COORD BufferCoord; - SMALL_RECT WriteRegion; + HANDLE hConOld; if (cb == NULL || !cb->IsValid) return FALSE; - /* - * Before restoring the buffer contents, clear the current buffer, and - * restore the cursor position and window information. Doing this now - * prevents old buffer contents from "flashing" onto the screen. - */ - if (RestoreScreen) - ClearConsoleBuffer(cb->Info.wAttributes); - - FitConsoleWindow(cb->Info.dwSize, TRUE); - if (!SetConsoleScreenBufferSize(g_hConOut, cb->Info.dwSize)) - return FALSE; - if (!SetConsoleTextAttribute(g_hConOut, cb->Info.wAttributes)) - return FALSE; - - if (!RestoreScreen) - { - /* - * No need to restore the screen buffer contents, so we're done. - */ - return TRUE; - } - - if (!SetConsoleCursorPosition(g_hConOut, cb->Info.dwCursorPosition)) - return FALSE; - if (!SetConsoleWindowInfo(g_hConOut, TRUE, &cb->Info.srWindow)) - return FALSE; - - /* - * Restore the screen buffer contents. - */ - if (cb->Buffer != NULL) - { - BufferCoord.X = 0; - BufferCoord.Y = 0; - WriteRegion.Left = 0; - WriteRegion.Top = 0; - WriteRegion.Right = cb->Info.dwSize.X - 1; - WriteRegion.Bottom = cb->Info.dwSize.Y - 1; - if (!WriteConsoleOutput(g_hConOut, /* output handle */ - cb->Buffer, /* our buffer */ - cb->BufferSize, /* dimensions of our buffer */ - BufferCoord, /* offset in our buffer */ - &WriteRegion)) /* region to restore */ - { - return FALSE; - } - } + hConOld = g_hConOut; + g_hConOut = cb->handle; + if (!RestoreScreen && exiting) + CopyOldConsoleBuffer(cb, hConOld); + SetConsoleActiveScreenBuffer(g_hConOut); return TRUE; } -#define FEAT_RESTORE_ORIG_SCREEN -#ifdef FEAT_RESTORE_ORIG_SCREEN -static ConsoleBuffer g_cbOrig = { 0 }; -#endif static ConsoleBuffer g_cbNonTermcap = { 0 }; static ConsoleBuffer g_cbTermcap = { 0 }; @@ -2498,9 +2454,6 @@ static DWORD g_cmodeout = 0; void mch_init(void) { -#ifndef FEAT_RESTORE_ORIG_SCREEN - CONSOLE_SCREEN_BUFFER_INFO csbi; -#endif #ifndef __MINGW32__ extern int _fmode; #endif @@ -2521,16 +2474,14 @@ mch_init(void) else create_conin(); g_hConOut = GetStdHandle(STD_OUTPUT_HANDLE); - -#ifdef FEAT_RESTORE_ORIG_SCREEN - /* Save the initial console buffer for later restoration */ - SaveConsoleBuffer(&g_cbOrig); - g_attrCurrent = g_attrDefault = g_cbOrig.Info.wAttributes; -#else + g_cbNonTermcap.handle = g_hConOut; + g_cbTermcap.handle = CreateConsoleScreenBuffer( + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CONSOLE_TEXTMODE_BUFFER, NULL); + /* Get current text attributes */ - GetConsoleScreenBufferInfo(g_hConOut, &csbi); - g_attrCurrent = g_attrDefault = csbi.wAttributes; -#endif + SaveConsoleBuffer(&g_cbNonTermcap); + g_attrCurrent = g_attrDefault = g_cbNonTermcap.Info.wAttributes; if (cterm_normal_fg_color == 0) cterm_normal_fg_color = (g_attrCurrent & 0xf) + 1; if (cterm_normal_bg_color == 0) @@ -2630,6 +2581,8 @@ mch_exit(int r) SetConsoleMode(g_hConIn, g_cmodein); SetConsoleMode(g_hConOut, g_cmodeout); + CloseHandle(g_cbTermcap.handle); + #ifdef DYNAMIC_GETTEXT dyn_libintl_end(); #endif @@ -5002,6 +4955,8 @@ termcap_mode_start(void) * screen buffer, and resize the buffer to match the current window * size. We will use this as the size of our editing environment. */ + g_hConOut = g_cbTermcap.handle; + SetConsoleActiveScreenBuffer(g_hConOut); ClearConsoleBuffer(g_attrCurrent); ResizeConBufAndWindow(g_hConOut, Columns, Rows); } @@ -5045,11 +5000,7 @@ termcap_mode_end(void) cmodein &= ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT); SetConsoleMode(g_hConIn, cmodein); -#ifdef FEAT_RESTORE_ORIG_SCREEN - cb = exiting ? &g_cbOrig : &g_cbNonTermcap; -#else cb = &g_cbNonTermcap; -#endif RestoreConsoleBuffer(cb, p_rs); SetConsoleCursorInfo(g_hConOut, &g_cci); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -742,6 +742,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 851, +/**/ 850, /**/ 849,