ScrollWindow fix for windows with WS_CLIPCHILDREN style, with tests - version 2

Rein Klazes wijn at wanadoo.nl
Wed Mar 30 12:38:57 CST 2005


On 29 Mar 2005 21:03:27 +0200, you wrote:

> Rein Klazes <wijn at wanadoo.nl> writes:
> 
> > windows		: scroll.c
> > dlls/user/tests	: win.c
> > 
> > If ScrollWindowEx is called with SW_SCROLLCHILDREN flags for a window
> > with a WS_CLIPCHILDREN style, then do not use the DCX_USESTYLE flag
> > option to get a DC for this window. With a couple of regression tests.
> 
> DCX_USESTYLE has other effects, is it really correct to disable them
> all? And if so, wouldn't it be better to never use DCX_USESTYLE?

Close inspection today shows that you were correct to be concerned, my
patch relies on a problem with GetDCEx(): it looks like the
DCX_CLIPSIBLINGS flag is always active. 
You can see this by changing the GetDC( hwnd1) in test_scrollvalidate()
to GetDCEx( hwnd1, 0, DCX_CACHE). Under Windows this makes all the tests
depending on the WS_CLIPSIBLINGS fail, under Wine those tests still
succeed.

I cannot use DCX_USESTYLE because there appears not to be something like
a DCX_NOCLIPCHILDREN flag. So here is the next attempt, using the
meaning of DCX_USESTYLE except where I do not need it.

Changelog:

windows		: scroll.c
dlls/user/tests	: win.c

If ScrollWindowEx do not use the DCX_USESTYLE to get a DC. Instead
calculate DCX_CLIPSIBLINGS, DCX_PARENTCLIP and DCX_CLIPCHILDREN. The
DCX_CLIPCHILDREN is not used when ScrollWindowEx is called with a
SW_SCROLLCHILDREN flag. With a couple of regression tests.

Rein.
-------------- next part --------------
--- wine/windows/scroll.c	2005-03-25 20:54:05.000000000 +0100
+++ mywine/windows/scroll.c	2005-03-30 20:25:57.000000000 +0200
@@ -104,10 +104,17 @@ INT WINAPI ScrollWindowEx( HWND hwnd, IN
     else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
 
     if( !IsRectEmpty(&cliprc) && (dx || dy)) {
+        DWORD dcxflags = DCX_CACHE;
+        DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
         caretrc = rc;
         hwndCaret = fix_caret(hwnd, &caretrc, flags);
 
-        hDC = GetDCEx( hwnd, 0, DCX_CACHE | DCX_USESTYLE );
+        if( style & WS_CLIPSIBLINGS) dcxflags |= DCX_CLIPSIBLINGS;
+        if( GetClassLongW( hwnd, GCL_STYLE ) & CS_PARENTDC)
+            dcxflags |= DCX_PARENTCLIP;
+        if( !(flags & SW_SCROLLCHILDREN) && (style & WS_CLIPCHILDREN))
+            dcxflags |= DCX_CLIPCHILDREN;
+        hDC = GetDCEx( hwnd, 0, dcxflags);
         if (hDC)
         {
             ScrollDC( hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate );
--- wine/dlls/user/tests/win.c	2005-03-26 08:11:50.000000000 +0100
+++ mywine/dlls/user/tests/win.c	2005-03-30 20:02:17.000000000 +0200
@@ -2603,12 +2603,14 @@ void test_scrollvalidate( HWND parent)
     /* create two overlapping child windows. The visual region
      * of hwnd1 is clipped by the overlapping part of
      * hwnd2 because of the WS_CLIPSIBLING style */
-    HWND hwnd2 = CreateWindowExA(0, "static", NULL, 
-            WS_CHILD| WS_VISIBLE | WS_CLIPSIBLINGS | WS_BORDER , 
-            75, 30, 100, 100, parent, 0, 0, NULL); 
-    HWND hwnd1 = CreateWindowExA(0, "static", NULL, 
-            WS_CHILD| WS_VISIBLE | WS_CLIPSIBLINGS | WS_BORDER , 
-            25, 50, 100, 100, parent, 0, 0, NULL); 
+    HWND hwnd1, hwnd2;
+
+    hwnd2 = CreateWindowExA(0, "static", NULL,
+            WS_CHILD| WS_VISIBLE | WS_CLIPSIBLINGS | WS_BORDER ,
+            75, 30, 100, 100, parent, 0, 0, NULL);
+    hwnd1 = CreateWindowExA(0, "static", NULL,
+            WS_CHILD| WS_VISIBLE | WS_CLIPSIBLINGS | WS_BORDER ,
+            25, 50, 100, 100, parent, 0, 0, NULL);
     ShowWindow( parent, SW_SHOW);
     UpdateWindow( parent);
     GetClientRect( hwnd1, &rc);
@@ -2642,6 +2644,63 @@ void test_scrollvalidate( HWND parent)
     trace("update rect is %ld,%ld - %ld,%ld\n",
             rcu.left,rcu.top,rcu.right,rcu.bottom);
     ReleaseDC( hwnd1, hdc);
+
+    /* now test ScrollWindowEx with a combination of
+     * WS_CLIPCHILDREN style and SW_SCROLLCHILDREN flag */
+    /* make hwnd2 the child of hwnd1 */
+    DestroyWindow( hwnd2);
+    hwnd2 = CreateWindowExA(0, "static", NULL,
+            WS_CHILD| WS_VISIBLE | WS_BORDER ,
+            50, 50, 100, 100, hwnd1, 0, 0, NULL);
+    SetWindowLong( hwnd1, GWL_STYLE, GetWindowLong( hwnd1, GWL_STYLE) & ~WS_CLIPSIBLINGS);
+    GetClientRect( hwnd1, &rc);
+    cliprc=rc;
+
+    /* WS_CLIPCHILDREN and SW_SCROLLCHILDREN */
+    SetWindowLong( hwnd1, GWL_STYLE, GetWindowLong( hwnd1, GWL_STYLE) | WS_CLIPCHILDREN );
+    ValidateRect( hwnd1, NULL);
+    ValidateRect( hwnd2, NULL);
+    ScrollWindowEx( hwnd1, -10, -10, &rc, &cliprc, hrgn, &rcu,
+      SW_SCROLLCHILDREN | SW_INVALIDATE);
+    if (winetest_debug > 0) dump_region(hrgn);
+    exprgn = CreateRectRgn( 88,0,98,88);
+    tmprgn = CreateRectRgn( 0,88,98,98);
+    CombineRgn( exprgn, exprgn, tmprgn, RGN_OR);
+    ok( EqualRgn( exprgn, hrgn), "wrong update region\n");
+
+    /* SW_SCROLLCHILDREN */
+    SetWindowLong( hwnd1, GWL_STYLE, GetWindowLong( hwnd1, GWL_STYLE) & ~WS_CLIPCHILDREN );
+    ValidateRect( hwnd1, NULL);
+    ValidateRect( hwnd2, NULL);
+    ScrollWindowEx( hwnd1, -10, -10, &rc, &cliprc, hrgn, &rcu, SW_SCROLLCHILDREN | SW_INVALIDATE);
+    if (winetest_debug > 0) dump_region(hrgn);
+    /* expected region is the same as in previous test */
+    ok( EqualRgn( exprgn, hrgn), "wrong update region\n");
+
+    /* no SW_SCROLLCHILDREN */
+    SetWindowLong( hwnd1, GWL_STYLE, GetWindowLong( hwnd1, GWL_STYLE) & ~WS_CLIPCHILDREN );
+    ValidateRect( hwnd1, NULL);
+    ValidateRect( hwnd2, NULL);
+    ScrollWindowEx( hwnd1, -10, -10, &rc, &cliprc, hrgn, &rcu, SW_INVALIDATE);
+    if (winetest_debug > 0) dump_region(hrgn);
+    /* expected region is the same as in previous test */
+    ok( EqualRgn( exprgn, hrgn), "wrong update region\n");
+
+    /* WS_CLIPCHILDREN and no SW_SCROLLCHILDREN */
+    SetWindowLong( hwnd1, GWL_STYLE, GetWindowLong( hwnd1, GWL_STYLE) | WS_CLIPCHILDREN );
+    ValidateRect( hwnd1, NULL);
+    ValidateRect( hwnd2, NULL);
+    ScrollWindowEx( hwnd1, -10, -10, &rc, &cliprc, hrgn, &rcu, SW_INVALIDATE);
+    if (winetest_debug > 0) dump_region(hrgn);
+    exprgn = CreateRectRgn( 88,0,98,20);
+    tmprgn = CreateRectRgn( 20,20,98,30);
+    CombineRgn( exprgn, exprgn, tmprgn, RGN_OR);
+    tmprgn = CreateRectRgn( 20,30,30,88);
+    CombineRgn( exprgn, exprgn, tmprgn, RGN_OR);
+    tmprgn = CreateRectRgn( 0,88,30,98);
+    CombineRgn( exprgn, exprgn, tmprgn, RGN_OR);
+    ok( EqualRgn( exprgn, hrgn), "wrong update region\n");
+
     /* clean up */
     DeleteObject( hrgn);
     DeleteObject( exprgn);
@@ -2711,6 +2770,6 @@ START_TEST(win)
     test_scrollvalidate( hwndMain);
 
     UnhookWindowsHookEx(hhook);
-    
+
     test_window_styles();
 }


More information about the wine-devel mailing list