update for HEAD-2003021201
[reactos.git] / subsys / win32k / ntuser / painting.c
1 /* $Id$
2  *
3  * COPYRIGHT:        See COPYING in the top level directory
4  * PROJECT:          ReactOS kernel
5  * PURPOSE:          Painting
6  * FILE:             subsys/win32k/ntuser/painting.c
7  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
8  * REVISION HISTORY:
9  *       06-06-2001  CSH  Created
10  */
11 /* INCLUDES ******************************************************************/
12
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>
21 #include <windows.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>
27
28
29 #define NDEBUG
30 #include <debug.h>
31
32 /* GLOBALS *******************************************************************/
33
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)
40
41 /* FUNCTIONS *****************************************************************/
42
43 HRGN STATIC
44 PaintDoPaint(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags, ULONG ExFlags)
45 {
46   HDC hDC;
47   HWND hWnd = Window->Self;
48   BOOL bIcon = (Window->Style & WS_MINIMIZE) &&
49     NtUserGetClassLong(hWnd, GCL_HICON);
50
51   if (ExFlags & RDW_EX_DELAY_NCPAINT ||
52       PaintHaveToDelayNCPaint(Window, 0))
53     {
54       ExFlags |= RDW_EX_DELAY_NCPAINT;
55     }
56
57   if (Flags & RDW_UPDATENOW)
58     {
59       if (Window->UpdateRegion != NULL)
60         {
61           NtUserSendMessage(hWnd, bIcon ? WM_PAINTICON : WM_PAINT, bIcon, 0);
62         }
63     }
64   else if (Flags & RDW_ERASENOW || ExFlags & RDW_EX_TOPFRAME)
65     {
66       UINT Dcx = DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN |
67         DCX_WINDOWPAINT | DCX_CACHE;
68       HRGN hRgnRet;
69
70       hRgnRet =
71         PaintUpdateNCRegion(Window,
72                          hRgn,
73                          UNC_REGION | UNC_CHECK |
74                          ((ExFlags & RDW_EX_TOPFRAME) ? UNC_ENTIRE : 0) |
75                          ((ExFlags & RDW_EX_DELAY_NCPAINT) ?
76                           UNC_DELAY_NCPAINT : 0));
77       if (hRgnRet != NULL)
78         {
79           if (hRgnRet != (HRGN)1)
80             {
81               hRgn = hRgnRet;
82             }
83           else
84             {
85               hRgnRet = NULL;
86             }
87           if (Window->Flags & WINDOWOBJECT_NEED_ERASEBACKGRD)
88             {
89               if (bIcon)
90                 {
91                   Dcx |= DCX_WINDOW;
92                 }
93               if (hRgnRet)
94                 {
95                   W32kOffsetRgn(hRgnRet,
96                                 Window->WindowRect.left -
97                                 Window->ClientRect.left,
98                                 Window->WindowRect.top -
99                                 Window->ClientRect.top);
100                 }
101               else
102                 {
103                   Dcx &= ~DCX_INTERSECTRGN;
104                 }
105               if ((hDC = NtUserGetDCEx(hWnd, hRgnRet, Dcx)) != NULL)
106                 {
107                   LRESULT Result;
108                   Result = NtUserSendMessage(hWnd, bIcon ? WM_ICONERASEBKGND :
109                                              WM_ERASEBKGND, (WPARAM)hDC, 0);
110                   Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
111                   NtUserReleaseDC(hWnd, hDC);
112                 }
113             }
114         }
115     }
116
117   /* FIXME: Check that the window is still valid at this point. */
118
119   ExFlags &= ~RDW_EX_TOPFRAME;
120
121   /* FIXME: Paint child windows. */
122
123   return(hRgn);
124 }
125
126 VOID STATIC
127 PaintUpdateInternalPaint(PWINDOW_OBJECT Window, ULONG Flags)
128 {
129   if (Flags & RDW_INTERNALPAINT)
130     {
131       if (Window->UpdateRegion == NULL &&
132           !(Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
133         {
134           MsqIncPaintCountQueue(Window->MessageQueue);
135         }
136       Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
137     }
138   else if (Flags & RDW_NOINTERNALPAINT)
139     {
140       if (Window->UpdateRegion == NULL &&
141           (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
142         {
143           MsqDecPaintCountQueue(Window->MessageQueue);
144         }
145       Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
146     }
147 }
148
149 VOID STATIC
150 PaintValidateParent(PWINDOW_OBJECT Child)
151 {
152   HWND DesktopHandle = W32kGetDesktopWindow();
153   PWINDOW_OBJECT Parent = Child->Parent;
154   PWINDOW_OBJECT Desktop = W32kGetWindowObject(DesktopHandle);
155   HRGN hRgn;
156
157   if (Child->UpdateRegion == (HANDLE)1)
158     {
159       RECT Rect;
160
161       Rect.left = Rect.top = 0;
162       Rect.right = Child->WindowRect.right - Child->WindowRect.left;
163       Rect.bottom = Child->WindowRect.bottom - Child->WindowRect.top;
164
165       hRgn = UnsafeW32kCreateRectRgnIndirect(&Rect);
166     }
167   else
168     {
169       hRgn = Child->UpdateRegion;
170     }
171
172   while (Parent != NULL && Parent != Desktop)
173     {
174       if (!(Parent->Style & WS_CLIPCHILDREN))
175         {
176           if (Parent->UpdateRegion != (HANDLE)0)
177             {
178               POINT Offset;
179
180               if (Parent->UpdateRegion == (HANDLE)1)
181                 {
182                   RECT Rect1;
183
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;
189
190                   Parent->UpdateRegion = 
191                     UnsafeW32kCreateRectRgnIndirect(&Rect1);
192                 }
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,
197                              RGN_DIFF);
198               W32kOffsetRgn(hRgn, -Offset.x, -Offset.y);
199             }
200         }
201       Parent = Parent->Parent;
202     }
203   if (hRgn != Child->UpdateRegion)
204     {
205       W32kDeleteObject(Child->UpdateRegion);
206     }
207   W32kReleaseWindowObject(Desktop);
208 }
209
210 VOID STATIC
211 PaintUpdateRgns(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags,
212                 BOOL First)
213 {
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));
218   RECT Rect;
219
220   Rect.left = Rect.top = 0;
221   Rect.right = Window->WindowRect.right - Window->WindowRect.left;
222   Rect.bottom = Window->WindowRect.bottom - Window->WindowRect.top;
223
224   if (Flags & RDW_INVALIDATE)
225     {
226       if (hRgn > (HANDLE)1)
227         {
228           if (Window->UpdateRegion > (HANDLE)1)
229             {
230               W32kCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
231                              hRgn, RGN_OR);
232               Window->UpdateRegion =
233                 REGION_CropRgn(Window->UpdateRegion,
234                                Window->UpdateRegion, &Rect, NULL);
235               if (!HadOne)
236                 {
237                   W32kGetRgnBox(Window->UpdateRegion, &Rect);
238                   if (W32kIsEmptyRect(&Rect))
239                     {
240                       W32kDeleteObject(Window->UpdateRegion);
241                       Window->UpdateRegion = NULL;
242                       PaintUpdateInternalPaint(Window, Flags);
243                       return;
244                     }
245                 }
246             }
247           else if (Window->UpdateRegion == 0)
248             {
249               Window->UpdateRegion =
250                 REGION_CropRgn(Window->UpdateRegion, hRgn, &Rect, NULL);
251               if (!HadOne)
252                 {
253                   W32kGetRgnBox(Window->UpdateRegion, &Rect);
254                   if (W32kIsEmptyRect(&Rect))
255                     {
256                       W32kDeleteObject(Window->UpdateRegion);
257                       Window->UpdateRegion = NULL;
258                       PaintUpdateInternalPaint(Window, Flags);
259                       return;
260                     }
261                 }
262             }
263         }
264       else if (hRgn == (HANDLE)1)
265         {
266           if (Window->UpdateRegion > (HANDLE)1)
267             {
268               W32kDeleteObject(Window->UpdateRegion);
269             }
270           Window->UpdateRegion = (HANDLE)1;
271         }
272       else
273         {
274           hRgn = Window->UpdateRegion;
275         }
276
277       if (!HadOne && !(Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
278         {
279           MsqIncPaintCountQueue(Window->MessageQueue);
280         }
281
282       if (Flags & RDW_FRAME)
283         {
284           Window->Flags |= WINDOWOBJECT_NEED_NCPAINT;
285         }
286       if (Flags & RDW_ERASE)
287         {
288           Window->Flags |= WINDOWOBJECT_NEED_ERASEBACKGRD;
289         }
290       Flags |= RDW_FRAME;
291     }
292   else if (Flags & RDW_VALIDATE)
293     {
294       if (Window->UpdateRegion != NULL)
295         {
296           if (hRgn > (HANDLE)1)
297             {
298               if (Window->UpdateRegion == (HANDLE)1)
299                 {
300                   Window->UpdateRegion = 
301                     UnsafeW32kCreateRectRgnIndirect(&Rect);
302                 }
303               if (W32kCombineRgn(Window->UpdateRegion, 
304                                  Window->UpdateRegion, hRgn, 
305                                  RGN_DIFF) == NULLREGION)
306                 {
307                   if (Window->UpdateRegion > (HANDLE)1)
308                     {
309                       W32kDeleteObject(Window->UpdateRegion);
310                     }
311                   Window->UpdateRegion = NULL;
312                 }
313             }
314           else
315             {
316               if (Window->UpdateRegion > (HANDLE)1)
317                 {
318                   W32kDeleteObject(Window->UpdateRegion);
319                 }
320               Window->UpdateRegion = NULL;
321             }
322
323           if (Window->UpdateRegion == NULL)
324             {
325               Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
326               if (!(Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
327                 {
328                   MsqIncPaintCountQueue(Window->MessageQueue);
329                 }
330             }
331         }
332
333       if (Flags & RDW_NOFRAME)
334         {
335           Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
336         }
337       if (Flags & RDW_NOERASE)
338         {
339           Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
340         }
341     }
342
343   if (First && Window->UpdateRegion != NULL && (Flags & RDW_UPDATENOW))
344     {
345       PaintValidateParent(Window);
346     }
347
348   if (Flags & (RDW_INVALIDATE | RDW_VALIDATE))
349     {
350       if (hRgn > (HANDLE)1 && HasChildren)
351         {
352           POINT Total = {0, 0};
353           POINT PrevOrign = {0, 0};
354           POINT Client;
355           PWINDOW_OBJECT Child;
356           PLIST_ENTRY ChildListEntry;
357
358           Client.x = Window->ClientRect.left - Window->WindowRect.left;
359           Client.y = Window->ClientRect.top - Window->WindowRect.top;     
360
361           ChildListEntry = Window->ChildrenListHead.Flink;
362           while (ChildListEntry != &Window->ChildrenListHead)
363             {
364               Child = CONTAINING_RECORD(ChildListEntry, WINDOW_OBJECT, 
365                                         SiblingListEntry);
366               if (Child->Style & WS_VISIBLE)
367                 {
368                   POINT Offset;
369
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;
374
375                   Offset.x = Rect.left - PrevOrign.x;
376                   Offset.y = Rect.top - PrevOrign.y;
377                   W32kOffsetRect(&Rect, -Total.x, -Total.y);
378
379                   if (W32kRectInRegion(hRgn, &Rect))
380                     {
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;
385                       Total.x += Offset.x;
386                       Total.y += Offset.y;
387                     }
388                 }
389             }
390           W32kOffsetRgn(hRgn, Total.x, Total.y);
391           HasChildren = FALSE;
392         }
393     }
394
395   if (HasChildren)
396     {
397       PWINDOW_OBJECT Child;
398       PLIST_ENTRY ChildListEntry;
399
400       ChildListEntry = Window->ChildrenListHead.Flink;
401       while (ChildListEntry != &Window->ChildrenListHead)
402         {
403           Child = CONTAINING_RECORD(ChildListEntry, WINDOW_OBJECT, 
404                                     SiblingListEntry);
405           if (Child->Style & WS_VISIBLE)
406             {
407               PaintUpdateRgns(Child, hRgn, Flags, FALSE);
408             }
409         }
410     }
411
412   PaintUpdateInternalPaint(Window, Flags);
413 }
414
415 BOOL
416 PaintRedrawWindow(HWND hWnd, const RECT* UpdateRect, HRGN UpdateRgn,
417                   ULONG Flags, ULONG ExFlags)
418 {
419   PWINDOW_OBJECT Window;
420   RECT Rect, Rect2;
421   POINT Pt;
422   HRGN hRgn;
423
424   /* FIXME: Return if this is for a desktop. */
425
426   Window = W32kGetWindowObject(hWnd);
427   if (Window == NULL)
428     {
429       return(FALSE);
430     }
431
432   if (Flags & RDW_FRAME)
433     {
434       Rect = Window->WindowRect;
435     }
436   else
437     {
438       Rect = Window->ClientRect;
439     }
440
441   if (ExFlags & RDW_EX_XYWINDOW)
442     {
443       Pt.x = Pt.y = 0;
444       W32kOffsetRect(&Rect, -Window->WindowRect.left, -Window->WindowRect.top);
445     }
446   else
447     {
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);
451     }
452
453   if (Flags & RDW_INVALIDATE)
454     {
455       if (UpdateRgn != NULL)
456         {
457           if (Window->UpdateRegion != NULL)
458             {
459               hRgn = REGION_CropRgn(0, UpdateRgn, NULL, &Pt);
460             }
461           else
462             {
463               Window->UpdateRegion = REGION_CropRgn(0, UpdateRgn, &Rect, &Pt);
464             }
465         }
466       else if (UpdateRect != NULL)
467         {
468           if (!W32kIntersectRect(&Rect2, &Rect, UpdateRect))
469             {
470               W32kReleaseWindowObject(Window);
471               if (hRgn != NULL && hRgn != (HRGN)1)
472                 {
473                   W32kDeleteObject(hRgn);
474                 }
475               return(TRUE);
476             }
477           if (Window->UpdateRegion == NULL)
478             {
479               Window->UpdateRegion = 
480                 UnsafeW32kCreateRectRgnIndirect(&Rect2);
481             }
482           else
483             {
484               hRgn = UnsafeW32kCreateRectRgnIndirect(&Rect2);
485             }
486         }
487       else
488         {
489           if (Flags & RDW_FRAME)
490             {
491               hRgn = (HRGN)1;
492             }
493           else
494             {
495               W32kGetClientRect(hWnd, &Rect2);
496               hRgn = UnsafeW32kCreateRectRgnIndirect(&Rect2);
497             }
498         }
499     }
500   else if (Flags & RDW_VALIDATE)
501     {
502       /* FIXME: Implement this. */
503     }
504
505   PaintUpdateRgns(Window, hRgn, Flags, TRUE);
506
507   hRgn = PaintDoPaint(Window, hRgn == (HANDLE)1 ? 0 : hRgn, Flags, ExFlags);
508
509   if (hRgn != (HANDLE)1 && hRgn != UpdateRgn)
510     {
511       W32kDeleteObject(hRgn);
512     }
513   W32kReleaseWindowObject(Window);
514   return(TRUE);
515 }
516
517 BOOL STDCALL
518 PaintHaveToDelayNCPaint(PWINDOW_OBJECT Window, ULONG Flags)
519 {
520   if (Flags & UNC_DELAY_NCPAINT)
521     {
522       return(TRUE);
523     }
524
525   if (Flags & UNC_IN_BEGINPAINT)
526     {
527       return(FALSE);
528     }
529
530   Window = Window->Parent;
531   while (Window != NULL)
532     {
533       if (Window->Style & WS_CLIPCHILDREN && Window->UpdateRegion != NULL)
534         {
535           return(TRUE);
536         }
537       Window = Window->Parent;
538     }
539   return(FALSE);
540 }
541
542 HWND STDCALL
543 PaintingFindWinToRepaint(HWND hWnd, PW32THREAD Thread)
544 {
545   PWINDOW_OBJECT Window;
546   PWINDOW_OBJECT BaseWindow;
547   PLIST_ENTRY current_entry;
548   HWND hFoundWnd = NULL;
549
550   if (hWnd == NULL)
551     {
552       ExAcquireFastMutex(&Thread->WindowListLock);
553       current_entry = Thread->WindowListHead.Flink;
554       while (current_entry != &Thread->WindowListHead)
555         {
556           Window = CONTAINING_RECORD(current_entry, WINDOW_OBJECT,
557                                      ThreadListEntry);
558           if (Window->Style & WS_VISIBLE)
559             {
560               hFoundWnd = 
561                 PaintingFindWinToRepaint(Window->Self, Thread);
562               if (hFoundWnd != NULL)
563                 {
564                   ExReleaseFastMutex(&Thread->WindowListLock);
565                   return(hFoundWnd);
566                 }
567             }
568           current_entry = current_entry->Flink;
569         }
570       ExReleaseFastMutex(&Thread->WindowListLock);
571       return(NULL);
572     }
573
574   BaseWindow = W32kGetWindowObject(hWnd);
575   if (BaseWindow == NULL)
576     {
577       return(NULL);
578     }
579   if (BaseWindow->UpdateRegion != NULL ||
580       BaseWindow->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
581     {
582       W32kReleaseWindowObject(BaseWindow);
583       return(hWnd);
584     }
585
586   ExAcquireFastMutex(&BaseWindow->ChildrenListLock);
587   current_entry = Thread->WindowListHead.Flink;
588   while (current_entry != &Thread->WindowListHead)
589     {
590       Window = CONTAINING_RECORD(current_entry, WINDOW_OBJECT,
591                                  ThreadListEntry);
592       if (Window->Style & WS_VISIBLE)
593         {
594           hFoundWnd = PaintingFindWinToRepaint(Window->Self, Thread);
595           if (hFoundWnd != NULL)
596             {
597               break;
598             }
599         }
600       current_entry = current_entry->Flink;
601     }
602   ExReleaseFastMutex(&BaseWindow->ChildrenListLock);
603   W32kReleaseWindowObject(BaseWindow);
604   return(hFoundWnd);
605 }
606
607 HRGN STDCALL
608 PaintUpdateNCRegion(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
609 {
610   HRGN hRgnRet;
611   RECT ClientRect;
612   HRGN hClip = NULL;
613
614   /* Desktop has no parent. */
615   if (Window->Parent == NULL)
616     {
617       Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
618       if (Window->UpdateRegion > (HANDLE)1)
619         {
620           hRgnRet = REGION_CropRgn(hRgn, Window->UpdateRegion, NULL, NULL);
621         }
622       else
623         {
624           hRgnRet = Window->UpdateRegion;
625         }
626       return(hRgnRet);
627     }
628
629   if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT &&
630       !PaintHaveToDelayNCPaint(Window, Flags))
631     {
632       RECT UpdateRegionBox;
633       RECT Rect;
634
635       Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
636       W32kGetClientRect(Window, &ClientRect);
637
638       if (Window->UpdateRegion > (HRGN)1)
639         {
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)
644             {
645               hClip = Window->UpdateRegion;
646               Window->UpdateRegion = REGION_CropRgn(hRgn, hClip,
647                                                  &Rect, NULL);
648               if (Flags & UNC_REGION)
649                 {
650                   hRgnRet = hClip;
651                 }
652             }
653
654           if (Flags & UNC_CHECK)
655             {
656               W32kGetRgnBox(Window->UpdateRegion, &UpdateRegionBox);
657               if (W32kIsEmptyRect(&UpdateRegionBox))
658                 {
659                   W32kDeleteObject(Window->UpdateRegion);
660                   Window->UpdateRegion = NULL;
661                   MsqDecPaintCountQueue(Window->MessageQueue);
662                   Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
663                 }
664             }
665
666           if (!hClip && Window->UpdateRegion && Flags & UNC_REGION)
667             {
668               hRgnRet = REGION_CropRgn(hRgn, Window->UpdateRegion, NULL,
669                                     NULL);
670             }
671         }
672       else if (Window->UpdateRegion == (HRGN)1)
673         {
674           if (Flags & UNC_UPDATE)
675             {
676               Window->UpdateRegion =
677                 UnsafeW32kCreateRectRgnIndirect(&ClientRect);
678             }
679           if (Flags & UNC_REGION)
680             {
681               hRgnRet = (HANDLE)1;
682             }
683           Flags |= UNC_ENTIRE;
684         }
685     }
686   else
687     {
688       if (Window->UpdateRegion > (HANDLE)1 && Flags & UNC_REGION)
689         {
690           hRgnRet = REGION_CropRgn(hRgn, Window->UpdateRegion, NULL, NULL);
691         }
692       else if (Window->UpdateRegion == (HANDLE)1 && Flags & UNC_UPDATE)
693         {
694           W32kGetClientRect(Window, &ClientRect);
695           Window->UpdateRegion =
696             UnsafeW32kCreateRectRgnIndirect(&ClientRect);
697           if (Flags & UNC_REGION)
698             {
699               hRgnRet = (HANDLE)1;
700             }
701         }
702     }
703
704   if (hClip == NULL && Flags & UNC_ENTIRE)
705     {
706       if (RtlCompareMemory(&Window->WindowRect, &Window->ClientRect,
707                            sizeof(RECT)) != sizeof(RECT))
708         {
709           hClip = (HANDLE)1;
710         }
711       else
712         {
713           hClip = 0;
714         }
715     }
716
717   if (hClip != 0)
718     {
719       if (hClip == hRgnRet && hRgnRet > (HANDLE)1)
720         {
721           hClip = W32kCreateRectRgn(0, 0, 0, 0);
722           W32kCombineRgn(hClip, hRgnRet, 0, RGN_COPY);
723         }
724
725       NtUserSendMessage(Window->Self, WM_NCPAINT, (WPARAM)hClip, 0);
726
727       if (hClip > (HANDLE)1 && hClip != hRgn && hClip != hRgnRet)
728         {
729           W32kDeleteObject(hClip);
730           /* FIXME: Need to check the window is still valid. */
731         }
732     }
733   return(hRgnRet);
734 }
735
736 BOOL STDCALL
737 NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* lPs)
738 {
739   NtUserReleaseDC(hWnd, lPs->hdc);
740   /* FIXME: Show claret. */
741   return(TRUE);
742 }
743
744 HDC STDCALL
745 NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* lPs)
746 {
747   BOOL IsIcon;
748   PWINDOW_OBJECT Window;
749   HRGN UpdateRegion;
750   RECT ClientRect;
751   RECT ClipRect;
752   NTSTATUS Status;
753
754   Status =
755     ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
756                                hWnd,
757                                otWindow,
758                                (PVOID*)&Window);
759   if (!NT_SUCCESS(Status))
760     {
761       return(NULL);
762     }
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);
766
767   Window->Flags &= ~WINDOWOBJECT_NEED_BEGINPAINT;
768
769   /* Send WM_NCPAINT */
770   PaintUpdateNCRegion(Window, 0, UNC_UPDATE | UNC_IN_BEGINPAINT);
771
772   /* FIXME: Check the window is still valid. */
773
774   UpdateRegion = Window->UpdateRegion;
775   Window->UpdateRegion = 0;
776   if (UpdateRegion != NULL ||
777       (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
778     {
779       MsqDecPaintCountQueue(Window->MessageQueue);
780     }
781   Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
782
783   /* FIXME: Hide claret. */
784
785
786   if (NtUserGetClassLong(Window->Self, GCL_STYLE) & CS_PARENTDC)
787     {
788       if (UpdateRegion != NULL)
789         {
790           W32kDeleteObject(UpdateRegion);
791         }
792       lPs->hdc = NtUserGetDCEx(hWnd, 0, DCX_WINDOWPAINT | DCX_USESTYLE |
793                                (IsIcon ? DCX_WINDOW : 0));
794     }
795   else
796     {
797       if (UpdateRegion != NULL)
798         {
799           W32kOffsetRgn(UpdateRegion,
800                         Window->WindowRect.left -
801                         Window->ClientRect.left,
802                         Window->WindowRect.top -
803                         Window->ClientRect.top);
804         }
805       lPs->hdc = NtUserGetDCEx(hWnd, UpdateRegion, DCX_INTERSECTRGN |
806                                DCX_WINDOWPAINT | DCX_USESTYLE |
807                                (IsIcon ? DCX_WINDOW : 0));
808     }
809
810   /* FIXME: Check for DC creation failure. */
811
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);
817
818   if (Window->Flags & WINDOWOBJECT_NEED_ERASEBACKGRD)
819     {
820       BOOLEAN Result;
821 DbgPrint("[dne:0]");
822       Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
823       Result = NtUserSendMessage(hWnd,
824                                  IsIcon ? WM_ICONERASEBKGND : WM_ERASEBKGND,
825                                  (WPARAM)lPs->hdc,
826                                  0);
827       lPs->fErase = !Result;
828     }
829   else
830     {
831 DbgPrint("[dne:1]");
832       lPs->fErase = FALSE;
833     }
834
835   ObmDereferenceObject(Window);
836   return(lPs->hdc);
837 }