Index: ddraw_private.h
===================================================================
RCS file: /home/wine/wine/dlls/ddraw/ddraw_private.h,v
retrieving revision 1.40
diff -u -r1.40 ddraw_private.h
--- ddraw_private.h	15 Sep 2003 20:00:03 -0000	1.40
+++ ddraw_private.h	21 Jan 2004 05:12:34 -0000
@@ -268,7 +268,7 @@
     DDSURFACEDESC2 surface_desc;
 
     HDC hDC;
-    RECT lastlockrect;
+    RECT dirtyrect;
     DWORD lastlocktype;
     BOOL dc_in_use;
 
Index: dsurface/user.c
===================================================================
RCS file: /home/wine/wine/dlls/ddraw/dsurface/user.c,v
retrieving revision 1.15
diff -u -r1.15 user.c
--- dsurface/user.c	6 Nov 2002 19:53:45 -0000	1.15
+++ dsurface/user.c	21 Jan 2004 05:12:38 -0000
@@ -30,6 +30,7 @@
 #include "dsurface/dib.h"
 #include "dsurface/user.h"
 #include "dsurface/wndproc.h"
+#include "limits.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
 
@@ -47,6 +48,8 @@
 #endif
 #ifndef SYNC_UPDATE
 static DWORD CALLBACK User_update_thread(LPVOID);
+BOOL User_get_dirty_rect(IDirectDrawSurfaceImpl* This, RECT* pRect);
+void User_add_dirty_rect(IDirectDrawSurfaceImpl* This, LPCRECT pRect);
 #endif
 static void User_copy_to_screen(IDirectDrawSurfaceImpl* This, LPCRECT rc);
 
@@ -231,12 +234,6 @@
 	User_copy_from_screen(This, pRect);
 #endif
     if (dwFlags & DDLOCK_WAIT) User_DirectDrawSurface_wait_update(This);
-
-    if (pRect) {
-	This->lastlockrect = *pRect;
-    } else {
-	This->lastlockrect.left = This->lastlockrect.right = 0;
-    }
 }
 
 void User_DirectDrawSurface_unlock_update(IDirectDrawSurfaceImpl* This,
@@ -247,8 +244,7 @@
 #ifdef SYNC_UPDATE
 	User_copy_to_screen(This, pRect);
 #else
-	USER_PRIV_VAR(priv, This);
-	SetEvent(priv->user.update_event);
+	User_add_dirty_rect(This, pRect);
 #endif
     }
 }
@@ -276,16 +272,12 @@
 					   DWORD dwStart, DWORD dwCount,
 					   LPPALETTEENTRY palent)
 {
-#ifndef SYNC_UPDATE
-    USER_PRIV_VAR(priv, This);
-#endif
-
     DIB_DirectDrawSurface_update_palette(This, pal, dwStart, dwCount, palent);
     /* FIXME: realize palette on display window */
 
 #ifndef SYNC_UPDATE
     /* with async updates, it's probably cool to force an update */
-    SetEvent(priv->user.update_event);
+    User_add_dirty_rect(This, NULL);
 #endif
 }
 
@@ -316,15 +308,12 @@
 void User_DirectDrawSurface_flip_update(IDirectDrawSurfaceImpl* This, DWORD dwFlags)
 {
 #ifdef SYNC_UPDATE
-    This->lastlockrect.left = This->lastlockrect.right = 0;
     assert(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE);
     User_copy_to_screen(This,NULL);
 #else
-    USER_PRIV_VAR(priv, This);
     assert(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE);
     if (dwFlags & DDFLIP_WAIT) User_DirectDrawSurface_wait_update(This);
-    This->lastlockrect.left = This->lastlockrect.right = 0;
-    SetEvent(priv->user.update_event);
+    User_add_dirty_rect(This, NULL);
 #endif
 }
 
@@ -479,8 +468,40 @@
 #endif
 
 #ifndef SYNC_UPDATE
+BOOL User_get_dirty_rect(IDirectDrawSurfaceImpl* This, RECT* pRect)
+{
+    USER_PRIV_VAR(priv, This);
+    EnterCriticalSection(&priv->user.crit);
+    CopyRect(pRect, &This->dirtyrect);
+    This->dirtyrect.left = This->dirtyrect.right = 0;
+    LeaveCriticalSection(&priv->user.crit);
+    return (IsRectEmpty(pRect) ? FALSE : TRUE);
+}
+
+void User_add_dirty_rect(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
+{
+    USER_PRIV_VAR(priv, This);
+    if ( (pRect != NULL) && IsRectEmpty(pRect) ) return;  /* empty rectangle - nothing to do */
+    EnterCriticalSection(&priv->user.crit);
+    if (pRect)
+    {
+/* TODO: Implement some clever algorithm for dirty rectangles */
+	UnionRect(&This->dirtyrect, &This->dirtyrect, pRect);
+    }
+    else
+    {
+/* NULL passed, entire surface is dirty */
+	This->dirtyrect.left = This->dirtyrect.top = 0;
+	This->dirtyrect.right = This->dirtyrect.bottom = LONG_MAX;
+    }
+    LeaveCriticalSection(&priv->user.crit);
+/* signal update */
+    SetEvent(priv->user.update_event);
+}
+
 static DWORD CALLBACK User_update_thread(LPVOID arg)
 {
+    RECT rect;
     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)arg;
     USER_PRIV_VAR(priv, This);
     volatile HANDLE *pActive = (volatile HANDLE *)&priv->user.update_event;
@@ -518,7 +539,7 @@
 	{
 	    if (*pActive) {
 		priv->user.in_refresh = TRUE;
-		User_copy_to_screen(This, NULL);
+		while (User_get_dirty_rect(This, &rect)) User_copy_to_screen(This, &rect);
 		EnterCriticalSection(&priv->user.crit);
 		priv->user.in_refresh = FALSE;
 		if (priv->user.wait_count)
@@ -577,14 +598,9 @@
 		IntersectRect(&drawrect,&drawrect,&xrc);
 	    }
 	}
-	if (rc)
-	    IntersectRect(&drawrect,&drawrect,rc);
-	else {
-	    /* Only use this if the caller did not pass a rectangle, since
-	     * due to double locking this could be the wrong one ... */
-	    if (This->lastlockrect.left != This->lastlockrect.right)
-		IntersectRect(&drawrect,&drawrect,&This->lastlockrect);
-	}
+
+	if (rc) IntersectRect(&drawrect,&drawrect,rc);
+
 	BitBlt(hDisplayDC,
 		drawrect.left-offset.x, drawrect.top-offset.y,
 		drawrect.right-drawrect.left, drawrect.bottom-drawrect.top,
