summaryrefslogtreecommitdiff
path: root/src/gui_w32.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-10-29 20:08:21 +0100
committerBram Moolenaar <Bram@vim.org>2020-10-29 20:08:21 +0100
commit185577e47e5004a5d08a5405a02ab6a261078e42 (patch)
tree273e1dd88fdee22a0b3998eb5311cf3653b580a4 /src/gui_w32.c
parentdcdd42a8ccb9bafd857735d694b074269f337333 (diff)
downloadvim-git-185577e47e5004a5d08a5405a02ab6a261078e42.tar.gz
patch 8.2.1922: Win32: scrolling problems when part of window is off-screenv8.2.1922
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)
Diffstat (limited to 'src/gui_w32.c')
-rw-r--r--src/gui_w32.c59
1 files changed, 49 insertions, 10 deletions
diff --git a/src/gui_w32.c b/src/gui_w32.c
index 5bc5a3903..b29686144 100644
--- 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?