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());