3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
6 * FILE: subsys/win32k/ntuser/painting.c
7 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
9 * 06-06-2001 CSH Created
11 /* INCLUDES ******************************************************************/
13 #include <ddk/ntddk.h>
14 #include <win32k/win32k.h>
15 #include <include/object.h>
16 #include <include/guicheck.h>
17 #include <include/window.h>
18 #include <include/class.h>
19 #include <include/error.h>
20 #include <include/winsta.h>
22 #include <include/painting.h>
23 #include <user32/wininternal.h>
24 #include <include/rect.h>
25 #include <win32k/coord.h>
26 #include <win32k/region.h>
32 /* GLOBALS *******************************************************************/
34 #define UNC_DELAY_NCPAINT (0x00000001)
35 #define UNC_IN_BEGINPAINT (0x00000002)
36 #define UNC_CHECK (0x00000004)
37 #define UNC_REGION (0x00000008)
38 #define UNC_ENTIRE (0x00000010)
39 #define UNC_UPDATE (0x00000020)
41 /* FUNCTIONS *****************************************************************/
44 PaintDoPaint(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags, ULONG ExFlags)
47 HWND hWnd = Window->Self;
48 BOOL bIcon = (Window->Style & WS_MINIMIZE) &&
49 NtUserGetClassLong(hWnd, GCL_HICON);
51 if (ExFlags & RDW_EX_DELAY_NCPAINT ||
52 PaintHaveToDelayNCPaint(Window, 0))
54 ExFlags |= RDW_EX_DELAY_NCPAINT;
57 if (Flags & RDW_UPDATENOW)
59 if (Window->UpdateRegion != NULL)
61 NtUserSendMessage(hWnd, bIcon ? WM_PAINTICON : WM_PAINT, bIcon, 0);
64 else if (Flags & RDW_ERASENOW || ExFlags & RDW_EX_TOPFRAME)
66 UINT Dcx = DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN |
67 DCX_WINDOWPAINT | DCX_CACHE;
71 PaintUpdateNCRegion(Window,
73 UNC_REGION | UNC_CHECK |
74 ((ExFlags & RDW_EX_TOPFRAME) ? UNC_ENTIRE : 0) |
75 ((ExFlags & RDW_EX_DELAY_NCPAINT) ?
76 UNC_DELAY_NCPAINT : 0));
79 if (hRgnRet != (HRGN)1)
87 if (Window->Flags & WINDOWOBJECT_NEED_ERASEBACKGRD)
95 W32kOffsetRgn(hRgnRet,
96 Window->WindowRect.left -
97 Window->ClientRect.left,
98 Window->WindowRect.top -
99 Window->ClientRect.top);
103 Dcx &= ~DCX_INTERSECTRGN;
105 if ((hDC = NtUserGetDCEx(hWnd, hRgnRet, Dcx)) != NULL)
108 Result = NtUserSendMessage(hWnd, bIcon ? WM_ICONERASEBKGND :
109 WM_ERASEBKGND, (WPARAM)hDC, 0);
110 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
111 NtUserReleaseDC(hWnd, hDC);
117 /* FIXME: Check that the window is still valid at this point. */
119 ExFlags &= ~RDW_EX_TOPFRAME;
121 /* FIXME: Paint child windows. */
127 PaintUpdateInternalPaint(PWINDOW_OBJECT Window, ULONG Flags)
129 if (Flags & RDW_INTERNALPAINT)
131 if (Window->UpdateRegion == NULL &&
132 !(Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
134 MsqIncPaintCountQueue(Window->MessageQueue);
136 Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
138 else if (Flags & RDW_NOINTERNALPAINT)
140 if (Window->UpdateRegion == NULL &&
141 (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
143 MsqDecPaintCountQueue(Window->MessageQueue);
145 Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
150 PaintValidateParent(PWINDOW_OBJECT Child)
152 HWND DesktopHandle = W32kGetDesktopWindow();
153 PWINDOW_OBJECT Parent = Child->Parent;
154 PWINDOW_OBJECT Desktop = W32kGetWindowObject(DesktopHandle);
157 if (Child->UpdateRegion == (HANDLE)1)
161 Rect.left = Rect.top = 0;
162 Rect.right = Child->WindowRect.right - Child->WindowRect.left;
163 Rect.bottom = Child->WindowRect.bottom - Child->WindowRect.top;
165 hRgn = UnsafeW32kCreateRectRgnIndirect(&Rect);
169 hRgn = Child->UpdateRegion;
172 while (Parent != NULL && Parent != Desktop)
174 if (!(Parent->Style & WS_CLIPCHILDREN))
176 if (Parent->UpdateRegion != (HANDLE)0)
180 if (Parent->UpdateRegion == (HANDLE)1)
184 Rect1.left = Rect1.top = 0;
185 Rect1.right = Parent->WindowRect.right -
186 Parent->WindowRect.left;
187 Rect1.bottom = Parent->WindowRect.bottom -
188 Parent->WindowRect.top;
190 Parent->UpdateRegion =
191 UnsafeW32kCreateRectRgnIndirect(&Rect1);
193 Offset.x = Child->WindowRect.left - Parent->WindowRect.left;
194 Offset.y = Child->WindowRect.top - Parent->WindowRect.top;
195 W32kOffsetRgn(hRgn, Offset.x, Offset.y);
196 W32kCombineRgn(Parent->UpdateRegion, Parent->UpdateRegion, hRgn,
198 W32kOffsetRgn(hRgn, -Offset.x, -Offset.y);
201 Parent = Parent->Parent;
203 if (hRgn != Child->UpdateRegion)
205 W32kDeleteObject(Child->UpdateRegion);
207 W32kReleaseWindowObject(Desktop);
211 PaintUpdateRgns(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags,
214 BOOL HadOne = Window->UpdateRegion != NULL && hRgn;
215 BOOL HasChildren = !IsListEmpty(&Window->ChildrenListHead) &&
216 !(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
217 ((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN));
220 Rect.left = Rect.top = 0;
221 Rect.right = Window->WindowRect.right - Window->WindowRect.left;
222 Rect.bottom = Window->WindowRect.bottom - Window->WindowRect.top;
224 if (Flags & RDW_INVALIDATE)
226 if (hRgn > (HANDLE)1)
228 if (Window->UpdateRegion > (HANDLE)1)
230 W32kCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
232 Window->UpdateRegion =
233 REGION_CropRgn(Window->UpdateRegion,
234 Window->UpdateRegion, &Rect, NULL);
237 W32kGetRgnBox(Window->UpdateRegion, &Rect);
238 if (W32kIsEmptyRect(&Rect))
240 W32kDeleteObject(Window->UpdateRegion);
241 Window->UpdateRegion = NULL;
242 PaintUpdateInternalPaint(Window, Flags);
247 else if (Window->UpdateRegion == 0)
249 Window->UpdateRegion =
250 REGION_CropRgn(Window->UpdateRegion, hRgn, &Rect, NULL);
253 W32kGetRgnBox(Window->UpdateRegion, &Rect);
254 if (W32kIsEmptyRect(&Rect))
256 W32kDeleteObject(Window->UpdateRegion);
257 Window->UpdateRegion = NULL;
258 PaintUpdateInternalPaint(Window, Flags);
264 else if (hRgn == (HANDLE)1)
266 if (Window->UpdateRegion > (HANDLE)1)
268 W32kDeleteObject(Window->UpdateRegion);
270 Window->UpdateRegion = (HANDLE)1;
274 hRgn = Window->UpdateRegion;
277 if (!HadOne && !(Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
279 MsqIncPaintCountQueue(Window->MessageQueue);
282 if (Flags & RDW_FRAME)
284 Window->Flags |= WINDOWOBJECT_NEED_NCPAINT;
286 if (Flags & RDW_ERASE)
288 Window->Flags |= WINDOWOBJECT_NEED_ERASEBACKGRD;
292 else if (Flags & RDW_VALIDATE)
294 if (Window->UpdateRegion != NULL)
296 if (hRgn > (HANDLE)1)
298 if (Window->UpdateRegion == (HANDLE)1)
300 Window->UpdateRegion =
301 UnsafeW32kCreateRectRgnIndirect(&Rect);
303 if (W32kCombineRgn(Window->UpdateRegion,
304 Window->UpdateRegion, hRgn,
305 RGN_DIFF) == NULLREGION)
307 if (Window->UpdateRegion > (HANDLE)1)
309 W32kDeleteObject(Window->UpdateRegion);
311 Window->UpdateRegion = NULL;
316 if (Window->UpdateRegion > (HANDLE)1)
318 W32kDeleteObject(Window->UpdateRegion);
320 Window->UpdateRegion = NULL;
323 if (Window->UpdateRegion == NULL)
325 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
326 if (!(Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
328 MsqIncPaintCountQueue(Window->MessageQueue);
333 if (Flags & RDW_NOFRAME)
335 Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
337 if (Flags & RDW_NOERASE)
339 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
343 if (First && Window->UpdateRegion != NULL && (Flags & RDW_UPDATENOW))
345 PaintValidateParent(Window);
348 if (Flags & (RDW_INVALIDATE | RDW_VALIDATE))
350 if (hRgn > (HANDLE)1 && HasChildren)
352 POINT Total = {0, 0};
353 POINT PrevOrign = {0, 0};
355 PWINDOW_OBJECT Child;
356 PLIST_ENTRY ChildListEntry;
358 Client.x = Window->ClientRect.left - Window->WindowRect.left;
359 Client.y = Window->ClientRect.top - Window->WindowRect.top;
361 ChildListEntry = Window->ChildrenListHead.Flink;
362 while (ChildListEntry != &Window->ChildrenListHead)
364 Child = CONTAINING_RECORD(ChildListEntry, WINDOW_OBJECT,
366 if (Child->Style & WS_VISIBLE)
370 Rect.left = Window->WindowRect.left + Client.x;
371 Rect.right = Window->WindowRect.right + Client.x;
372 Rect.top = Window->WindowRect.top + Client.y;
373 Rect.bottom = Window->WindowRect.bottom + Client.y;
375 Offset.x = Rect.left - PrevOrign.x;
376 Offset.y = Rect.top - PrevOrign.y;
377 W32kOffsetRect(&Rect, -Total.x, -Total.y);
379 if (W32kRectInRegion(hRgn, &Rect))
381 W32kOffsetRgn(hRgn, -Total.x, -Total.y);
382 PaintUpdateRgns(Child, hRgn, Flags, FALSE);
383 PrevOrign.x = Rect.left + Total.x;
384 PrevOrign.y = Rect.right + Total.y;
390 W32kOffsetRgn(hRgn, Total.x, Total.y);
397 PWINDOW_OBJECT Child;
398 PLIST_ENTRY ChildListEntry;
400 ChildListEntry = Window->ChildrenListHead.Flink;
401 while (ChildListEntry != &Window->ChildrenListHead)
403 Child = CONTAINING_RECORD(ChildListEntry, WINDOW_OBJECT,
405 if (Child->Style & WS_VISIBLE)
407 PaintUpdateRgns(Child, hRgn, Flags, FALSE);
412 PaintUpdateInternalPaint(Window, Flags);
416 PaintRedrawWindow(HWND hWnd, const RECT* UpdateRect, HRGN UpdateRgn,
417 ULONG Flags, ULONG ExFlags)
419 PWINDOW_OBJECT Window;
424 /* FIXME: Return if this is for a desktop. */
426 Window = W32kGetWindowObject(hWnd);
432 if (Flags & RDW_FRAME)
434 Rect = Window->WindowRect;
438 Rect = Window->ClientRect;
441 if (ExFlags & RDW_EX_XYWINDOW)
444 W32kOffsetRect(&Rect, -Window->WindowRect.left, -Window->WindowRect.top);
448 Pt.x = Window->ClientRect.left - Window->WindowRect.left;
449 Pt.y = Window->ClientRect.top - Window->WindowRect.top;
450 W32kOffsetRect(&Rect, -Window->ClientRect.left, -Window->WindowRect.top);
453 if (Flags & RDW_INVALIDATE)
455 if (UpdateRgn != NULL)
457 if (Window->UpdateRegion != NULL)
459 hRgn = REGION_CropRgn(0, UpdateRgn, NULL, &Pt);
463 Window->UpdateRegion = REGION_CropRgn(0, UpdateRgn, &Rect, &Pt);
466 else if (UpdateRect != NULL)
468 if (!W32kIntersectRect(&Rect2, &Rect, UpdateRect))
470 W32kReleaseWindowObject(Window);
471 if (hRgn != NULL && hRgn != (HRGN)1)
473 W32kDeleteObject(hRgn);
477 if (Window->UpdateRegion == NULL)
479 Window->UpdateRegion =
480 UnsafeW32kCreateRectRgnIndirect(&Rect2);
484 hRgn = UnsafeW32kCreateRectRgnIndirect(&Rect2);
489 if (Flags & RDW_FRAME)
495 W32kGetClientRect(hWnd, &Rect2);
496 hRgn = UnsafeW32kCreateRectRgnIndirect(&Rect2);
500 else if (Flags & RDW_VALIDATE)
502 /* FIXME: Implement this. */
505 PaintUpdateRgns(Window, hRgn, Flags, TRUE);
507 hRgn = PaintDoPaint(Window, hRgn == (HANDLE)1 ? 0 : hRgn, Flags, ExFlags);
509 if (hRgn != (HANDLE)1 && hRgn != UpdateRgn)
511 W32kDeleteObject(hRgn);
513 W32kReleaseWindowObject(Window);
518 PaintHaveToDelayNCPaint(PWINDOW_OBJECT Window, ULONG Flags)
520 if (Flags & UNC_DELAY_NCPAINT)
525 if (Flags & UNC_IN_BEGINPAINT)
530 Window = Window->Parent;
531 while (Window != NULL)
533 if (Window->Style & WS_CLIPCHILDREN && Window->UpdateRegion != NULL)
537 Window = Window->Parent;
543 PaintingFindWinToRepaint(HWND hWnd, PW32THREAD Thread)
545 PWINDOW_OBJECT Window;
546 PWINDOW_OBJECT BaseWindow;
547 PLIST_ENTRY current_entry;
548 HWND hFoundWnd = NULL;
552 ExAcquireFastMutex(&Thread->WindowListLock);
553 current_entry = Thread->WindowListHead.Flink;
554 while (current_entry != &Thread->WindowListHead)
556 Window = CONTAINING_RECORD(current_entry, WINDOW_OBJECT,
558 if (Window->Style & WS_VISIBLE)
561 PaintingFindWinToRepaint(Window->Self, Thread);
562 if (hFoundWnd != NULL)
564 ExReleaseFastMutex(&Thread->WindowListLock);
568 current_entry = current_entry->Flink;
570 ExReleaseFastMutex(&Thread->WindowListLock);
574 BaseWindow = W32kGetWindowObject(hWnd);
575 if (BaseWindow == NULL)
579 if (BaseWindow->UpdateRegion != NULL ||
580 BaseWindow->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
582 W32kReleaseWindowObject(BaseWindow);
586 ExAcquireFastMutex(&BaseWindow->ChildrenListLock);
587 current_entry = Thread->WindowListHead.Flink;
588 while (current_entry != &Thread->WindowListHead)
590 Window = CONTAINING_RECORD(current_entry, WINDOW_OBJECT,
592 if (Window->Style & WS_VISIBLE)
594 hFoundWnd = PaintingFindWinToRepaint(Window->Self, Thread);
595 if (hFoundWnd != NULL)
600 current_entry = current_entry->Flink;
602 ExReleaseFastMutex(&BaseWindow->ChildrenListLock);
603 W32kReleaseWindowObject(BaseWindow);
608 PaintUpdateNCRegion(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
614 /* Desktop has no parent. */
615 if (Window->Parent == NULL)
617 Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
618 if (Window->UpdateRegion > (HANDLE)1)
620 hRgnRet = REGION_CropRgn(hRgn, Window->UpdateRegion, NULL, NULL);
624 hRgnRet = Window->UpdateRegion;
629 if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT &&
630 !PaintHaveToDelayNCPaint(Window, Flags))
632 RECT UpdateRegionBox;
635 Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
636 W32kGetClientRect(Window, &ClientRect);
638 if (Window->UpdateRegion > (HRGN)1)
640 W32kGetRgnBox(Window->UpdateRegion, &UpdateRegionBox);
641 W32kUnionRect(&Rect, &ClientRect, &UpdateRegionBox);
642 if (Rect.left != ClientRect.left || Rect.top != ClientRect.top ||
643 Rect.right != ClientRect.right || Rect.right != ClientRect.right)
645 hClip = Window->UpdateRegion;
646 Window->UpdateRegion = REGION_CropRgn(hRgn, hClip,
648 if (Flags & UNC_REGION)
654 if (Flags & UNC_CHECK)
656 W32kGetRgnBox(Window->UpdateRegion, &UpdateRegionBox);
657 if (W32kIsEmptyRect(&UpdateRegionBox))
659 W32kDeleteObject(Window->UpdateRegion);
660 Window->UpdateRegion = NULL;
661 MsqDecPaintCountQueue(Window->MessageQueue);
662 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
666 if (!hClip && Window->UpdateRegion && Flags & UNC_REGION)
668 hRgnRet = REGION_CropRgn(hRgn, Window->UpdateRegion, NULL,
672 else if (Window->UpdateRegion == (HRGN)1)
674 if (Flags & UNC_UPDATE)
676 Window->UpdateRegion =
677 UnsafeW32kCreateRectRgnIndirect(&ClientRect);
679 if (Flags & UNC_REGION)
688 if (Window->UpdateRegion > (HANDLE)1 && Flags & UNC_REGION)
690 hRgnRet = REGION_CropRgn(hRgn, Window->UpdateRegion, NULL, NULL);
692 else if (Window->UpdateRegion == (HANDLE)1 && Flags & UNC_UPDATE)
694 W32kGetClientRect(Window, &ClientRect);
695 Window->UpdateRegion =
696 UnsafeW32kCreateRectRgnIndirect(&ClientRect);
697 if (Flags & UNC_REGION)
704 if (hClip == NULL && Flags & UNC_ENTIRE)
706 if (RtlCompareMemory(&Window->WindowRect, &Window->ClientRect,
707 sizeof(RECT)) != sizeof(RECT))
719 if (hClip == hRgnRet && hRgnRet > (HANDLE)1)
721 hClip = W32kCreateRectRgn(0, 0, 0, 0);
722 W32kCombineRgn(hClip, hRgnRet, 0, RGN_COPY);
725 NtUserSendMessage(Window->Self, WM_NCPAINT, (WPARAM)hClip, 0);
727 if (hClip > (HANDLE)1 && hClip != hRgn && hClip != hRgnRet)
729 W32kDeleteObject(hClip);
730 /* FIXME: Need to check the window is still valid. */
737 NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* lPs)
739 NtUserReleaseDC(hWnd, lPs->hdc);
740 /* FIXME: Show claret. */
745 NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* lPs)
748 PWINDOW_OBJECT Window;
755 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
759 if (!NT_SUCCESS(Status))
763 if (Window->Flags & WINDOWOBJECT_NEED_ERASEBACKGRD) { DbgPrint("[ayes:0]"); } else { DbgPrint("[ano:0]"); } /*testing*/
764 IsIcon = Window->Style & WS_MINIMIZE &&
765 NtUserGetClassLong(Window->Self, GCL_HICON);
767 Window->Flags &= ~WINDOWOBJECT_NEED_BEGINPAINT;
769 /* Send WM_NCPAINT */
770 PaintUpdateNCRegion(Window, 0, UNC_UPDATE | UNC_IN_BEGINPAINT);
772 /* FIXME: Check the window is still valid. */
774 UpdateRegion = Window->UpdateRegion;
775 Window->UpdateRegion = 0;
776 if (UpdateRegion != NULL ||
777 (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
779 MsqDecPaintCountQueue(Window->MessageQueue);
781 Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
783 /* FIXME: Hide claret. */
786 if (NtUserGetClassLong(Window->Self, GCL_STYLE) & CS_PARENTDC)
788 if (UpdateRegion != NULL)
790 W32kDeleteObject(UpdateRegion);
792 lPs->hdc = NtUserGetDCEx(hWnd, 0, DCX_WINDOWPAINT | DCX_USESTYLE |
793 (IsIcon ? DCX_WINDOW : 0));
797 if (UpdateRegion != NULL)
799 W32kOffsetRgn(UpdateRegion,
800 Window->WindowRect.left -
801 Window->ClientRect.left,
802 Window->WindowRect.top -
803 Window->ClientRect.top);
805 lPs->hdc = NtUserGetDCEx(hWnd, UpdateRegion, DCX_INTERSECTRGN |
806 DCX_WINDOWPAINT | DCX_USESTYLE |
807 (IsIcon ? DCX_WINDOW : 0));
810 /* FIXME: Check for DC creation failure. */
812 W32kGetClientRect(Window, &ClientRect);
813 W32kGetClipBox(lPs->hdc, &ClipRect);
814 W32kLPtoDP(lPs->hdc, (LPPOINT)&ClipRect, 2);
815 W32kIntersectRect(&lPs->rcPaint, &ClientRect, &ClipRect);
816 W32kDPtoLP(lPs->hdc, (LPPOINT)&lPs->rcPaint, 2);
818 if (Window->Flags & WINDOWOBJECT_NEED_ERASEBACKGRD)
822 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
823 Result = NtUserSendMessage(hWnd,
824 IsIcon ? WM_ICONERASEBKGND : WM_ERASEBKGND,
827 lPs->fErase = !Result;
835 ObmDereferenceObject(Window);