Skip to content

Commit 4c0aac5

Browse files
committed
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)
1 parent a0f849e commit 4c0aac5

File tree

2 files changed

+130
-120
lines changed

2 files changed

+130
-120
lines changed

src/os_win32.c

Lines changed: 128 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,6 @@ static int suppress_winsize = 1; /* don't fiddle with console */
234234

235235
static char_u *exe_path = NULL;
236236

237-
static BOOL is_win7 = FALSE;
238237
static 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
21902187
SaveConsoleBuffer(
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
23002340
static ConsoleBuffer g_cbNonTermcap = { 0 };
23012341
static ConsoleBuffer g_cbTermcap = { 0 };
23022342

@@ -2435,6 +2475,9 @@ static DWORD g_cmodeout = 0;
24352475
void
24362476
mch_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

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,8 @@ static char *(features[]) =
741741

742742
static int included_patches[] =
743743
{ /* Add new patch number below this line */
744+
/**/
745+
902,
744746
/**/
745747
901,
746748
/**/

0 commit comments

Comments
 (0)