[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
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)
{
if (ParentWnd->style & WS_CLIPCHILDREN)
@ -81,6 +91,81 @@ IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse)
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
*
@ -166,6 +251,7 @@ IntGetNCUpdateRgn(PWND Window, BOOL Validate)
{
GreDeleteObject(hRgnWindow);
GreDeleteObject(hRgnNonClient);
Window->state &= ~WNDS_UPDATEDIRTY;
return NULL;
}
@ -181,6 +267,7 @@ IntGetNCUpdateRgn(PWND Window, BOOL Validate)
{
IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
GreDeleteObject(Window->hrgnUpdate);
Window->state &= ~WNDS_UPDATEDIRTY;
Window->hrgnUpdate = NULL;
if (!(Window->state & WNDS_INTERNALPAINT))
MsqDecPaintCountQueue(Window->head.pti->MessageQueue);
@ -210,6 +297,8 @@ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
HWND hWnd = Wnd->head.h;
HRGN TempRegion;
Wnd->state &= ~WNDS_PAINTNOTPROCESSED;
if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
{
if (Wnd->hrgnUpdate)
@ -220,20 +309,26 @@ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
if (Flags & RDW_UPDATENOW)
{
if (Wnd->hrgnUpdate != NULL ||
Wnd->state & WNDS_INTERNALPAINT)
if ((Wnd->hrgnUpdate != NULL ||
Wnd->state & WNDS_INTERNALPAINT))
{
Wnd->state2 |= WNDS2_WMPAINTSENT;
co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
}
}
else
else if (Wnd->head.pti == PsGetCurrentThreadWin32Thread())
{
if (Wnd->state & WNDS_SENDNCPAINT)
{
TempRegion = IntGetNCUpdateRgn(Wnd, TRUE);
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)
@ -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
@ -306,6 +405,8 @@ IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
TRACE("IntInvalidateWindows start\n");
Wnd->state |= WNDS_PAINTNOTPROCESSED;
/*
* If the nonclient is not to be redrawn, clip the region to the client
* rect
@ -362,10 +463,14 @@ IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
if (Flags & RDW_INVALIDATE && RgnType != NULLREGION)
{
Wnd->state &= ~WNDS_NONCPAINT;
/* If not the same thread set it dirty. */
if (Wnd->head.pti != PsGetCurrentThreadWin32Thread())
{
Wnd->state |= WNDS_UPDATEDIRTY;
if (Wnd->state2 & WNDS2_WMPAINTSENT)
Wnd->state2 |= WNDS2_ENDPAINTINVALIDATE;
}
if (Flags & RDW_FRAME)
@ -572,6 +677,7 @@ co_UserRedrawWindow(
if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
{
if (Flags & RDW_ERASENOW) IntSendSyncPaint(Window, Flags);
co_IntPaintWindows(Window, Flags, FALSE);
}
@ -853,7 +959,7 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)hRgn, 0);
if (hRgn != HRGN_WINDOW && hRgn != NULL && GreIsHandleValid(hRgn))
{
/* NOTE: The region can already by deleted! */
/* NOTE: The region can already be deleted! */
GreDeleteObject(hRgn);
}
}
@ -928,7 +1034,7 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
CLEANUP:
if (Window) UserDerefObjectCo(Window);
TRACE("Leave NtUserBeginPaint, ret=%i\n",_ret_);
TRACE("Leave NtUserBeginPaint, ret=%p\n",_ret_);
UserLeave();
END_CLEANUP;
@ -1869,11 +1975,13 @@ cleanup:
return Ret;
}
BOOL FASTCALL IntPaintDesktop(HDC hDC);
INT
FASTCALL
UserRealizePalette(HDC hdc)
{
HWND hWnd;
HWND hWnd, hWndDesktop;
DWORD Ret;
Ret = IntGdiRealizePalette(hdc);
@ -1882,6 +1990,15 @@ UserRealizePalette(HDC hdc)
hWnd = IntWindowFromDC(hdc);
if (hWnd) // Send broadcast if dc is associated with a window.
{ // 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);
}
}

View file

@ -1209,13 +1209,20 @@ User32DefWindowProc(HWND hWnd,
case WM_PAINT:
{
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);
if (hDC)
{
HICON hIcon;
if (GetWindowLongPtrW(hWnd, GWL_STYLE) & WS_MINIMIZE &&
(hIcon = (HICON)GetClassLongPtrW(hWnd, GCL_HICON)) != NULL)
if (IsIconic(hWnd) && ((hIcon = (HICON)GetClassLongPtrW( hWnd, GCLP_HICON))))
{
RECT ClientRect;
INT x, y;