📄 painting.c
字号:
}
}
/*
* IntIsWindowDrawable
*
* Remarks
* Window is drawable when it is visible and all parents are not
* minimized.
*/
BOOL FASTCALL
IntIsWindowDrawable(PWINDOW_OBJECT Window)
{
PWINDOW_OBJECT Wnd;
for (Wnd = Window; Wnd != NULL; Wnd = Wnd->Parent)
{
if (!(Wnd->Style & WS_VISIBLE) ||
((Wnd->Style & WS_MINIMIZE) && (Wnd != Window)))
{
return FALSE;
}
}
return TRUE;
}
/*
* IntRedrawWindow
*
* Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
* first parameter.
*/
BOOL FASTCALL
co_UserRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
ULONG Flags)
{
HRGN hRgn = NULL;
/*
* Step 1.
* Validation of passed parameters.
*/
if (!IntIsWindowDrawable(Window) ||
(Flags & (RDW_VALIDATE | RDW_INVALIDATE)) ==
(RDW_VALIDATE | RDW_INVALIDATE))
{
return FALSE;
}
/*
* Step 2.
* Transform the parameters UpdateRgn and UpdateRect into
* a region hRgn specified in screen coordinates.
*/
if (Flags & (RDW_INVALIDATE | RDW_VALIDATE))
{
if (UpdateRgn != NULL)
{
hRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
if (NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY) == NULLREGION)
{
NtGdiDeleteObject(hRgn);
hRgn = NULL;
}
else
NtGdiOffsetRgn(hRgn, Window->ClientRect.left, Window->ClientRect.top);
}
else if (UpdateRect != NULL)
{
if (!IntGdiIsEmptyRect(UpdateRect))
{
hRgn = UnsafeIntCreateRectRgnIndirect((RECT *)UpdateRect);
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))
{
if (!IntGdiIsEmptyRect(&Window->WindowRect))
hRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
}
else
{
if (!IntGdiIsEmptyRect(&Window->ClientRect))
hRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
}
}
/*
* Step 3.
* Adjust the window update region depending on hRgn and flags.
*/
if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT) &&
hRgn != NULL)
{
IntInvalidateWindows(Window, hRgn, Flags);
}
/*
* Step 4.
* Repaint and erase windows if needed.
*/
if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
{
co_IntPaintWindows(Window, Flags, FALSE);
}
/*
* Step 5.
* Cleanup ;-)
*/
if (hRgn != NULL)
{
NtGdiDeleteObject(hRgn);
}
return TRUE;
}
BOOL FASTCALL
IntIsWindowDirty(PWINDOW_OBJECT Window)
{
return (Window->Style & WS_VISIBLE) &&
((Window->UpdateRegion != NULL) ||
(Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT) ||
(Window->Flags & WINDOWOBJECT_NEED_NCPAINT));
}
HWND FASTCALL
IntFindWindowToRepaint(PWINDOW_OBJECT Window, PW32THREAD Thread)
{
HWND hChild;
PWINDOW_OBJECT TempWindow;
for (; Window != NULL; Window = Window->NextSibling)
{
if (IntWndBelongsToThread(Window, Thread) &&
IntIsWindowDirty(Window))
{
/* Make sure all non-transparent siblings are already drawn. */
if (Window->ExStyle & WS_EX_TRANSPARENT)
{
for (TempWindow = Window->NextSibling; TempWindow != NULL;
TempWindow = TempWindow->NextSibling)
{
if (!(TempWindow->ExStyle & WS_EX_TRANSPARENT) &&
IntWndBelongsToThread(TempWindow, Thread) &&
IntIsWindowDirty(TempWindow))
{
return TempWindow->hSelf;
}
}
}
return Window->hSelf;
}
if (Window->FirstChild)
{
hChild = IntFindWindowToRepaint(Window->FirstChild, Thread);
if (hChild != NULL)
return hChild;
}
}
return NULL;
}
BOOL FASTCALL
IntGetPaintMessage(HWND hWnd, UINT MsgFilterMin, UINT MsgFilterMax,
PW32THREAD Thread, MSG *Message, BOOL Remove)
{
PUSER_MESSAGE_QUEUE MessageQueue = (PUSER_MESSAGE_QUEUE)Thread->MessageQueue;
if (!MessageQueue->PaintCount)
return FALSE;
if ((MsgFilterMin != 0 || MsgFilterMax != 0) &&
(MsgFilterMin > WM_PAINT || MsgFilterMax < WM_PAINT))
return FALSE;
Message->hwnd = IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetCurrentThreadWin32Thread());
if (Message->hwnd == NULL)
{
DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
return FALSE;
}
if (hWnd != NULL && Message->hwnd != hWnd)
return FALSE;
Message->message = WM_PAINT;
Message->wParam = Message->lParam = 0;
return TRUE;
}
static
HWND FASTCALL
co_IntFixCaret(PWINDOW_OBJECT Window, LPRECT lprc, UINT flags)
{
PDESKTOP_OBJECT Desktop;
PTHRDCARETINFO CaretInfo;
HWND hWndCaret;
PWINDOW_OBJECT WndCaret;
ASSERT_REFS_CO(Window);
Desktop = ((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->Desktop;
CaretInfo = ((PUSER_MESSAGE_QUEUE)Desktop->ActiveMessageQueue)->CaretInfo;
hWndCaret = CaretInfo->hWnd;
WndCaret = UserGetWindowObject(hWndCaret);
//fix: check for WndCaret can be null
if (WndCaret == Window ||
((flags & SW_SCROLLCHILDREN) && IntIsChildWindow(Window, WndCaret)))
{
POINT pt, FromOffset, ToOffset, Offset;
RECT rcCaret;
pt.x = CaretInfo->Pos.x;
pt.y = CaretInfo->Pos.y;
IntGetClientOrigin(WndCaret, &FromOffset);
IntGetClientOrigin(Window, &ToOffset);
Offset.x = FromOffset.x - ToOffset.x;
Offset.y = FromOffset.y - ToOffset.y;
rcCaret.left = pt.x;
rcCaret.top = pt.y;
rcCaret.right = pt.x + CaretInfo->Size.cx;
rcCaret.bottom = pt.y + CaretInfo->Size.cy;
if (IntGdiIntersectRect(lprc, lprc, &rcCaret))
{
co_UserHideCaret(0);
lprc->left = pt.x;
lprc->top = pt.y;
return hWndCaret;
}
}
return 0;
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*
* NtUserBeginPaint
*
* Status
* @implemented
*/
HDC STDCALL
NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
{
PWINDOW_OBJECT Window = NULL;
PAINTSTRUCT Ps;
PROSRGNDATA Rgn;
NTSTATUS Status;
DECLARE_RETURN(HDC);
USER_REFERENCE_ENTRY Ref;
DPRINT("Enter NtUserBeginPaint\n");
UserEnterExclusive();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN( NULL);
}
UserRefObjectCo(Window, &Ref);
co_UserHideCaret(Window);
if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
{
HRGN hRgn;
hRgn = IntGetNCUpdateRgn(Window, FALSE);
Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
MsqDecPaintCountQueue(Window->MessageQueue);
co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)hRgn, 0);
if (hRgn != (HANDLE)1 && hRgn != NULL)
{
/* NOTE: The region can already by deleted! */
GDIOBJ_FreeObj(GdiHandleTable, hRgn, GDI_OBJECT_TYPE_REGION | GDI_OBJECT_TYPE_SILENT);
}
}
RtlZeroMemory(&Ps, sizeof(PAINTSTRUCT));
Ps.hdc = UserGetDCEx(Window, Window->UpdateRegion, DCX_INTERSECTRGN | DCX_USESTYLE);
if (!Ps.hdc)
{
RETURN(NULL);
}
if (Window->UpdateRegion != NULL)
{
MsqDecPaintCountQueue(Window->MessageQueue);
Rgn = RGNDATA_LockRgn(Window->UpdateRegion);
if (NULL != Rgn)
{
UnsafeIntGetRgnBox(Rgn, &Ps.rcPaint);
RGNDATA_UnlockRgn(Rgn);
IntGdiIntersectRect(&Ps.rcPaint, &Ps.rcPaint, &Window->ClientRect);
if (! IntGdiIsEmptyRect(&Ps.rcPaint))
{
IntGdiOffsetRect(&Ps.rcPaint,
-Window->ClientRect.left,
-Window->ClientRect.top);
}
}
else
{
IntGetClientRect(Window, &Ps.rcPaint);
}
GDIOBJ_SetOwnership(GdiHandleTable, Window->UpdateRegion, PsGetCurrentProcess());
/* The region is part of the dc now and belongs to the process! */
Window->UpdateRegion = NULL;
}
else
{
if (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
MsqDecPaintCountQueue(Window->MessageQueue);
IntGetClientRect(Window, &Ps.rcPaint);
}
Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
{
Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
Ps.fErase = !co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)Ps.hdc, 0);
}
else
{
Ps.fErase = FALSE;
}
if (Window->UpdateRegion)
{
if (!(Window->Style & WS_CLIPCHILDREN))
{
PWINDOW_OBJECT Child;
for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
{
IntInvalidateWindows(Child, Window->UpdateRegion, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
}
}
}
Status = MmCopyToCaller(UnsafePs, &Ps, sizeof(PAINTSTRUCT));
if (! NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN(NULL);
}
RETURN(Ps.hdc);
CLEANUP:
if (Window) UserDerefObjectCo(Window);
DPRINT("Leave NtUserBeginPaint, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* NtUserEndPaint
*
* Status
* @implemented
*/
BOOL STDCALL
NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* pUnsafePs)
{
NTSTATUS Status = STATUS_SUCCESS;
PWINDOW_OBJECT Window;
DECLARE_RETURN(BOOL);
USER_REFERENCE_ENTRY Ref;
HDC hdc = NULL;
DPRINT("Enter NtUserEndPaint\n");
UserEnterExclusive();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN(FALSE);
}
_SEH_TRY
{
ProbeForRead(pUnsafePs, sizeof(*pUnsafePs), 1);
hdc = pUnsafePs->hdc;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END
if (!NT_SUCCESS(Status))
{
RETURN(FALSE);
}
UserReleaseDC(Window, hdc, TRUE);
UserRefObjectCo(Window, &Ref);
co_UserShowCaret(Window);
UserDerefObjectCo(Window);
RETURN(TRUE);
CLEANUP:
DPRINT("Leave NtUserEndPaint, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
INT FASTCALL
co_UserGetUpdateRgn(PWINDOW_OBJECT Window, HRGN hRgn, BOOL bErase)
{
int RegionType;
RECT Rect;
ASSERT_REFS_CO(Window);
if (Window->UpdateRegion == NULL)
{
RegionType = (NtGdiSetRectRgn(hRgn, 0, 0, 0, 0) ? NULLREGION : ERROR);
}
else
{
Rect = Window->ClientRect;
IntIntersectWithParents(Window, &Rect);
NtGdiSetRectRgn(hRgn, Rect.left, Rect.top, Rect.right, Rect.bottom);
RegionType = NtGdiCombineRgn(hRgn, hRgn, Window->UpdateRegion, RGN_AND);
NtGdiOffsetRgn(hRgn, -Window->ClientRect.left, -Window->ClientRect.top);
}
if (bErase && RegionType != NULLREGION && RegionType != ERROR)
{
co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
}
return RegionType;
}
/*
* NtUserGetUpdateRgn
*
* Status
* @implemented
*/
INT STDCALL
NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
{
DECLARE_RETURN(INT);
PWINDOW_OBJECT Window;
INT ret;
USER_REFERENCE_ENTRY Ref;
DPRINT("Enter NtUserGetUpdateRgn\n");
UserEnterExclusive();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN(ERROR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -