From: Jinoh Kang jinoh.kang.kr@gmail.com
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/user32/tests/msg.c | 278 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 2705914d5e5..67f58032cb3 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -9035,6 +9035,278 @@ static void test_paint_messages(void) DeleteObject( hrgn2 ); }
+static void visualize_region_differences( HWND hwnd, HWND hother, HRGN hrgn_expect, HRGN hrgn_actual ) +{ + HBRUSH b_expectonly, b_actualonly, b_intersect; + HRGN hrgn_intersect; + HWND hchild, hshow, hhide; + HDC hdc, hdctmp; + HBITMAP hbitmap; + MSG msg; + RECT rect; + DWORD start_time, elapsed, timeout = 60 * 1000; + BOOL wait = TRUE, toggle = TRUE; + + b_expectonly = CreateSolidBrush( RGB( 64, 64, 255 )); + b_actualonly = CreateSolidBrush( RGB( 255, 64, 64 )); + b_intersect = CreateSolidBrush( RGB( 159, 64, 159 )); + + hrgn_intersect = CreateRectRgn( 0, 0, 0, 0 ); + CombineRgn( hrgn_intersect, hrgn_expect, hrgn_actual, RGN_AND ); + + GetClientRect( hwnd, &rect ); + hdc = GetDC( hwnd ); + hbitmap = CreateCompatibleBitmap( hdc, rect.right, rect.bottom ); + hdctmp = CreateCompatibleDC( hdc ); + ReleaseDC( hwnd, hdc ); + + SelectObject( hdctmp, hbitmap ); + FillRgn( hdctmp, hrgn_expect, b_expectonly ); + FillRgn( hdctmp, hrgn_actual, b_actualonly ); + FillRgn( hdctmp, hrgn_intersect, b_intersect ); + + DeleteObject( hdctmp ); + DeleteObject( hrgn_intersect ); + DeleteObject( b_intersect ); + DeleteObject( b_actualonly ); + DeleteObject( b_expectonly ); + + hchild = CreateWindowExA( 0, WC_STATICA, "", WS_CHILD | SS_BITMAP, + 0, 0, rect.right, rect.bottom, hwnd, 0, 0, NULL ); + SendMessageA( hchild, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbitmap ); + + hshow = hchild; + hhide = hother; + + start_time = GetTickCount(); + for (;;) + { + if (toggle) + { + HWND htmp; + if (hhide) + { + ShowWindow( hhide, SW_HIDE ); + } + if (hshow) + { + SetWindowPos( hshow, HWND_TOP, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW ); + } + htmp = hshow; + hshow = hhide; + hhide = htmp; + toggle = FALSE; + } + if ((elapsed = GetTickCount() - start_time) >= timeout) + { + break; + } + if (wait) + { + MsgWaitForMultipleObjects( 0, NULL, FALSE, timeout - elapsed, QS_ALLINPUT ); + wait = FALSE; + continue; + } + if (!PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) + { + wait = TRUE; + continue; + } + TranslateMessage( &msg ); + DispatchMessageA( &msg ); + if (msg.message == WM_MOUSEMOVE) + { + start_time = GetTickCount(); + } + else if (msg.message == WM_LBUTTONUP) + { + toggle = TRUE; + } + else if (msg.message == WM_RBUTTONUP) + { + break; + } + } + + DestroyWindow( hchild ); + DeleteObject( hbitmap ); +} + +#define subtest_swp_paint_regions(w,p,c) subtest_swp_paint_regions_(__LINE__,w,p,c) + +static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR parent_class, LPCSTR child_class ) +{ + static const struct exposure_test { + int ex_style, style; + } exposure_tests[] = { + { 0, WS_CLIPCHILDREN }, + { 0, 0 }, + { WS_EX_COMPOSITED, WS_CLIPCHILDREN }, + { WS_EX_COMPOSITED, 0 }, + }; + size_t i; + HWND htoplevel = NULL, hparent, hchild; + RECT rect_old = { 10, 10, 100, 100 }, rect_cli; + HRGN hrgn_clip; + HRGN hrgn_old = CreateRectRgnIndirect( &rect_old ); + HRGN hrgn_new = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_expect = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 ); + int base_style; + BOOL is_composition_possible, has_parentdc_anomaly; + WNDCLASSA parent_wc; + + if (wrap_toplevel) + { + htoplevel = CreateWindowExA( 0, "SimpleWindowClass", "Test toplevel", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 400, 400, 0, 0, 0, NULL ); + ok( htoplevel != 0, "Failed to create top-level window: %lu\n", GetLastError() ); + base_style = WS_CHILD | WS_VISIBLE; + } + else + { + base_style = WS_OVERLAPPEDWINDOW | WS_VISIBLE; + } + + ok( GetClassInfoA( GetModuleHandleA( NULL ), parent_class, &parent_wc ), + "GetClassInfoA failed\n" ); + + is_composition_possible = (base_style & (WS_POPUP|WS_CHILD)) != WS_CHILD || + (parent_wc.style & CS_PARENTDC) == 0; + + has_parentdc_anomaly = (base_style & (WS_POPUP|WS_CHILD)) != WS_CHILD && + (parent_wc.style & CS_PARENTDC) != 0; + + hparent = CreateWindowExA( 0, parent_class, "Test parent", base_style, + 80, 80, 200, 200, htoplevel, 0, 0, NULL ); + ok( hparent != 0, "Creating parent window (%s) returned error %lu\n", + debugstr_a( parent_class ), GetLastError() ); + + hchild = CreateWindowExA( 0, child_class, "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER, + rect_old.left, rect_old.top, + rect_old.right - rect_old.left, rect_old.bottom - rect_old.top, + hparent, 0, 0, NULL ); + ok( hchild != 0, "Creating child window (%s) returned error %lu\n", + debugstr_a( child_class ), GetLastError() ); + + GetClientRect( hparent, &rect_cli ); + hrgn_clip = CreateRectRgnIndirect( &rect_cli ); + + for (i = 0; i < ARRAY_SIZE(exposure_tests); i++) + { + const struct exposure_test *extest = &exposure_tests[i]; + BOOL is_composited = (extest->ex_style & WS_EX_COMPOSITED) != 0; + int delta; + + winetest_push_context( "%d: SetWindowPos redraw #%Id (ex_style = %#x, style = %#x)", + line, i, extest->ex_style, extest->style ); + + SetWindowLongA( hparent, GWL_EXSTYLE, extest->ex_style ); + SetWindowLongA( hparent, GWL_STYLE, base_style | extest->style ); + RedrawWindow( hparent, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME ); + + for (delta = -20; delta <= 20; delta += 20) + { + RECT rect_new = rect_old; + int rgn_equal; + int region_op = (is_composition_possible && is_composited) ? RGN_OR : RGN_DIFF; + + winetest_push_context( "delta = %+d", delta ); + + OffsetRect( &rect_new, delta, delta ); + SetRectRgn( hrgn_new, rect_new.left, rect_new.top, rect_new.right, rect_new.bottom ); + if (EqualRect( &rect_old, &rect_new )) + { + SetRectRgn( hrgn_expect, 0, 0, 0, 0 ); + } + else + { + CombineRgn( hrgn_expect, hrgn_old, hrgn_new, region_op ); + CombineRgn( hrgn_expect, hrgn_expect, hrgn_clip, RGN_AND ); + } + SetRectRgn( hrgn_actual, 0, 0, 0, 0 ); + + SetWindowPos( hchild, 0, + rect_old.left, + rect_old.top, + rect_old.right - rect_old.left, + rect_old.bottom - rect_old.top, + SWP_NOACTIVATE | SWP_NOZORDER ); + + UpdateWindow( hparent ); + flush_events(); + + SetWindowPos( hchild, 0, + rect_new.left, + rect_new.top, + rect_new.right - rect_new.left, + rect_new.bottom - rect_new.top, + SWP_NOACTIVATE | SWP_NOZORDER ); + + ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR, + "GetUpdateRgn shall succeed\n" ); + + rgn_equal = EqualRgn( hrgn_expect, hrgn_actual ); + if (!rgn_equal && broken( has_parentdc_anomaly && is_composited && + LOBYTE(LOWORD(GetVersion())) < 8 ) /* Win7 */) + { + trace( "Forcing composited update region (broken)\n" ); + CombineRgn( hrgn_expect, hrgn_old, hrgn_new, RGN_DIFF ); + CombineRgn( hrgn_expect, hrgn_expect, hrgn_clip, RGN_AND ); + rgn_equal = EqualRgn( hrgn_expect, hrgn_actual ); + } + todo_wine_if( !EqualRect( &rect_old, &rect_new ) && + ((extest->style & WS_CLIPCHILDREN) == 0 || region_op == RGN_OR) ) + ok( !!rgn_equal, "Update region shall match expected region\n" ); + + flush_events(); + + if (!rgn_equal && winetest_debug > 0) + { + printf( "Expected update region: " ); + dump_region( hrgn_expect ); + printf( "Actual update region: " ); + dump_region( hrgn_actual ); + printf( "Old window position: " ); + dump_region( hrgn_old ); + printf( "New window position: " ); + dump_region( hrgn_new ); + + if (winetest_interactive) + { + visualize_region_differences( hparent, hchild, hrgn_expect, hrgn_actual ); + } + } + + winetest_pop_context(); + } + + winetest_pop_context(); + } + + DestroyWindow( hchild ); + DestroyWindow( hparent ); + if (htoplevel) DestroyWindow( htoplevel ); + + DeleteObject( hrgn_actual ); + DeleteObject( hrgn_expect ); + DeleteObject( hrgn_new ); + DeleteObject( hrgn_old ); +} + +static void test_swp_paint_regions(void) +{ + subtest_swp_paint_regions( 1, "SimpleWindowClass", "SimpleWindowClass" ); + subtest_swp_paint_regions( 1, "SimpleWindowClass", "SimpleWindowClassWithParentDC" ); + subtest_swp_paint_regions( 1, "SimpleWindowClassWithParentDC", "SimpleWindowClass" ); + subtest_swp_paint_regions( 1, "SimpleWindowClassWithParentDC", "SimpleWindowClassWithParentDC" ); + subtest_swp_paint_regions( 0, "SimpleWindowClass", "SimpleWindowClass" ); + subtest_swp_paint_regions( 0, "SimpleWindowClass", "SimpleWindowClassWithParentDC" ); + subtest_swp_paint_regions( 0, "SimpleWindowClassWithParentDC", "SimpleWindowClass" ); + subtest_swp_paint_regions( 0, "SimpleWindowClassWithParentDC", "SimpleWindowClassWithParentDC" ); +} + struct wnd_event { HWND hwnd; @@ -10387,6 +10659,11 @@ static BOOL RegisterWindowClasses(void) cls.lpszClassName = "TestDialogClass"; if(!RegisterClassA(&cls)) return FALSE;
+ cls.lpfnWndProc = DefWindowProcA; + cls.style = CS_PARENTDC; + cls.lpszClassName = "SimpleWindowClassWithParentDC"; + if(!RegisterClassA(&cls)) return FALSE; + clsW.style = 0; clsW.lpfnWndProc = MsgCheckProcW; clsW.cbClsExtra = 0; @@ -18870,6 +19147,7 @@ START_TEST(msg) test_combobox_messages(); test_wmime_keydown_message(); test_paint_messages(); + test_swp_paint_regions(); test_interthread_messages(); test_message_conversion(); test_accelerators();