[NtUser] Fix Paint Messages

This is a HACK for forcing painting of non client areas. Paint code
seems very restricted.

See CORE-7166 & CORE-15934.
This commit is contained in:
jimtabor 2019-05-13 11:31:58 -05:00
parent 0bcf43482b
commit 2161dd85dc

View file

@ -1653,6 +1653,68 @@ WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
return TRUE;
}
//
// This is a NC HACK fix for forcing painting of non client areas.
// Further troubleshooting in painting.c is required to remove this hack.
// See CORE-7166 & CORE-15934
//
VOID
ForceNCPaintErase(PWND Wnd, HRGN hRgn, PREGION pRgn)
{
HDC hDC;
PREGION RgnUpdate;
UINT RgnType;
BOOL Create = FALSE;
if (Wnd->hrgnUpdate == NULL)
{
Wnd->hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0);
IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC);
Create = TRUE;
}
if (Wnd->hrgnUpdate != HRGN_WINDOW)
{
RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate);
if (RgnUpdate)
{
RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, pRgn, RGN_OR);
REGION_UnlockRgn(RgnUpdate);
if (RgnType == NULLREGION)
{
IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
GreDeleteObject(Wnd->hrgnUpdate);
Wnd->hrgnUpdate = NULL;
Create = FALSE;
}
}
}
IntSendNCPaint( Wnd, hRgn ); // Region can be deleted by the application.
if (Wnd->hrgnUpdate)
{
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(UserHMGetHandle(Wnd), WM_ERASEBKGND, (WPARAM)hDC, 0))
{
Wnd->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
}
UserReleaseDC(Wnd, hDC, FALSE);
}
if (Create)
{
IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
GreDeleteObject(Wnd->hrgnUpdate);
Wnd->hrgnUpdate = NULL;
}
}
/* x and y are always screen relative */
BOOLEAN FASTCALL
co_WinPosSetWindowPos(
@ -1862,6 +1924,14 @@ co_WinPosSetWindowPos(
DceResetActiveDCEs(Window); // For WS_VISIBLE changes.
// Change or update, set send non-client paint flag.
if ( Window->style & WS_VISIBLE &&
(WinPos.flags & SWP_STATECHANGED || (!(Window->state2 & WNDS2_WIN31COMPAT) && WinPos.flags & SWP_NOREDRAW ) ) )
{
TRACE("Set WNDS_SENDNCPAINT %p\n",Window);
Window->state |= WNDS_SENDNCPAINT;
}
if (!(WinPos.flags & SWP_NOREDRAW))
{
/* Determine the new visible region */
@ -2018,7 +2088,7 @@ co_WinPosSetWindowPos(
IntInvalidateWindows( Window, DirtyRgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
}
}
else if ( RgnType != ERROR && RgnType == NULLREGION ) // Must be the same. See CORE-7166 & CORE-15934
else if ( RgnType != ERROR && RgnType == NULLREGION ) // Must be the same. See CORE-7166 & CORE-15934, NC HACK fix.
{
if ( !PosChanged &&
!(WinPos.flags & SWP_DEFERERASE) &&
@ -2035,7 +2105,13 @@ co_WinPosSetWindowPos(
if ( !(pwnd->style & WS_CHILD) )
{
IntSendNCPaint(pwnd, HRGN_WINDOW); // Paint the whole frame.
HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
PREGION DcRgnObj = REGION_LockRgn(DcRgn);
TRACE("SWP_FRAMECHANGED win %p hRgn %p\n",pwnd, DcRgn);
IntGdiCombineRgn(DcRgnObj, VisBefore, NULL, RGN_COPY);
REGION_UnlockRgn(DcRgnObj);
ForceNCPaintErase(pwnd, DcRgn, DcRgnObj);
GreDeleteObject(DcRgn);
}
}
}
@ -2106,8 +2182,8 @@ co_WinPosSetWindowPos(
PWND Parent = Window->spwndParent;
if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN))
{
TRACE("SWP_FRAMECHANGED Parent WS_CLIPCHILDREN\n");
UserSyncAndPaintWindows( Parent, RDW_CLIPCHILDREN);
TRACE("SWP_FRAMECHANGED Parent %p WS_CLIPCHILDREN %p\n",Parent,Window);
UserSyncAndPaintWindows( Parent, RDW_CLIPCHILDREN); // NC should redraw here, see NC HACK fix.
}
}