@@ -234,7 +234,6 @@ static int suppress_winsize = 1; /* don't fiddle with console */
234234
235235static char_u * exe_path = NULL ;
236236
237- static BOOL is_win7 = FALSE;
238237static BOOL win8_or_later = FALSE;
239238
240239/*
@@ -681,9 +680,6 @@ PlatformId(void)
681680
682681 g_PlatformId = ovi .dwPlatformId ;
683682
684- if ((ovi .dwMajorVersion == 6 && ovi .dwMinorVersion == 1 ))
685- is_win7 = TRUE;
686-
687683 if ((ovi .dwMajorVersion == 6 && ovi .dwMinorVersion >= 2 )
688684 || ovi .dwMajorVersion > 6 )
689685 win8_or_later = TRUE;
@@ -2173,7 +2169,8 @@ typedef struct ConsoleBufferStruct
21732169{
21742170 BOOL IsValid ;
21752171 CONSOLE_SCREEN_BUFFER_INFO Info ;
2176- HANDLE handle ;
2172+ PCHAR_INFO Buffer ;
2173+ COORD BufferSize ;
21772174} ConsoleBuffer ;
21782175
21792176/*
@@ -2190,81 +2187,77 @@ typedef struct ConsoleBufferStruct
21902187SaveConsoleBuffer (
21912188 ConsoleBuffer * cb )
21922189{
2190+ DWORD NumCells ;
2191+ COORD BufferCoord ;
2192+ SMALL_RECT ReadRegion ;
2193+ WORD Y , Y_incr ;
2194+
21932195 if (cb == NULL )
21942196 return FALSE;
21952197
2196- if (!GetConsoleScreenBufferInfo (cb -> handle , & cb -> Info ))
2198+ if (!GetConsoleScreenBufferInfo (g_hConOut , & cb -> Info ))
21972199 {
21982200 cb -> IsValid = FALSE;
21992201 return FALSE;
22002202 }
22012203 cb -> IsValid = TRUE;
22022204
2203- return TRUE;
2204- }
2205-
2206- /*
2207- * CopyOldConsoleBuffer()
2208- * Description:
2209- * Copies the old console buffer contents to the current console buffer.
2210- * This is used when 'restorescreen' is off.
2211- * Returns:
2212- * TRUE on success
2213- */
2214- static BOOL
2215- CopyOldConsoleBuffer (
2216- ConsoleBuffer * cb ,
2217- HANDLE hConOld )
2218- {
2219- COORD BufferCoord ;
2220- COORD BufferSize ;
2221- PCHAR_INFO Buffer ;
2222- DWORD NumCells ;
2223- SMALL_RECT ReadRegion ;
2224-
22252205 /*
2226- * Before copying the buffer contents, clear the current buffer, and
2227- * restore the window information . Doing this now prevents old buffer
2228- * contents from "flashing" onto the screen .
2206+ * Allocate a buffer large enough to hold the entire console screen
2207+ * buffer . If this ConsoleBuffer structure has already been initialized
2208+ * with a buffer of the correct size, then just use that one .
22292209 */
2230- ClearConsoleBuffer (cb -> Info .wAttributes );
2231-
2232- /* We only need to copy the window area, not whole buffer. */
2233- BufferSize .X = cb -> Info .srWindow .Right - cb -> Info .srWindow .Left + 1 ;
2234- BufferSize .Y = cb -> Info .srWindow .Bottom - cb -> Info .srWindow .Top + 1 ;
2235- ReadRegion .Left = 0 ;
2236- ReadRegion .Right = BufferSize .X - 1 ;
2237- ReadRegion .Top = 0 ;
2238- ReadRegion .Bottom = BufferSize .Y - 1 ;
2239-
2240- NumCells = BufferSize .X * BufferSize .Y ;
2241- Buffer = (PCHAR_INFO )alloc (NumCells * sizeof (CHAR_INFO ));
2242- if (Buffer == NULL )
2243- return FALSE;
2210+ if (!cb -> IsValid || cb -> Buffer == NULL ||
2211+ cb -> BufferSize .X != cb -> Info .dwSize .X ||
2212+ cb -> BufferSize .Y != cb -> Info .dwSize .Y )
2213+ {
2214+ cb -> BufferSize .X = cb -> Info .dwSize .X ;
2215+ cb -> BufferSize .Y = cb -> Info .dwSize .Y ;
2216+ NumCells = cb -> BufferSize .X * cb -> BufferSize .Y ;
2217+ vim_free (cb -> Buffer );
2218+ cb -> Buffer = (PCHAR_INFO )alloc (NumCells * sizeof (CHAR_INFO ));
2219+ if (cb -> Buffer == NULL )
2220+ return FALSE;
2221+ }
22442222
2223+ /*
2224+ * We will now copy the console screen buffer into our buffer.
2225+ * ReadConsoleOutput() seems to be limited as far as how much you
2226+ * can read at a time. Empirically, this number seems to be about
2227+ * 12000 cells (rows * columns). Start at position (0, 0) and copy
2228+ * in chunks until it is all copied. The chunks will all have the
2229+ * same horizontal characteristics, so initialize them now. The
2230+ * height of each chunk will be (12000 / width).
2231+ */
22452232 BufferCoord .X = 0 ;
2246- BufferCoord .Y = 0 ;
2247-
2248- if (!ReadConsoleOutputW (hConOld , /* output handle */
2249- Buffer , /* our buffer */
2250- BufferSize , /* dimensions of our buffer */
2251- BufferCoord , /* offset in our buffer */
2252- & ReadRegion )) /* region to save */
2253- {
2254- vim_free (Buffer );
2255- return FALSE;
2256- }
2257- if (!WriteConsoleOutputW (g_hConOut , /* output handle */
2258- Buffer , /* our buffer */
2259- BufferSize , /* dimensions of our buffer */
2260- BufferCoord , /* offset in our buffer */
2261- & ReadRegion )) /* region to restore */
2233+ ReadRegion .Left = 0 ;
2234+ ReadRegion .Right = cb -> Info .dwSize .X - 1 ;
2235+ Y_incr = 12000 / cb -> Info .dwSize .X ;
2236+ for (Y = 0 ; Y < cb -> BufferSize .Y ; Y += Y_incr )
22622237 {
2263- vim_free (Buffer );
2264- return FALSE;
2238+ /*
2239+ * Read into position (0, Y) in our buffer.
2240+ */
2241+ BufferCoord .Y = Y ;
2242+ /*
2243+ * Read the region whose top left corner is (0, Y) and whose bottom
2244+ * right corner is (width - 1, Y + Y_incr - 1). This should define
2245+ * a region of size width by Y_incr. Don't worry if this region is
2246+ * too large for the remaining buffer; it will be cropped.
2247+ */
2248+ ReadRegion .Top = Y ;
2249+ ReadRegion .Bottom = Y + Y_incr - 1 ;
2250+ if (!ReadConsoleOutput (g_hConOut , /* output handle */
2251+ cb -> Buffer , /* our buffer */
2252+ cb -> BufferSize , /* dimensions of our buffer */
2253+ BufferCoord , /* offset in our buffer */
2254+ & ReadRegion )) /* region to save */
2255+ {
2256+ vim_free (cb -> Buffer );
2257+ cb -> Buffer = NULL ;
2258+ return FALSE;
2259+ }
22652260 }
2266- vim_free (Buffer );
2267- SetConsoleWindowInfo (g_hConOut , TRUE, & ReadRegion );
22682261
22692262 return TRUE;
22702263}
@@ -2283,20 +2276,67 @@ RestoreConsoleBuffer(
22832276 ConsoleBuffer * cb ,
22842277 BOOL RestoreScreen )
22852278{
2286- HANDLE hConOld ;
2279+ COORD BufferCoord ;
2280+ SMALL_RECT WriteRegion ;
22872281
22882282 if (cb == NULL || !cb -> IsValid )
22892283 return FALSE;
22902284
2291- hConOld = g_hConOut ;
2292- g_hConOut = cb -> handle ;
2293- if (!RestoreScreen && exiting )
2294- CopyOldConsoleBuffer (cb , hConOld );
2295- SetConsoleActiveScreenBuffer (g_hConOut );
2285+ /*
2286+ * Before restoring the buffer contents, clear the current buffer, and
2287+ * restore the cursor position and window information. Doing this now
2288+ * prevents old buffer contents from "flashing" onto the screen.
2289+ */
2290+ if (RestoreScreen )
2291+ ClearConsoleBuffer (cb -> Info .wAttributes );
2292+
2293+ FitConsoleWindow (cb -> Info .dwSize , TRUE);
2294+ if (!SetConsoleScreenBufferSize (g_hConOut , cb -> Info .dwSize ))
2295+ return FALSE;
2296+ if (!SetConsoleTextAttribute (g_hConOut , cb -> Info .wAttributes ))
2297+ return FALSE;
2298+
2299+ if (!RestoreScreen )
2300+ {
2301+ /*
2302+ * No need to restore the screen buffer contents, so we're done.
2303+ */
2304+ return TRUE;
2305+ }
2306+
2307+ if (!SetConsoleCursorPosition (g_hConOut , cb -> Info .dwCursorPosition ))
2308+ return FALSE;
2309+ if (!SetConsoleWindowInfo (g_hConOut , TRUE, & cb -> Info .srWindow ))
2310+ return FALSE;
2311+
2312+ /*
2313+ * Restore the screen buffer contents.
2314+ */
2315+ if (cb -> Buffer != NULL )
2316+ {
2317+ BufferCoord .X = 0 ;
2318+ BufferCoord .Y = 0 ;
2319+ WriteRegion .Left = 0 ;
2320+ WriteRegion .Top = 0 ;
2321+ WriteRegion .Right = cb -> Info .dwSize .X - 1 ;
2322+ WriteRegion .Bottom = cb -> Info .dwSize .Y - 1 ;
2323+ if (!WriteConsoleOutput (g_hConOut , /* output handle */
2324+ cb -> Buffer , /* our buffer */
2325+ cb -> BufferSize , /* dimensions of our buffer */
2326+ BufferCoord , /* offset in our buffer */
2327+ & WriteRegion )) /* region to restore */
2328+ {
2329+ return FALSE;
2330+ }
2331+ }
22962332
22972333 return TRUE;
22982334}
22992335
2336+ #define FEAT_RESTORE_ORIG_SCREEN
2337+ #ifdef FEAT_RESTORE_ORIG_SCREEN
2338+ static ConsoleBuffer g_cbOrig = { 0 };
2339+ #endif
23002340static ConsoleBuffer g_cbNonTermcap = { 0 };
23012341static ConsoleBuffer g_cbTermcap = { 0 };
23022342
@@ -2435,6 +2475,9 @@ static DWORD g_cmodeout = 0;
24352475 void
24362476mch_init (void )
24372477{
2478+ #ifndef FEAT_RESTORE_ORIG_SCREEN
2479+ CONSOLE_SCREEN_BUFFER_INFO csbi ;
2480+ #endif
24382481#ifndef __MINGW32__
24392482 extern int _fmode ;
24402483#endif
@@ -2455,14 +2498,16 @@ mch_init(void)
24552498 else
24562499 create_conin ();
24572500 g_hConOut = GetStdHandle (STD_OUTPUT_HANDLE );
2458- g_cbNonTermcap .handle = g_hConOut ;
2459- g_cbTermcap .handle = CreateConsoleScreenBuffer (
2460- GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ | FILE_SHARE_WRITE ,
2461- NULL , CONSOLE_TEXTMODE_BUFFER , NULL );
24622501
2502+ #ifdef FEAT_RESTORE_ORIG_SCREEN
2503+ /* Save the initial console buffer for later restoration */
2504+ SaveConsoleBuffer (& g_cbOrig );
2505+ g_attrCurrent = g_attrDefault = g_cbOrig .Info .wAttributes ;
2506+ #else
24632507 /* Get current text attributes */
2464- SaveConsoleBuffer (& g_cbNonTermcap );
2465- g_attrCurrent = g_attrDefault = g_cbNonTermcap .Info .wAttributes ;
2508+ GetConsoleScreenBufferInfo (g_hConOut , & csbi );
2509+ g_attrCurrent = g_attrDefault = csbi .wAttributes ;
2510+ #endif
24662511 if (cterm_normal_fg_color == 0 )
24672512 cterm_normal_fg_color = (g_attrCurrent & 0xf ) + 1 ;
24682513 if (cterm_normal_bg_color == 0 )
@@ -2562,8 +2607,6 @@ mch_exit(int r)
25622607 SetConsoleMode (g_hConIn , g_cmodein );
25632608 SetConsoleMode (g_hConOut , g_cmodeout );
25642609
2565- CloseHandle (g_cbTermcap .handle );
2566-
25672610#ifdef DYNAMIC_GETTEXT
25682611 dyn_libintl_end ();
25692612#endif
@@ -4585,12 +4628,11 @@ mch_system(char *cmd, int options)
45854628 else
45864629 return mch_system_classic (cmd , options );
45874630}
4588-
45894631#else
45904632
45914633# ifdef FEAT_MBYTE
45924634 static int
4593- mch_system1 (char * cmd , int options )
4635+ mch_system (char * cmd , int options )
45944636{
45954637 if (enc_codepage >= 0 && (int )GetACP () != enc_codepage )
45964638 {
@@ -4605,45 +4647,9 @@ mch_system1(char *cmd, int options)
46054647 return system (cmd );
46064648}
46074649# else
4608- # define mch_system1 (c , o ) system(c)
4650+ # define mch_system (c , o ) system(c)
46094651# endif
46104652
4611- static int
4612- mch_system (char * cmd , int options )
4613- {
4614- int ret ;
4615- HANDLE hTemp = INVALID_HANDLE_VALUE ;
4616-
4617- /*
4618- * Call DuplicateHandle before executing an external program, because msys
4619- * and msys2's programs will call CreateConsoleScreenBuffer and
4620- * CloseHandle. CreateConsoleScreenBuffer returns the same handle which
4621- * created by vim. This causes a crash. This workaround is required on
4622- * Windows7.
4623- */
4624- if (is_win7
4625- && g_fTermcapMode
4626- && DuplicateHandle (
4627- GetCurrentProcess (),
4628- g_hConOut ,
4629- GetCurrentProcess (),
4630- & hTemp ,
4631- 0 ,
4632- TRUE,
4633- DUPLICATE_SAME_ACCESS ))
4634- SetConsoleActiveScreenBuffer (hTemp );
4635-
4636- ret = mch_system1 (cmd , options );
4637-
4638- if (hTemp != INVALID_HANDLE_VALUE )
4639- {
4640- SetConsoleActiveScreenBuffer (g_hConOut );
4641- CloseHandle (hTemp );
4642- }
4643-
4644- return ret ;
4645- }
4646-
46474653#endif
46484654
46494655/*
@@ -4973,8 +4979,6 @@ termcap_mode_start(void)
49734979 * screen buffer, and resize the buffer to match the current window
49744980 * size. We will use this as the size of our editing environment.
49754981 */
4976- g_hConOut = g_cbTermcap .handle ;
4977- SetConsoleActiveScreenBuffer (g_hConOut );
49784982 ClearConsoleBuffer (g_attrCurrent );
49794983 ResizeConBufAndWindow (g_hConOut , Columns , Rows );
49804984 }
@@ -5018,7 +5022,11 @@ termcap_mode_end(void)
50185022 cmodein &= ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT );
50195023 SetConsoleMode (g_hConIn , cmodein );
50205024
5025+ #ifdef FEAT_RESTORE_ORIG_SCREEN
5026+ cb = exiting ? & g_cbOrig : & g_cbNonTermcap ;
5027+ #else
50215028 cb = & g_cbNonTermcap ;
5029+ #endif
50225030 RestoreConsoleBuffer (cb , p_rs );
50235031 SetConsoleCursorInfo (g_hConOut , & g_cci );
50245032
0 commit comments