summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2015-09-01 20:23:37 +0200
committerBram Moolenaar <Bram@vim.org>2015-09-01 20:23:37 +0200
commit615942452eb74eee7d8386fd3d76a1534181fa06 (patch)
treea0e0c26f9919a4ada25585b6eade0c300629e1fb /src
parent544780248b5876339b316703fc2f330a9d316c45 (diff)
patch 7.4.851v7.4.851
Problem: Saving and restoring the console buffer does not work properly. Solution: Instead of ReadConsoleOutputA/WriteConsoleOutputA use CreateConsoleScreenBuffer and SetConsoleActiveScreenBuffer. (Ken Takata)
Diffstat (limited to 'src')
-rw-r--r--src/os_win32.c203
-rw-r--r--src/version.c2
2 files changed, 79 insertions, 126 deletions
diff --git a/src/os_win32.c b/src/os_win32.c
index d782a9d613..8f97c3bc27 100644
--- 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);
+ g_cbNonTermcap.handle = g_hConOut;
+ g_cbTermcap.handle = CreateConsoleScreenBuffer(
+ GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
-#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
/* 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
index f09e4f3d4e..559f0c1abb 100644
--- 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,