]> granicus.if.org Git - vim/commitdiff
patch 7.4.851 v7.4.851
authorBram Moolenaar <Bram@vim.org>
Tue, 1 Sep 2015 18:23:37 +0000 (20:23 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 1 Sep 2015 18:23:37 +0000 (20:23 +0200)
Problem:    Saving and restoring the console buffer does not work properly.
Solution:   Instead of ReadConsoleOutputA/WriteConsoleOutputA use
            CreateConsoleScreenBuffer and SetConsoleActiveScreenBuffer.
            (Ken Takata)

src/os_win32.c
src/version.c

index d782a9d613b218c533f8c3e31ef7891998160bd5..8f97c3bc274720394f689f952f0e7f8a743ed163 100644 (file)
@@ -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);
 
index f09e4f3d4eb1aaf5f55071b96d669ba637583ac6..559f0c1abbf3c792f86916e0230c44d866a0a329 100644 (file)
@@ -741,6 +741,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    851,
 /**/
     850,
 /**/