Fixed typo
[reactos.git] / reactos / subsys / win32k / ntuser / painting.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: painting.c,v 1.33 2003/09/11 22:11:44 gvg Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Painting
24 * FILE: subsys/win32k/ntuser/painting.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29 /* INCLUDES ******************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <win32k/win32k.h>
33 #include <include/object.h>
34 #include <include/guicheck.h>
35 #include <include/window.h>
36 #include <include/class.h>
37 #include <include/error.h>
38 #include <include/winsta.h>
39 #include <windows.h>
40 #include <include/painting.h>
41 #include <user32/wininternal.h>
42 #include <include/rect.h>
43 #include <win32k/coord.h>
44 #include <win32k/region.h>
45 #include <include/vis.h>
46
47 #define NDEBUG
48 #include <debug.h>
49
50
51 /* GLOBALS *******************************************************************/
52
53 /* client rect in window coordinates */
54 #define GETCLIENTRECTW(wnd, r) (r).left = (wnd)->ClientRect.left - (wnd)->WindowRect.left; \
55 (r).top = (wnd)->ClientRect.top - (wnd)->WindowRect.top; \
56 (r).right = (wnd)->ClientRect.right - (wnd)->WindowRect.left; \
57 (r).bottom = (wnd)->ClientRect.bottom - (wnd)->WindowRect.top
58
59 /* FUNCTIONS *****************************************************************/
60
61 HRGN STATIC STDCALL
62 PaintDoPaint(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags, ULONG ExFlags)
63 {
64 HDC hDC;
65 HWND hWnd = Window->Self;
66 BOOL bIcon = (0 != (Window->Style & WS_MINIMIZE)) &&
67 (0 != IntGetClassLong(Window, GCL_HICON, FALSE));
68
69 if (0 != (ExFlags & RDW_EX_DELAY_NCPAINT) ||
70 PaintHaveToDelayNCPaint(Window, 0))
71 {
72 ExFlags |= RDW_EX_DELAY_NCPAINT;
73 }
74
75 if (Flags & RDW_UPDATENOW)
76 {
77 if (NULL != Window->UpdateRegion)
78 {
79 if (IntIsDesktopWindow(Window))
80 {
81 VIS_RepaintDesktop(Window->Self, Window->UpdateRegion);
82 }
83 else
84 {
85 NtUserSendMessage(hWnd, bIcon ? WM_PAINTICON : WM_PAINT, bIcon, 0);
86 }
87 }
88 }
89 else if (Flags & RDW_ERASENOW || ExFlags & RDW_EX_TOPFRAME)
90 {
91 UINT Dcx = DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN |
92 DCX_WINDOWPAINT | DCX_CACHE;
93 HRGN hRgnRet;
94
95 hRgnRet =
96 PaintUpdateNCRegion(Window,
97 hRgn,
98 UNC_REGION | UNC_CHECK |
99 ((ExFlags & RDW_EX_TOPFRAME) ? UNC_ENTIRE : 0) |
100 ((ExFlags & RDW_EX_DELAY_NCPAINT) ?
101 UNC_DELAY_NCPAINT : 0));
102 if (NULL != hRgnRet)
103 {
104 if ((HRGN) 1 < hRgnRet)
105 {
106 hRgn = hRgnRet;
107 }
108 else
109 {
110 hRgnRet = NULL;
111 }
112 if (0 != (Window->Flags & WINDOWOBJECT_NEED_ERASEBACKGRD))
113 {
114 if (bIcon)
115 {
116 Dcx |= DCX_WINDOW;
117 }
118 if (NULL != hRgnRet)
119 {
120 NtGdiOffsetRgn(hRgnRet,
121 Window->WindowRect.left -
122 Window->ClientRect.left,
123 Window->WindowRect.top -
124 Window->ClientRect.top);
125 }
126 else
127 {
128 Dcx &= ~DCX_INTERSECTRGN;
129 }
130 if (NULL != (hDC = NtUserGetDCEx(hWnd, hRgnRet, Dcx)))
131 {
132 if (IntIsDesktopWindow(Window))
133 {
134 VIS_RepaintDesktop(Window->Self, Window->UpdateRegion);
135 NtGdiDeleteObject(Window->UpdateRegion);
136 Window->UpdateRegion = 0;
137 }
138 else
139 {
140 if (0 != NtUserSendMessage(hWnd, bIcon ? WM_ICONERASEBKGND :
141 WM_ERASEBKGND, (WPARAM)hDC, 0))
142 {
143 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
144 }
145 }
146 NtUserReleaseDC(hWnd, hDC);
147 }
148 }
149 }
150 }
151
152 /* FIXME: Check that the window is still valid at this point. */
153
154 ExFlags &= ~RDW_EX_TOPFRAME;
155
156 /* FIXME: Paint child windows. */
157
158 return(hRgn);
159 }
160
161 VOID STATIC FASTCALL
162 PaintUpdateInternalPaint(PWINDOW_OBJECT Window, ULONG Flags)
163 {
164 if (Flags & RDW_INTERNALPAINT)
165 {
166 if (Window->UpdateRegion == NULL &&
167 !(Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
168 {
169 MsqIncPaintCountQueue(Window->MessageQueue);
170 }
171 Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
172 }
173 else if (Flags & RDW_NOINTERNALPAINT)
174 {
175 if (Window->UpdateRegion == NULL &&
176 (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
177 {
178 MsqDecPaintCountQueue(Window->MessageQueue);
179 }
180 Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
181 }
182 }
183
184 VOID STATIC FASTCALL
185 PaintValidateParent(PWINDOW_OBJECT Child)
186 {
187 HWND DesktopHandle = IntGetDesktopWindow();
188 PWINDOW_OBJECT Parent = Child->Parent;
189 PWINDOW_OBJECT Desktop = IntGetWindowObject(DesktopHandle);
190 HRGN hRgn;
191
192 if ((HRGN) 1 == Child->UpdateRegion)
193 {
194 RECT Rect;
195
196 Rect.left = Rect.top = 0;
197 Rect.right = Child->WindowRect.right - Child->WindowRect.left;
198 Rect.bottom = Child->WindowRect.bottom - Child->WindowRect.top;
199
200 hRgn = UnsafeIntCreateRectRgnIndirect(&Rect);
201 }
202 else
203 {
204 hRgn = Child->UpdateRegion;
205 }
206
207 while (NULL != Parent && Parent != Desktop)
208 {
209 if (0 == (Parent->Style & WS_CLIPCHILDREN))
210 {
211 if (NULL != Parent->UpdateRegion)
212 {
213 POINT Offset;
214
215 if ((HRGN) 1 == Parent->UpdateRegion)
216 {
217 RECT Rect1;
218
219 Rect1.left = Rect1.top = 0;
220 Rect1.right = Parent->WindowRect.right -
221 Parent->WindowRect.left;
222 Rect1.bottom = Parent->WindowRect.bottom -
223 Parent->WindowRect.top;
224
225 Parent->UpdateRegion =
226 UnsafeIntCreateRectRgnIndirect(&Rect1);
227 }
228 Offset.x = Child->WindowRect.left - Parent->WindowRect.left;
229 Offset.y = Child->WindowRect.top - Parent->WindowRect.top;
230 NtGdiOffsetRgn(hRgn, Offset.x, Offset.y);
231 NtGdiCombineRgn(Parent->UpdateRegion, Parent->UpdateRegion, hRgn,
232 RGN_DIFF);
233 NtGdiOffsetRgn(hRgn, -Offset.x, -Offset.y);
234 }
235 }
236 Parent = Parent->Parent;
237 }
238 if (hRgn != Child->UpdateRegion)
239 {
240 NtGdiDeleteObject(Child->UpdateRegion);
241 }
242 IntReleaseWindowObject(Desktop);
243 }
244
245 VOID STATIC STDCALL
246 PaintUpdateRgns(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags,
247 BOOL First)
248 {
249 /*
250 * Called only when one of the following is set:
251 * (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT)
252 */
253
254 BOOL HadOne = NULL != Window->UpdateRegion && NULL != hRgn;
255 BOOL HasChildren = Window->FirstChild &&
256 !(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
257 ((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN));
258 RECT Rect;
259
260 Rect.left = Rect.top = 0;
261 Rect.right = Window->WindowRect.right - Window->WindowRect.left;
262 Rect.bottom = Window->WindowRect.bottom - Window->WindowRect.top;
263
264 if (Flags & RDW_INVALIDATE)
265 {
266 if ((HRGN) 1 < hRgn)
267 {
268 if ((HRGN) 1 != Window->UpdateRegion)
269 {
270 if ((HRGN) 1 < Window->UpdateRegion)
271 {
272 NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
273 hRgn, RGN_OR);
274 }
275 Window->UpdateRegion =
276 REGION_CropRgn(Window->UpdateRegion,
277 Window->UpdateRegion ? Window->UpdateRegion : hRgn,
278 &Rect, NULL);
279 if (! HadOne)
280 {
281 UnsafeIntGetRgnBox(Window->UpdateRegion, &Rect);
282 if (NtGdiIsEmptyRect(&Rect))
283 {
284 NtGdiDeleteObject(Window->UpdateRegion);
285 Window->UpdateRegion = NULL;
286 PaintUpdateInternalPaint(Window, Flags);
287 return;
288 }
289 }
290 }
291 }
292 else if ((HRGN) 1 == hRgn)
293 {
294 if ((HRGN) 1 < Window->UpdateRegion)
295 {
296 NtGdiDeleteObject(Window->UpdateRegion);
297 }
298 Window->UpdateRegion = (HRGN) 1;
299 }
300 else
301 {
302 hRgn = Window->UpdateRegion; /* this is a trick that depends on code in PaintRedrawWindow() */
303 }
304
305 if (! HadOne && 0 == (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT) &&
306 !IntIsDesktopWindow(Window))
307 {
308 MsqIncPaintCountQueue(Window->MessageQueue);
309 }
310
311 if (Flags & RDW_FRAME)
312 {
313 Window->Flags |= WINDOWOBJECT_NEED_NCPAINT;
314 }
315 if (Flags & RDW_ERASE)
316 {
317 Window->Flags |= WINDOWOBJECT_NEED_ERASEBACKGRD;
318 }
319 Flags |= RDW_FRAME;
320 }
321 else if (Flags & RDW_VALIDATE)
322 {
323 if (NULL != Window->UpdateRegion)
324 {
325 if ((HRGN) 1 < hRgn)
326 {
327 if ((HRGN) 1 == Window->UpdateRegion)
328 {
329 /* If no NCPAINT needed or if we're going to turn it off
330 the special value 1 means the whole client rect */
331 if (0 == (Window->Flags & WINDOWOBJECT_NEED_NCPAINT) ||
332 0 != (Flags & RDW_NOFRAME))
333 {
334 Rect.left = Window->ClientRect.left - Window->WindowRect.left;
335 Rect.top = Window->ClientRect.top - Window->WindowRect.top;
336 Rect.right = Window->ClientRect.right - Window->WindowRect.left;
337 Rect.bottom = Window->ClientRect.bottom - Window->WindowRect.top;
338 }
339 Window->UpdateRegion =
340 UnsafeIntCreateRectRgnIndirect(&Rect);
341 }
342 if (NtGdiCombineRgn(Window->UpdateRegion,
343 Window->UpdateRegion, hRgn,
344 RGN_DIFF) == NULLREGION)
345 {
346 NtGdiDeleteObject(Window->UpdateRegion);
347 Window->UpdateRegion = NULL;
348 }
349 }
350 else /* validate everything */
351 {
352 if ((HRGN) 1 < Window->UpdateRegion)
353 {
354 NtGdiDeleteObject(Window->UpdateRegion);
355 }
356 Window->UpdateRegion = NULL;
357 }
358
359 if (NULL != Window->UpdateRegion)
360 {
361 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
362 if (0 != (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
363 {
364 MsqDecPaintCountQueue(Window->MessageQueue);
365 }
366 }
367 }
368
369 if (Flags & RDW_NOFRAME)
370 {
371 Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
372 }
373 if (Flags & RDW_NOERASE)
374 {
375 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
376 }
377 }
378
379 if (First && NULL != Window->UpdateRegion && 0 != (Flags & RDW_UPDATENOW))
380 {
381 PaintValidateParent(Window); /* validate parent covered by region */
382 }
383
384 /* in/validate child windows that intersect with the region if it
385 * is a valid handle. */
386
387 if (0 != (Flags & (RDW_INVALIDATE | RDW_VALIDATE)))
388 {
389 if ((HRGN) 1 < hRgn && HasChildren)
390 {
391 POINT Total = {0, 0};
392 POINT PrevOrign = {0, 0};
393 PWINDOW_OBJECT Child;
394
395 ExAcquireFastMutexUnsafe(&Window->ChildrenListLock);
396 Child = Window->FirstChild;
397 while (Child)
398 {
399 if (0 != (Child->Style & WS_VISIBLE))
400 {
401 POINT Offset;
402
403 Rect.left = Child->WindowRect.left - Window->WindowRect.left;
404 Rect.top = Child->WindowRect.top - Window->WindowRect.top;
405 Rect.right = Child->WindowRect.right - Window->WindowRect.left;
406 Rect.bottom = Child->WindowRect.bottom - Window->WindowRect.top;
407
408 Offset.x = Rect.left - PrevOrign.x;
409 Offset.y = Rect.top - PrevOrign.y;
410 NtGdiOffsetRect(&Rect, -Total.x, -Total.y);
411
412 if (UnsafeIntRectInRegion(hRgn, &Rect))
413 {
414 NtGdiOffsetRgn(hRgn, -Offset.x, -Offset.y);
415 PaintUpdateRgns(Child, hRgn, Flags, FALSE);
416 PrevOrign.x = Rect.left + Total.x;
417 PrevOrign.y = Rect.top + Total.y;
418 Total.x += Offset.x;
419 Total.y += Offset.y;
420 }
421 }
422 Child = Child->NextSibling;
423 }
424 ExReleaseFastMutexUnsafe(&Window->ChildrenListLock);
425
426 NtGdiOffsetRgn(hRgn, Total.x, Total.y);
427 HasChildren = FALSE;
428 }
429 }
430
431 if (HasChildren)
432 {
433 PWINDOW_OBJECT Child;
434
435 ExAcquireFastMutexUnsafe(&Window->ChildrenListLock);
436 Child = Window->FirstChild;
437 while (Child)
438 {
439 if (Child->Style & WS_VISIBLE)
440 {
441 PaintUpdateRgns(Child, hRgn, Flags, FALSE);
442 }
443 Child = Child->NextSibling;
444 }
445 ExReleaseFastMutexUnsafe(&Window->ChildrenListLock);
446 }
447
448 PaintUpdateInternalPaint(Window, Flags);
449 }
450
451 BOOL STDCALL
452 PaintRedrawWindow( PWINDOW_OBJECT Window,
453 const RECT* UpdateRect,
454 HRGN UpdateRgn,
455 ULONG Flags,
456 ULONG ExFlags)
457 {
458 RECT Rect, Rect2;
459 POINT Pt;
460 HRGN hRgn = NULL;
461
462 DPRINT("[win32k.sys:painting] In PaintRedrawWindow()\n");
463
464 if ((RDW_INVALIDATE | RDW_FRAME) == (Flags & (RDW_INVALIDATE | RDW_FRAME)) ||
465 (RDW_VALIDATE | RDW_NOFRAME) == (Flags & (RDW_VALIDATE | RDW_NOFRAME)))
466 {
467 Rect = Window->WindowRect;
468 }
469 else
470 {
471 Rect = Window->ClientRect;
472 }
473
474 if (ExFlags & RDW_EX_XYWINDOW)
475 {
476 Pt.x = Pt.y = 0;
477 NtGdiOffsetRect(&Rect, -Window->WindowRect.left, -Window->WindowRect.top);
478 }
479 else
480 {
481 Pt.x = Window->ClientRect.left - Window->WindowRect.left;
482 Pt.y = Window->ClientRect.top - Window->WindowRect.top;
483 NtGdiOffsetRect(&Rect, -Window->ClientRect.left, -Window->ClientRect.top);
484 }
485
486 if (0 != (Flags & RDW_INVALIDATE)) /* ------------------------- Invalidate */
487 {
488 if (NULL != UpdateRgn)
489 {
490 if (NULL != Window->UpdateRegion)
491 {
492 hRgn = REGION_CropRgn(NULL, UpdateRgn, NULL, &Pt);
493 }
494 else
495 {
496 Window->UpdateRegion = REGION_CropRgn(NULL, UpdateRgn, &Rect, &Pt);
497 }
498 }
499 else if (NULL != UpdateRect)
500 {
501 if (! NtGdiIntersectRect(&Rect2, &Rect, UpdateRect))
502 {
503
504 if ((HRGN) 1 < hRgn && hRgn != UpdateRgn)
505 {
506 NtGdiDeleteObject(hRgn);
507 }
508 return TRUE;
509 }
510 NtGdiOffsetRect(&Rect2, Pt.x, Pt.y);
511 if (NULL == Window->UpdateRegion)
512 {
513 Window->UpdateRegion =
514 UnsafeIntCreateRectRgnIndirect(&Rect2);
515 }
516 else
517 {
518 hRgn = UnsafeIntCreateRectRgnIndirect(&Rect2);
519 }
520 }
521 else /* entire window or client depending on RDW_FRAME */
522 {
523 if (Flags & RDW_FRAME)
524 {
525 if (NULL != Window->UpdateRegion)
526 {
527 hRgn = (HRGN) 1;
528 }
529 else
530 {
531 Window->UpdateRegion = (HRGN) 1;
532 }
533 }
534 else
535 {
536 GETCLIENTRECTW(Window, Rect2);
537 if (NULL == Window->UpdateRegion)
538 {
539 Window->UpdateRegion = UnsafeIntCreateRectRgnIndirect(&Rect2);
540 }
541 else
542 {
543 hRgn = UnsafeIntCreateRectRgnIndirect(&Rect2);
544 }
545 }
546 }
547 }
548 else if (Flags & RDW_VALIDATE)
549 {
550 /* In this we cannot leave with zero hRgn */
551 if (NULL != UpdateRgn)
552 {
553 hRgn = REGION_CropRgn(hRgn, UpdateRgn, &Rect, &Pt);
554 UnsafeIntGetRgnBox(hRgn, &Rect2);
555 if (NtGdiIsEmptyRect(&Rect2))
556 {
557
558 if ((HRGN) 1 < hRgn && hRgn != UpdateRgn)
559 {
560 NtGdiDeleteObject(hRgn);
561 }
562 return TRUE;
563 }
564 }
565 else if (NULL != UpdateRect)
566 {
567 if (! NtGdiIntersectRect(&Rect2, &Rect, UpdateRect))
568 {
569
570 if ((HRGN) 1 < hRgn && hRgn != UpdateRgn)
571 {
572 NtGdiDeleteObject(hRgn);
573 }
574 return TRUE;
575 }
576 NtGdiOffsetRect(&Rect2, Pt.x, Pt.y);
577 hRgn = UnsafeIntCreateRectRgnIndirect(&Rect2);
578 }
579 else /* entire window or client depending on RDW_NOFRAME */
580 {
581 if (0 != (Flags & RDW_NOFRAME))
582 {
583 hRgn = (HRGN) 1;
584 }
585 else
586 {
587 GETCLIENTRECTW(Window, Rect2);
588 hRgn = UnsafeIntCreateRectRgnIndirect(&Rect2);
589 }
590 }
591 }
592
593 /* At this point hRgn is either an update region in window coordinates or 1 or 0 */
594
595 PaintUpdateRgns(Window, hRgn, Flags, TRUE);
596
597 /* Erase/update windows, from now on hRgn is a scratch region */
598
599 hRgn = PaintDoPaint(Window, (HRGN) 1 == hRgn ? NULL : hRgn, Flags, ExFlags);
600
601 if ((HRGN) 1 < hRgn && hRgn != UpdateRgn)
602 {
603 NtGdiDeleteObject(hRgn);
604 }
605
606 return TRUE;
607 }
608
609 BOOL STDCALL
610 PaintHaveToDelayNCPaint(PWINDOW_OBJECT Window, ULONG Flags)
611 {
612 if (Flags & UNC_DELAY_NCPAINT)
613 {
614 return(TRUE);
615 }
616
617 if (Flags & UNC_IN_BEGINPAINT)
618 {
619 return(FALSE);
620 }
621
622 Window = Window->Parent;
623 while (Window != NULL)
624 {
625 if (Window->Style & WS_CLIPCHILDREN && Window->UpdateRegion != NULL)
626 {
627 return TRUE;
628 }
629 Window = Window->Parent;
630 }
631
632 return FALSE;
633 }
634
635 HWND STDCALL
636 PaintingFindWinToRepaint(HWND hWnd, PW32THREAD Thread)
637 {
638 PWINDOW_OBJECT Window;
639 PWINDOW_OBJECT BaseWindow;
640 PLIST_ENTRY current_entry;
641 HWND hFoundWnd = NULL;
642
643 if (hWnd == NULL)
644 {
645 ExAcquireFastMutex(&Thread->WindowListLock);
646 current_entry = Thread->WindowListHead.Flink;
647 while (current_entry != &Thread->WindowListHead)
648 {
649 Window = CONTAINING_RECORD(current_entry, WINDOW_OBJECT,
650 ThreadListEntry);
651 if (Window->Style & WS_VISIBLE)
652 {
653 hFoundWnd =
654 PaintingFindWinToRepaint(Window->Self, Thread);
655 if (hFoundWnd != NULL)
656 {
657 ExReleaseFastMutex(&Thread->WindowListLock);
658 return(hFoundWnd);
659 }
660 }
661 current_entry = current_entry->Flink;
662 }
663 ExReleaseFastMutex(&Thread->WindowListLock);
664 return(NULL);
665 }
666
667 BaseWindow = IntGetWindowObject(hWnd);
668 if (BaseWindow == NULL)
669 {
670 return(NULL);
671 }
672 if (BaseWindow->UpdateRegion != NULL ||
673 BaseWindow->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
674 {
675 IntReleaseWindowObject(BaseWindow);
676 return(hWnd);
677 }
678
679 ExAcquireFastMutex(&BaseWindow->ChildrenListLock);
680 Window = BaseWindow->FirstChild;
681 while (Window)
682 {
683 if (Window->Style & WS_VISIBLE)
684 {
685 hFoundWnd = PaintingFindWinToRepaint(Window->Self, Thread);
686 if (hFoundWnd != NULL)
687 {
688 break;
689 }
690 }
691 Window = Window->NextSibling;
692 }
693 ExReleaseFastMutex(&BaseWindow->ChildrenListLock);
694
695 IntReleaseWindowObject(BaseWindow);
696 return(hFoundWnd);
697 }
698
699 HRGN STDCALL
700 PaintUpdateNCRegion(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
701 {
702 HRGN hRgnRet;
703 RECT ClientRect;
704 HRGN hClip = NULL;
705
706 /* Desktop has no parent. */
707 if (Window->Parent == NULL)
708 {
709 Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
710 if ((HRGN) 1 < Window->UpdateRegion)
711 {
712 hRgnRet = REGION_CropRgn(hRgn, Window->UpdateRegion, NULL, NULL);
713 }
714 else
715 {
716 hRgnRet = Window->UpdateRegion;
717 }
718 return(hRgnRet);
719 }
720
721 #if 0 /* NtUserGetFOregroundWindow() not implemented yet */
722 if ((Window->Self == NtUserGetForegroundWindow()) &&
723 0 == (Window->Flags & WIN_NCACTIVATED) )
724 {
725 Window->Flags |= WIN_NCACTIVATED;
726 Flags |= UNC_ENTIRE;
727 }
728 #endif
729
730 /*
731 * If the window's non-client area needs to be painted,
732 */
733 if (0 != (Window->Flags & WINDOWOBJECT_NEED_NCPAINT) &&
734 ! PaintHaveToDelayNCPaint(Window, Flags))
735 {
736 RECT UpdateRegionBox;
737 RECT Rect;
738
739 Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
740 GETCLIENTRECTW(Window, ClientRect);
741
742 if ((HRGN) 1 < Window->UpdateRegion)
743 {
744 UnsafeIntGetRgnBox(Window->UpdateRegion, &UpdateRegionBox);
745 NtGdiUnionRect(&Rect, &ClientRect, &UpdateRegionBox);
746 if (Rect.left != ClientRect.left || Rect.top != ClientRect.top ||
747 Rect.right != ClientRect.right || Rect.bottom != ClientRect.bottom)
748 {
749 hClip = Window->UpdateRegion;
750 Window->UpdateRegion = REGION_CropRgn(hRgn, hClip,
751 &ClientRect, NULL);
752 if (Flags & UNC_REGION)
753 {
754 hRgnRet = hClip;
755 }
756 }
757
758 if (Flags & UNC_CHECK)
759 {
760 UnsafeIntGetRgnBox(Window->UpdateRegion, &UpdateRegionBox);
761 if (NtGdiIsEmptyRect(&UpdateRegionBox))
762 {
763 NtGdiDeleteObject(Window->UpdateRegion);
764 Window->UpdateRegion = NULL;
765 if (0 == (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
766 {
767 MsqDecPaintCountQueue(Window->MessageQueue);
768 }
769 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
770 }
771 }
772
773 if (0 == hClip && 0 != Window->UpdateRegion)
774 {
775 goto copyrgn;
776 }
777 }
778 else if ((HRGN) 1 == Window->UpdateRegion)
779 {
780 if (0 != (Flags & UNC_UPDATE))
781 {
782 Window->UpdateRegion =
783 UnsafeIntCreateRectRgnIndirect(&ClientRect);
784 }
785 if (Flags & UNC_REGION)
786 {
787 hRgnRet = (HRGN) 1;
788 }
789 Flags |= UNC_ENTIRE;
790 }
791 }
792 else /* no WM_NCPAINT unless forced */
793 {
794 if ((HRGN) 1 < Window->UpdateRegion)
795 {
796 copyrgn:
797 if (0 != (Flags & UNC_REGION))
798 {
799 hRgnRet = REGION_CropRgn(hRgn, Window->UpdateRegion, NULL, NULL);
800 }
801 }
802 else if ((HRGN) 1 == Window->UpdateRegion && 0 != (Flags & UNC_UPDATE))
803 {
804 GETCLIENTRECTW(Window, ClientRect);
805 Window->UpdateRegion =
806 UnsafeIntCreateRectRgnIndirect(&ClientRect);
807 if (Flags & UNC_REGION)
808 {
809 hRgnRet = (HRGN) 1;
810 }
811 }
812 }
813
814 if (NULL == hClip && 0 != (Flags & UNC_ENTIRE))
815 {
816 if (RtlCompareMemory(&Window->WindowRect, &Window->ClientRect,
817 sizeof(RECT)) != sizeof(RECT))
818 {
819 hClip = (HRGN) 1;
820 }
821 else
822 {
823 hClip = NULL;
824 }
825 }
826
827 if (NULL != hClip) /* NOTE: WM_NCPAINT allows wParam to be 1 */
828 {
829 if (hClip == hRgnRet && (HRGN) 1 < hRgnRet)
830 {
831 hClip = NtGdiCreateRectRgn(0, 0, 0, 0);
832 NtGdiCombineRgn(hClip, hRgnRet, 0, RGN_COPY);
833 }
834
835 NtUserSendMessage(Window->Self, WM_NCPAINT, (WPARAM) hClip, 0);
836
837 if ((HRGN) 1 < hClip && hClip != hRgn && hClip != hRgnRet)
838 {
839 NtGdiDeleteObject(hClip);
840 }
841
842 /* FIXME: Need to check the window is still valid. */
843 }
844 return(hRgnRet);
845 }
846
847 BOOL STDCALL
848 NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* lPs)
849 {
850 NtUserReleaseDC(hWnd, lPs->hdc);
851 /* FIXME: Show claret. */
852 return(TRUE);
853 }
854
855 static
856 HRGN FASTCALL
857 GetClientUpdateRegion(PWINDOW_OBJECT Window)
858 {
859 POINT Offset;
860 RECT Rect;
861
862 if ((DWORD) Window->UpdateRegion <= 1)
863 {
864 return Window->UpdateRegion;
865 }
866
867 Offset.x = Window->WindowRect.left - Window->ClientRect.left;
868 Offset.y = Window->WindowRect.top - Window->ClientRect.top;
869 Rect.left = - Offset.x;
870 Rect.top = - Offset.y;
871 Rect.right = Rect.left + (Window->ClientRect.right - Window->ClientRect.left);
872 Rect.bottom = Rect.top + (Window->ClientRect.bottom - Window->ClientRect.top);
873
874 return REGION_CropRgn(NULL, Window->UpdateRegion, &Rect, &Offset);
875 }
876
877 HDC STDCALL
878 NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* lPs)
879 {
880 BOOL IsIcon;
881 PWINDOW_OBJECT Window;
882 HRGN UpdateRegion;
883 RECT ClientRect;
884 RECT ClipRect;
885 //NTSTATUS Status;
886 INT DcxFlags;
887
888 if (!(Window = IntGetWindowObject(hWnd)))
889 {
890 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
891 return NULL;
892 }
893
894 /* Send WM_NCPAINT */
895 PaintUpdateNCRegion(Window, 0, UNC_UPDATE | UNC_IN_BEGINPAINT);
896
897 /* Check ifthe window is still valid. */
898 if (!IntGetWindowObject(hWnd))
899 {
900 return 0;
901 }
902
903 /* retrieve update region */
904 UpdateRegion = GetClientUpdateRegion(Window);
905 if (1 < (DWORD) Window->UpdateRegion)
906 {
907 NtGdiDeleteObject(Window->UpdateRegion);
908 }
909 Window->UpdateRegion = 0;
910 if (UpdateRegion != NULL || (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
911 {
912 MsqDecPaintCountQueue(Window->MessageQueue);
913 }
914 Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
915
916 /* FIXME: Hide caret. */
917
918 IsIcon = (Window->Style & WS_MINIMIZE) && IntGetClassLong(Window, GCL_HICON, FALSE);
919
920 DcxFlags = DCX_INTERSECTRGN | DCX_WINDOWPAINT | DCX_USESTYLE;
921 if (IsIcon)
922 {
923 DcxFlags |= DCX_WINDOW;
924 }
925 if (IntGetClassLong(Window, GCL_STYLE, FALSE) & CS_PARENTDC)
926 {
927 /* Don't clip the output to the update region for CS_PARENTDC window */
928 if ((HRGN) 1 < UpdateRegion)
929 {
930 NtGdiDeleteObject(UpdateRegion);
931 }
932 UpdateRegion = NULL;
933 DcxFlags &= ~DCX_INTERSECTRGN;
934 }
935 else
936 {
937 if (NULL == UpdateRegion) /* empty region, clip everything */
938 {
939 UpdateRegion = NtGdiCreateRectRgn(0, 0, 0, 0);
940 }
941 else if ((HRGN) 1 == UpdateRegion) /* whole client area, don't clip */
942 {
943 UpdateRegion = NULL;
944 DcxFlags &= ~DCX_INTERSECTRGN;
945 }
946 }
947 lPs->hdc = NtUserGetDCEx(hWnd, UpdateRegion, DcxFlags);
948
949 /* FIXME: Check for DC creation failure. */
950
951 IntGetClientRect(Window, &ClientRect);
952 NtGdiGetClipBox(lPs->hdc, &ClipRect);
953 NtGdiLPtoDP(lPs->hdc, (LPPOINT)&ClipRect, 2);
954 NtGdiIntersectRect(&lPs->rcPaint, &ClientRect, &ClipRect);
955 NtGdiDPtoLP(lPs->hdc, (LPPOINT)&lPs->rcPaint, 2);
956
957 if (Window->Flags & WINDOWOBJECT_NEED_ERASEBACKGRD)
958 {
959 BOOLEAN Result;
960 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
961 Result = NtUserSendMessage(hWnd,
962 IsIcon ? WM_ICONERASEBKGND : WM_ERASEBKGND,
963 (WPARAM)lPs->hdc,
964 0);
965 lPs->fErase = !Result;
966 }
967 else
968 {
969 lPs->fErase = FALSE;
970 }
971
972 ObmDereferenceObject(Window);
973 return(lPs->hdc);
974 }
975
976 DWORD
977 STDCALL
978 NtUserInvalidateRect(
979 HWND hWnd,
980 CONST RECT *Rect,
981 WINBOOL Erase)
982 {
983 return NtUserRedrawWindow(hWnd, Rect, 0, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
984 }
985
986 DWORD
987 STDCALL
988 NtUserInvalidateRgn(
989 HWND hWnd,
990 HRGN Rgn,
991 WINBOOL Erase)
992 {
993 return NtUserRedrawWindow(hWnd, NULL, Rgn, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
994 }
995
996 BOOL
997 STDCALL
998 NtUserValidateRgn(
999 HWND hWnd,
1000 HRGN hRgn)
1001 {
1002 return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_VALIDATE | RDW_NOCHILDREN);
1003 }
1004
1005 int
1006 STDCALL
1007 NtUserGetUpdateRgn(
1008 HWND hWnd,
1009 HRGN hRgn,
1010 WINBOOL bErase)
1011 {
1012 PWINDOW_OBJECT Window;
1013 int RegionType;
1014
1015 if (!(Window = IntGetWindowObject(hWnd)))
1016 {
1017 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1018 return ERROR;
1019 }
1020
1021 if (NULL == Window->UpdateRegion)
1022 {
1023 RegionType = (NtGdiSetRectRgn(hRgn, 0, 0, 0, 0) ? NULLREGION : ERROR);
1024 }
1025 else if ((HRGN) 1 == Window->UpdateRegion)
1026 {
1027 RegionType = (NtGdiSetRectRgn(hRgn,
1028 0, 0,
1029 Window->ClientRect.right - Window->ClientRect.left,
1030 Window->ClientRect.bottom - Window->ClientRect.top) ?
1031 SIMPLEREGION : ERROR);
1032 }
1033 else
1034 {
1035 RegionType = NtGdiCombineRgn(hRgn, Window->UpdateRegion, hRgn, RGN_COPY);
1036 NtGdiOffsetRgn(hRgn, Window->WindowRect.left - Window->ClientRect.left,
1037 Window->WindowRect.top - Window->ClientRect.top );
1038 }
1039
1040 if (bErase &&
1041 (SIMPLEREGION == RegionType || COMPLEXREGION == RegionType))
1042 {
1043 PaintRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN, 0);
1044 }
1045
1046 IntReleaseWindowObject(Window);
1047
1048 return RegionType;
1049 }
1050
1051 /* EOF */