fixed releasing window object
[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.42 2003/12/07 13:14:22 weiden Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window painting function
24 * FILE: subsys/win32k/ntuser/painting.c
25 * PROGRAMER: Filip Navara (xnavara@volny.cz)
26 * REVISION HISTORY:
27 * 06/06/2001 Created (?)
28 * 18/11/2003 Complete rewrite
29 */
30
31 /* INCLUDES ******************************************************************/
32
33 #include <ddk/ntddk.h>
34 #include <internal/safe.h>
35 #include <win32k/win32k.h>
36 #include <include/object.h>
37 #include <include/guicheck.h>
38 #include <include/window.h>
39 #include <include/class.h>
40 #include <include/error.h>
41 #include <include/winsta.h>
42 #include <windows.h>
43 #include <include/painting.h>
44 #include <user32/wininternal.h>
45 #include <include/rect.h>
46 #include <win32k/coord.h>
47 #include <win32k/region.h>
48 #include <include/vis.h>
49
50 #define NDEBUG
51 #include <debug.h>
52
53 /* GLOBALS ********************************************************************/
54
55 /*
56 * Define this after the desktop will be moved to CSRSS and will
57 * get proper message queue.
58 */
59 /* #define DESKTOP_IN_CSRSS */
60
61 /* PRIVATE FUNCTIONS **********************************************************/
62
63 VOID FASTCALL
64 IntValidateParent(PWINDOW_OBJECT Child)
65 {
66 HWND Parent;
67 PWINDOW_OBJECT ParentWindow;
68
69 Parent = NtUserGetAncestor(Child->Self, GA_PARENT);
70 while (Parent && Parent != IntGetDesktopWindow())
71 {
72 ParentWindow = IntGetWindowObject(Parent);
73 if (ParentWindow && !(ParentWindow->Style & WS_CLIPCHILDREN))
74 {
75 if (ParentWindow->UpdateRegion != 0)
76 {
77 INT OffsetX, OffsetY;
78
79 /*
80 * We must offset the child region by the offset of the
81 * child rect in the parent.
82 */
83 OffsetX = Child->WindowRect.left - ParentWindow->WindowRect.left;
84 OffsetY = Child->WindowRect.top - ParentWindow->WindowRect.top;
85 NtGdiOffsetRgn(Child->UpdateRegion, OffsetX, OffsetY );
86 NtGdiCombineRgn(ParentWindow->UpdateRegion, ParentWindow->UpdateRegion,
87 Child->UpdateRegion, RGN_DIFF);
88 /* FIXME: If the resulting region is empty, remove fake posted paint message */
89 NtGdiOffsetRgn(Child->UpdateRegion, -OffsetX, -OffsetY);
90 }
91 }
92 IntReleaseWindowObject(ParentWindow);
93 Parent = NtUserGetAncestor(Parent, GA_PARENT);
94 }
95 }
96
97 /*
98 * IntGetNCUpdateRegion
99 *
100 * Get nonclient part of window update region.
101 *
102 * Return Value
103 * Handle to region that represents invalid nonclient window area. The
104 * caller is responsible for deleting it.
105 *
106 * Remarks
107 * This function also marks the nonclient update region of window
108 * as valid, clears the WINDOWOBJECT_NEED_NCPAINT flag and removes
109 * the fake paint message from message queue if the Remove is set
110 * to TRUE.
111 */
112
113 HRGN FASTCALL
114 IntGetNCUpdateRegion(PWINDOW_OBJECT Window, BOOL Remove)
115 {
116 HRGN WindowRgn;
117 HRGN NonclientRgn;
118
119 WindowRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
120 NtGdiOffsetRgn(WindowRgn,
121 -Window->WindowRect.left,
122 -Window->WindowRect.top);
123 NonclientRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
124 if (NtGdiCombineRgn(NonclientRgn, Window->UpdateRegion,
125 WindowRgn, RGN_DIFF) == NULLREGION)
126 {
127 NtGdiDeleteObject(NonclientRgn);
128 NonclientRgn = NULL;
129 }
130 if (Remove)
131 {
132 if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
133 WindowRgn, RGN_AND) == NULLREGION)
134 {
135 NtGdiDeleteObject(Window->UpdateRegion);
136 Window->UpdateRegion = NULL;
137 }
138 Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
139 MsqDecPaintCountQueue(Window->MessageQueue);
140 }
141
142 return NonclientRgn;
143 }
144
145 /*
146 * IntPaintWindows
147 *
148 * Internal function used by IntRedrawWindow.
149 */
150
151 VOID FASTCALL
152 IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
153 {
154 HDC hDC;
155 HWND hWnd = Window->Self;
156
157 if (!(Window->Style & WS_VISIBLE))
158 {
159 return;
160 }
161
162 if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
163 {
164 if (IntIsDesktopWindow(Window))
165 {
166 /*
167 * Repainting of desktop window
168 */
169
170 #ifndef DESKTOP_IN_CSRSS
171 VIS_RepaintDesktop(hWnd, Window->UpdateRegion);
172 Window->Flags &= ~(WINDOWOBJECT_NEED_NCPAINT |
173 WINDOWOBJECT_NEED_INTERNALPAINT | WINDOWOBJECT_NEED_ERASEBKGND);
174 NtGdiDeleteObject(Window->UpdateRegion);
175 Window->UpdateRegion = NULL;
176 #else
177 if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
178 {
179 MsqDecPaintCountQueue(Window->MessageQueue);
180 Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
181 }
182 if (Window->UpdateRegion ||
183 Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
184 {
185 MsqDecPaintCountQueue(Window->MessageQueue);
186 Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
187 }
188 if (Window->UpdateRegion)
189 {
190 hDC = NtUserGetDCEx(hWnd, 0, DCX_CACHE | DCX_USESTYLE |
191 DCX_INTERSECTUPDATE);
192 if (hDC != NULL)
193 {
194 NtUserSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0);
195 NtUserReleaseDC(hWnd, hDC);
196 NtGdiDeleteObject(Window->UpdateRegion);
197 Window->UpdateRegion = NULL;
198 }
199 }
200 #endif
201 }
202 else
203 {
204 /*
205 * Repainting of non-desktop window
206 */
207
208 if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
209 {
210 NtUserSendMessage(hWnd, WM_NCPAINT, (WPARAM)IntGetNCUpdateRegion(Window, TRUE), 0);
211 }
212
213 if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
214 {
215 if (Window->UpdateRegion)
216 {
217 hDC = NtUserGetDCEx(hWnd, 0, DCX_CACHE | DCX_USESTYLE |
218 DCX_INTERSECTUPDATE);
219 if (hDC != NULL)
220 {
221 if (NtUserSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0))
222 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
223 NtUserReleaseDC(hWnd, hDC);
224 }
225 }
226 }
227
228 if (Flags & RDW_UPDATENOW)
229 {
230 if (Window->UpdateRegion != NULL ||
231 Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
232 {
233 NtUserSendMessage(hWnd, WM_PAINT, 0, 0);
234 if (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
235 {
236 Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
237 if (Window->UpdateRegion == NULL)
238 {
239 MsqDecPaintCountQueue(Window->MessageQueue);
240 }
241 }
242 }
243 }
244 }
245 }
246
247 /*
248 * Check that the window is still valid at this point
249 */
250
251 if (!IntIsWindow(hWnd))
252 return;
253
254 /*
255 * Paint child windows.
256 */
257
258 if (!(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
259 ((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN)))
260 {
261 HWND *List, *phWnd;
262
263 if ((List = IntWinListChildren(Window)))
264 {
265 for (phWnd = List; *phWnd; ++phWnd)
266 {
267 Window = IntGetWindowObject(*phWnd);
268 if (Window)
269 {
270 IntPaintWindows(Window, Flags);
271 IntReleaseWindowObject(Window);
272 }
273 }
274 ExFreePool(List);
275 }
276 }
277 }
278
279 /*
280 * IntInvalidateWindows
281 *
282 * Internal function used by IntRedrawWindow.
283 */
284
285 VOID FASTCALL
286 IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags,
287 BOOL ValidateParent)
288 {
289 INT RgnType;
290 BOOL HadPaintMessage, HadNCPaintMessage;
291 BOOL HasPaintMessage, HasNCPaintMessage;
292 HRGN hRgnWindow;
293
294 /*
295 * Clip the given region with window rectangle (or region)
296 */
297
298 #ifdef TODO
299 if (!Window->WindowRegion)
300 #endif
301 {
302 hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
303 NtGdiOffsetRgn(hRgnWindow,
304 -Window->WindowRect.left,
305 -Window->WindowRect.top);
306 RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnWindow, RGN_AND);
307 NtGdiDeleteObject(hRgnWindow);
308 }
309 #ifdef TODO
310 else
311 {
312 RgnType = NtGdiCombineRgn(hRgn, hRgn, Window->WindowRegion, RGN_AND);
313 }
314 #endif
315
316 /*
317 * Save current state of pending updates
318 */
319
320 HadPaintMessage = Window->UpdateRegion != NULL ||
321 Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT;
322 HadNCPaintMessage = Window->Flags & WINDOWOBJECT_NEED_NCPAINT;
323
324 /*
325 * Update the region and flags
326 */
327
328 if (Flags & RDW_INVALIDATE && RgnType != NULLREGION)
329 {
330 if (Window->UpdateRegion == NULL)
331 {
332 Window->UpdateRegion = NtGdiCreateRectRgn(0, 0, 0, 0);
333 }
334
335 if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
336 hRgn, RGN_OR) == NULLREGION)
337 {
338 NtGdiDeleteObject(Window->UpdateRegion);
339 Window->UpdateRegion = NULL;
340 }
341
342 if (Flags & RDW_FRAME)
343 Window->Flags |= WINDOWOBJECT_NEED_NCPAINT;
344 if (Flags & RDW_ERASE)
345 Window->Flags |= WINDOWOBJECT_NEED_ERASEBKGND;
346
347 Flags |= RDW_FRAME;
348 }
349
350 if (Flags & RDW_VALIDATE && RgnType != NULLREGION)
351 {
352 if (Window->UpdateRegion != NULL)
353 {
354 if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
355 hRgn, RGN_DIFF) == NULLREGION)
356 {
357 NtGdiDeleteObject(Window->UpdateRegion);
358 Window->UpdateRegion = NULL;
359 }
360 }
361
362 if (Window->UpdateRegion == NULL)
363 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
364 if (Flags & RDW_NOFRAME)
365 Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
366 if (Flags & RDW_NOERASE)
367 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
368 }
369
370 if (Flags & RDW_INTERNALPAINT)
371 {
372 Window->Flags |= WINDOWOBJECT_NEED_INTERNALPAINT;
373 }
374
375 if (Flags & RDW_NOINTERNALPAINT)
376 {
377 Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
378 }
379
380 /*
381 * Validate parent covered by region
382 */
383
384 if (ValidateParent)
385 {
386 IntValidateParent(Window);
387 }
388
389 /*
390 * Process children if needed
391 */
392
393 if (!(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
394 ((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN)))
395 {
396 HWND *List, *phWnd;
397 PWINDOW_OBJECT Child;
398
399 if ((List = IntWinListChildren(Window)))
400 {
401 for (phWnd = List; *phWnd; ++phWnd)
402 {
403 Child = IntGetWindowObject(*phWnd);
404 if ((Child->Style & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE)
405 {
406 /*
407 * Recursive call to update children UpdateRegion
408 */
409 HRGN hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
410 NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY);
411 NtGdiOffsetRgn(hRgnTemp,
412 Window->WindowRect.left - Child->WindowRect.left,
413 Window->WindowRect.top - Child->WindowRect.top);
414 IntInvalidateWindows(Child, hRgnTemp, Flags, FALSE);
415
416 /*
417 * Update our UpdateRegion depending on children
418 */
419 NtGdiCombineRgn(hRgnTemp, Child->UpdateRegion, 0, RGN_COPY);
420 NtGdiOffsetRgn(hRgnTemp,
421 Child->WindowRect.left - Window->WindowRect.left,
422 Child->WindowRect.top - Window->WindowRect.top);
423 hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
424 NtGdiOffsetRgn(hRgnWindow,
425 -Window->WindowRect.left,
426 -Window->WindowRect.top);
427 NtGdiCombineRgn(hRgnTemp, hRgnTemp, hRgnWindow, RGN_AND);
428 if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
429 hRgnTemp, RGN_DIFF) == NULLREGION)
430 {
431 NtGdiDeleteObject(Window->UpdateRegion);
432 Window->UpdateRegion = NULL;
433 }
434 NtGdiDeleteObject(hRgnTemp);
435 }
436 IntReleaseWindowObject(Child);
437 }
438 ExFreePool(List);
439 }
440 }
441
442 /*
443 * Fake post paint messages to window message queue if needed
444 */
445
446 #ifndef DESKTOP_IN_CSRSS
447 if (Window->MessageQueue)
448 #endif
449 {
450 HasPaintMessage = Window->UpdateRegion != NULL ||
451 Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT;
452 HasNCPaintMessage = Window->Flags & WINDOWOBJECT_NEED_NCPAINT;
453
454 if (HasPaintMessage != HadPaintMessage)
455 {
456 if (HadPaintMessage)
457 MsqDecPaintCountQueue(Window->MessageQueue);
458 else
459 MsqIncPaintCountQueue(Window->MessageQueue);
460 }
461
462 if (HasNCPaintMessage != HadNCPaintMessage)
463 {
464 if (HadNCPaintMessage)
465 MsqDecPaintCountQueue(Window->MessageQueue);
466 else
467 MsqIncPaintCountQueue(Window->MessageQueue);
468 }
469 #ifndef DESKTOP_IN_CSRSS
470 }
471 #endif
472 }
473
474 /*
475 * IntIsWindowDrawable
476 *
477 * Remarks
478 * Window is drawable when it is visible, all parents are not
479 * minimized, and it is itself not minimized.
480 */
481
482 BOOL FASTCALL
483 IntIsWindowDrawable(PWINDOW_OBJECT Window)
484 {
485 for (; Window; Window = Window->Parent)
486 {
487 if ((Window->Style & (WS_VISIBLE | WS_MINIMIZE)) != WS_VISIBLE)
488 return FALSE;
489 }
490
491 return TRUE;
492 }
493
494 /*
495 * IntRedrawWindow
496 *
497 * Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
498 * first parameter.
499 */
500
501 BOOL FASTCALL
502 IntRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
503 ULONG Flags)
504 {
505 HRGN hRgn = NULL;
506
507 /*
508 * Step 1.
509 * Validation of passed parameters.
510 */
511
512 if (!IntIsWindowDrawable(Window) ||
513 (Flags & (RDW_VALIDATE | RDW_INVALIDATE)) ==
514 (RDW_VALIDATE | RDW_INVALIDATE))
515 {
516 return FALSE;
517 }
518
519 /*
520 * Step 2.
521 * Transform the parameters UpdateRgn and UpdateRect into
522 * a region hRgn specified in window coordinates.
523 */
524
525 if (Flags & (RDW_INVALIDATE | RDW_VALIDATE))
526 {
527 if (UpdateRgn != NULL)
528 {
529 hRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
530 NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY);
531 NtGdiOffsetRgn(hRgn,
532 Window->ClientRect.left - Window->WindowRect.left,
533 Window->ClientRect.top - Window->WindowRect.top);
534 } else
535 if (UpdateRect != NULL)
536 {
537 hRgn = UnsafeIntCreateRectRgnIndirect((RECT *)UpdateRect);
538 NtGdiOffsetRgn(hRgn,
539 Window->ClientRect.left - Window->WindowRect.left,
540 Window->ClientRect.top - Window->WindowRect.top);
541 } else
542 if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) ||
543 (Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME))
544 {
545 hRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
546 NtGdiOffsetRgn(hRgn,
547 -Window->WindowRect.left,
548 -Window->WindowRect.top);
549 }
550 else
551 {
552 hRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
553 NtGdiOffsetRgn(hRgn,
554 -Window->WindowRect.left,
555 -Window->WindowRect.top);
556 }
557 }
558
559 /*
560 * Step 3.
561 * Adjust the window update region depending on hRgn and flags.
562 */
563
564 if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT))
565 {
566 IntInvalidateWindows(Window, hRgn, Flags, TRUE);
567 } else
568 if (Window->UpdateRegion != NULL && Flags & RDW_ERASENOW)
569 {
570 /* Validate parent covered by region. */
571 IntValidateParent(Window);
572 }
573
574 /*
575 * Step 4.
576 * Repaint and erase windows if needed.
577 */
578
579 if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
580 {
581 IntPaintWindows(Window, Flags);
582 }
583
584 /*
585 * Step 5.
586 * Cleanup ;-)
587 */
588
589 if (NULL != hRgn)
590 {
591 NtGdiDeleteObject(hRgn);
592 }
593
594 return TRUE;
595 }
596
597 HWND STDCALL
598 IntFindWindowToRepaint(HWND hWnd, PW32THREAD Thread)
599 {
600 PWINDOW_OBJECT Window;
601 PWINDOW_OBJECT Child;
602 HWND hFoundWnd = NULL;
603
604 if (hWnd == NULL)
605 {
606 PLIST_ENTRY CurrentEntry;
607
608 ExAcquireFastMutex(&Thread->WindowListLock);
609
610 for (CurrentEntry = Thread->WindowListHead.Flink;
611 CurrentEntry != &Thread->WindowListHead;
612 CurrentEntry = CurrentEntry->Flink)
613 {
614 Window = CONTAINING_RECORD(CurrentEntry, WINDOW_OBJECT, ThreadListEntry);
615 if (Window->Parent != NULL && !IntIsDesktopWindow(Window->Parent))
616 {
617 continue;
618 }
619 if (Window->Style & WS_VISIBLE)
620 {
621 hFoundWnd = IntFindWindowToRepaint(Window->Self, Thread);
622 if (hFoundWnd != NULL)
623 {
624 ExReleaseFastMutex(&Thread->WindowListLock);
625 return hFoundWnd;
626 }
627 }
628 }
629
630 ExReleaseFastMutex(&Thread->WindowListLock);
631 return NULL;
632 }
633 else
634 {
635 Window = IntGetWindowObject(hWnd);
636 if (Window == NULL)
637 return NULL;
638
639 if (Window->UpdateRegion != NULL ||
640 Window->Flags & (WINDOWOBJECT_NEED_INTERNALPAINT | WINDOWOBJECT_NEED_NCPAINT))
641 {
642 IntReleaseWindowObject(Window);
643 return hWnd;
644 }
645
646 ExAcquireFastMutex(&Window->ChildrenListLock);
647
648 for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
649 {
650 if (Child->Style & WS_VISIBLE &&
651 (Child->UpdateRegion != NULL ||
652 Child->Flags & WINDOWOBJECT_NEED_INTERNALPAINT ||
653 Child->Flags & WINDOWOBJECT_NEED_NCPAINT))
654 {
655 hFoundWnd = Child->Self;
656 break;
657 }
658 }
659
660 if (hFoundWnd == NULL)
661 {
662 for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
663 {
664 if (Child->Style & WS_VISIBLE)
665 {
666 hFoundWnd = IntFindWindowToRepaint(Child->Self, Thread);
667 if (hFoundWnd != NULL)
668 break;
669 }
670 }
671 }
672
673 ExReleaseFastMutex(&Window->ChildrenListLock);
674 IntReleaseWindowObject(Window);
675
676 return hFoundWnd;
677 }
678 }
679
680 BOOL FASTCALL
681 IntGetPaintMessage(HWND hWnd, PW32THREAD Thread, MSG *Message,
682 BOOL Remove)
683 {
684 PWINDOW_OBJECT Window;
685 PUSER_MESSAGE_QUEUE MessageQueue = (PUSER_MESSAGE_QUEUE)Thread->MessageQueue;
686
687 if (!MessageQueue->PaintPosted)
688 return FALSE;
689
690 if (hWnd)
691 Message->hwnd = IntFindWindowToRepaint(hWnd, PsGetWin32Thread());
692 else
693 Message->hwnd = IntFindWindowToRepaint(NULL, PsGetWin32Thread());
694
695 if (Message->hwnd == NULL)
696 {
697 #if 0
698 DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
699 /* FIXME: Lock the queue! */
700 MessageQueue->PaintPosted = 0;
701 MessageQueue->PaintCount = 0;
702 #endif
703 return FALSE;
704 }
705
706 Window = IntGetWindowObject(Message->hwnd);
707 if (Window != NULL)
708 {
709 if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
710 {
711 Message->message = WM_NCPAINT;
712 Message->wParam = (WPARAM)IntGetNCUpdateRegion(Window, Remove);
713 Message->lParam = 0;
714 } else
715 {
716 Message->message = WM_PAINT;
717 Message->wParam = Message->lParam = 0;
718 if (Remove && Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
719 {
720 Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
721 if (Window->UpdateRegion == NULL)
722 {
723 MsqDecPaintCountQueue(Window->MessageQueue);
724 }
725 }
726 }
727
728 IntReleaseWindowObject(Window);
729 return TRUE;
730 }
731
732 return FALSE;
733 }
734
735 /* PUBLIC FUNCTIONS ***********************************************************/
736
737 /*
738 * NtUserBeginPaint
739 *
740 * Status
741 * @implemented
742 */
743
744 HDC STDCALL
745 NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* lPs)
746 {
747 PWINDOW_OBJECT Window;
748 RECT ClientRect;
749 RECT ClipRect;
750 INT DcxFlags;
751
752 if (!(Window = IntGetWindowObject(hWnd)))
753 {
754 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
755 return NULL;
756 }
757
758 NtUserHideCaret(hWnd);
759
760 DcxFlags = DCX_INTERSECTUPDATE | DCX_WINDOWPAINT | DCX_USESTYLE;
761 if (IntGetClassLong(Window, GCL_STYLE, FALSE) & CS_PARENTDC)
762 {
763 /* FIXME: Is this correct? */
764 /* Don't clip the output to the update region for CS_PARENTDC window */
765 DcxFlags &= ~DCX_INTERSECTUPDATE;
766 }
767
768 lPs->hdc = NtUserGetDCEx(hWnd, 0, DcxFlags);
769
770 if (!lPs->hdc)
771 {
772 IntReleaseWindowObject(Window);
773 return NULL;
774 }
775
776 /* IntRedrawWindow(Window, NULL, 0, RDW_NOINTERNALPAINT | RDW_VALIDATE | RDW_NOCHILDREN);*/
777 if (Window->UpdateRegion != NULL)
778 {
779 MsqDecPaintCountQueue(Window->MessageQueue);
780 IntValidateParent(Window);
781 NtGdiDeleteObject(Window->UpdateRegion);
782 Window->UpdateRegion = NULL;
783 }
784
785 IntGetClientRect(Window, &ClientRect);
786 NtGdiGetClipBox(lPs->hdc, &ClipRect);
787 NtGdiLPtoDP(lPs->hdc, (LPPOINT)&ClipRect, 2);
788 NtGdiIntersectRect(&lPs->rcPaint, &ClientRect, &ClipRect);
789 NtGdiDPtoLP(lPs->hdc, (LPPOINT)&lPs->rcPaint, 2);
790
791 if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
792 {
793 Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
794 lPs->fErase = !NtUserSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)lPs->hdc, 0);
795 }
796 else
797 {
798 lPs->fErase = FALSE;
799 }
800
801 IntReleaseWindowObject(Window);
802
803 return lPs->hdc;
804 }
805
806 /*
807 * NtUserEndPaint
808 *
809 * Status
810 * @implemented
811 */
812
813 BOOL STDCALL
814 NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* lPs)
815 {
816 NtUserReleaseDC(hWnd, lPs->hdc);
817 NtUserShowCaret(hWnd);
818
819 return TRUE;
820 }
821
822 /*
823 * NtUserInvalidateRect
824 *
825 * Status
826 * @implemented
827 */
828
829 DWORD STDCALL
830 NtUserInvalidateRect(HWND hWnd, CONST RECT *Rect, BOOL Erase)
831 {
832 return NtUserRedrawWindow(hWnd, Rect, 0, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
833 }
834
835 /*
836 * NtUserInvalidateRgn
837 *
838 * Status
839 * @implemented
840 */
841
842 DWORD STDCALL
843 NtUserInvalidateRgn(HWND hWnd, HRGN Rgn, BOOL Erase)
844 {
845 return NtUserRedrawWindow(hWnd, NULL, Rgn, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
846 }
847
848 /*
849 * NtUserValidateRgn
850 *
851 * Status
852 * @implemented
853 */
854
855 BOOL STDCALL
856 NtUserValidateRgn(HWND hWnd, HRGN hRgn)
857 {
858 return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_VALIDATE | RDW_NOCHILDREN);
859 }
860
861 /*
862 * NtUserUpdateWindow
863 *
864 * Status
865 * @implemented
866 */
867
868 BOOL STDCALL
869 NtUserUpdateWindow(HWND hWnd)
870 {
871 return NtUserRedrawWindow(hWnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
872 }
873
874 /*
875 * NtUserGetUpdateRgn
876 *
877 * Status
878 * @implemented
879 */
880
881 INT STDCALL
882 NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
883 {
884 PWINDOW_OBJECT Window;
885 int RegionType;
886
887 if (!(Window = IntGetWindowObject(hWnd)))
888 {
889 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
890 return ERROR;
891 }
892
893 if (Window->UpdateRegion == NULL)
894 {
895 RegionType = (NtGdiSetRectRgn(hRgn, 0, 0, 0, 0) ? NULLREGION : ERROR);
896 }
897 else
898 {
899 RegionType = NtGdiCombineRgn(hRgn, Window->UpdateRegion, hRgn, RGN_COPY);
900 NtGdiOffsetRgn(
901 hRgn,
902 Window->WindowRect.left - Window->ClientRect.left,
903 Window->WindowRect.top - Window->ClientRect.top);
904 }
905
906 IntReleaseWindowObject(Window);
907
908 if (bErase && RegionType != NULLREGION && RegionType != ERROR)
909 {
910 NtUserRedrawWindow(hWnd, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
911 }
912
913 return RegionType;
914 }
915
916 /*
917 * NtUserGetUpdateRect
918 *
919 * Status
920 * @implemented
921 */
922
923 BOOL STDCALL
924 NtUserGetUpdateRect(HWND hWnd, LPRECT lpRect, BOOL fErase)
925 {
926 HRGN hRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
927
928 if (!lpRect)
929 {
930 SetLastWin32Error(ERROR_INVALID_PARAMETER);
931 return FALSE;
932 }
933
934 NtUserGetUpdateRgn(hWnd, hRgn, fErase);
935 NtGdiGetRgnBox(hRgn, lpRect);
936
937 return lpRect->left < lpRect->right && lpRect->top < lpRect->bottom;
938 }
939
940 /*
941 * NtUserRedrawWindow
942 *
943 * Status
944 * @implemented
945 */
946
947 BOOL STDCALL
948 NtUserRedrawWindow(HWND hWnd, CONST RECT *lprcUpdate, HRGN hrgnUpdate,
949 UINT flags)
950 {
951 RECT SafeUpdateRect;
952 NTSTATUS Status;
953 PWINDOW_OBJECT Wnd;
954
955 if (!(Wnd = IntGetWindowObject(hWnd ? hWnd : IntGetDesktopWindow())))
956 {
957 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
958 return FALSE;
959 }
960
961 if (lprcUpdate != NULL)
962 {
963 Status = MmCopyFromCaller(&SafeUpdateRect, (PRECT)lprcUpdate,
964 sizeof(RECT));
965
966 if (!NT_SUCCESS(Status))
967 {
968 SetLastWin32Error(ERROR_INVALID_PARAMETER);
969 return FALSE;
970 }
971 }
972
973 Status = IntRedrawWindow(Wnd, NULL == lprcUpdate ? NULL : &SafeUpdateRect,
974 hrgnUpdate, flags);
975
976 if (!NT_SUCCESS(Status))
977 {
978 /* IntRedrawWindow fails only in case that flags are invalid */
979 SetLastWin32Error(ERROR_INVALID_PARAMETER);
980 return FALSE;
981 }
982
983 return TRUE;
984 }
985
986 /* EOF */