To: vim_dev@googlegroups.com Subject: Patch 8.2.1922 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.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) Files: src/gui_w32.c *** ../vim-8.2.1921/src/gui_w32.c 2020-09-27 13:16:41.701465056 +0200 --- src/gui_w32.c 2020-10-29 20:06:01.178842454 +0100 *************** *** 2986,2991 **** --- 2986,3027 ---- } /* + * 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,3010 **** 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)) return SW_INVALIDATE; // Check if there is an window (partly) on top of us. for (hwnd = s_hwnd; (hwnd = GetWindow(hwnd, GW_HWNDPREV)) != (HWND)0; ) if (IsWindowVisible(hwnd)) { --- 3032,3043 ---- HWND hwnd; RECT rcVim, rcOther, rcDest; ! // 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,3059 **** rc.bottom = FILL_Y(gui.scroll_region_bot + 1); #if defined(FEAT_DIRECTX) ! if (IS_ENABLE_DIRECTX()) { DWriteContext_Scroll(s_dwc, 0, -num_lines * gui.char_height, &rc); - DWriteContext_Flush(s_dwc); } else #endif { intel_gpu_workaround(); ScrollWindowEx(s_textArea, 0, -num_lines * gui.char_height, &rc, &rc, NULL, NULL, get_scroll_flags()); --- 3079,3095 ---- rc.bottom = FILL_Y(gui.scroll_region_bot + 1); #if defined(FEAT_DIRECTX) ! if (IS_ENABLE_DIRECTX() && is_window_onscreen(s_hwnd)) { DWriteContext_Scroll(s_dwc, 0, -num_lines * gui.char_height, &rc); } 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,3101 **** rc.bottom = FILL_Y(gui.scroll_region_bot + 1); #if defined(FEAT_DIRECTX) ! if (IS_ENABLE_DIRECTX()) { DWriteContext_Scroll(s_dwc, 0, num_lines * gui.char_height, &rc); - DWriteContext_Flush(s_dwc); } else #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? --- 3124,3140 ---- rc.bottom = FILL_Y(gui.scroll_region_bot + 1); #if defined(FEAT_DIRECTX) ! if (IS_ENABLE_DIRECTX() && is_window_onscreen(s_hwnd)) { DWriteContext_Scroll(s_dwc, 0, num_lines * gui.char_height, &rc); } 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? *** ../vim-8.2.1921/src/version.c 2020-10-29 18:57:57.791880416 +0100 --- src/version.c 2020-10-29 20:07:59.262546054 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 1922, /**/ -- hundred-and-one symptoms of being an internet addict: 151. You find yourself engaged to someone you've never actually met, except through e-mail. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///