changeset 22748:837983942264 v8.2.1922

patch 8.2.1922: Win32: scrolling problems when part of window is off-screen Commit: https://github.com/vim/vim/commit/185577e47e5004a5d08a5405a02ab6a261078e42 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Oct 29 20:08:21 2020 +0100 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)
author Bram Moolenaar <Bram@vim.org>
date Thu, 29 Oct 2020 20:15:04 +0100
parents 609b66f6b6bf
children 9ba58f7e5ae2
files src/gui_w32.c src/version.c
diffstat 2 files changed, 51 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/gui_w32.c
+++ b/src/gui_w32.c
@@ -2986,6 +2986,42 @@ gui_mch_flash(int msec)
 }
 
 /*
+ * 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
  * off-screen. Refer to MS KB Q75236.
@@ -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?
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1922,
+/**/
     1921,
 /**/
     1920,