changeset 7184:0a256475412f v7.4.902

commit https://github.com/vim/vim/commit/4c0aac57599092da404f6726e88701ba441a4a6d Author: Bram Moolenaar <Bram@vim.org> Date: Fri Oct 30 16:46:55 2015 +0100 patch 7.4.902 Problem: Problems with using the MS-Windows console. Solution: Revert patches 7.4.851, 7.4.876 and 7.4.886 until we find a better solution. (suggested by Ken Takata)
author Christian Brabandt <cb@256bit.org>
date Fri, 30 Oct 2015 17:00:04 +0100
parents ffad29dc7eee
children b8b6bf43ec2f
files src/os_win32.c src/version.c
diffstat 2 files changed, 131 insertions(+), 121 deletions(-) [+]
line wrap: on
line diff
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -234,7 +234,6 @@ static int suppress_winsize = 1;	/* don'
 
 static char_u *exe_path = NULL;
 
-static BOOL is_win7 = FALSE;
 static BOOL win8_or_later = FALSE;
 
 /*
@@ -681,9 +680,6 @@ PlatformId(void)
 
 	g_PlatformId = ovi.dwPlatformId;
 
-	if ((ovi.dwMajorVersion == 6 && ovi.dwMinorVersion == 1))
-	    is_win7 = TRUE;
-
 	if ((ovi.dwMajorVersion == 6 && ovi.dwMinorVersion >= 2)
 		|| ovi.dwMajorVersion > 6)
 	    win8_or_later = TRUE;
@@ -2173,7 +2169,8 @@ typedef struct ConsoleBufferStruct
 {
     BOOL			IsValid;
     CONSOLE_SCREEN_BUFFER_INFO	Info;
-    HANDLE			handle;
+    PCHAR_INFO			Buffer;
+    COORD			BufferSize;
 } ConsoleBuffer;
 
 /*
@@ -2190,81 +2187,77 @@ typedef struct ConsoleBufferStruct
 SaveConsoleBuffer(
     ConsoleBuffer *cb)
 {
+    DWORD NumCells;
+    COORD BufferCoord;
+    SMALL_RECT ReadRegion;
+    WORD Y, Y_incr;
+
     if (cb == NULL)
 	return FALSE;
 
-    if (!GetConsoleScreenBufferInfo(cb->handle, &cb->Info))
+    if (!GetConsoleScreenBufferInfo(g_hConOut, &cb->Info))
     {
 	cb->IsValid = FALSE;
 	return FALSE;
     }
     cb->IsValid = TRUE;
 
-    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;
+    /*
+     * 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;
+    }
 
     /*
-     * 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.
+     * 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).
      */
-    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 = 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 */
+    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)
     {
-	vim_free(Buffer);
-	return FALSE;
+	/*
+	 * 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;
+	}
     }
-    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;
 }
@@ -2283,20 +2276,67 @@ RestoreConsoleBuffer(
     ConsoleBuffer   *cb,
     BOOL	    RestoreScreen)
 {
-    HANDLE hConOld;
+    COORD BufferCoord;
+    SMALL_RECT WriteRegion;
 
     if (cb == NULL || !cb->IsValid)
 	return FALSE;
 
-    hConOld = g_hConOut;
-    g_hConOut = cb->handle;
-    if (!RestoreScreen && exiting)
-	CopyOldConsoleBuffer(cb, hConOld);
-    SetConsoleActiveScreenBuffer(g_hConOut);
+    /*
+     * 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;
+	}
+    }
 
     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 };
 
@@ -2435,6 +2475,9 @@ 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
@@ -2455,14 +2498,16 @@ 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 */
-    SaveConsoleBuffer(&g_cbNonTermcap);
-    g_attrCurrent = g_attrDefault = g_cbNonTermcap.Info.wAttributes;
+    GetConsoleScreenBufferInfo(g_hConOut, &csbi);
+    g_attrCurrent = g_attrDefault = csbi.wAttributes;
+#endif
     if (cterm_normal_fg_color == 0)
 	cterm_normal_fg_color = (g_attrCurrent & 0xf) + 1;
     if (cterm_normal_bg_color == 0)
@@ -2562,8 +2607,6 @@ 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
@@ -4585,12 +4628,11 @@ mch_system(char *cmd, int options)
     else
 	return mch_system_classic(cmd, options);
 }
-
 #else
 
 # ifdef FEAT_MBYTE
     static int
-mch_system1(char *cmd, int options)
+mch_system(char *cmd, int options)
 {
     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
     {
@@ -4605,45 +4647,9 @@ mch_system1(char *cmd, int options)
     return system(cmd);
 }
 # else
-#  define mch_system1(c, o) system(c)
+#  define mch_system(c, o) system(c)
 # endif
 
-    static int
-mch_system(char *cmd, int options)
-{
-    int ret;
-    HANDLE hTemp = INVALID_HANDLE_VALUE;
-
-    /*
-     * Call DuplicateHandle before executing an external program, because msys
-     * and msys2's programs will call CreateConsoleScreenBuffer and
-     * CloseHandle.  CreateConsoleScreenBuffer returns the same handle which
-     * created by vim.  This causes a crash. This workaround is required on
-     * Windows7.
-     */
-    if (is_win7
-	    && g_fTermcapMode
-	    && DuplicateHandle(
-		    GetCurrentProcess(),
-		    g_hConOut,
-		    GetCurrentProcess(),
-		    &hTemp,
-		    0,
-		    TRUE,
-		    DUPLICATE_SAME_ACCESS))
-	SetConsoleActiveScreenBuffer(hTemp);
-
-    ret = mch_system1(cmd, options);
-
-    if (hTemp != INVALID_HANDLE_VALUE)
-    {
-	SetConsoleActiveScreenBuffer(g_hConOut);
-	CloseHandle(hTemp);
-    }
-
-    return ret;
-}
-
 #endif
 
 /*
@@ -4973,8 +4979,6 @@ 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);
     }
@@ -5018,7 +5022,11 @@ 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);
 
--- 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 */
 /**/
+    902,
+/**/
     901,
 /**/
     900,