ScrollWindowEx fix with tests
Rein Klazes
wijn at wanadoo.nl
Tue Feb 8 06:12:14 CST 2005
Hi,
This fixes the endless RedrawWindow looping regression in Xnews. The
looping bug may still be there, this fix addresses the RDW_ERASENOW flag
that was wrongly passed to RedrawWindow.
Contrary to what MSDN documentation suggests, ScrollWindowEx does not
send WM_ERASEBKGND message itself, it merely sets the eraseflag.
One question: the tests show that ScrollWindowEx in windows manages to
move child windows without the WM_POSCHANGING and WM_POSCHANGED
messages, instead it sends in some, but not all, cases a WM_MOVE
message. That does not seem to be possible with SetWindowPos and
friends, how should this be implemented?
Changelog:
windows : scroll.c
dlls/user/tests : msg.c
ScrollWindowEx when called with the SW_ERASE flag does not
send a WM_ERASEBKGND message, it just sets the erase flag.
With some tests that show this behavior.
Rein.
-------------- next part --------------
--- wine/windows/scroll.c 2004-12-09 19:08:50.000000000 +0100
+++ mywine/windows/scroll.c 2005-02-08 12:01:57.000000000 +0100
@@ -75,6 +75,7 @@ INT WINAPI ScrollWindowEx( HWND hwnd, IN
INT retVal = NULLREGION;
BOOL bOwnRgn = TRUE;
BOOL bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
+ int rdw_flags;
HRGN hrgnTemp;
HDC hDC;
RECT rc, cliprc;
@@ -84,6 +85,11 @@ INT WINAPI ScrollWindowEx( HWND hwnd, IN
TRACE( "%p, %d,%d hrgnUpdate=%p rcUpdate = %p %s %04x\n",
hwnd, dx, dy, hrgnUpdate, rcUpdate, wine_dbgstr_rect(rect), flags );
TRACE( "clipRect = %s\n", wine_dbgstr_rect(clipRect));
+ if( flags & ~( SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE))
+ FIXME("some flags (%04x) are unhandled\n", flags);
+
+ rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ?
+ RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE ;
if (!WIN_IsWindowDrawable( hwnd, TRUE )) return ERROR;
hwnd = WIN_GetFullHandle( hwnd );
@@ -109,7 +115,7 @@ INT WINAPI ScrollWindowEx( HWND hwnd, IN
ReleaseDC( hwnd, hDC );
if (!bUpdate)
- RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE );
+ RedrawWindow( hwnd, NULL, hrgnUpdate, rdw_flags);
}
/* Take into account the fact that some damage may have occurred during
@@ -121,7 +127,7 @@ INT WINAPI ScrollWindowEx( HWND hwnd, IN
HRGN hrgnClip = CreateRectRgnIndirect(&cliprc);
OffsetRgn( hrgnTemp, dx, dy );
CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
- RedrawWindow( hwnd, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE );
+ RedrawWindow( hwnd, NULL, hrgnTemp, rdw_flags);
DeleteObject( hrgnClip );
}
DeleteObject( hrgnTemp );
@@ -153,8 +159,7 @@ INT WINAPI ScrollWindowEx( HWND hwnd, IN
}
if( flags & (SW_INVALIDATE | SW_ERASE) )
- RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
- ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
+ RedrawWindow( hwnd, NULL, hrgnUpdate, rdw_flags |
((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ) );
if( hwndCaret ) {
--- wine/dlls/user/tests/msg.c 2005-01-28 17:10:14.000000000 +0100
+++ mywine/dlls/user/tests/msg.c 2005-02-08 11:59:01.000000000 +0100
@@ -5222,6 +5222,72 @@ static void test_set_hook(void)
"unexpected error %ld\n", GetLastError());
}
+static const struct message ScrollWindowPaint1[] = {
+ { WM_PAINT, sent },
+ { WM_ERASEBKGND, sent|beginpaint },
+ { 0 }
+};
+
+static const struct message ScrollWindowPaint2[] = {
+ { WM_PAINT, sent },
+ { 0 }
+};
+
+static void test_scrollwindowex(void)
+{
+ HWND hwnd, hchild;
+ RECT rect={0,0,130,130};
+ MSG msg;
+
+ hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
+ WS_VISIBLE|WS_OVERLAPPEDWINDOW,
+ 100, 100, 200, 200, 0, 0, 0, NULL);
+ ok (hwnd != 0, "Failed to create overlapped window\n");
+ hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
+ WS_VISIBLE|WS_CAPTION|WS_CHILD,
+ 10, 10, 150, 150, hwnd, 0, 0, NULL);
+ ok (hchild != 0, "Failed to create child\n");
+ UpdateWindow(hwnd);
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ flush_sequence();
+
+ /* scroll without the child window */
+ trace("start scroll\n");
+ ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
+ SW_ERASE|SW_INVALIDATE);
+ ok_sequence(WmEmptySeq, "ScrollWindowEx\n", 0);
+ trace("end scroll\n");
+ flush_sequence();
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence(ScrollWindowPaint1, "ScrollWindowEx\n", 0);
+
+ /* Now without the SW_ERASE flag */
+ trace("start scroll\n");
+ ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
+ ok_sequence(WmEmptySeq, "ScrollWindowEx\n", 0);
+ trace("end scroll\n");
+ flush_sequence();
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence(ScrollWindowPaint2, "ScrollWindowEx\n", 0);
+
+ /* now scroll the child window as well */
+ trace("start scroll\n");
+ ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
+ SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
+ todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
+ /* windows sometimes a WM_MOVE */
+ ok_sequence(WmEmptySeq, "ScrollWindowEx\n", 0);
+ }
+ trace("end scroll\n");
+ flush_sequence();
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence(ScrollWindowPaint1, "ScrollWindowEx\n", 0);
+
+ ok(DestroyWindow(hchild), "failed to destroy window\n");
+ ok(DestroyWindow(hwnd), "failed to destroy window\n");
+ flush_sequence();
+}
+
START_TEST(msg)
{
HMODULE user32 = GetModuleHandleA("user32.dll");
@@ -5258,6 +5324,7 @@ START_TEST(msg)
hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
assert(hCBT_hook);
+ test_scrollwindowex();
test_messages();
test_mdi_messages();
test_button_messages();
More information about the wine-patches
mailing list