From: Paul Gofman Subject: [resend PATCH] user32: Set PAINTSTRUCT fErase field depending on the last WM_ERASEBKGND result. Message-Id: <20200407085136.355006-1-gofmanp@gmail.com> Date: Tue, 7 Apr 2020 11:51:36 +0300 Fixes menu update in Diablo 1. Signed-off-by: Paul Gofman --- dlls/user32/painting.c | 26 +++++++++++- dlls/user32/tests/win.c | 94 +++++++++++++++++++++++++++++++++++++++++ dlls/user32/win.h | 1 + 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c index 313c5fa1e6..6ab53a2372 100644 --- a/dlls/user32/painting.c +++ b/dlls/user32/painting.c @@ -725,7 +725,20 @@ static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn, { /* don't erase if the clip box is empty */ if (type != NULLREGION) + { + WND *wnd_ptr; + need_erase = !SendMessageW( hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0 ); + if ((wnd_ptr = WIN_GetPtr( hwnd )) && wnd_ptr != WND_OTHER_PROCESS && wnd_ptr != WND_DESKTOP) + { + if (need_erase) + wnd_ptr->flags |= WIN_PS_NEED_ERASE_BKGND; + else + wnd_ptr->flags &= ~WIN_PS_NEED_ERASE_BKGND; + + WIN_ReleasePtr( wnd_ptr ); + } + } } if (!hdc_ret) release_dc( hwnd, hdc, TRUE ); } @@ -943,6 +956,7 @@ HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps ) BOOL erase; RECT rect; UINT flags = UPDATE_NONCLIENT | UPDATE_ERASE | UPDATE_PAINT | UPDATE_INTERNALPAINT | UPDATE_NOCHILDREN; + WND *wnd_ptr; HideCaret( hwnd ); @@ -957,7 +971,17 @@ HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps ) release_dc( hwnd, hdc, TRUE ); return 0; } - lps->fErase = erase; + + if (!(wnd_ptr = WIN_GetPtr( hwnd )) || wnd_ptr == WND_OTHER_PROCESS || wnd_ptr == WND_DESKTOP) + { + lps->fErase = erase; + } + else + { + lps->fErase = !!(wnd_ptr->flags & WIN_PS_NEED_ERASE_BKGND); + WIN_ReleasePtr( wnd_ptr ); + } + lps->rcPaint = rect; lps->hdc = hdc; return hdc; diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 25d643f54a..c02af08a90 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -11830,6 +11830,99 @@ static void test_other_process_window(const char *argv0) DestroyWindow(hwnd); } +static BOOL test_paintstruct_erase_bkgnd; +static BOOL test_paintstruct_wm_erasebkgnd_received; +static BOOL test_paintstruct_wm_paint_received, test_paintstruct_ferase; + +static LRESULT WINAPI paintstruct_erase_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_ERASEBKGND: + { + test_paintstruct_wm_erasebkgnd_received = TRUE; + return test_paintstruct_erase_bkgnd; + } + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc; + + test_paintstruct_wm_paint_received = TRUE; + hdc = BeginPaint(hwnd, &ps); + ok(!!hdc, "Null hdc.\n"); + test_paintstruct_ferase = ps.fErase; + EndPaint(hwnd, &ps); + return 0; + } + } + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +static void test_paintstruct_erase(void) +{ + WNDCLASSA cls; + HWND hwnd; + BOOL ret; + + cls.style = 0; + cls.lpfnWndProc = paintstruct_erase_window_procA; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(0); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "paintstruct_erase_class"; + ret = RegisterClassA(&cls); + ok(ret, "Failed to register a test class.\n"); + + test_paintstruct_wm_paint_received = test_paintstruct_wm_erasebkgnd_received = FALSE; + test_paintstruct_erase_bkgnd = FALSE; + hwnd = CreateWindowExA(0, "paintstruct_erase_class", NULL, WS_POPUP | WS_VISIBLE, + 100, 100, 100, 100, 0, 0, NULL, NULL); + ok(!!hwnd, "CreateWindowEx failed.\n"); + + flush_events(TRUE); + ok(test_paintstruct_wm_erasebkgnd_received, "WM_ERASEBKGND not received.\n"); + ok(test_paintstruct_wm_paint_received, "WM_PAINT not received.\n"); + ok(test_paintstruct_ferase, "Unexpected fErase %#x.\n", test_paintstruct_ferase); + + test_paintstruct_wm_paint_received = test_paintstruct_wm_erasebkgnd_received = FALSE; + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE); + flush_events(TRUE); + ok(!test_paintstruct_wm_erasebkgnd_received, "WM_ERASEBKGND received.\n"); + ok(test_paintstruct_wm_paint_received, "WM_PAINT not received.\n"); + ok(test_paintstruct_ferase, "Unexpected fErase %#x.\n", test_paintstruct_ferase); + + test_paintstruct_wm_paint_received = test_paintstruct_wm_erasebkgnd_received = FALSE; + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE); + flush_events(TRUE); + ok(!test_paintstruct_wm_erasebkgnd_received, "WM_ERASEBKGND received.\n"); + ok(test_paintstruct_wm_paint_received, "WM_PAINT not received.\n"); + ok(test_paintstruct_ferase, "Unexpected fErase %#x.\n", test_paintstruct_ferase); + + test_paintstruct_erase_bkgnd = TRUE; + test_paintstruct_wm_paint_received = test_paintstruct_wm_erasebkgnd_received = FALSE; + RedrawWindow(hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE); + flush_events(TRUE); + ok(test_paintstruct_wm_erasebkgnd_received, "WM_ERASEBKGND not received.\n"); + ok(test_paintstruct_wm_paint_received, "WM_PAINT not received.\n"); + ok(!test_paintstruct_ferase, "Unexpected fErase %#x.\n", test_paintstruct_ferase); + + test_paintstruct_wm_paint_received = test_paintstruct_wm_erasebkgnd_received = FALSE; + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE); + flush_events(TRUE); + ok(!test_paintstruct_wm_erasebkgnd_received, "WM_ERASEBKGND received.\n"); + ok(test_paintstruct_wm_paint_received, "WM_PAINT not received.\n"); + ok(!test_paintstruct_ferase, "Unexpected fErase %#x.\n", test_paintstruct_ferase); + + DestroyWindow(hwnd); + UnregisterClassA("paintstruct_erase_class", GetModuleHandleA(NULL)); +} + START_TEST(win) { char **argv; @@ -11995,6 +12088,7 @@ START_TEST(win) test_window_placement(); test_arrange_iconic_windows(); test_other_process_window(argv[0]); + test_paintstruct_erase(); /* add the tests above this line */ if (hhook) UnhookWindowsHookEx(hhook); diff --git a/dlls/user32/win.h b/dlls/user32/win.h index 1f51fd6331..eecfa20eea 100644 --- a/dlls/user32/win.h +++ b/dlls/user32/win.h @@ -79,6 +79,7 @@ typedef struct tagWND #define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0020 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */ #define WIN_CHILDREN_MOVED 0x0040 /* children may have moved, ignore stored positions */ #define WIN_HAS_IME_WIN 0x0080 /* the window has been registered with imm32 */ +#define WIN_PS_NEED_ERASE_BKGND 0x0100 /* Need to set fErase in PAINTSTRUCT */ /* Window functions */ extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN; -- 2.25.2