0
0
mirror of https://github.com/vim/vim.git synced 2025-10-04 05:25:06 -04:00

patch 8.2.1922: Win32: scrolling problems when part of window is off-screen

Problem:    Win32: scrolling doesn't work properly when part of window is
            off-screen.
Solution:   Fall back to GDI scrolling if part of the window is off-screen.
            Handle multi-monitor setup better. (Ken Takata, closes #7219)
This commit is contained in:
Bram Moolenaar
2020-10-29 20:08:21 +01:00
parent dcdd42a8cc
commit 185577e47e
2 changed files with 51 additions and 10 deletions

View File

@@ -2985,6 +2985,42 @@ gui_mch_flash(int msec)
InvertRect(s_hdc, &rc);
}
/*
* Check if the specified point is on-screen. (multi-monitor aware)
*/
static BOOL
is_point_onscreen(int x, int y)
{
POINT pt = {x, y};
return MonitorFromPoint(pt, MONITOR_DEFAULTTONULL) != NULL;
}
/*
* Check if the whole area of the specified window is on-screen.
*
* Note about DirectX: Windows 10 1809 or above no longer maintains image of
* the window portion that is off-screen. Scrolling by DWriteContext_Scroll()
* only works when the whole window is on-screen.
*/
static BOOL
is_window_onscreen(HWND hwnd)
{
RECT rc;
GetWindowRect(hwnd, &rc);
if (!is_point_onscreen(rc.left, rc.top))
return FALSE;
if (!is_point_onscreen(rc.left, rc.bottom))
return FALSE;
if (!is_point_onscreen(rc.right, rc.top))
return FALSE;
if (!is_point_onscreen(rc.right, rc.bottom))
return FALSE;
return TRUE;
}
/*
* Return flags used for scrolling.
* The SW_INVALIDATE is required when part of the window is covered or
@@ -2996,15 +3032,12 @@ get_scroll_flags(void)
HWND hwnd;
RECT rcVim, rcOther, rcDest;
GetWindowRect(s_hwnd, &rcVim);
// Check if the window is partly above or below the screen. We don't care
// about partly left or right of the screen, it is not relevant when
// scrolling up or down.
if (rcVim.top < 0 || rcVim.bottom > GetSystemMetrics(SM_CYFULLSCREEN))
// Check if the window is (partly) off-screen.
if (!is_window_onscreen(s_hwnd))
return SW_INVALIDATE;
// Check if there is an window (partly) on top of us.
GetWindowRect(s_hwnd, &rcVim);
for (hwnd = s_hwnd; (hwnd = GetWindow(hwnd, GW_HWNDPREV)) != (HWND)0; )
if (IsWindowVisible(hwnd))
{
@@ -3046,14 +3079,17 @@ gui_mch_delete_lines(
rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
if (IS_ENABLE_DIRECTX() && is_window_onscreen(s_hwnd))
{
DWriteContext_Scroll(s_dwc, 0, -num_lines * gui.char_height, &rc);
DWriteContext_Flush(s_dwc);
}
else
#endif
{
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
intel_gpu_workaround();
ScrollWindowEx(s_textArea, 0, -num_lines * gui.char_height,
&rc, &rc, NULL, NULL, get_scroll_flags());
@@ -3088,14 +3124,17 @@ gui_mch_insert_lines(
rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
if (IS_ENABLE_DIRECTX() && is_window_onscreen(s_hwnd))
{
DWriteContext_Scroll(s_dwc, 0, num_lines * gui.char_height, &rc);
DWriteContext_Flush(s_dwc);
}
else
#endif
{
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
intel_gpu_workaround();
// The SW_INVALIDATE is required when part of the window is covered or
// off-screen. How do we avoid it when it's not needed?