From 1e0937de1caf86ea1b8040534ee0a88da756ea14 Mon Sep 17 00:00:00 2001 From: James Tabor Date: Thu, 5 Jul 2012 22:04:47 +0000 Subject: [PATCH] [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 --- reactos/win32ss/user/ntuser/painting.c | 133 +++++++++++++++++-- reactos/win32ss/user/user32/windows/defwnd.c | 11 +- 2 files changed, 134 insertions(+), 10 deletions(-) diff --git a/reactos/win32ss/user/ntuser/painting.c b/reactos/win32ss/user/ntuser/painting.c index 5c12688599b..b26111b5132 100644 --- a/reactos/win32ss/user/ntuser/painting.c +++ b/reactos/win32ss/user/ntuser/painting.c @@ -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); } } diff --git a/reactos/win32ss/user/user32/windows/defwnd.c b/reactos/win32ss/user/user32/windows/defwnd.c index 7835df6c5ad..dc18842d2a0 100644 --- a/reactos/win32ss/user/user32/windows/defwnd.c +++ b/reactos/win32ss/user/user32/windows/defwnd.c @@ -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;