Mercurial > vim
comparison src/gui_w32.c @ 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 | c19acd92ee83 |
children | 5d8990ad211e |
comparison
equal
deleted
inserted
replaced
22747:609b66f6b6bf | 22748:837983942264 |
---|---|
2984 | 2984 |
2985 InvertRect(s_hdc, &rc); | 2985 InvertRect(s_hdc, &rc); |
2986 } | 2986 } |
2987 | 2987 |
2988 /* | 2988 /* |
2989 * Check if the specified point is on-screen. (multi-monitor aware) | |
2990 */ | |
2991 static BOOL | |
2992 is_point_onscreen(int x, int y) | |
2993 { | |
2994 POINT pt = {x, y}; | |
2995 | |
2996 return MonitorFromPoint(pt, MONITOR_DEFAULTTONULL) != NULL; | |
2997 } | |
2998 | |
2999 /* | |
3000 * Check if the whole area of the specified window is on-screen. | |
3001 * | |
3002 * Note about DirectX: Windows 10 1809 or above no longer maintains image of | |
3003 * the window portion that is off-screen. Scrolling by DWriteContext_Scroll() | |
3004 * only works when the whole window is on-screen. | |
3005 */ | |
3006 static BOOL | |
3007 is_window_onscreen(HWND hwnd) | |
3008 { | |
3009 RECT rc; | |
3010 | |
3011 GetWindowRect(hwnd, &rc); | |
3012 | |
3013 if (!is_point_onscreen(rc.left, rc.top)) | |
3014 return FALSE; | |
3015 if (!is_point_onscreen(rc.left, rc.bottom)) | |
3016 return FALSE; | |
3017 if (!is_point_onscreen(rc.right, rc.top)) | |
3018 return FALSE; | |
3019 if (!is_point_onscreen(rc.right, rc.bottom)) | |
3020 return FALSE; | |
3021 return TRUE; | |
3022 } | |
3023 | |
3024 /* | |
2989 * Return flags used for scrolling. | 3025 * Return flags used for scrolling. |
2990 * The SW_INVALIDATE is required when part of the window is covered or | 3026 * The SW_INVALIDATE is required when part of the window is covered or |
2991 * off-screen. Refer to MS KB Q75236. | 3027 * off-screen. Refer to MS KB Q75236. |
2992 */ | 3028 */ |
2993 static int | 3029 static int |
2994 get_scroll_flags(void) | 3030 get_scroll_flags(void) |
2995 { | 3031 { |
2996 HWND hwnd; | 3032 HWND hwnd; |
2997 RECT rcVim, rcOther, rcDest; | 3033 RECT rcVim, rcOther, rcDest; |
2998 | 3034 |
3035 // Check if the window is (partly) off-screen. | |
3036 if (!is_window_onscreen(s_hwnd)) | |
3037 return SW_INVALIDATE; | |
3038 | |
3039 // Check if there is an window (partly) on top of us. | |
2999 GetWindowRect(s_hwnd, &rcVim); | 3040 GetWindowRect(s_hwnd, &rcVim); |
3000 | |
3001 // Check if the window is partly above or below the screen. We don't care | |
3002 // about partly left or right of the screen, it is not relevant when | |
3003 // scrolling up or down. | |
3004 if (rcVim.top < 0 || rcVim.bottom > GetSystemMetrics(SM_CYFULLSCREEN)) | |
3005 return SW_INVALIDATE; | |
3006 | |
3007 // Check if there is an window (partly) on top of us. | |
3008 for (hwnd = s_hwnd; (hwnd = GetWindow(hwnd, GW_HWNDPREV)) != (HWND)0; ) | 3041 for (hwnd = s_hwnd; (hwnd = GetWindow(hwnd, GW_HWNDPREV)) != (HWND)0; ) |
3009 if (IsWindowVisible(hwnd)) | 3042 if (IsWindowVisible(hwnd)) |
3010 { | 3043 { |
3011 GetWindowRect(hwnd, &rcOther); | 3044 GetWindowRect(hwnd, &rcOther); |
3012 if (IntersectRect(&rcDest, &rcVim, &rcOther)) | 3045 if (IntersectRect(&rcDest, &rcVim, &rcOther)) |
3044 rc.right = FILL_X(gui.scroll_region_right + 1); | 3077 rc.right = FILL_X(gui.scroll_region_right + 1); |
3045 rc.top = FILL_Y(row); | 3078 rc.top = FILL_Y(row); |
3046 rc.bottom = FILL_Y(gui.scroll_region_bot + 1); | 3079 rc.bottom = FILL_Y(gui.scroll_region_bot + 1); |
3047 | 3080 |
3048 #if defined(FEAT_DIRECTX) | 3081 #if defined(FEAT_DIRECTX) |
3049 if (IS_ENABLE_DIRECTX()) | 3082 if (IS_ENABLE_DIRECTX() && is_window_onscreen(s_hwnd)) |
3050 { | 3083 { |
3051 DWriteContext_Scroll(s_dwc, 0, -num_lines * gui.char_height, &rc); | 3084 DWriteContext_Scroll(s_dwc, 0, -num_lines * gui.char_height, &rc); |
3052 DWriteContext_Flush(s_dwc); | |
3053 } | 3085 } |
3054 else | 3086 else |
3055 #endif | 3087 #endif |
3056 { | 3088 { |
3089 #if defined(FEAT_DIRECTX) | |
3090 if (IS_ENABLE_DIRECTX()) | |
3091 DWriteContext_Flush(s_dwc); | |
3092 #endif | |
3057 intel_gpu_workaround(); | 3093 intel_gpu_workaround(); |
3058 ScrollWindowEx(s_textArea, 0, -num_lines * gui.char_height, | 3094 ScrollWindowEx(s_textArea, 0, -num_lines * gui.char_height, |
3059 &rc, &rc, NULL, NULL, get_scroll_flags()); | 3095 &rc, &rc, NULL, NULL, get_scroll_flags()); |
3060 UpdateWindow(s_textArea); | 3096 UpdateWindow(s_textArea); |
3061 } | 3097 } |
3086 rc.right = FILL_X(gui.scroll_region_right + 1); | 3122 rc.right = FILL_X(gui.scroll_region_right + 1); |
3087 rc.top = FILL_Y(row); | 3123 rc.top = FILL_Y(row); |
3088 rc.bottom = FILL_Y(gui.scroll_region_bot + 1); | 3124 rc.bottom = FILL_Y(gui.scroll_region_bot + 1); |
3089 | 3125 |
3090 #if defined(FEAT_DIRECTX) | 3126 #if defined(FEAT_DIRECTX) |
3091 if (IS_ENABLE_DIRECTX()) | 3127 if (IS_ENABLE_DIRECTX() && is_window_onscreen(s_hwnd)) |
3092 { | 3128 { |
3093 DWriteContext_Scroll(s_dwc, 0, num_lines * gui.char_height, &rc); | 3129 DWriteContext_Scroll(s_dwc, 0, num_lines * gui.char_height, &rc); |
3094 DWriteContext_Flush(s_dwc); | |
3095 } | 3130 } |
3096 else | 3131 else |
3097 #endif | 3132 #endif |
3098 { | 3133 { |
3134 #if defined(FEAT_DIRECTX) | |
3135 if (IS_ENABLE_DIRECTX()) | |
3136 DWriteContext_Flush(s_dwc); | |
3137 #endif | |
3099 intel_gpu_workaround(); | 3138 intel_gpu_workaround(); |
3100 // The SW_INVALIDATE is required when part of the window is covered or | 3139 // The SW_INVALIDATE is required when part of the window is covered or |
3101 // off-screen. How do we avoid it when it's not needed? | 3140 // off-screen. How do we avoid it when it's not needed? |
3102 ScrollWindowEx(s_textArea, 0, num_lines * gui.char_height, | 3141 ScrollWindowEx(s_textArea, 0, num_lines * gui.char_height, |
3103 &rc, &rc, NULL, NULL, get_scroll_flags()); | 3142 &rc, &rc, NULL, NULL, get_scroll_flags()); |