Delay WM_NCPAINT message until the "painter's algorithm" kicks in.
diff --git a/include/win.h b/include/win.h
index 4b0c708..637b90c 100644
--- a/include/win.h
+++ b/include/win.h
@@ -49,6 +49,7 @@
#define RDW_EX_DELETEHRGN 0x0002
#define RDW_EX_XYWINDOW 0x0004
#define RDW_EX_TOPFRAME 0x0010
+#define RDW_EX_DELAY_NCPAINT 0x0020
struct tagCLASS;
struct tagDCE;
@@ -163,6 +164,8 @@
#define UNC_ENTIRE 0x0002
#define UNC_REGION 0x0004
#define UNC_UPDATE 0x0008
+#define UNC_DELAY_NCPAINT 0x0010
+#define UNC_IN_BEGINPAINT 0x0020
/* Window functions */
extern void WIN_Init( void );
diff --git a/windows/painting.c b/windows/painting.c
index 569c3bf..35bb804 100644
--- a/windows/painting.c
+++ b/windows/painting.c
@@ -28,6 +28,84 @@
/***********************************************************************
+ * WIN_HaveToDelayNCPAINT
+ *
+ * Currently, in the Wine painting mechanism, the WM_NCPAINT message
+ * is generated as soon as a region intersecting the non-client area
+ * of a window is invalidated.
+ *
+ * This technique will work fine for all windows whose parents
+ * have the WS_CLIPCHILDREN style. When the parents have that style,
+ * they are not going to override the contents of their children.
+ * However, when the parent doesn't have that style, Windows relies
+ * on a "painter's algorithm" to display the contents of the windows.
+ * That is, windows are painted from back to front. This includes the
+ * non-client area.
+ *
+ * This method looks at the current state of a window to determine
+ * if the sending of the WM_NCPAINT message should be delayed until
+ * the BeginPaint call.
+ *
+ * PARAMS:
+ * wndPtr - A Locked window pointer to the window we're
+ * examining.
+ * uncFlags - This is the flag passed to the WIN_UpdateNCRgn
+ * function. This is a shortcut for the cases when
+ * we already know when to avoid scanning all the
+ * parents of a window. If you already know that this
+ * window's NCPAINT should be delayed, set the
+ * UNC_DELAY_NCPAINT flag for this parameter.
+ *
+ * This shortcut behavior is implemented in the
+ * RDW_Paint() method.
+ *
+ */
+static BOOL WIN_HaveToDelayNCPAINT(
+ WND* wndPtr,
+ UINT uncFlags)
+{
+ WND* parentWnd = NULL;
+
+ /*
+ * Test the shortcut first. (duh)
+ */
+ if (uncFlags & UNC_DELAY_NCPAINT)
+ return TRUE;
+
+ /*
+ * The UNC_IN_BEGINPAINT flag is set in the BeginPaint
+ * method only. This is another shortcut to avoid going
+ * up the parent's chain of the window to finally
+ * figure-out that none of them has an invalid region.
+ */
+ if (uncFlags & UNC_IN_BEGINPAINT)
+ return FALSE;
+
+ /*
+ * Scan all the parents of this window to find a window
+ * that doesn't have the WS_CLIPCHILDREN style and that
+ * has an invalid region.
+ */
+ parentWnd = WIN_LockWndPtr(wndPtr->parent);
+
+ while (parentWnd!=NULL)
+ {
+ if ( ((parentWnd->dwStyle & WS_CLIPCHILDREN) == 0) &&
+ (parentWnd->hrgnUpdate != 0) )
+ {
+ WIN_ReleaseWndPtr(parentWnd);
+ return TRUE;
+ }
+
+ WIN_UpdateWndPtr(&parentWnd, parentWnd->parent);
+ }
+
+ WIN_ReleaseWndPtr(parentWnd);
+
+ return FALSE;
+}
+
+/***********************************************************************
* WIN_UpdateNCRgn
*
* Things to do:
@@ -72,7 +150,11 @@
uncFlags |= UNC_ENTIRE;
}
- if( wnd->flags & WIN_NEEDS_NCPAINT )
+ /*
+ * If the window's non-client area needs to be painted,
+ */
+ if ( ( wnd->flags & WIN_NEEDS_NCPAINT ) &&
+ !WIN_HaveToDelayNCPAINT(wnd, uncFlags) )
{
RECT r2, r3;
@@ -184,7 +266,7 @@
wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
/* send WM_NCPAINT and make sure hrgnUpdate is a valid rgn handle */
- WIN_UpdateNCRgn( wndPtr, 0, UNC_UPDATE );
+ WIN_UpdateNCRgn( wndPtr, 0, UNC_UPDATE | UNC_IN_BEGINPAINT);
/*
* Make sure the window is still a window. All window locks are suspended
@@ -626,6 +708,13 @@
TRACE_(win)("\thwnd %04x [%04x] -> hrgn [%04x], flags [%04x]\n", hWnd, wndPtr->hrgnUpdate, hrgn, flags );
+ /*
+ * Check if this window should delay it's processing of WM_NCPAINT.
+ * See WIN_HaveToDelayNCPAINT for a description of the mechanism
+ */
+ if ((ex & RDW_EX_DELAY_NCPAINT) || WIN_HaveToDelayNCPAINT(wndPtr, 0) )
+ ex |= RDW_EX_DELAY_NCPAINT;
+
if (flags & RDW_UPDATENOW)
{
if (wndPtr->hrgnUpdate) /* wm_painticon wparam is 1 */
@@ -634,8 +723,14 @@
else if ((flags & RDW_ERASENOW) || (ex & RDW_EX_TOPFRAME))
{
UINT dcx = DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN | DCX_WINDOWPAINT | DCX_CACHE;
- HRGN hrgnRet = WIN_UpdateNCRgn( wndPtr, hrgn, UNC_REGION | UNC_CHECK |
- ((ex & RDW_EX_TOPFRAME) ? UNC_ENTIRE : 0) );
+ HRGN hrgnRet;
+
+ hrgnRet = WIN_UpdateNCRgn(wndPtr,
+ hrgn,
+ UNC_REGION | UNC_CHECK |
+ ((ex & RDW_EX_TOPFRAME) ? UNC_ENTIRE : 0) |
+ ((ex & RDW_EX_DELAY_NCPAINT) ? UNC_DELAY_NCPAINT : 0) );
+
if( hrgnRet )
{
if( hrgnRet > 1 ) hrgn = hrgnRet; else hrgnRet = 0; /* entire client */
@@ -678,7 +773,7 @@
if (!IsWindow(wndPtr->hwndSelf)) continue;
if ( (wndPtr->dwStyle & WS_VISIBLE) &&
(wndPtr->hrgnUpdate || (wndPtr->flags & WIN_INTERNAL_PAINT)) )
- hrgn = RDW_Paint( wndPtr, hrgn, flags, ex );
+ hrgn = RDW_Paint( wndPtr, hrgn, flags, ex );
}
WIN_ReleaseWndPtr(wndPtr);
WIN_ReleaseWinArray(list);