Author: jimtabor Date: Mon Jul 20 19:34:35 2015 New Revision: 68474
URL: http://svn.reactos.org/svn/reactos?rev=68474&view=rev Log: [Win32k] - Improve painting messages, separated functions and dual functions for isolating drawing issues. Next thing to do is fix Set Window Position; Still no SWP_FRAMECHANGED support. - See CORE-7447 for test results.
Modified: trunk/reactos/win32ss/user/ntuser/defwnd.c trunk/reactos/win32ss/user/ntuser/message.c trunk/reactos/win32ss/user/ntuser/painting.c trunk/reactos/win32ss/user/ntuser/painting.h trunk/reactos/win32ss/user/ntuser/simplecall.c trunk/reactos/win32ss/user/ntuser/window.c trunk/reactos/win32ss/user/ntuser/winpos.c trunk/reactos/win32ss/user/ntuser/winpos.h
Modified: trunk/reactos/win32ss/user/ntuser/defwnd.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/defwnd.... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/defwnd.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/defwnd.c [iso-8859-1] Mon Jul 20 19:34:35 2015 @@ -2,7 +2,7 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Win32k subsystem * PURPOSE: Miscellaneous User functions - * FILE: subsystems/win32/win32k/ntuser/defwnd.c + * FILE: win32ss/user/ntuser/defwnd.c * PROGRAMER: */
@@ -638,6 +638,7 @@ }
if ( IntIsWindow(UserHMGetHandle(pwnd)) ) + { if ( iconic ) { /* Single click brings up the system menu when iconized */ @@ -647,6 +648,7 @@ co_IntSendMessage( UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y)); } } + } }
// @@ -773,7 +775,7 @@ { case HTERROR: { - //// This is the real fix for CORE-6129! This was a "Code Whole". + //// This is the real fix for CORE-6129! This was a "Code hole". USER_REFERENCE_ENTRY Ref;
if (Msg == WM_LBUTTONDOWN) @@ -1107,19 +1109,21 @@
case WM_SYNCPAINT: { - PREGION Rgn; + HRGN hRgn; Wnd->state &= ~WNDS_SYNCPAINTPENDING; - ERR("WM_SYNCPAINT\n"); - Rgn = IntSysCreateRectpRgn(0, 0, 0, 0); - if (Rgn) - { - if (co_UserGetUpdateRgn(Wnd, Rgn, FALSE) != NULLREGION) + TRACE("WM_SYNCPAINT\n"); + hRgn = NtGdiCreateRectRgn(0, 0, 0, 0); + if (hRgn) + { + if (co_UserGetUpdateRgn(Wnd, hRgn, FALSE) != NULLREGION) { + PREGION pRgn = REGION_LockRgn(hRgn); + if (pRgn) REGION_UnlockRgn(pRgn); if (!wParam) wParam = (RDW_ERASENOW | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN); - co_UserRedrawWindow(Wnd, NULL, Rgn, wParam); + co_UserRedrawWindow(Wnd, NULL, pRgn, wParam); } - REGION_Delete(Rgn); + GreDeleteObject(hRgn); } return 0; }
Modified: trunk/reactos/win32ss/user/ntuser/message.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/message... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/message.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/message.c [iso-8859-1] Mon Jul 20 19:34:35 2015 @@ -763,14 +763,14 @@ pMsg->lParam, -1);
- if (pMsg->message == WM_PAINT) - { - PREGION Rgn; + if ( pMsg->message == WM_PAINT && + VerifyWnd(Window) && + Window->state & WNDS_PAINTNOTPROCESSED ) // <--- Cleared, paint was already processed! + { Window->state2 &= ~WNDS2_WMPAINTSENT; - /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */ - Rgn = IntSysCreateRectpRgn( 0, 0, 0, 0 ); - co_UserGetUpdateRgn( Window, Rgn, TRUE ); - REGION_Delete(Rgn); + /* send a WM_ERASEBKGND if the non-client area is still invalid */ + ERR("Message WM_PAINT\n"); + co_IntPaintWindows( Window, RDW_NOCHILDREN, FALSE ); }
return retval; @@ -1076,7 +1076,7 @@
co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg);
- if ( bGMSG ) break; + if ( bGMSG || pMsg->message == WM_PAINT) break; }
if ( bGMSG )
Modified: trunk/reactos/win32ss/user/ntuser/painting.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/paintin... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/painting.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/painting.c [iso-8859-1] Mon Jul 20 19:34:35 2015 @@ -2,12 +2,15 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Win32k subsystem * PURPOSE: Window painting function - * FILE: subsystems/win32/win32k/ntuser/painting.c + * FILE: win32ss/user/ntuser/painting.c * PROGRAMER: Filip Navara (xnavara@volny.cz) */
#include <win32k.h> DBG_DEFAULT_CHANNEL(UserPainting); + +#define RDW_CLIPCHILDREN 4096 +#define RDW_NOUPDATEDIRTY 32768
/* PRIVATE FUNCTIONS **********************************************************/
@@ -33,21 +36,21 @@ { PWND ParentWnd;
+ if (Child->ExStyle & WS_EX_REDIRECTED) + return TRUE; + ParentWnd = Child->spwndParent; while (ParentWnd != NULL) { - if (!(ParentWnd->style & WS_VISIBLE) || - (ParentWnd->style & WS_MINIMIZE)) + if (!(ParentWnd->style & WS_VISIBLE) || + (ParentWnd->style & WS_MINIMIZE) || + !RECTL_bIntersectRect(WindowRect, WindowRect, &ParentWnd->rcClient) ) { return FALSE; }
- if (!RECTL_bIntersectRect(WindowRect, WindowRect, &ParentWnd->rcClient)) - { - return FALSE; - } - - /* FIXME: Layered windows. */ + if (ParentWnd->ExStyle & WS_EX_REDIRECTED) + return TRUE;
ParentWnd = ParentWnd->spwndParent; } @@ -56,9 +59,12 @@ }
BOOL FASTCALL -IntValidateParent(PWND Child, PREGION ValidateRgn, BOOL Recurse) -{ +IntValidateParents(PWND Child, BOOL Recurse) +{ + RECTL ParentRect, Rect; + BOOL Start, Ret = TRUE; PWND ParentWnd = Child; + PREGION Rgn = NULL;
if (ParentWnd->style & WS_CHILD) { @@ -66,9 +72,11 @@ ParentWnd = ParentWnd->spwndParent; while (ParentWnd->style & WS_CHILD); } -// Hax out for drawing issues. -// if (!(ParentWnd->state & WNDS_SYNCPAINTPENDING)) Recurse = FALSE; - + + // No pending nonclient paints. + if (!(ParentWnd->state & WNDS_SYNCPAINTPENDING)) Recurse = FALSE; + + Start = TRUE; ParentWnd = Child->spwndParent; while (ParentWnd) { @@ -78,17 +86,43 @@ if (ParentWnd->hrgnUpdate != 0) { if (Recurse) - return FALSE; + { + Ret = FALSE; + break; + } + // Start with child clipping. + if (Start) + { + Start = FALSE; + + Rect = Child->rcWindow; + + if (!IntIntersectWithParents(Child, &Rect)) break; + + Rgn = IntSysCreateRectpRgnIndirect(&Rect); + + if (Child->hrgnClip) + { + PREGION RgnClip = REGION_LockRgn(Child->hrgnClip); + IntGdiCombineRgn(Rgn, Rgn, RgnClip, RGN_AND); + REGION_UnlockRgn(RgnClip); + } + } + + ParentRect = ParentWnd->rcWindow; + + if (!IntIntersectWithParents(ParentWnd, &ParentRect)) break;
IntInvalidateWindows( ParentWnd, - ValidateRgn, - RDW_VALIDATE | RDW_NOCHILDREN); - } - + Rgn, + RDW_VALIDATE | RDW_NOCHILDREN | RDW_NOUPDATEDIRTY); + } ParentWnd = ParentWnd->spwndParent; }
- return TRUE; + if (Rgn) REGION_Delete(Rgn); + + return Ret; }
/* @@ -113,7 +147,7 @@ Wnd->style & WS_VISIBLE) { // For testing, if you see this, break out the Champagne and have a party! - ERR("SendSyncPaint Wnd in State!\n"); + TRACE("SendSyncPaint Wnd in State!\n"); if (!IsListEmpty(&ptiWnd->SentMessagesListHead)) { // Scan sent queue messages to see if we received sync paint messages. @@ -136,7 +170,7 @@ } if (bSend) { - ERR("Sending WM_SYNCPAINT\n"); + TRACE("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; @@ -165,7 +199,7 @@ } }
-/** +/* * @name IntCalcWindowRgn * * Get a window or client region. @@ -207,7 +241,7 @@ return hRgnWindow; }
-/** +/* * @name IntGetNCUpdateRgn * * Get non-client update region of a window and optionally validate it. @@ -227,7 +261,8 @@ { HRGN hRgnNonClient; HRGN hRgnWindow; - UINT RgnType; + UINT RgnType, NcType; + RECT update;
if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW) @@ -250,8 +285,10 @@ return HRGN_WINDOW; }
- RgnType = NtGdiCombineRgn(hRgnNonClient, hRgnNonClient, - hRgnWindow, RGN_DIFF); + NcType = IntGdiGetRgnBox(hRgnNonClient, &update); + + RgnType = NtGdiCombineRgn(hRgnNonClient, hRgnNonClient, hRgnWindow, RGN_DIFF); + if (RgnType == ERROR) { GreDeleteObject(hRgnWindow); @@ -273,8 +310,7 @@
if (Validate) { - if (NtGdiCombineRgn(Window->hrgnUpdate, Window->hrgnUpdate, - hRgnWindow, RGN_AND) == NULLREGION) + if (NtGdiCombineRgn(Window->hrgnUpdate, Window->hrgnUpdate, hRgnWindow, RGN_AND) == NULLREGION) { IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED); GreDeleteObject(Window->hrgnUpdate); @@ -285,6 +321,19 @@ } }
+ /* check if update rgn contains complete nonclient area */ + if (NcType == SIMPLEREGION) + { + RECT window; + IntGetWindowRect( Window, &window ); + + if (IntEqualRect( &window, &update )) + { + GreDeleteObject(hRgnNonClient); + hRgnNonClient = HRGN_WINDOW; + } + } + GreDeleteObject(hRgnWindow);
return hRgnNonClient; @@ -292,6 +341,45 @@ else { return Window->hrgnUpdate; + } +} + +VOID FASTCALL +IntSendNCPaint(PWND pWnd, HRGN hRgn) +{ + pWnd->state &= ~WNDS_SENDNCPAINT; + + if ( pWnd == GetW32ThreadInfo()->MessageQueue->spwndActive && + !(pWnd->state & WNDS_ACTIVEFRAME)) + { + pWnd->state |= WNDS_ACTIVEFRAME; + pWnd->state &= ~WNDS_NONCPAINT; + hRgn = HRGN_WINDOW; + } + + if (pWnd->state2 & WNDS2_FORCEFULLNCPAINTCLIPRGN) + { + pWnd->state2 &= ~WNDS2_FORCEFULLNCPAINTCLIPRGN; + hRgn = HRGN_WINDOW; + } + + if (hRgn) co_IntSendMessage(UserHMGetHandle(pWnd), WM_NCPAINT, (WPARAM)hRgn, 0); +} + +VOID FASTCALL +IntSendChildNCPaint(PWND pWnd) +{ + pWnd = pWnd->spwndChild; + while(pWnd) + { + if (pWnd->hrgnUpdate == NULL && pWnd->state & WNDS_SENDNCPAINT) + { + USER_REFERENCE_ENTRY Ref; + UserRefObjectCo(pWnd, &Ref); + IntSendNCPaint(pWnd, HRGN_WINDOW); + UserDerefObjectCo(pWnd); + } + pWnd = pWnd->spwndNext; } }
@@ -306,72 +394,66 @@ { HDC hDC; HWND hWnd = Wnd->head.h; - HRGN TempRegion; + HRGN TempRegion = NULL;
Wnd->state &= ~WNDS_PAINTNOTPROCESSED;
- if (Flags & (RDW_ERASENOW | RDW_UPDATENOW)) - { - if (Wnd->hrgnUpdate) - { - PREGION RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate); - if (RgnUpdate) - { - if (!IntValidateParent(Wnd, RgnUpdate, Recurse)) - { - REGION_UnlockRgn(RgnUpdate); - return; - } - REGION_UnlockRgn(RgnUpdate); - } - } - - if (Flags & RDW_UPDATENOW) - { - if ((Wnd->hrgnUpdate != NULL || - Wnd->state & WNDS_INTERNALPAINT)) - { - Wnd->state2 |= WNDS2_WMPAINTSENT; - co_IntSendMessage(hWnd, WM_PAINT, 0, 0); - } - } - else if (Wnd->head.pti == PsGetCurrentThreadWin32Thread()) - { - if (Wnd->state & WNDS_SENDNCPAINT) - { - TempRegion = IntGetNCUpdateRgn(Wnd, TRUE); - Wnd->state &= ~WNDS_SENDNCPAINT; - if ( Wnd == GetW32ThreadInfo()->MessageQueue->spwndActive && - !(Wnd->state & WNDS_ACTIVEFRAME)) + if (Wnd->state & WNDS_SENDNCPAINT || + Wnd->state & WNDS_SENDERASEBACKGROUND) + { + if (!(Wnd->style & WS_VISIBLE)) + { + Wnd->state &= ~(WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); + return; + } + else + { + if (Wnd->hrgnUpdate == NULL) + { + Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); + } + + if (Wnd->head.pti == PsGetCurrentThreadWin32Thread()) + { + if (Wnd->state & WNDS_SENDNCPAINT) { - Wnd->state |= WNDS_ACTIVEFRAME; - Wnd->state &= ~WNDS_NONCPAINT; + TempRegion = IntGetNCUpdateRgn(Wnd, TRUE); + + IntSendNCPaint(Wnd, TempRegion); + + if (TempRegion > HRGN_WINDOW && GreIsHandleValid(TempRegion)) + { + /* NOTE: The region can already be deleted! */ + GreDeleteObject(TempRegion); + } } - if (TempRegion) co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0); - } - - if (Wnd->state & WNDS_SENDERASEBACKGROUND) - { - if (Wnd->hrgnUpdate) + + if (Wnd->state & WNDS_SENDERASEBACKGROUND) { - hDC = UserGetDCEx( Wnd, - Wnd->hrgnUpdate, - DCX_CACHE|DCX_USESTYLE|DCX_INTERSECTRGN|DCX_KEEPCLIPRGN); - - Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); - // Kill the loop, so Clear before we send. - if (!co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0)) + PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); + if (Wnd->hrgnUpdate) { - Wnd->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); + hDC = UserGetDCEx( Wnd, + Wnd->hrgnUpdate, + DCX_CACHE|DCX_USESTYLE|DCX_INTERSECTRGN|DCX_KEEPCLIPRGN); + + if (Wnd->head.pti->ppi != pti->ppi) + { + ERR("Sending DC to another Process!!!\n"); + } + + Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); + // Kill the loop, so Clear before we send. + if (!co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0)) + { + Wnd->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); + } + UserReleaseDC(Wnd, hDC, FALSE); } - UserReleaseDC(Wnd, hDC, FALSE); } } - } - } - else - { - Wnd->state &= ~(WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); + + } }
/* @@ -385,19 +467,26 @@ /* * Paint child windows. */ + if (!(Flags & RDW_NOCHILDREN) && !(Wnd->style & WS_MINIMIZE) && - ((Flags & RDW_ALLCHILDREN) || !(Wnd->style & WS_CLIPCHILDREN)) ) + ( Flags & RDW_ALLCHILDREN || + (Flags & RDW_CLIPCHILDREN && Wnd->style & WS_CLIPCHILDREN) ) ) { HWND *List, *phWnd; + PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
if ((List = IntWinListChildren(Wnd))) { - /* FIXME: Handle WS_EX_TRANSPARENT */ for (phWnd = List; *phWnd; ++phWnd) { - Wnd = UserGetWindowObject(*phWnd); - if (Wnd && (Wnd->style & WS_VISIBLE)) + if ((Wnd = UserGetWindowObject(*phWnd)) == NULL) + continue; + + if (Wnd->head.pti != pti && Wnd->style & WS_CHILD) + continue; + + if (Wnd->style & WS_VISIBLE) { USER_REFERENCE_ENTRY Ref; UserRefObjectCo(Wnd, &Ref); @@ -411,10 +500,133 @@ }
/* + * IntUpdateWindows + * + * Internal function used by IntRedrawWindow, simplecall. + */ + +VOID FASTCALL +co_IntUpdateWindows(PWND Wnd, ULONG Flags, BOOL Recurse) +{ + HWND hWnd = Wnd->head.h; + + if ((Wnd->hrgnUpdate != NULL || Wnd->state & WNDS_INTERNALPAINT)) + { + if (Wnd->hrgnUpdate) + { + if (!IntValidateParents(Wnd, Recurse)) + { + return; + } + } + + if (Wnd->state & WNDS_INTERNALPAINT) + { + Wnd->state &= ~WNDS_INTERNALPAINT; + + if (Wnd->hrgnUpdate == NULL) + MsqDecPaintCountQueue(Wnd->head.pti); + } + + Wnd->state |= WNDS_PAINTNOTPROCESSED; + Wnd->state &= ~WNDS_UPDATEDIRTY; + + Wnd->state2 |= WNDS2_WMPAINTSENT; + co_IntSendMessage(hWnd, WM_PAINT, 0, 0); + + if (Wnd->state & WNDS_PAINTNOTPROCESSED) + { + USER_REFERENCE_ENTRY Ref; + UserRefObjectCo(Wnd, &Ref); + co_IntPaintWindows(Wnd, RDW_NOCHILDREN, FALSE); + UserDerefObjectCo(Wnd); + } + } + + // Force flags as a toggle. Fixes msg:test_paint_messages:WmChildPaintNc. + Flags = (Flags & RDW_NOCHILDREN) ? RDW_NOCHILDREN : RDW_ALLCHILDREN; // All children is the default. + + /* + * Update child windows. + */ + + if (!(Flags & RDW_NOCHILDREN) && + Flags & RDW_ALLCHILDREN && + Wnd != UserGetDesktopWindow() ) + { + PWND Child; + + for (Child = Wnd->spwndChild; Child; Child = Child->spwndNext) + { + /* transparent window, check for non-transparent sibling to paint first, then skip it */ + if ( Child->ExStyle & WS_EX_TRANSPARENT && + ( Child->hrgnUpdate != NULL || Child->state & WNDS_INTERNALPAINT ) ) + { + PWND Next = Child->spwndNext; + while (Next) + { + if ( Next->hrgnUpdate != NULL || Next->state & WNDS_INTERNALPAINT ) break; + + Next = Next->spwndNext; + } + + if (Next) continue; + } + + if ( Child->style & WS_VISIBLE) + { + USER_REFERENCE_ENTRY Ref; + UserRefObjectCo(Child, &Ref); + co_IntUpdateWindows(Child, Flags, TRUE); + UserDerefObjectCo(Child); + } + } + } +} + +VOID FASTCALL +UserUpdateWindows(PWND pWnd, ULONG Flags) +{ + // If transparent and any sibling windows below needs to be painted, leave. + if (pWnd->ExStyle & WS_EX_TRANSPARENT) + { + PWND Next = pWnd->spwndNext; + + while(Next) + { + if ( Next->head.pti == pWnd->head.pti && + ( Next->hrgnUpdate != NULL || Next->state & WNDS_INTERNALPAINT) ) + { + return; + } + + Next = Next->spwndNext; + } + } + co_IntUpdateWindows(pWnd, Flags, FALSE); +} + +VOID FASTCALL +UserSyncAndPaintWindows(PWND pWnd, ULONG Flags) +{ + PWND Parent = pWnd; + // Find parent, if it needs to be painted, leave. + while(TRUE) + { + if ((Parent = Parent->spwndParent) == NULL) break; + if ( Parent->style & WS_CLIPCHILDREN ) break; + if ( Parent->hrgnUpdate != NULL || Parent->state & WNDS_INTERNALPAINT ) return; + } + + IntSendSyncPaint(pWnd, Flags); + co_IntPaintWindows(pWnd, Flags, FALSE); +} + +/* * IntInvalidateWindows * * Internal function used by IntRedrawWindow, UserRedrawDesktop, - * co_WinPosSetWindowPos, IntValidateParent, co_UserRedrawWindow. + * co_WinPosSetWindowPos, co_UserRedrawWindow. */ VOID FASTCALL IntInvalidateWindows(PWND Wnd, PREGION Rgn, ULONG Flags) @@ -422,53 +634,58 @@ INT RgnType = NULLREGION; BOOL HadPaintMessage;
- TRACE("IntInvalidateWindows start\n"); - - Wnd->state |= WNDS_PAINTNOTPROCESSED; - - /* - * If the nonclient is not to be redrawn, clip the region to the client - * rect - */ - if (0 != (Flags & RDW_INVALIDATE) && 0 == (Flags & RDW_FRAME)) - { - PREGION RgnClient; - - RgnClient = IntSysCreateRectpRgnIndirect(&Wnd->rcClient); - if (RgnClient) - { - RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClient, RGN_AND); - REGION_Delete(RgnClient); - } - } - - /* - * Clip the given region with window rectangle (or region) - */ - - if (!Wnd->hrgnClip || (Wnd->style & WS_MINIMIZE)) - { - PREGION RgnWindow = IntSysCreateRectpRgnIndirect(&Wnd->rcWindow); - if (RgnWindow) - { - RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnWindow, RGN_AND); - REGION_Delete(RgnWindow); + TRACE("IntInvalidateWindows start Rgn %p\n",Rgn); + + if ( Rgn > PRGN_WINDOW ) + { + /* + * If the nonclient is not to be redrawn, clip the region to the client + * rect + */ + if ((Flags & RDW_INVALIDATE) != 0 && (Flags & RDW_FRAME) == 0) + { + PREGION RgnClient; + + RgnClient = IntSysCreateRectpRgnIndirect(&Wnd->rcClient); + if (RgnClient) + { + RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClient, RGN_AND); + REGION_Delete(RgnClient); + } + } + + /* + * Clip the given region with window rectangle (or region) + */ + + if (!Wnd->hrgnClip || (Wnd->style & WS_MINIMIZE)) + { + PREGION RgnWindow = IntSysCreateRectpRgnIndirect(&Wnd->rcWindow); + if (RgnWindow) + { + RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnWindow, RGN_AND); + REGION_Delete(RgnWindow); + } + } + else + { + PREGION RgnClip = REGION_LockRgn(Wnd->hrgnClip); + if (RgnClip) + { + REGION_bOffsetRgn(Rgn, + -Wnd->rcWindow.left, + -Wnd->rcWindow.top); + RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClip, RGN_AND); + REGION_bOffsetRgn(Rgn, + Wnd->rcWindow.left, + Wnd->rcWindow.top); + REGION_UnlockRgn(RgnClip); + } } } else { - PREGION RgnClip = REGION_LockRgn(Wnd->hrgnClip); - if (RgnClip) - { - REGION_bOffsetRgn(Rgn, - -Wnd->rcWindow.left, - -Wnd->rcWindow.top); - RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClip, RGN_AND); - REGION_bOffsetRgn(Rgn, - Wnd->rcWindow.left, - Wnd->rcWindow.top); - REGION_UnlockRgn(RgnClip); - } + RgnType == NULLREGION; }
/* @@ -489,7 +706,7 @@ Wnd->state |= WNDS_INTERNALPAINT; }
- if (Flags & RDW_INVALIDATE && RgnType != NULLREGION) + if (Flags & RDW_INVALIDATE ) { PREGION RgnUpdate;
@@ -505,47 +722,64 @@
if (Flags & RDW_FRAME) Wnd->state |= WNDS_SENDNCPAINT; + if (Flags & RDW_ERASE) Wnd->state |= WNDS_SENDERASEBACKGROUND;
- if (Wnd->hrgnUpdate == NULL) - { - Wnd->hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0); - IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC); - } - - RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate); - if (RgnUpdate) - { - RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_OR); - REGION_UnlockRgn(RgnUpdate); - if (RgnType == NULLREGION) - { - IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED); - GreDeleteObject(Wnd->hrgnUpdate); - Wnd->hrgnUpdate = NULL; - } - } - Flags |= RDW_FRAME; // For children. - } + if (RgnType != NULLREGION && Rgn > PRGN_WINDOW) + { + if (Wnd->hrgnUpdate == NULL) + { + Wnd->hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0); + IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC); + } + + if (Wnd->hrgnUpdate != HRGN_WINDOW) + { + RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate); + if (RgnUpdate) + { + RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_OR); + REGION_UnlockRgn(RgnUpdate); + if (RgnType == NULLREGION) + { + IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED); + GreDeleteObject(Wnd->hrgnUpdate); + Wnd->hrgnUpdate = NULL; + } + } + } + } + + Flags |= RDW_ERASE|RDW_FRAME; // For children. + + } + + if (!HadPaintMessage && IntIsWindowDirty(Wnd)) + { + MsqIncPaintCountQueue(Wnd->head.pti); + } + } // The following flags are used to validate the window. else if (Flags & (RDW_VALIDATE|RDW_NOINTERNALPAINT|RDW_NOERASE|RDW_NOFRAME)) { - /* FIXME: Handle WNDS_UPDATEDIRTY */ + if (Wnd->state & WNDS_UPDATEDIRTY && !(Flags & RDW_NOUPDATEDIRTY)) + return;
if (Flags & RDW_NOINTERNALPAINT) { Wnd->state &= ~WNDS_INTERNALPAINT; }
- if (Flags & RDW_VALIDATE && RgnType != NULLREGION) + if (Flags & RDW_VALIDATE) { if (Flags & RDW_NOFRAME) Wnd->state &= ~WNDS_SENDNCPAINT; + if (Flags & RDW_NOERASE) Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
- if (Wnd->hrgnUpdate != NULL) + if (Wnd->hrgnUpdate > HRGN_WINDOW && RgnType != NULLREGION && Rgn > PRGN_WINDOW) { PREGION RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate);
@@ -554,7 +788,7 @@ RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_DIFF); REGION_UnlockRgn(RgnUpdate);
- if(RgnType == NULLREGION) + if (RgnType == NULLREGION) { IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED); GreDeleteObject(Wnd->hrgnUpdate); @@ -562,9 +796,16 @@ } } } - + // If update is null, do not erase. if (Wnd->hrgnUpdate == NULL) + { Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); + } + } + + if (HadPaintMessage && !IntIsWindowDirty(Wnd)) + { + MsqDecPaintCountQueue(Wnd->head.pti); } }
@@ -572,9 +813,10 @@ * Process children if needed */
- if (!(Flags & RDW_NOCHILDREN) && !(Wnd->style & WS_MINIMIZE) && + if (!(Flags & RDW_NOCHILDREN) && + !(Wnd->style & WS_MINIMIZE) && ((Flags & RDW_ALLCHILDREN) || !(Wnd->style & WS_CLIPCHILDREN))) - { + { PWND Child;
for (Child = Wnd->spwndChild; Child; Child = Child->spwndNext) @@ -587,24 +829,12 @@ PREGION RgnTemp = IntSysCreateRectpRgn(0, 0, 0, 0); if (RgnTemp) { - IntGdiCombineRgn(RgnTemp, Rgn, 0, RGN_COPY); - IntInvalidateWindows(Child, RgnTemp, Flags); + if (Rgn > PRGN_WINDOW) IntGdiCombineRgn(RgnTemp, Rgn, 0, RGN_COPY); + IntInvalidateWindows(Child, ((Rgn > PRGN_WINDOW)?RgnTemp:Rgn), Flags); REGION_Delete(RgnTemp); } } } - } - - /* - * Fake post paint messages to window message queue if needed - */ - - if (HadPaintMessage != IntIsWindowDirty(Wnd)) - { - if (HadPaintMessage) - MsqDecPaintCountQueue(Wnd->head.pti); - else - MsqIncPaintCountQueue(Wnd->head.pti); } TRACE("IntInvalidateWindows exit\n"); } @@ -652,7 +882,7 @@ ULONG Flags) { PREGION TmpRgn = NULL; - TRACE("co_UserRedrawWindow start\n"); + TRACE("co_UserRedrawWindow start Rgn %p\n",UpdateRgn);
/* * Step 1. @@ -662,6 +892,11 @@ if (!IntIsWindowDrawable(Window)) { return TRUE; // Just do nothing!!! + } + + if (Window == NULL) + { + Window = UserGetDesktopWindow(); }
/* @@ -672,38 +907,59 @@
if (Flags & (RDW_INVALIDATE | RDW_VALIDATE)) // Both are OKAY! { + /* We can't hold lock on GDI objects while doing roundtrips to user mode, + * so use a copy instead */ if (UpdateRgn) { TmpRgn = IntSysCreateRectpRgn(0, 0, 0, 0); - if (IntGdiCombineRgn(TmpRgn, UpdateRgn, NULL, RGN_COPY) == NULLREGION) + + if (UpdateRgn > PRGN_WINDOW) { - REGION_Delete(TmpRgn); - TmpRgn = NULL; + IntGdiCombineRgn(TmpRgn, UpdateRgn, NULL, RGN_COPY); } - else + + if (Window != UserGetDesktopWindow()) { - REGION_bOffsetRgn(TmpRgn, Window->rcClient.left, Window->rcClient.top); + REGION_bOffsetRgn(TmpRgn, Window->rcClient.left, Window->rcClient.top); } } - else if (UpdateRect != NULL) - { - if (!RECTL_bIsEmptyRect(UpdateRect)) - { - TmpRgn = IntSysCreateRectpRgnIndirect(UpdateRect); - REGION_bOffsetRgn(TmpRgn, Window->rcClient.left, Window->rcClient.top); - } - } - else if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) || - (Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME)) - { - if (!RECTL_bIsEmptyRect(&Window->rcWindow)) - TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcWindow); - } else { - if (!RECTL_bIsEmptyRect(&Window->rcClient)) - TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcClient); - } + if (UpdateRect != NULL) + { + if (Window == UserGetDesktopWindow()) + { + TmpRgn = IntSysCreateRectpRgnIndirect(UpdateRect); + } + else + { + TmpRgn = IntSysCreateRectpRgn(Window->rcClient.left + UpdateRect->left, + Window->rcClient.top + UpdateRect->top, + Window->rcClient.left + UpdateRect->right, + Window->rcClient.top + UpdateRect->bottom); + } + } + else + { + if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) || + (Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME)) + { + if (!RECTL_bIsEmptyRect(&Window->rcWindow)) + TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcWindow); + } + else + { + if (!RECTL_bIsEmptyRect(&Window->rcClient)) + TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcClient); + } + } + } + } + + /* Fixes test RDW_INTERNALPAINT behavior */ + if (TmpRgn == NULL) + { + TmpRgn = PRGN_WINDOW; // Need a region so the bits can be set!!! }
/* @@ -722,10 +978,16 @@ * Repaint and erase windows if needed. */
- if (Flags & (RDW_ERASENOW | RDW_UPDATENOW)) - { - if (Flags & RDW_ERASENOW) IntSendSyncPaint(Window, Flags); - co_IntPaintWindows(Window, Flags, FALSE); + if (Flags & RDW_UPDATENOW) + { + UserUpdateWindows(Window, Flags); + } + else if (Flags & RDW_ERASENOW) + { + if ((Flags & (RDW_NOCHILDREN|RDW_ALLCHILDREN)) == 0) + Flags |= RDW_CLIPCHILDREN; + + UserSyncAndPaintWindows(Window, Flags); }
/* @@ -733,7 +995,7 @@ * Cleanup ;-) */
- if (TmpRgn != NULL) + if (TmpRgn > PRGN_WINDOW) { REGION_Delete(TmpRgn); } @@ -750,6 +1012,14 @@ Wnd->state & WNDS_INTERNALPAINT ) ); }
+/* + Conditions to paint any window: + + 1. Update region is not null. + 2. Internal paint flag is set. + 3. Paint count is not zero. + + */ PWND FASTCALL IntFindWindowToRepaint(PWND Window, PTHREADINFO Thread) { @@ -758,27 +1028,28 @@
for (; Window != NULL; Window = Window->spwndNext) { - if (IntWndBelongsToThread(Window, Thread) && - IntIsWindowDirty(Window)) - { - /* Make sure all non-transparent siblings are already drawn. */ - if (Window->ExStyle & WS_EX_TRANSPARENT) - { - for (TempWindow = Window->spwndNext; TempWindow != NULL; - TempWindow = TempWindow->spwndNext) + if (IntWndBelongsToThread(Window, Thread)) + { + if (IntIsWindowDirty(Window)) + { + /* Make sure all non-transparent siblings are already drawn. */ + if (Window->ExStyle & WS_EX_TRANSPARENT) { - if (!(TempWindow->ExStyle & WS_EX_TRANSPARENT) && - IntWndBelongsToThread(TempWindow, Thread) && - IntIsWindowDirty(TempWindow)) + for (TempWindow = Window->spwndNext; TempWindow != NULL; + TempWindow = TempWindow->spwndNext) { - return TempWindow; + if (!(TempWindow->ExStyle & WS_EX_TRANSPARENT) && + IntWndBelongsToThread(TempWindow, Thread) && + IntIsWindowDirty(TempWindow)) + { + return TempWindow; + } } } - } - - return Window; - } - + return Window; + } + } + /* find a child of the specified window that needs repainting */ if (Window->spwndChild) { hChild = IntFindWindowToRepaint(Window->spwndChild, Thread); @@ -798,7 +1069,7 @@ MSG *Message, BOOL Remove) { - PWND PaintWnd; + PWND PaintWnd, StartWnd;
if ((MsgFilterMin != 0 || MsgFilterMax != 0) && (MsgFilterMin > WM_PAINT || MsgFilterMax < WM_PAINT)) @@ -809,19 +1080,26 @@ ERR("WM_PAINT is in a System Thread!\n"); }
- PaintWnd = IntFindWindowToRepaint(UserGetDesktopWindow(), Thread); + StartWnd = UserGetDesktopWindow(); + PaintWnd = IntFindWindowToRepaint(StartWnd, Thread);
Message->hwnd = PaintWnd ? UserHMGetHandle(PaintWnd) : NULL;
- if (Message->hwnd == NULL) - { - ERR("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found! Counts %u\n",Thread->cPaintsReady); - /* Hack to stop spamming the debuglog ! */ + if (Message->hwnd == NULL && Thread->cPaintsReady) + { + // Find note in window.c:"PAINTING BUG". + ERR("WARNING SOMETHING HAS GONE WRONG: Thread marked as containing dirty windows, but no dirty windows found! Counts %u\n",Thread->cPaintsReady); + /* Hack to stop spamming the debug log ! */ Thread->cPaintsReady = 0; return FALSE; }
- if (Window != NULL && PaintWnd != Window) + if (Message->hwnd == NULL) + return FALSE; + + if (!(Window == NULL || + PaintWnd == Window || + IntIsChildWindow(Window, PaintWnd))) /* check that it is a child of the specified parent */ return FALSE;
if (PaintWnd->state & WNDS_INTERNALPAINT) @@ -830,8 +1108,20 @@ if (!PaintWnd->hrgnUpdate) MsqDecPaintCountQueue(Thread); } - PaintWnd->state2 &= ~WNDS2_WMPAINTSENT; + PaintWnd->state2 &= ~WNDS2_STARTPAINT; PaintWnd->state &= ~WNDS_UPDATEDIRTY; + + Window = PaintWnd; + while( Window && Window != UserGetDesktopWindow()) + { + // Role back and check for clip children, do not set if any. + if (Window->spwndParent && !(Window->spwndParent->style & WS_CLIPCHILDREN)) + { + PaintWnd->state2 |= WNDS2_WMPAINTSENT; + } + Window = Window->spwndParent; + } + Message->wParam = Message->lParam = 0; Message->message = WM_PAINT; return TRUE; @@ -915,7 +1205,7 @@ return FALSE;
/* Update the window just incase. */ - co_IntPaintWindows( pwnd, RDW_ERASENOW|RDW_UPDATENOW, FALSE); + co_IntUpdateWindows( pwnd, RDW_ALLCHILDREN, FALSE);
hdcSrc = UserGetDCEx( pwnd, NULL, DCX_CACHE|DCX_WINDOW); /* Print window to printer context. */ @@ -1072,6 +1362,10 @@ HDC FASTCALL IntBeginPaint(PWND Window, PPAINTSTRUCT Ps) { + RECT Rect; + INT type; + BOOL Erase = FALSE; + co_UserHideCaret(Window);
Window->state2 |= WNDS2_STARTPAINT; @@ -1080,36 +1374,50 @@ if (Window->state & WNDS_SENDNCPAINT) { HRGN hRgn; - + // Application can keep update dirty. + do + { + Window->state &= ~WNDS_UPDATEDIRTY; + hRgn = IntGetNCUpdateRgn(Window, FALSE); + IntSendNCPaint(Window, hRgn); + if (hRgn > HRGN_WINDOW && GreIsHandleValid(hRgn)) + { + /* NOTE: The region can already be deleted! */ + GreDeleteObject(hRgn); + } + } + while(Window->state & WNDS_UPDATEDIRTY); + } + else + { Window->state &= ~WNDS_UPDATEDIRTY; - hRgn = IntGetNCUpdateRgn(Window, FALSE); - Window->state &= ~WNDS_SENDNCPAINT; - co_IntSendMessage(UserHMGetHandle(Window), WM_NCPAINT, (WPARAM)hRgn, 0); - if (hRgn != HRGN_WINDOW && hRgn != NULL && GreIsHandleValid(hRgn)) - { - /* NOTE: The region can already be deleted! */ - GreDeleteObject(hRgn); - } - } - else - { - Window->state &= ~WNDS_UPDATEDIRTY; }
RtlZeroMemory(Ps, sizeof(PAINTSTRUCT));
+ if (Window->state2 & WNDS2_ENDPAINTINVALIDATE) + { + ERR("BP: Another thread invalidated this window\n"); + } + Ps->hdc = UserGetDCEx( Window, - Window->hrgnUpdate, - DCX_INTERSECTRGN | DCX_USESTYLE); + Window->hrgnUpdate, + DCX_INTERSECTRGN | DCX_USESTYLE); if (!Ps->hdc) { return NULL; }
+ // If set, always clear flags out due to the conditions later on for sending the message. + if (Window->state & WNDS_SENDERASEBACKGROUND) + { + Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); + Erase = TRUE; + } + if (Window->hrgnUpdate != NULL) { MsqDecPaintCountQueue(Window->head.pti); - GdiGetClipBox(Ps->hdc, &Ps->rcPaint); IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED); /* The region is part of the dc now and belongs to the process! */ Window->hrgnUpdate = NULL; @@ -1118,15 +1426,19 @@ { if (Window->state & WNDS_INTERNALPAINT) MsqDecPaintCountQueue(Window->head.pti); - - IntGetClientRect(Window, &Ps->rcPaint); - } + } + + type = GdiGetClipBox(Ps->hdc, &Ps->rcPaint); + + IntGetClientRect(Window, &Rect);
Window->state &= ~WNDS_INTERNALPAINT;
- if (Window->state & WNDS_SENDERASEBACKGROUND) - { - Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); + if ( Erase && // Set to erase, + type != NULLREGION && // don't erase if the clip box is empty, + (!(Window->pcls->style & CS_PARENTDC) || // not parent dc or + RECTL_bIntersectRect( &Rect, &Rect, &Ps->rcPaint) ) ) // intersecting. + { Ps->fErase = !co_IntSendMessage(UserHMGetHandle(Window), WM_ERASEBKGND, (WPARAM)Ps->hdc, 0); if ( Ps->fErase ) { @@ -1137,18 +1449,9 @@ { Ps->fErase = FALSE; } - if (Window->hrgnUpdate) - { - if (!(Window->style & WS_CLIPCHILDREN)) - { - PWND Child; - for (Child = Window->spwndChild; Child; Child = Child->spwndNext) - { - if (Child->hrgnUpdate == NULL && Child->state & WNDS_SENDNCPAINT) // Helped fixing test_redrawnow. - IntInvalidateWindows(Child, NULL, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN); - } - } - } + + IntSendChildNCPaint(Window); + return Ps->hdc; }
@@ -1160,6 +1463,12 @@ hdc = Ps->hdc;
UserReleaseDC(Wnd, hdc, TRUE); + + if (Wnd->state2 & WNDS2_ENDPAINTINVALIDATE) + { + ERR("EP: Another thread invalidated this window\n"); + Wnd->state2 &= ~WNDS2_ENDPAINTINVALIDATE; + }
Wnd->state2 &= ~(WNDS2_WMPAINTSENT|WNDS2_STARTPAINT);
@@ -1310,40 +1619,130 @@ return Ret; }
+/* + GetUpdateRgn, this fails the same as the old one. + */ INT FASTCALL -co_UserGetUpdateRgn(PWND Window, PREGION Rgn, BOOL bErase) -{ - int RegionType; - RECTL Rect; - PREGION UpdateRgn; - - ASSERT_REFS_CO(Window); - - Window->state &= ~WNDS_UPDATEDIRTY; - - if (Window->hrgnUpdate == NULL) - { - REGION_SetRectRgn(Rgn, 0, 0, 0, 0); - return NULLREGION; - } - - UpdateRgn = REGION_LockRgn(Window->hrgnUpdate); - if (!UpdateRgn) - return ERROR; - - Rect = Window->rcClient; - IntIntersectWithParents(Window, &Rect); - REGION_SetRectRgn(Rgn, Rect.left, Rect.top, Rect.right, Rect.bottom); - RegionType = IntGdiCombineRgn(Rgn, Rgn, UpdateRgn, RGN_AND); - REGION_bOffsetRgn(Rgn, -Window->rcClient.left, -Window->rcClient.top); - REGION_UnlockRgn(UpdateRgn); - - if (bErase && RegionType != NULLREGION && RegionType != ERROR) - { - co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN); - } - +co_UserGetUpdateRgn(PWND Window, HRGN hRgn, BOOL bErase) +{ + int RegionType; + BOOL Type; + RECTL Rect; + + ASSERT_REFS_CO(Window); + + if (bErase) + { + USER_REFERENCE_ENTRY Ref; + UserRefObjectCo(Window, &Ref); + co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE); + UserDerefObjectCo(Window); + } + + Window->state &= ~WNDS_UPDATEDIRTY; + + if (Window->hrgnUpdate == NULL) + { + NtGdiSetRectRgn(hRgn, 0, 0, 0, 0); + return NULLREGION; + } + + Rect = Window->rcClient; + Type = IntIntersectWithParents(Window, &Rect); + + if (Window->hrgnUpdate == HRGN_WINDOW) + { + // Trap it out. + ERR("GURn: Caller is passing Window Region 1\n"); + if (!Type) + { + NtGdiSetRectRgn(hRgn, 0, 0, 0, 0); + return NULLREGION; + } + + RegionType = SIMPLEREGION; + + if (Window != UserGetDesktopWindow()) // Window->fnid == FNID_DESKTOP + { + RECTL_vOffsetRect(&Rect, + -Window->rcClient.left, + -Window->rcClient.top); + } + GreSetRectRgnIndirect(hRgn, &Rect); + } + else + { + HRGN hrgnTemp = GreCreateRectRgnIndirect(&Rect); + + RegionType = NtGdiCombineRgn(hRgn, hrgnTemp, Window->hrgnUpdate, RGN_AND); + + if (RegionType == ERROR || RegionType == NULLREGION) + { + if (hrgnTemp) GreDeleteObject(hrgnTemp); + NtGdiSetRectRgn(hRgn, 0, 0, 0, 0); + return NULLREGION; + } + + if (Window != UserGetDesktopWindow()) // Window->fnid == FNID_DESKTOP + { + NtGdiOffsetRgn(hRgn, + -Window->rcClient.left, + -Window->rcClient.top); + } + if (hrgnTemp) GreDeleteObject(hrgnTemp); + } return RegionType; +} + +BOOL FASTCALL +co_UserGetUpdateRect(PWND Window, PRECT pRect, BOOL bErase) +{ + INT RegionType; + BOOL Ret = TRUE; + + if (bErase) + { + USER_REFERENCE_ENTRY Ref; + UserRefObjectCo(Window, &Ref); + co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE); + UserDerefObjectCo(Window); + } + + Window->state &= ~WNDS_UPDATEDIRTY; + + if (Window->hrgnUpdate == NULL) + { + pRect->left = pRect->top = pRect->right = pRect->bottom = 0; + Ret = FALSE; + } + else + { + /* Get the update region bounding box. */ + if (Window->hrgnUpdate == HRGN_WINDOW) + { + *pRect = Window->rcClient; + ERR("GURt: Caller is retrieving Window Region 1\n"); + } + else + { + RegionType = IntGdiGetRgnBox(Window->hrgnUpdate, pRect); + + if (RegionType != ERROR && RegionType != NULLREGION) + RECTL_bIntersectRect(pRect, pRect, &Window->rcClient); + } + + if (IntIntersectWithParents(Window, pRect)) + { + RECTL_vOffsetRect(pRect, + -Window->rcClient.left, + -Window->rcClient.top); + } + else + { + pRect->left = pRect->top = pRect->right = pRect->bottom = 0; + } + } + return Ret; }
/* @@ -1359,8 +1758,6 @@ DECLARE_RETURN(INT); PWND Window; INT ret; - USER_REFERENCE_ENTRY Ref; - PREGION Rgn = NULL;
TRACE("Enter NtUserGetUpdateRgn\n"); UserEnterExclusive(); @@ -1370,36 +1767,11 @@ RETURN(ERROR); }
- /* Use a system region, we can't hold GDI locks when doing roundtrips to user mode */ - Rgn = IntSysCreateRectpRgn(0, 0, 0, 0); - if (!Rgn) - RETURN(ERROR); - - UserRefObjectCo(Window, &Ref); - ret = co_UserGetUpdateRgn(Window, Rgn, bErase); - UserDerefObjectCo(Window); + ret = co_UserGetUpdateRgn(Window, hRgn, bErase);
RETURN(ret);
CLEANUP: - if (Rgn && (_ret_ != ERROR)) - { - PREGION TheRgn = REGION_LockRgn(hRgn); - if (!TheRgn) - { - EngSetLastError(ERROR_INVALID_HANDLE); - _ret_ = ERROR; - } - else - { - IntGdiCombineRgn(TheRgn, Rgn, NULL, RGN_COPY); - REGION_UnlockRgn(TheRgn); - } - } - - if (Rgn) - REGION_Delete(Rgn); - TRACE("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; @@ -1417,9 +1789,8 @@ { PWND Window; RECTL Rect; - INT RegionType; - PREGION RgnData; NTSTATUS Status; + BOOL Ret; DECLARE_RETURN(BOOL);
TRACE("Enter NtUserGetUpdateRect\n"); @@ -1430,48 +1801,7 @@ RETURN(FALSE); }
- Window->state &= ~WNDS_UPDATEDIRTY; - - if (Window->hrgnUpdate == NULL) - { - Rect.left = Rect.top = Rect.right = Rect.bottom = 0; - } - else - { - /* Get the update region bounding box. */ - if (Window->hrgnUpdate == HRGN_WINDOW) - { - Rect = Window->rcClient; - } - else - { - RgnData = REGION_LockRgn(Window->hrgnUpdate); - ASSERT(RgnData != NULL); - RegionType = REGION_GetRgnBox(RgnData, &Rect); - REGION_UnlockRgn(RgnData); - - if (RegionType != ERROR && RegionType != NULLREGION) - RECTL_bIntersectRect(&Rect, &Rect, &Window->rcClient); - } - - if (IntIntersectWithParents(Window, &Rect)) - { - RECTL_vOffsetRect(&Rect, - -Window->rcClient.left, - -Window->rcClient.top); - } else - { - Rect.left = Rect.top = Rect.right = Rect.bottom = 0; - } - } - - if (bErase && !RECTL_bIsEmptyRect(&Rect)) - { - USER_REFERENCE_ENTRY Ref; - UserRefObjectCo(Window, &Ref); - co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN); - UserDerefObjectCo(Window); - } + Ret = co_UserGetUpdateRect(Window, &Rect, bErase);
if (UnsafeRect != NULL) { @@ -1483,7 +1813,7 @@ } }
- RETURN(!RECTL_bIsEmptyRect(&Rect)); + RETURN(Ret);
CLEANUP: TRACE("Leave NtUserGetUpdateRect, ret=%i\n",_ret_); @@ -1549,27 +1879,22 @@ RETURN( FALSE); }
- /* We can't hold lock on GDI obects while doing roundtrips to user mode, - * so use a copy instead */ - if (hrgnUpdate) - { - PREGION RgnTemp; - - RgnUpdate = IntSysCreateRectpRgn(0, 0, 0, 0); + /* We can't hold lock on GDI objects while doing roundtrips to user mode, + * so it will be copied. + */ + if (hrgnUpdate > HRGN_WINDOW) + { + RgnUpdate = REGION_LockRgn(hrgnUpdate); if (!RgnUpdate) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); RETURN(FALSE); } - - RgnTemp = REGION_LockRgn(hrgnUpdate); - if (!RgnTemp) - { - EngSetLastError(ERROR_INVALID_HANDLE); - RETURN(FALSE); - } - IntGdiCombineRgn(RgnUpdate, RgnTemp, NULL, RGN_COPY); - REGION_UnlockRgn(RgnTemp); + REGION_UnlockRgn(RgnUpdate); + } + else if (hrgnUpdate == HRGN_WINDOW) // Trap it out. + { + ERR("NTRW: Caller is passing Window Region 1\n"); }
UserRefObjectCo(Wnd, &Ref); @@ -1584,11 +1909,48 @@ RETURN( Ret);
CLEANUP: - if (RgnUpdate) - REGION_Delete(RgnUpdate); TRACE("Leave NtUserRedrawWindow, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; +} + +/* + Old GetUpdateRgn, for scrolls, see above note. + */ +INT FASTCALL +co_IntGetUpdateRgn(PWND Window, PREGION Rgn, BOOL bErase) +{ + int RegionType; + RECTL Rect; + PREGION UpdateRgn; + + ASSERT_REFS_CO(Window); + + if (bErase) + { + co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE); + } + + Window->state &= ~WNDS_UPDATEDIRTY; + + if (Window->hrgnUpdate == NULL) + { + REGION_SetRectRgn(Rgn, 0, 0, 0, 0); + return NULLREGION; + } + + UpdateRgn = REGION_LockRgn(Window->hrgnUpdate); + if (!UpdateRgn) + return ERROR; + + Rect = Window->rcClient; + IntIntersectWithParents(Window, &Rect); + REGION_SetRectRgn(Rgn, Rect.left, Rect.top, Rect.right, Rect.bottom); + RegionType = IntGdiCombineRgn(Rgn, Rgn, UpdateRgn, RGN_AND); + REGION_bOffsetRgn(Rgn, -Window->rcClient.left, -Window->rcClient.top); + REGION_UnlockRgn(UpdateRgn); + + return RegionType; }
static @@ -1935,7 +2297,7 @@ RETURN(ERROR); }
- rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ? RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE ; + rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ? RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE ;
rcCaret = rcScroll; hwndCaret = co_IntFixCaret(Window, &rcCaret, flags); @@ -1963,7 +2325,7 @@ RETURN(ERROR); }
- if (co_UserGetUpdateRgn(Window, RgnTemp, FALSE) != NULLREGION) + if (co_IntGetUpdateRgn(Window, RgnTemp, FALSE) != NULLREGION) { PREGION RgnClip = IntSysCreateRectpRgnIndirect(&rcClip); if (RgnClip) @@ -1973,11 +2335,16 @@ RgnWinupd = IntSysCreateRectpRgn( 0, 0, 0, 0); IntGdiCombineRgn( RgnWinupd, RgnTemp, 0, RGN_COPY); } + REGION_bOffsetRgn(RgnTemp, dx, dy); + IntGdiCombineRgn(RgnTemp, RgnTemp, RgnClip, RGN_AND); + if (hrgnUpdate) IntGdiCombineRgn( RgnWinupd, RgnWinupd, RgnTemp, RGN_OR ); + co_UserRedrawWindow(Window, NULL, RgnTemp, rdw_flags ); + REGION_Delete(RgnClip); } } @@ -1990,8 +2357,10 @@ POINT ClientOrigin; USER_REFERENCE_ENTRY WndRef; RECTL rcDummy; + LPARAM lParam;
IntGetClientOrigin(Window, &ClientOrigin); + for (Child = Window->spwndChild; Child; Child = Child->spwndNext) { rcChild = Child->rcWindow; @@ -2000,12 +2369,19 @@ rcChild.right -= ClientOrigin.x; rcChild.bottom -= ClientOrigin.y;
- if (! prcUnsafeScroll || RECTL_bIntersectRect(&rcDummy, &rcChild, &rcScroll)) + if (!prcUnsafeScroll || RECTL_bIntersectRect(&rcDummy, &rcChild, &rcScroll)) { UserRefObjectCo(Child, &WndRef); - co_WinPosSetWindowPos(Child, 0, rcChild.left + dx, rcChild.top + dy, 0, 0, - SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | - SWP_NOREDRAW | SWP_DEFERERASE); + + if (Window->spwndParent == UserGetDesktopWindow()) // Window->spwndParent->fnid == FNID_DESKTOP ) + lParam = MAKELONG(Child->rcClient.left, Child->rcClient.top); + else + lParam = MAKELONG(rcChild.left + dx, rcChild.top + dy); + + /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */ + /* windows sometimes a WM_MOVE */ + co_IntSendMessage(UserHMGetHandle(Child), WM_MOVE, 0, lParam); + UserDerefObjectCo(Child); } } @@ -2013,9 +2389,11 @@
if (flags & (SW_INVALIDATE | SW_ERASE)) { - co_UserRedrawWindow(Window, NULL, RgnUpdate, rdw_flags | - ((flags & SW_ERASE) ? RDW_ERASENOW : 0) | - ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0)); + co_UserRedrawWindow( Window, + NULL, + RgnUpdate, + rdw_flags | /* HACK */ + ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : RDW_NOCHILDREN) ); }
if (hwndCaret && (CaretWnd = UserGetWindowObject(hwndCaret)))
Modified: trunk/reactos/win32ss/user/ntuser/painting.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/paintin... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/painting.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/painting.h [iso-8859-1] Mon Jul 20 19:34:35 2015 @@ -8,13 +8,25 @@ #define FLASHW_KILLSYSTIMER 0x00004000 #define FLASHW_ACTIVE 0x00008000
+#define PRGN_NULL ((PREGION)0) /* NULL empty region */ +#define PRGN_WINDOW ((PREGION)1) /* region from window rcWindow */ +#define PRGN_MONITOR ((PREGION)2) /* region from monitor region. */ + +#define GreCreateRectRgnIndirect(prc) \ + NtGdiCreateRectRgn((prc)->left, (prc)->top, (prc)->right, (prc)->bottom) + +#define GreSetRectRgnIndirect(hRgn, prc) \ + NtGdiSetRectRgn(hRgn, (prc)->left, (prc)->top, (prc)->right, (prc)->bottom); + BOOL FASTCALL co_UserRedrawWindow(PWND Wnd, const RECTL* UpdateRect, PREGION UpdateRgn, ULONG Flags); VOID FASTCALL IntInvalidateWindows(PWND Window, PREGION Rgn, ULONG Flags); BOOL FASTCALL IntGetPaintMessage(PWND Window, UINT MsgFilterMin, UINT MsgFilterMax, PTHREADINFO Thread, MSG *Message, BOOL Remove); INT FASTCALL UserRealizePalette(HDC); -INT FASTCALL co_UserGetUpdateRgn(PWND, PREGION, BOOL); +INT FASTCALL co_UserGetUpdateRgn(PWND, HRGN, BOOL); +BOOL FASTCALL co_UserGetUpdateRect(PWND, PRECT, BOOL); VOID FASTCALL co_IntPaintWindows(PWND Window, ULONG Flags, BOOL Recurse); -BOOL FASTCALL IntValidateParent(PWND Child, PREGION ValidateRgn, BOOL Recurse); +VOID FASTCALL IntSendSyncPaint(PWND, ULONG); +VOID FASTCALL co_IntUpdateWindows(PWND, ULONG, BOOL); BOOL FASTCALL IntIsWindowDirty(PWND); BOOL FASTCALL IntEndPaint(PWND,PPAINTSTRUCT); HDC FASTCALL IntBeginPaint(PWND,PPAINTSTRUCT);
Modified: trunk/reactos/win32ss/user/ntuser/simplecall.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/simplec... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/simplecall.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/simplecall.c [iso-8859-1] Mon Jul 20 19:34:35 2015 @@ -544,7 +544,8 @@ break;
case HWNDLOCK_ROUTINE_UPDATEWINDOW: - Ret = co_UserRedrawWindow( Window, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN); + co_IntUpdateWindows(Window, RDW_ALLCHILDREN, FALSE); + Ret = TRUE; break; }
Modified: trunk/reactos/win32ss/user/ntuser/window.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/window.... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/window.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/window.c [iso-8859-1] Mon Jul 20 19:34:35 2015 @@ -2,7 +2,7 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Win32k subsystem * PURPOSE: Windows - * FILE: subsystems/win32/win32k/ntuser/window.c + * FILE: win32ss/user/ntuser/window.c * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) */
@@ -570,6 +570,23 @@ if (ThreadData->MessageQueue->spwndCapture == Window) { IntReleaseCapture(); + } + + //// Now kill those remaining "PAINTING BUG: Thread marked as containing dirty windows" spam!!! + if ( Window->hrgnUpdate != NULL || Window->state & WNDS_INTERNALPAINT ) + { + MsqDecPaintCountQueue(Window->head.pti); + if (Window->hrgnUpdate > HRGN_WINDOW && GreIsHandleValid(Window->hrgnUpdate)) + { + GreDeleteObject(Window->hrgnUpdate); + } + Window->hrgnUpdate = NULL; + Window->state &= ~WNDS_INTERNALPAINT; + } + + if (Window->state & (WNDS_SENDERASEBACKGROUND|WNDS_SENDNCPAINT)) + { + Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_SENDNCPAINT); }
if ( ((Window->style & (WS_CHILD|WS_POPUP)) != WS_CHILD) &&
Modified: trunk/reactos/win32ss/user/ntuser/winpos.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/winpos.... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/winpos.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/winpos.c [iso-8859-1] Mon Jul 20 19:34:35 2015 @@ -2,7 +2,7 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: Windows - * FILE: subsystems/win32/win32k/ntuser/window.c + * FILE: win32ss/user/ntuser/window.c * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) */
@@ -81,6 +81,29 @@ */ } } + +BOOL FASTCALL +IntGetWindowRect(PWND Wnd, RECTL *Rect) +{ + ASSERT( Wnd ); + ASSERT( Rect ); + if (!Wnd) return FALSE; + if ( Wnd != UserGetDesktopWindow()) // Wnd->fnid != FNID_DESKTOP ) + { + *Rect = Wnd->rcWindow; + } + else + { + Rect->left = Rect->top = 0; + Rect->right = Wnd->rcWindow.right; + Rect->bottom = Wnd->rcWindow.bottom; +/* Do this until Init bug is fixed. This sets 640x480, see InitMetrics. + Rect->right = GetSystemMetrics(SM_CXSCREEN); + Rect->bottom = GetSystemMetrics(SM_CYSCREEN); +*/ } + return TRUE; +} +
INT FASTCALL IntMapWindowPoints(PWND FromWnd, PWND ToWnd, LPPOINT lpPoints, UINT cPoints) @@ -1099,6 +1122,38 @@ }
static +BOOL +IntValidateParent(PWND Child, PREGION ValidateRgn) +{ + PWND ParentWnd = Child; + + if (ParentWnd->style & WS_CHILD) + { + do + ParentWnd = ParentWnd->spwndParent; + while (ParentWnd->style & WS_CHILD); + } + + ParentWnd = Child->spwndParent; + while (ParentWnd) + { + if (ParentWnd->style & WS_CLIPCHILDREN) + break; + + if (ParentWnd->hrgnUpdate != 0) + { + IntInvalidateWindows( ParentWnd, + ValidateRgn, + RDW_VALIDATE | RDW_NOCHILDREN); + } + + ParentWnd = ParentWnd->spwndParent; + } + + return TRUE; +} + +static VOID FASTCALL FixClientRect(PRECTL ClientRect, PRECTL WindowRect) { @@ -1320,8 +1375,6 @@ } }
- WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE; - if (!(WinPos->flags & SWP_NOMOVE)) { INT X, Y; @@ -1331,9 +1384,6 @@
Parent = Window->spwndParent;
- // Fix wine msg test_SetParent:WmSetParentSeq_2:19 wParam bits. - WinPos->flags &= ~SWP_NOCLIENTMOVE; - // Parent child position issue is in here. SetParent_W7 test CORE-6651. if (//((Window->style & WS_CHILD) != 0) && <- Fixes wine msg test_SetParent: "rects do not match", the last test. Parent && @@ -1353,6 +1403,7 @@ RECTL_vOffsetRect(ClientRect, X - Window->rcWindow.left, Y - Window->rcWindow.top); } + WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n", WinPos->hwnd, WinPos->hwndInsertAfter, WinPos->x, WinPos->y, @@ -1387,7 +1438,6 @@
TRACE("(%p) hInsertAfter = %p\n", Window, hWndInsertAfter );
- Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL; Style = Window->style;
if (Style & WS_CHILD) @@ -1395,6 +1445,8 @@ TRACE("Window is child\n"); return hWndInsertAfter; } + + Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
if (Owner) { @@ -1438,7 +1490,7 @@
if (hWndInsertAfter == HWND_BOTTOM) { - ERR("Window is HWND_BOTTOM\n"); + ERR("Window is HWND_BOTTOM hwnd %p\n",hWndInsertAfter); if (List) ExFreePoolWithTag(List, USERTAG_WINDOWLIST); goto done; } @@ -1981,7 +2033,7 @@ 0);
UserReleaseDC(Window, Dc, FALSE); - IntValidateParent(Window, CopyRgn, FALSE); + IntValidateParent(Window, CopyRgn); GreDeleteObject(DcRgn); } } @@ -2004,6 +2056,7 @@ { RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY); } + if (RgnType != ERROR && RgnType != NULLREGION) { /* old code @@ -2017,23 +2070,16 @@
PWND Parent = Window->spwndParent;
- REGION_bOffsetRgn( DirtyRgn, - Window->rcWindow.left, - Window->rcWindow.top); - if ( (Window->style & WS_CHILD) && - (Parent) && - !(Parent->style & WS_CLIPCHILDREN)) + REGION_bOffsetRgn( DirtyRgn, Window->rcWindow.left, Window->rcWindow.top); + + if ( (Window->style & WS_CHILD) && (Parent) && !(Parent->style & WS_CLIPCHILDREN)) { - IntInvalidateWindows( Parent, - DirtyRgn, - RDW_ERASE | RDW_INVALIDATE); - co_IntPaintWindows(Parent, RDW_ERASENOW, FALSE); + IntInvalidateWindows( Parent, DirtyRgn, RDW_ERASE | RDW_INVALIDATE); + co_IntPaintWindows(Parent, RDW_NOCHILDREN, FALSE); } else { - IntInvalidateWindows( Window, - DirtyRgn, - RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); + IntInvalidateWindows( Window, DirtyRgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); } } REGION_Delete(DirtyRgn);
Modified: trunk/reactos/win32ss/user/ntuser/winpos.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/winpos.... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/winpos.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/winpos.h [iso-8859-1] Mon Jul 20 19:34:35 2015 @@ -44,6 +44,16 @@ y - pwnd->rcWindow.top); }
+FORCEINLINE BOOL +IntEqualRect(RECTL *lprc1, RECTL *lprc2) +{ + if (lprc1 == NULL || lprc2 == NULL) + return FALSE; + + return (lprc1->left == lprc2->left) && (lprc1->top == lprc2->top) && + (lprc1->right == lprc2->right) && (lprc1->bottom == lprc2->bottom); +} + BOOL FASTCALL ActivateOtherWindowMin(PWND); UINT FASTCALL co_WinPosArrangeIconicWindows(PWND parent); BOOL FASTCALL IntGetClientOrigin(PWND Window, LPPOINT Point); @@ -58,3 +68,4 @@ PWND FASTCALL IntRealChildWindowFromPoint(PWND,LONG,LONG); BOOL FASTCALL IntScreenToClient(PWND,LPPOINT); BOOL FASTCALL IntClientToScreen(PWND,LPPOINT); +BOOL FASTCALL IntGetWindowRect(PWND,RECTL*);