[Win32SS]

- Paint updates and signaling flags.
- WIP: Implement WM_SYNCPAINT support, for synchronize painting to the top-level windows of other threads.
- Tested with wine tests and passes,
  http://www.winehq.org/pipermail/wine-patches/2012-June/114714.html
  http://www.winehq.org/pipermail/wine-patches/2012-June/114715.html

svn path=/trunk/; revision=56839
This commit is contained in:
James Tabor 2012-07-05 22:04:47 +00:00
parent a117d3a0ca
commit 1e0937de1c
2 changed files with 134 additions and 10 deletions

View file

@ -58,8 +58,18 @@ IntIntersectWithParents(PWND Child, RECTL *WindowRect)
BOOL FASTCALL BOOL FASTCALL
IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse) IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse)
{ {
PWND ParentWnd = Child->spwndParent; PWND ParentWnd = Child;
if (ParentWnd->style & WS_CHILD)
{
do
ParentWnd = ParentWnd->spwndParent;
while (ParentWnd->style & WS_CHILD);
}
// Hax out for drawing issues.
// if (!(ParentWnd->state & WNDS_SYNCPAINTPENDING)) Recurse = FALSE;
ParentWnd = Child->spwndParent;
while (ParentWnd) while (ParentWnd)
{ {
if (ParentWnd->style & WS_CLIPCHILDREN) if (ParentWnd->style & WS_CLIPCHILDREN)
@ -81,6 +91,81 @@ IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse)
return TRUE; return TRUE;
} }
/*
Synchronize painting to the top-level windows of other threads.
*/
VOID FASTCALL
IntSendSyncPaint(PWND Wnd, ULONG Flags)
{
PTHREADINFO ptiCur;
PUSER_MESSAGE_QUEUE MessageQueue;
PUSER_SENT_MESSAGE Message;
PLIST_ENTRY Entry;
BOOL bSend = TRUE;
MessageQueue = Wnd->head.pti->MessageQueue;
ptiCur = PsGetCurrentThreadWin32Thread();
/*
Not the current thread, Wnd is in send Nonclient paint also in send erase background and it is visiable.
*/
if ( Wnd->head.pti != ptiCur &&
Wnd->state & WNDS_SENDNCPAINT &&
Wnd->state & WNDS_SENDERASEBACKGROUND &&
Wnd->style & WS_VISIBLE)
{
// For testing, if you see this, break out the Champagne and have a party!
ERR("SendSyncPaint Wnd in State!\n");
if (!IsListEmpty(&MessageQueue->SentMessagesListHead))
{
// Scan sent queue messages to see if we received sync paint messages.
Entry = MessageQueue->SentMessagesListHead.Flink;
Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
do
{
ERR("LOOP it\n");
if (Message->Msg.message == WM_SYNCPAINT &&
Message->Msg.hwnd == UserHMGetHandle(Wnd))
{ // Already received so exit out.
ERR("SendSyncPaint Found one in the Sent Msg Queue!\n");
bSend = FALSE;
break;
}
Entry = Message->ListEntry.Flink;
Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
}
while (Entry != &MessageQueue->SentMessagesListHead);
}
if (bSend)
{
ERR("Sending WM_SYNCPAINT\n");
// This message has no parameters. But it does! Pass Flags along.
co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SYNCPAINT, Flags, 0);
Wnd->state |= WNDS_SYNCPAINTPENDING;
}
}
// Send to all the children if this is the desktop window.
if ( Wnd == UserGetDesktopWindow() )
{
if ( Flags & RDW_ALLCHILDREN ||
( !(Flags & RDW_NOCHILDREN) && Wnd->style & WS_CLIPCHILDREN))
{
PWND spwndChild = Wnd->spwndChild;
while(spwndChild)
{
if ( spwndChild->style & WS_CHILD &&
spwndChild->head.pti != ptiCur)
{
spwndChild = spwndChild->spwndNext;
continue;
}
IntSendSyncPaint( spwndChild, Flags );
spwndChild = spwndChild->spwndNext;
}
}
}
}
/** /**
* @name IntCalcWindowRgn * @name IntCalcWindowRgn
* *
@ -166,6 +251,7 @@ IntGetNCUpdateRgn(PWND Window, BOOL Validate)
{ {
GreDeleteObject(hRgnWindow); GreDeleteObject(hRgnWindow);
GreDeleteObject(hRgnNonClient); GreDeleteObject(hRgnNonClient);
Window->state &= ~WNDS_UPDATEDIRTY;
return NULL; return NULL;
} }
@ -181,6 +267,7 @@ IntGetNCUpdateRgn(PWND Window, BOOL Validate)
{ {
IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED); IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
GreDeleteObject(Window->hrgnUpdate); GreDeleteObject(Window->hrgnUpdate);
Window->state &= ~WNDS_UPDATEDIRTY;
Window->hrgnUpdate = NULL; Window->hrgnUpdate = NULL;
if (!(Window->state & WNDS_INTERNALPAINT)) if (!(Window->state & WNDS_INTERNALPAINT))
MsqDecPaintCountQueue(Window->head.pti->MessageQueue); MsqDecPaintCountQueue(Window->head.pti->MessageQueue);
@ -210,6 +297,8 @@ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
HWND hWnd = Wnd->head.h; HWND hWnd = Wnd->head.h;
HRGN TempRegion; HRGN TempRegion;
Wnd->state &= ~WNDS_PAINTNOTPROCESSED;
if (Flags & (RDW_ERASENOW | RDW_UPDATENOW)) if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
{ {
if (Wnd->hrgnUpdate) if (Wnd->hrgnUpdate)
@ -220,20 +309,26 @@ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
if (Flags & RDW_UPDATENOW) if (Flags & RDW_UPDATENOW)
{ {
if (Wnd->hrgnUpdate != NULL || if ((Wnd->hrgnUpdate != NULL ||
Wnd->state & WNDS_INTERNALPAINT) Wnd->state & WNDS_INTERNALPAINT))
{ {
Wnd->state2 |= WNDS2_WMPAINTSENT; Wnd->state2 |= WNDS2_WMPAINTSENT;
co_IntSendMessage(hWnd, WM_PAINT, 0, 0); co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
} }
} }
else else if (Wnd->head.pti == PsGetCurrentThreadWin32Thread())
{ {
if (Wnd->state & WNDS_SENDNCPAINT) if (Wnd->state & WNDS_SENDNCPAINT)
{ {
TempRegion = IntGetNCUpdateRgn(Wnd, TRUE); TempRegion = IntGetNCUpdateRgn(Wnd, TRUE);
Wnd->state &= ~WNDS_SENDNCPAINT; Wnd->state &= ~WNDS_SENDNCPAINT;
co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0); if ( Wnd == GetW32ThreadInfo()->MessageQueue->spwndActive &&
!(Wnd->state & WNDS_ACTIVEFRAME))
{
Wnd->state |= WNDS_ACTIVEFRAME;
Wnd->state &= ~WNDS_NONCPAINT;
}
if (TempRegion) co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0);
} }
if (Wnd->state & WNDS_SENDERASEBACKGROUND) if (Wnd->state & WNDS_SENDERASEBACKGROUND)
@ -255,6 +350,10 @@ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
} }
} }
} }
else
{
Wnd->state &= ~(WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
}
/* /*
* Check that the window is still valid at this point * Check that the window is still valid at this point
@ -306,6 +405,8 @@ IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
TRACE("IntInvalidateWindows start\n"); TRACE("IntInvalidateWindows start\n");
Wnd->state |= WNDS_PAINTNOTPROCESSED;
/* /*
* If the nonclient is not to be redrawn, clip the region to the client * If the nonclient is not to be redrawn, clip the region to the client
* rect * rect
@ -362,10 +463,14 @@ IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
if (Flags & RDW_INVALIDATE && RgnType != NULLREGION) if (Flags & RDW_INVALIDATE && RgnType != NULLREGION)
{ {
Wnd->state &= ~WNDS_NONCPAINT;
/* If not the same thread set it dirty. */ /* If not the same thread set it dirty. */
if (Wnd->head.pti != PsGetCurrentThreadWin32Thread()) if (Wnd->head.pti != PsGetCurrentThreadWin32Thread())
{ {
Wnd->state |= WNDS_UPDATEDIRTY; Wnd->state |= WNDS_UPDATEDIRTY;
if (Wnd->state2 & WNDS2_WMPAINTSENT)
Wnd->state2 |= WNDS2_ENDPAINTINVALIDATE;
} }
if (Flags & RDW_FRAME) if (Flags & RDW_FRAME)
@ -572,6 +677,7 @@ co_UserRedrawWindow(
if (Flags & (RDW_ERASENOW | RDW_UPDATENOW)) if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
{ {
if (Flags & RDW_ERASENOW) IntSendSyncPaint(Window, Flags);
co_IntPaintWindows(Window, Flags, FALSE); co_IntPaintWindows(Window, Flags, FALSE);
} }
@ -853,7 +959,7 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)hRgn, 0); co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)hRgn, 0);
if (hRgn != HRGN_WINDOW && hRgn != NULL && GreIsHandleValid(hRgn)) if (hRgn != HRGN_WINDOW && hRgn != NULL && GreIsHandleValid(hRgn))
{ {
/* NOTE: The region can already by deleted! */ /* NOTE: The region can already be deleted! */
GreDeleteObject(hRgn); GreDeleteObject(hRgn);
} }
} }
@ -928,7 +1034,7 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
CLEANUP: CLEANUP:
if (Window) UserDerefObjectCo(Window); if (Window) UserDerefObjectCo(Window);
TRACE("Leave NtUserBeginPaint, ret=%i\n",_ret_); TRACE("Leave NtUserBeginPaint, ret=%p\n",_ret_);
UserLeave(); UserLeave();
END_CLEANUP; END_CLEANUP;
@ -1869,11 +1975,13 @@ cleanup:
return Ret; return Ret;
} }
BOOL FASTCALL IntPaintDesktop(HDC hDC);
INT INT
FASTCALL FASTCALL
UserRealizePalette(HDC hdc) UserRealizePalette(HDC hdc)
{ {
HWND hWnd; HWND hWnd, hWndDesktop;
DWORD Ret; DWORD Ret;
Ret = IntGdiRealizePalette(hdc); Ret = IntGdiRealizePalette(hdc);
@ -1882,6 +1990,15 @@ UserRealizePalette(HDC hdc)
hWnd = IntWindowFromDC(hdc); hWnd = IntWindowFromDC(hdc);
if (hWnd) // Send broadcast if dc is associated with a window. if (hWnd) // Send broadcast if dc is associated with a window.
{ // FYI: Thread locked in CallOneParam. { // FYI: Thread locked in CallOneParam.
hWndDesktop = IntGetDesktopWindow();
if ( hWndDesktop != hWnd )
{
PWND pWnd = UserGetWindowObject(hWndDesktop);
ERR("RealizePalette Desktop.");
hdc = UserGetWindowDC(pWnd);
IntPaintDesktop(hdc);
UserReleaseDC(pWnd,hdc,FALSE);
}
UserSendNotifyMessage((HWND)HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)hWnd, 0); UserSendNotifyMessage((HWND)HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)hWnd, 0);
} }
} }

View file

@ -1209,13 +1209,20 @@ User32DefWindowProc(HWND hWnd,
case WM_PAINT: case WM_PAINT:
{ {
PAINTSTRUCT Ps; PAINTSTRUCT Ps;
/* If already in Paint and Client area is not empty just return. */
if (pWnd->state2 & WNDS2_STARTPAINT && !IsRectEmpty(&pWnd->rcClient))
{
ERR("In Paint and Client area is not empty!\n");
return 0;
}
HDC hDC = BeginPaint(hWnd, &Ps); HDC hDC = BeginPaint(hWnd, &Ps);
if (hDC) if (hDC)
{ {
HICON hIcon; HICON hIcon;
if (GetWindowLongPtrW(hWnd, GWL_STYLE) & WS_MINIMIZE && if (IsIconic(hWnd) && ((hIcon = (HICON)GetClassLongPtrW( hWnd, GCLP_HICON))))
(hIcon = (HICON)GetClassLongPtrW(hWnd, GCL_HICON)) != NULL)
{ {
RECT ClientRect; RECT ClientRect;
INT x, y; INT x, y;