Partial clean-up of the painting functions:

- Get rid of the DCX_WINDOWPAINT flag (it wasn't used anyway).
- Remove the PaintPosted field from message queue, we don't need it.
- Use screen cooridnates for the WindowUpdate region instead of window relative ones.
- Fix the algorithm for retrieving paint messages to respect the painting order.
- Remove the NCUpdateRegion field from window object and calculate it on demand.
- Fix GetDCEx to take region in screen coordinates.

svn path=/trunk/; revision=17931
This commit is contained in:
Filip Navara 2005-09-19 10:39:26 +00:00
parent 0558c3abc5
commit 1d878e0ba5
9 changed files with 295 additions and 332 deletions

View file

@ -39,7 +39,7 @@ typedef struct tagDCE
#define DCX_DCEEMPTY 0x00000800
#define DCX_DCEBUSY 0x00001000
#define DCX_DCEDIRTY 0x00002000
#define DCX_WINDOWPAINT 0x00020000
#define DCX_USESTYLE 0x00010000
#define DCX_KEEPCLIPRGN 0x00040000
#define DCX_NOCLIPCHILDREN 0x00080000

View file

@ -81,8 +81,6 @@ typedef struct _USER_MESSAGE_QUEUE
ULONG LastMsgRead;
/* Current window with focus (ie. receives keyboard input) for this queue. */
HWND FocusWindow;
/* True if a window needs painting. */
BOOLEAN PaintPosted;
/* Count of paints pending. */
ULONG PaintCount;
/* Current active window for this queue. */

View file

@ -60,7 +60,6 @@ typedef struct _WINDOW_OBJECT
UINT IDMenu;
/* Handle of region of the window to be updated. */
HANDLE UpdateRegion;
HANDLE NCUpdateRegion;
/* Handle of the window region. */
HANDLE WindowRegion;
/* Pointer to the owning thread's message queue. */

View file

@ -103,7 +103,6 @@ VOID FASTCALL
MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
{
Queue->PaintCount++;
Queue->PaintPosted = TRUE;
Queue->QueueBits |= QS_PAINT;
Queue->ChangedBits |= QS_PAINT;
if (Queue->WakeMask & QS_PAINT)
@ -114,10 +113,6 @@ VOID FASTCALL
MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
{
Queue->PaintCount--;
if (Queue->PaintCount == 0)
{
Queue->PaintPosted = FALSE;
}
}
@ -1341,7 +1336,6 @@ MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQu
KeQueryTickCount(&LargeTickCount);
MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
MessageQueue->FocusWindow = NULL;
MessageQueue->PaintPosted = FALSE;
MessageQueue->PaintCount = 0;
MessageQueue->WakeMask = ~0;
MessageQueue->NewMessagesHandle = NULL;

View file

@ -35,10 +35,52 @@
#define NDEBUG
#include <debug.h>
#define DCX_USESTYLE 0x10000
/* PRIVATE FUNCTIONS **********************************************************/
/**
* @name IntIntersectWithParents
*
* Intersect window rectangle with all parent client rectangles.
*
* @param Child
* Pointer to child window to start intersecting from.
* @param WindowRect
* Pointer to rectangle that we want to intersect in screen
* coordinates on input and intersected rectangle on output (if TRUE
* is returned).
*
* @return
* If any parent is minimized or invisible or the resulting rectangle
* is empty then FALSE is returned. Otherwise TRUE is returned.
*/
BOOL FASTCALL
IntIntersectWithParents(PWINDOW_OBJECT Child, PRECT WindowRect)
{
PWINDOW_OBJECT ParentWindow;
ParentWindow = Child->Parent;
while (ParentWindow != NULL)
{
if (!(ParentWindow->Style & WS_VISIBLE) ||
(ParentWindow->Style & WS_MINIMIZE))
{
return FALSE;
}
if (!IntGdiIntersectRect(WindowRect, WindowRect, &ParentWindow->ClientRect))
{
return FALSE;
}
/* FIXME: Layered windows. */
ParentWindow = ParentWindow->Parent;
}
return TRUE;
}
VOID FASTCALL
IntValidateParent(PWINDOW_OBJECT Child, HRGN ValidRegion)
{
@ -46,30 +88,130 @@ IntValidateParent(PWINDOW_OBJECT Child, HRGN ValidRegion)
while (ParentWindow)
{
if (!(ParentWindow->Style & WS_CLIPCHILDREN))
{
if (ParentWindow->UpdateRegion != 0)
{
INT OffsetX, OffsetY;
if (ParentWindow->Style & WS_CLIPCHILDREN)
break;
/*
* We must offset the child region by the offset of the
* child rect in the parent.
*/
OffsetX = Child->WindowRect.left - ParentWindow->WindowRect.left;
OffsetY = Child->WindowRect.top - ParentWindow->WindowRect.top;
NtGdiOffsetRgn(ValidRegion, OffsetX, OffsetY);
NtGdiCombineRgn(ParentWindow->UpdateRegion, ParentWindow->UpdateRegion,
ValidRegion, RGN_DIFF);
/* FIXME: If the resulting region is empty, remove fake posted paint message */
NtGdiOffsetRgn(ValidRegion, -OffsetX, -OffsetY);
}
if (ParentWindow->UpdateRegion != 0)
{
NtGdiCombineRgn(ParentWindow->UpdateRegion, ParentWindow->UpdateRegion,
ValidRegion, RGN_DIFF);
/* FIXME: If the resulting region is empty, remove fake posted paint message */
}
ParentWindow = ParentWindow->Parent;
}
}
/**
* @name IntCalcWindowRgn
*
* Get a window or client region.
*/
HRGN FASTCALL
IntCalcWindowRgn(PWINDOW_OBJECT Window, BOOL Client)
{
HRGN hRgnWindow;
UINT RgnType;
if (Client)
hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
else
hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
if (Window->WindowRegion != NULL && !(Window->Style & WS_MINIMIZE))
{
NtGdiOffsetRgn(hRgnWindow,
-Window->WindowRect.left,
-Window->WindowRect.top);
RgnType = NtGdiCombineRgn(hRgnWindow, hRgnWindow, Window->WindowRegion, RGN_AND);
NtGdiOffsetRgn(hRgnWindow,
Window->WindowRect.left,
Window->WindowRect.top);
}
return hRgnWindow;
}
/**
* @name IntGetNCUpdateRgn
*
* Get non-client update region of a window and optionally validate it.
*
* @param Window
* Pointer to window to get the NC update region from.
* @param Validate
* Set to TRUE to force validating the NC update region.
*
* @return
* Handle to NC update region. The caller is responsible for deleting
* it.
*/
HRGN FASTCALL
IntGetNCUpdateRgn(PWINDOW_OBJECT Window, BOOL Validate)
{
HRGN hRgnNonClient;
HRGN hRgnWindow;
UINT RgnType;
if (Window->UpdateRegion != NULL &&
Window->UpdateRegion != (HRGN)1)
{
hRgnNonClient = NtGdiCreateRectRgn(0, 0, 0, 0);
hRgnWindow = IntCalcWindowRgn(Window, TRUE);
/*
* If region creation fails it's safe to fallback to whole
* window region.
*/
if (hRgnNonClient == NULL)
{
return (HRGN)1;
}
RgnType = NtGdiCombineRgn(hRgnNonClient, Window->UpdateRegion,
hRgnWindow, RGN_DIFF);
if (RgnType == ERROR)
{
NtGdiDeleteObject(hRgnNonClient);
return (HRGN)1;
}
else if (RgnType == NULLREGION)
{
NtGdiDeleteObject(hRgnNonClient);
return NULL;
}
/*
* Remove the nonclient region from the standard update region if
* we were asked for it.
*/
if (Validate)
{
if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
hRgnWindow, RGN_AND) == NULLREGION)
{
GDIOBJ_SetOwnership(Window->UpdateRegion, PsGetCurrentProcess());
NtGdiDeleteObject(Window->UpdateRegion);
Window->UpdateRegion = NULL;
if (!(Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
MsqDecPaintCountQueue(Window->MessageQueue);
}
}
NtGdiDeleteObject(hRgnWindow);
return hRgnNonClient;
}
else
{
return Window->UpdateRegion;
}
}
/*
* IntPaintWindows
*
@ -85,44 +227,37 @@ co_IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
{
if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
if (Window->UpdateRegion)
{
if (Window->NCUpdateRegion)
{
IntValidateParent(Window, Window->NCUpdateRegion);
}
TempRegion = Window->NCUpdateRegion;
if ((HANDLE) 1 != TempRegion && NULL != TempRegion)
{
GDIOBJ_SetOwnership(TempRegion, PsGetCurrentProcess());
}
Window->NCUpdateRegion = NULL;
Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
MsqDecPaintCountQueue(Window->MessageQueue);
co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0);
if ((HANDLE) 1 != TempRegion && NULL != TempRegion)
{
/* NOTE: The region can already be deleted! */
GDIOBJ_FreeObj(TempRegion, GDI_OBJECT_TYPE_REGION | GDI_OBJECT_TYPE_SILENT);
}
IntValidateParent(Window, Window->UpdateRegion);
}
if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
if (Flags & RDW_UPDATENOW)
{
if (Window->UpdateRegion)
if (Window->UpdateRegion != NULL ||
Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
{
/*
* This surely wrong! Why we would want to validate the parent?
* It breaks quite a few things including dummy WM_ERASEBKGND
* implementations that return only TRUE and have corresponding
* WM_PAINT that doesn't paint the whole client area.
* I left the code here so that no one will readd it again!
* - Filip
*/
/* IntValidateParent(Window, Window->UpdateRegion); */
hDC = UserGetDCEx(Window, 0, DCX_CACHE | DCX_USESTYLE |
DCX_INTERSECTUPDATE);
if (hDC != NULL)
co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
}
}
else
{
if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
{
TempRegion = IntGetNCUpdateRgn(Window, TRUE);
Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
MsqDecPaintCountQueue(Window->MessageQueue);
co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0);
if ((HANDLE) 1 != TempRegion && NULL != TempRegion)
{
/* NOTE: The region can already be deleted! */
GDIOBJ_FreeObj(TempRegion, GDI_OBJECT_TYPE_REGION | GDI_OBJECT_TYPE_SILENT);
}
}
if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
{
if (Window->UpdateRegion)
{
if (co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0))
{
@ -132,22 +267,12 @@ co_IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
}
}
}
if (Flags & RDW_UPDATENOW)
{
if (Window->UpdateRegion != NULL ||
Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
{
co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
}
}
}
/*
* Check that the window is still valid at this point
*/
if (! IntIsWindow(hWnd))
if (!IntIsWindow(hWnd))
{
return;
}
@ -156,7 +281,7 @@ co_IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
* Paint child windows.
*/
if (!(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN)))
((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN)))
{
HWND *List, *phWnd;
@ -164,13 +289,11 @@ co_IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
{
for (phWnd = List; *phWnd; ++phWnd)
{
Window = UserGetWindowObject(*phWnd);
Window = IntGetWindowObject(*phWnd);
if (Window && (Window->Style & WS_VISIBLE))
{
UserRefObjectCo(Window);
co_IntPaintWindows(Window, Flags);
UserDerefObjectCo(Window);
ObmDereferenceObject(Window);
}
}
ExFreePool(List);
@ -200,15 +323,18 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
HRGN hRgnWindow;
hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
NtGdiOffsetRgn(hRgnWindow,
-Window->WindowRect.left,
-Window->WindowRect.top);
RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnWindow, RGN_AND);
NtGdiDeleteObject(hRgnWindow);
}
else
{
NtGdiOffsetRgn(hRgn,
-Window->WindowRect.left,
-Window->WindowRect.top);
RgnType = NtGdiCombineRgn(hRgn, hRgn, Window->WindowRegion, RGN_AND);
NtGdiOffsetRgn(hRgn,
Window->WindowRect.left,
Window->WindowRect.top);
}
/*
@ -278,60 +404,6 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
}
/*
* Split the nonclient update region.
*/
if (NULL != Window->UpdateRegion)
{
HRGN hRgnWindow, hRgnNonClient;
hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
NtGdiOffsetRgn(hRgnWindow,
-Window->WindowRect.left,
-Window->WindowRect.top);
hRgnNonClient = NtGdiCreateRectRgn(0, 0, 0, 0);
if (NtGdiCombineRgn(hRgnNonClient, Window->UpdateRegion,
hRgnWindow, RGN_DIFF) == NULLREGION)
{
NtGdiDeleteObject(hRgnNonClient);
hRgnNonClient = NULL;
}
else
{
GDIOBJ_SetOwnership(hRgnNonClient, NULL);
}
/*
* Remove the nonclient region from the standard update region.
*/
if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
hRgnWindow, RGN_AND) == NULLREGION)
{
GDIOBJ_SetOwnership(Window->UpdateRegion, PsGetCurrentProcess());
NtGdiDeleteObject(Window->UpdateRegion);
Window->UpdateRegion = NULL;
}
if (Window->NCUpdateRegion == NULL)
{
Window->NCUpdateRegion = hRgnNonClient;
}
else
{
if(NULL != hRgnNonClient)
{
NtGdiCombineRgn(Window->NCUpdateRegion, Window->NCUpdateRegion,
hRgnNonClient, RGN_OR);
GDIOBJ_SetOwnership(hRgnNonClient, PsGetCurrentProcess());
NtGdiDeleteObject(hRgnNonClient);
}
}
NtGdiDeleteObject(hRgnWindow);
}
/*
* Process children if needed
*/
@ -358,9 +430,6 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
*/
HRGN hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY);
NtGdiOffsetRgn(hRgnTemp,
Window->WindowRect.left - Child->WindowRect.left,
Window->WindowRect.top - Child->WindowRect.top);
IntInvalidateWindows(Child, hRgnTemp, Flags);
NtGdiDeleteObject(hRgnTemp);
}
@ -407,20 +476,16 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
BOOL FASTCALL
IntIsWindowDrawable(PWINDOW_OBJECT Window)
{
PWINDOW_OBJECT Wnd = Window;
PWINDOW_OBJECT Wnd;
do
for (Wnd = Window; Wnd != NULL; Wnd = Wnd->Parent)
{
if (!(Wnd->Style & WS_VISIBLE) ||
((Wnd->Style & WS_MINIMIZE) && (Wnd != Window)))
{
return FALSE;
}
Wnd = Wnd->Parent;
}
while(Wnd);
return TRUE;
}
@ -453,7 +518,7 @@ co_UserRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRg
/*
* Step 2.
* Transform the parameters UpdateRgn and UpdateRect into
* a region hRgn specified in window coordinates.
* a region hRgn specified in screen coordinates.
*/
if (Flags & (RDW_INVALIDATE | RDW_VALIDATE))
@ -461,35 +526,30 @@ co_UserRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRg
if (UpdateRgn != NULL)
{
hRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY);
NtGdiOffsetRgn(hRgn,
Window->ClientRect.left - Window->WindowRect.left,
Window->ClientRect.top - Window->WindowRect.top);
if (NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY) == NULLREGION)
NtGdiDeleteObject(hRgn);
else
NtGdiOffsetRgn(hRgn, Window->ClientRect.left, Window->ClientRect.top);
}
else
if (UpdateRect != NULL)
else if (UpdateRect != NULL)
{
if (!IntGdiIsEmptyRect(UpdateRect))
{
hRgn = UnsafeIntCreateRectRgnIndirect((RECT *)UpdateRect);
NtGdiOffsetRgn(hRgn,
Window->ClientRect.left - Window->WindowRect.left,
Window->ClientRect.top - Window->WindowRect.top);
NtGdiOffsetRgn(hRgn, Window->ClientRect.left, Window->ClientRect.top);
}
else
if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) ||
(Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME))
{
hRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
NtGdiOffsetRgn(hRgn,
-Window->WindowRect.left,
-Window->WindowRect.top);
}
else
{
hRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
NtGdiOffsetRgn(hRgn,
-Window->WindowRect.left,
-Window->WindowRect.top);
}
}
else if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) ||
(Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME))
{
if (!IntGdiIsEmptyRect(&Window->WindowRect))
hRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
}
else
{
if (!IntGdiIsEmptyRect(&Window->ClientRect))
hRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
}
}
/*
@ -497,7 +557,8 @@ co_UserRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRg
* Adjust the window update region depending on hRgn and flags.
*/
if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT))
if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT) &&
hRgn != NULL)
{
IntInvalidateWindows(Window, hRgn, Flags);
}
@ -534,84 +595,55 @@ IntIsWindowDirty(PWINDOW_OBJECT Window)
(Window->Flags & WINDOWOBJECT_NEED_NCPAINT));
}
HWND STDCALL
IntFindWindowToRepaint(HWND hWnd, PW32THREAD Thread)
HWND FASTCALL
IntFindWindowToRepaint(PWINDOW_OBJECT Window, PW32THREAD Thread)
{
PWINDOW_OBJECT Window;
PWINDOW_OBJECT Child;
HWND hFoundWnd = NULL;
HWND hChild;
if (!(Window = UserGetWindowObject(hWnd)))
return NULL;
if (IntIsWindowDirty(Window) &&
IntWndBelongsToThread(Window, Thread))
while (Window != NULL)
{
return hWnd;
}
for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
{
if (IntIsWindowDirty(Child) &&
IntWndBelongsToThread(Child, Thread))
/* FIXME: Transparent windows. */
if (IntIsWindowDirty(Window) &&
IntWndBelongsToThread(Window, Thread))
{
hFoundWnd = Child->hSelf;
break;
return Window->hSelf;
}
}
if (hFoundWnd == NULL)
{
HWND *List;
INT i;
List = IntWinListChildren(Window);
if (List != NULL)
if (Window->FirstChild)
{
for (i = 0; List[i]; i++)
{
hFoundWnd = IntFindWindowToRepaint(List[i], Thread);
if (hFoundWnd != NULL)
break;
}
ExFreePool(List);
hChild = IntFindWindowToRepaint(Window->FirstChild, Thread);
if (hChild != NULL)
return hChild;
}
Window = Window->NextSibling;
}
return hFoundWnd;
return NULL;
}
BOOL FASTCALL
IntGetPaintMessage(HWND hWnd, UINT MsgFilterMin, UINT MsgFilterMax,
PW32THREAD Thread, MSG *Message, BOOL Remove)
{
PWINDOW_OBJECT Window;
PUSER_MESSAGE_QUEUE MessageQueue = (PUSER_MESSAGE_QUEUE)Thread->MessageQueue;
if (!MessageQueue->PaintPosted)
if (!MessageQueue->PaintCount)
return FALSE;
if ((MsgFilterMin != 0 || MsgFilterMax != 0) &&
(MsgFilterMin > WM_PAINT || MsgFilterMax < WM_PAINT))
return FALSE;
if (hWnd)
Message->hwnd = IntFindWindowToRepaint(hWnd, PsGetWin32Thread());
else
Message->hwnd = IntFindWindowToRepaint(IntGetDesktopWindow(), PsGetWin32Thread());
Message->hwnd = IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetWin32Thread());
if (Message->hwnd == NULL)
{
if (NULL == hWnd)
{
DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
MessageQueue->PaintPosted = 0;
MessageQueue->PaintCount = 0;
}
DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
return FALSE;
}
if (!(Window = UserGetWindowObject(Message->hwnd)))
if (hWnd != NULL && Message->hwnd != hWnd)
return FALSE;
Message->message = WM_PAINT;
@ -700,14 +732,7 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
{
HRGN hRgn;
if (Window->NCUpdateRegion != (HANDLE)1 &&
Window->NCUpdateRegion != NULL)
{
GDIOBJ_SetOwnership(Window->NCUpdateRegion, PsGetCurrentProcess());
}
hRgn = Window->NCUpdateRegion;
IntValidateParent(Window, Window->NCUpdateRegion);
Window->NCUpdateRegion = NULL;
hRgn = IntGetNCUpdateRgn(Window, FALSE);
Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
MsqDecPaintCountQueue(Window->MessageQueue);
co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)hRgn, 0);
@ -720,8 +745,7 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
RtlZeroMemory(&Ps, sizeof(PAINTSTRUCT));
Ps.hdc = UserGetDCEx(Window, 0, DCX_INTERSECTUPDATE | DCX_WINDOWPAINT | DCX_USESTYLE);
Ps.hdc = UserGetDCEx(Window, Window->UpdateRegion, DCX_INTERSECTRGN | DCX_USESTYLE);
if (!Ps.hdc)
{
RETURN( NULL);
@ -730,22 +754,20 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
if (Window->UpdateRegion != NULL)
{
MsqDecPaintCountQueue(Window->MessageQueue);
IntValidateParent(Window, Window->UpdateRegion);
Rgn = RGNDATA_LockRgn(Window->UpdateRegion);
if (NULL != Rgn)
{
UnsafeIntGetRgnBox(Rgn, &Ps.rcPaint);
RGNDATA_UnlockRgn(Rgn);
IntGdiOffsetRect(&Ps.rcPaint,
Window->WindowRect.left - Window->ClientRect.left,
Window->WindowRect.top - Window->ClientRect.top);
-Window->ClientRect.left,
-Window->ClientRect.top);
}
else
{
IntGetClientRect(Window, &Ps.rcPaint);
}
GDIOBJ_SetOwnership(Window->UpdateRegion, PsGetCurrentProcess());
NtGdiDeleteObject(Window->UpdateRegion);
Window->UpdateRegion = NULL;
}
else
@ -755,6 +777,7 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
IntGetClientRect(Window, &Ps.rcPaint);
}
Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
@ -898,10 +921,7 @@ co_UserGetUpdateRgn(PWINDOW_OBJECT Window, HRGN hRgn, BOOL bErase)
else
{
RegionType = NtGdiCombineRgn(hRgn, Window->UpdateRegion, hRgn, RGN_COPY);
NtGdiOffsetRgn(
hRgn,
Window->WindowRect.left - Window->ClientRect.left,
Window->WindowRect.top - Window->ClientRect.top);
NtGdiOffsetRgn(hRgn, -Window->ClientRect.left, -Window->ClientRect.top);
}
if (bErase && RegionType != NULLREGION && RegionType != ERROR)

View file

@ -38,37 +38,30 @@ VIS_ComputeVisibleRegion(
BOOLEAN ClipSiblings)
{
HRGN VisRgn, ClipRgn;
INT LeftOffset, TopOffset;
PWINDOW_OBJECT PreviousWindow, CurrentWindow, CurrentSibling;
if (!(Window->Style & WS_VISIBLE))
{
return NtGdiCreateRectRgn(0, 0, 0, 0);
return NULL;
}
if (ClientArea)
{
if(!(ClipRgn = VIS_ComputeVisibleRegion(Window, FALSE, ClipChildren, ClipSiblings)))
if (!(ClipRgn = VIS_ComputeVisibleRegion(Window, FALSE, ClipChildren, ClipSiblings)))
{
return NtGdiCreateRectRgn(0, 0, 0, 0);
return NULL;
}
if(!(VisRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect)))
if (!(VisRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect)))
{
NtGdiDeleteObject(VisRgn);
return NtGdiCreateRectRgn(0, 0, 0, 0);
return NULL;
}
LeftOffset = Window->ClientRect.left - Window->WindowRect.left;
TopOffset = Window->ClientRect.top - Window->WindowRect.top;
NtGdiOffsetRgn(VisRgn, -Window->WindowRect.left, -Window->WindowRect.top);
NtGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_AND);
NtGdiDeleteObject(ClipRgn);
NtGdiOffsetRgn(VisRgn, -LeftOffset, -TopOffset);
return VisRgn;
}
VisRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
LeftOffset = Window->WindowRect.left;
TopOffset = Window->WindowRect.top;
/*
* Walk through all parent windows and for each clip the visble region
@ -83,14 +76,15 @@ VIS_ComputeVisibleRegion(
if (!(CurrentWindow->Style & WS_VISIBLE))
{
NtGdiDeleteObject(VisRgn);
return NtGdiCreateRectRgn(0, 0, 0, 0);
return NULL;
}
ClipRgn = UnsafeIntCreateRectRgnIndirect(&CurrentWindow->ClientRect);
NtGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_AND);
NtGdiDeleteObject(ClipRgn);
if ((PreviousWindow->Style & WS_CLIPSIBLINGS) ||
(PreviousWindow == Window && ClipSiblings))
(PreviousWindow == Window && ClipSiblings))
{
CurrentSibling = CurrentWindow->FirstChild;
while (CurrentSibling != NULL && CurrentSibling != PreviousWindow)
@ -99,7 +93,7 @@ VIS_ComputeVisibleRegion(
{
ClipRgn = UnsafeIntCreateRectRgnIndirect(&CurrentSibling->WindowRect);
/* Combine it with the window region if available */
if(CurrentSibling->WindowRegion && !(CurrentSibling->Style & WS_MINIMIZE))
if (CurrentSibling->WindowRegion && !(CurrentSibling->Style & WS_MINIMIZE))
{
NtGdiOffsetRgn(ClipRgn, -CurrentSibling->WindowRect.left, -CurrentSibling->WindowRect.top);
NtGdiCombineRgn(ClipRgn, ClipRgn, CurrentSibling->WindowRegion, RGN_AND);
@ -125,7 +119,7 @@ VIS_ComputeVisibleRegion(
{
ClipRgn = UnsafeIntCreateRectRgnIndirect(&CurrentWindow->WindowRect);
/* Combine it with the window region if available */
if(CurrentWindow->WindowRegion && !(CurrentWindow->Style & WS_MINIMIZE))
if (CurrentWindow->WindowRegion && !(CurrentWindow->Style & WS_MINIMIZE))
{
NtGdiOffsetRgn(ClipRgn, -CurrentWindow->WindowRect.left, -CurrentWindow->WindowRect.top);
NtGdiCombineRgn(ClipRgn, ClipRgn, CurrentWindow->WindowRegion, RGN_AND);
@ -138,15 +132,13 @@ VIS_ComputeVisibleRegion(
}
}
if(Window->WindowRegion && !(Window->Style & WS_MINIMIZE))
if (Window->WindowRegion && !(Window->Style & WS_MINIMIZE))
{
NtGdiOffsetRgn(VisRgn, -LeftOffset, -TopOffset);
NtGdiOffsetRgn(VisRgn, -Window->WindowRect.left, -Window->WindowRect.top);
NtGdiCombineRgn(VisRgn, VisRgn, Window->WindowRegion, RGN_AND);
return VisRgn;
NtGdiOffsetRgn(VisRgn, Window->WindowRect.left, Window->WindowRect.top);
}
NtGdiOffsetRgn(VisRgn, -LeftOffset, -TopOffset);
return VisRgn;
}

View file

@ -34,8 +34,6 @@
#define NDEBUG
#include <debug.h>
#define DCX_USESTYLE 0x10000
/* GLOBALS *******************************************************************/
/* NOTE - I think we should store this per window station (including gdi objects) */
@ -187,7 +185,7 @@ DceSetDrawable(PWINDOW_OBJECT Window OPTIONAL, HDC hDC, ULONG Flags,
STATIC VOID FASTCALL
DceDeleteClipRgn(DCE* Dce)
{
Dce->DCXFlags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN | DCX_WINDOWPAINT);
Dce->DCXFlags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN);
if (Dce->DCXFlags & DCX_KEEPCLIPRGN )
{
@ -216,7 +214,7 @@ DceReleaseDC(DCE* dce)
/* restore previous visible region */
if ((dce->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) &&
(dce->DCXFlags & (DCX_CACHE | DCX_WINDOWPAINT)) )
(dce->DCXFlags & DCX_CACHE) )
{
DceDeleteClipRgn(dce);
}
@ -273,23 +271,6 @@ DceUpdateVisRgn(DCE *Dce, PWINDOW_OBJECT Window, ULONG Flags)
{
hRgnVisible = NtGdiCreateRectRgn(0, 0, 0, 0);
}
else
{
if (0 == (Flags & DCX_WINDOW))
{
NtGdiOffsetRgn(
hRgnVisible,
Parent->ClientRect.left - Window->ClientRect.left,
Parent->ClientRect.top - Window->ClientRect.top);
}
else
{
NtGdiOffsetRgn(
hRgnVisible,
Parent->WindowRect.left - Window->WindowRect.left,
Parent->WindowRect.top - Window->WindowRect.top);
}
}
}
else if (Window == NULL)
{
@ -482,7 +463,7 @@ UserGetDCEx(PWINDOW_OBJECT Window OPTIONAL, HANDLE ClipRegion, ULONG Flags)
}
Dce->hwndCurrent = (Window ? Window->hSelf : NULL);
Dce->DCXFlags = DcxFlags | (Flags & DCX_WINDOWPAINT) | DCX_DCEBUSY;
Dce->DCXFlags = DcxFlags | DCX_DCEBUSY;
if (0 == (Flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) && NULL != ClipRegion)
{
@ -498,21 +479,8 @@ UserGetDCEx(PWINDOW_OBJECT Window OPTIONAL, HANDLE ClipRegion, ULONG Flags)
if (0 != (Flags & DCX_INTERSECTUPDATE) && NULL == ClipRegion)
{
Dce->hClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
if (Dce->hClipRgn && Window->UpdateRegion)
{
GDIOBJ_SetOwnership(Dce->hClipRgn, NULL);
NtGdiCombineRgn(Dce->hClipRgn, Window->UpdateRegion, NULL, RGN_COPY);
if(Window->WindowRegion && !(Window->Style & WS_MINIMIZE))
NtGdiCombineRgn(Dce->hClipRgn, Dce->hClipRgn, Window->WindowRegion, RGN_AND);
if (!(Flags & DCX_WINDOW))
{
NtGdiOffsetRgn(Dce->hClipRgn,
Window->WindowRect.left - Window->ClientRect.left,
Window->WindowRect.top - Window->ClientRect.top);
}
}
Flags |= DCX_INTERSECTRGN;
Flags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN;
ClipRegion = Window->UpdateRegion;
}
if (ClipRegion == (HRGN) 1)
@ -521,40 +489,17 @@ UserGetDCEx(PWINDOW_OBJECT Window OPTIONAL, HANDLE ClipRegion, ULONG Flags)
{
Dce->hClipRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
GDIOBJ_SetOwnership(Dce->hClipRgn, NULL);
if(!Window->WindowRegion || (Window->Style & WS_MINIMIZE))
{
NtGdiOffsetRgn(Dce->hClipRgn, -Window->ClientRect.left, -Window->ClientRect.top);
}
else
{
NtGdiOffsetRgn(Dce->hClipRgn, -Window->WindowRect.left, -Window->WindowRect.top);
NtGdiCombineRgn(Dce->hClipRgn, Dce->hClipRgn, Window->WindowRegion, RGN_AND);
NtGdiOffsetRgn(Dce->hClipRgn, -(Window->ClientRect.left - Window->WindowRect.left),
-(Window->ClientRect.top - Window->WindowRect.top));
}
}
else
{
Dce->hClipRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
GDIOBJ_SetOwnership(Dce->hClipRgn, NULL);
NtGdiOffsetRgn(Dce->hClipRgn, -Window->WindowRect.left,
-Window->WindowRect.top);
if(Window->WindowRegion && !(Window->Style & WS_MINIMIZE))
NtGdiCombineRgn(Dce->hClipRgn, Dce->hClipRgn, Window->WindowRegion, RGN_AND);
}
}
else if (NULL != ClipRegion)
else if (ClipRegion != NULL)
{
Dce->hClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
if (Dce->hClipRgn)
{
GDIOBJ_SetOwnership(Dce->hClipRgn, NULL);
if(!Window->WindowRegion || (Window->Style & WS_MINIMIZE))
NtGdiCombineRgn(Dce->hClipRgn, ClipRegion, NULL, RGN_COPY);
else
NtGdiCombineRgn(Dce->hClipRgn, ClipRegion, Window->WindowRegion, RGN_AND);
}
NtGdiDeleteObject(ClipRegion);
Dce->hClipRgn = ClipRegion;
GDIOBJ_SetOwnership(Dce->hClipRgn, NULL);
}
DceSetDrawable(Window, Dce->hDC, Flags, UpdateClipOrigin);
@ -705,9 +650,9 @@ DceFreeDCE(PDCE dce, BOOLEAN Force)
}
NtGdiDeleteDC(dce->hDC);
GDIOBJ_SetOwnership(dce->hClipRgn, PsGetCurrentProcess());
if (dce->hClipRgn && ! (dce->DCXFlags & DCX_KEEPCLIPRGN))
{
GDIOBJ_SetOwnership(dce->hClipRgn, PsGetCurrentProcess());
NtGdiDeleteObject(dce->hClipRgn);
}

View file

@ -959,6 +959,7 @@ co_WinPosSetWindowPos(
else if(VisRgn)
{
RGNDATA_UnlockRgn(VisRgn);
NtGdiOffsetRgn(VisBefore, -Window->WindowRect.left, -Window->WindowRect.top);
}
}
}
@ -1081,6 +1082,13 @@ co_WinPosSetWindowPos(
Window->Style |= WS_VISIBLE;
}
if (Window->UpdateRegion != NULL && Window->UpdateRegion != (HRGN)1)
{
NtGdiOffsetRgn(Window->UpdateRegion,
NewWindowRect.left - OldWindowRect.left,
NewWindowRect.top - OldWindowRect.top);
}
DceResetActiveDCEs(Window);
if (!(WinPos.flags & SWP_NOREDRAW))
@ -1099,6 +1107,7 @@ co_WinPosSetWindowPos(
else if(VisRgn)
{
RGNDATA_UnlockRgn(VisRgn);
NtGdiOffsetRgn(VisAfter, -Window->WindowRect.left, -Window->WindowRect.top);
}
/*
@ -1136,11 +1145,9 @@ co_WinPosSetWindowPos(
/* No use in copying bits which are in the update region. */
if (Window->UpdateRegion != NULL)
{
NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
NtGdiCombineRgn(CopyRgn, CopyRgn, Window->UpdateRegion, RGN_DIFF);
}
if (Window->NCUpdateRegion != NULL)
{
NtGdiCombineRgn(CopyRgn, CopyRgn, Window->NCUpdateRegion, RGN_DIFF);
NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
}
/*
@ -1163,6 +1170,7 @@ co_WinPosSetWindowPos(
{
RGNDATA_UnlockRgn(VisRgn);
}
/*
* Small trick here: there is no function to bitblt a region. So
* we set the region as the clipping region, take the bounding box
@ -1172,11 +1180,10 @@ co_WinPosSetWindowPos(
* Since NtUserGetDCEx takes ownership of the clip region, we need
* to create a copy of CopyRgn and pass that. We need CopyRgn later
*/
HRGN ClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
NtGdiCombineRgn(ClipRgn, CopyRgn, NULL, RGN_COPY);
Dc = UserGetDCEx(Window, ClipRgn, DCX_WINDOW | DCX_CACHE |
DCX_INTERSECTRGN | DCX_CLIPSIBLINGS);
NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
Dc = UserGetDCEx(Window, CopyRgn, DCX_WINDOW | DCX_CACHE |
DCX_INTERSECTRGN | DCX_CLIPSIBLINGS |
DCX_KEEPCLIPRGN);
NtGdiBitBlt(Dc,
CopyRect.left, CopyRect.top, CopyRect.right - CopyRect.left,
CopyRect.bottom - CopyRect.top, Dc,
@ -1184,6 +1191,7 @@ co_WinPosSetWindowPos(
CopyRect.top + (OldWindowRect.top - NewWindowRect.top), SRCCOPY);
UserReleaseDC(Window, Dc);
IntValidateParent(Window, CopyRgn);
NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
}
else if(VisRgn)
{

View file

@ -83,10 +83,17 @@ NtGdiSelectVisRgn(HDC hdc, HRGN hrgn)
dc->w.hVisRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
GDIOBJ_CopyOwnership(hdc, dc->w.hVisRgn);
}
else
{
NtGdiOffsetRgn(dc->w.hVisRgn, dc->w.DCOrgX, dc->w.DCOrgY);
}
retval = NtGdiCombineRgn(dc->w.hVisRgn, hrgn, 0, RGN_COPY);
if ( retval != ERROR )
CLIPPING_UpdateGCRegion(dc);
{
NtGdiOffsetRgn(dc->w.hVisRgn, -dc->w.DCOrgX, -dc->w.DCOrgY);
CLIPPING_UpdateGCRegion(dc);
}
DC_UnlockDc(dc);
return retval;