2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window painting function
5 * FILE: win32ss/user/ntuser/painting.c
6 * PROGRAMER: Filip Navara (xnavara@volny.cz)
10 DBG_DEFAULT_CHANNEL(UserPainting
);
12 /* PRIVATE FUNCTIONS **********************************************************/
15 * @name IntIntersectWithParents
17 * Intersect window rectangle with all parent client rectangles.
20 * Pointer to child window to start intersecting from.
22 * Pointer to rectangle that we want to intersect in screen
23 * coordinates on input and intersected rectangle on output (if TRUE
27 * If any parent is minimized or invisible or the resulting rectangle
28 * is empty then FALSE is returned. Otherwise TRUE is returned.
32 IntIntersectWithParents(PWND Child
, RECTL
*WindowRect
)
36 if (Child
->ExStyle
& WS_EX_REDIRECTED
)
39 ParentWnd
= Child
->spwndParent
;
40 while (ParentWnd
!= NULL
)
42 if (!(ParentWnd
->style
& WS_VISIBLE
) ||
43 (ParentWnd
->style
& WS_MINIMIZE
) ||
44 !RECTL_bIntersectRect(WindowRect
, WindowRect
, &ParentWnd
->rcClient
) )
49 if (ParentWnd
->ExStyle
& WS_EX_REDIRECTED
)
52 ParentWnd
= ParentWnd
->spwndParent
;
59 IntValidateParents(PWND Child
, BOOL Recurse
)
61 RECTL ParentRect
, Rect
;
62 BOOL Start
, Ret
= TRUE
;
63 PWND ParentWnd
= Child
;
66 if (ParentWnd
->style
& WS_CHILD
)
69 ParentWnd
= ParentWnd
->spwndParent
;
70 while (ParentWnd
->style
& WS_CHILD
);
73 // No pending nonclient paints.
74 if (!(ParentWnd
->state
& WNDS_SYNCPAINTPENDING
)) Recurse
= FALSE
;
77 ParentWnd
= Child
->spwndParent
;
80 if (ParentWnd
->style
& WS_CLIPCHILDREN
)
83 if (ParentWnd
->hrgnUpdate
!= 0)
90 // Start with child clipping.
95 Rect
= Child
->rcWindow
;
97 if (!IntIntersectWithParents(Child
, &Rect
)) break;
99 Rgn
= IntSysCreateRectpRgnIndirect(&Rect
);
103 PREGION RgnClip
= REGION_LockRgn(Child
->hrgnClip
);
104 IntGdiCombineRgn(Rgn
, Rgn
, RgnClip
, RGN_AND
);
105 REGION_UnlockRgn(RgnClip
);
109 ParentRect
= ParentWnd
->rcWindow
;
111 if (!IntIntersectWithParents(ParentWnd
, &ParentRect
)) break;
113 IntInvalidateWindows( ParentWnd
,
115 RDW_VALIDATE
| RDW_NOCHILDREN
| RDW_NOUPDATEDIRTY
);
117 ParentWnd
= ParentWnd
->spwndParent
;
120 if (Rgn
) REGION_Delete(Rgn
);
126 Synchronize painting to the top-level windows of other threads.
129 IntSendSyncPaint(PWND Wnd
, ULONG Flags
)
131 PTHREADINFO ptiCur
, ptiWnd
;
132 PUSER_SENT_MESSAGE Message
;
136 ptiWnd
= Wnd
->head
.pti
;
137 ptiCur
= PsGetCurrentThreadWin32Thread();
139 Not the current thread, Wnd is in send Nonclient paint also in send erase background and it is visiable.
141 if ( Wnd
->head
.pti
!= ptiCur
&&
142 Wnd
->state
& WNDS_SENDNCPAINT
&&
143 Wnd
->state
& WNDS_SENDERASEBACKGROUND
&&
144 Wnd
->style
& WS_VISIBLE
)
146 // For testing, if you see this, break out the Champagne and have a party!
147 TRACE("SendSyncPaint Wnd in State!\n");
148 if (!IsListEmpty(&ptiWnd
->SentMessagesListHead
))
150 // Scan sent queue messages to see if we received sync paint messages.
151 Entry
= ptiWnd
->SentMessagesListHead
.Flink
;
152 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
156 if (Message
->Msg
.message
== WM_SYNCPAINT
&&
157 Message
->Msg
.hwnd
== UserHMGetHandle(Wnd
))
158 { // Already received so exit out.
159 ERR("SendSyncPaint Found one in the Sent Msg Queue!\n");
163 Entry
= Message
->ListEntry
.Flink
;
164 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
166 while (Entry
!= &ptiWnd
->SentMessagesListHead
);
170 TRACE("Sending WM_SYNCPAINT\n");
171 // This message has no parameters. But it does! Pass Flags along.
172 co_IntSendMessageNoWait(UserHMGetHandle(Wnd
), WM_SYNCPAINT
, Flags
, 0);
173 Wnd
->state
|= WNDS_SYNCPAINTPENDING
;
177 // Send to all the children if this is the desktop window.
178 if (UserIsDesktopWindow(Wnd
))
180 if ( Flags
& RDW_ALLCHILDREN
||
181 ( !(Flags
& RDW_NOCHILDREN
) && Wnd
->style
& WS_CLIPCHILDREN
))
183 PWND spwndChild
= Wnd
->spwndChild
;
186 if ( spwndChild
->style
& WS_CHILD
&&
187 spwndChild
->head
.pti
!= ptiCur
)
189 spwndChild
= spwndChild
->spwndNext
;
192 IntSendSyncPaint( spwndChild
, Flags
);
193 spwndChild
= spwndChild
->spwndNext
;
200 * @name IntCalcWindowRgn
202 * Get a window or client region.
206 IntCalcWindowRgn(PWND Wnd
, BOOL Client
)
212 hRgnWindow
= NtGdiCreateRectRgn(
216 Wnd
->rcClient
.bottom
);
220 hRgnWindow
= NtGdiCreateRectRgn(
224 Wnd
->rcWindow
.bottom
);
227 if (Wnd
->hrgnClip
!= NULL
&& !(Wnd
->style
& WS_MINIMIZE
))
229 NtGdiOffsetRgn(hRgnWindow
,
232 NtGdiCombineRgn(hRgnWindow
, hRgnWindow
, Wnd
->hrgnClip
, RGN_AND
);
233 NtGdiOffsetRgn(hRgnWindow
,
242 * @name IntGetNCUpdateRgn
244 * Get non-client update region of a window and optionally validate it.
247 * Pointer to window to get the NC update region from.
249 * Set to TRUE to force validating the NC update region.
252 * Handle to NC update region. The caller is responsible for deleting
257 IntGetNCUpdateRgn(PWND Window
, BOOL Validate
)
261 UINT RgnType
, NcType
;
264 if (Window
->hrgnUpdate
!= NULL
&&
265 Window
->hrgnUpdate
!= HRGN_WINDOW
)
267 hRgnNonClient
= IntCalcWindowRgn(Window
, FALSE
);
270 * If region creation fails it's safe to fallback to whole
273 if (hRgnNonClient
== NULL
)
278 hRgnWindow
= IntCalcWindowRgn(Window
, TRUE
);
279 if (hRgnWindow
== NULL
)
281 GreDeleteObject(hRgnNonClient
);
285 NcType
= IntGdiGetRgnBox(hRgnNonClient
, &update
);
287 RgnType
= NtGdiCombineRgn(hRgnNonClient
, hRgnNonClient
, hRgnWindow
, RGN_DIFF
);
289 if (RgnType
== ERROR
)
291 GreDeleteObject(hRgnWindow
);
292 GreDeleteObject(hRgnNonClient
);
295 else if (RgnType
== NULLREGION
)
297 GreDeleteObject(hRgnWindow
);
298 GreDeleteObject(hRgnNonClient
);
299 Window
->state
&= ~WNDS_UPDATEDIRTY
;
304 * Remove the nonclient region from the standard update region if
305 * we were asked for it.
310 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
, hRgnWindow
, RGN_AND
) == NULLREGION
)
312 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
313 GreDeleteObject(Window
->hrgnUpdate
);
314 Window
->state
&= ~WNDS_UPDATEDIRTY
;
315 Window
->hrgnUpdate
= NULL
;
316 if (!(Window
->state
& WNDS_INTERNALPAINT
))
317 MsqDecPaintCountQueue(Window
->head
.pti
);
321 /* check if update rgn contains complete nonclient area */
322 if (NcType
== SIMPLEREGION
)
325 IntGetWindowRect( Window
, &window
);
327 if (IntEqualRect( &window
, &update
))
329 GreDeleteObject(hRgnNonClient
);
330 hRgnNonClient
= HRGN_WINDOW
;
334 GreDeleteObject(hRgnWindow
);
336 return hRgnNonClient
;
340 return Window
->hrgnUpdate
;
345 IntSendNCPaint(PWND pWnd
, HRGN hRgn
)
347 pWnd
->state
&= ~WNDS_SENDNCPAINT
;
349 if ( pWnd
== GetW32ThreadInfo()->MessageQueue
->spwndActive
&&
350 !(pWnd
->state
& WNDS_ACTIVEFRAME
))
352 pWnd
->state
|= WNDS_ACTIVEFRAME
;
353 pWnd
->state
&= ~WNDS_NONCPAINT
;
357 if (pWnd
->state2
& WNDS2_FORCEFULLNCPAINTCLIPRGN
)
359 pWnd
->state2
&= ~WNDS2_FORCEFULLNCPAINTCLIPRGN
;
363 if (hRgn
) co_IntSendMessage(UserHMGetHandle(pWnd
), WM_NCPAINT
, (WPARAM
)hRgn
, 0);
367 IntSendChildNCPaint(PWND pWnd
)
372 List
= IntWinListChildren(UserGetDesktopWindow());
375 for (phWnd
= List
; *phWnd
; ++phWnd
)
377 Child
= ValidateHwndNoErr(*phWnd
);
378 if ( Child
&& Child
->hrgnUpdate
== NULL
&& Child
->state
& WNDS_SENDNCPAINT
)
380 USER_REFERENCE_ENTRY Ref
;
381 UserRefObjectCo(Child
, &Ref
);
382 IntSendNCPaint(Child
, HRGN_WINDOW
);
383 UserDerefObjectCo(Child
);
386 ExFreePoolWithTag(List
, USERTAG_WINDOWLIST
);
388 /* FIXME : Use snap shot mode until window death is fixed while surfing menus! Fix CORE-12085 and CORE-12071.
389 pWnd = pWnd->spwndChild;
392 if (pWnd->hrgnUpdate == NULL && pWnd->state & WNDS_SENDNCPAINT)
394 USER_REFERENCE_ENTRY Ref;
395 UserRefObjectCo(pWnd, &Ref);
396 IntSendNCPaint(pWnd, HRGN_WINDOW);
397 UserDerefObjectCo(pWnd);
399 pWnd = pWnd->spwndNext;
406 * Internal function used by IntRedrawWindow.
410 co_IntPaintWindows(PWND Wnd
, ULONG Flags
, BOOL Recurse
)
413 HWND hWnd
= Wnd
->head
.h
;
414 HRGN TempRegion
= NULL
;
416 Wnd
->state
&= ~WNDS_PAINTNOTPROCESSED
;
418 if (Wnd
->state
& WNDS_SENDNCPAINT
||
419 Wnd
->state
& WNDS_SENDERASEBACKGROUND
)
421 if (!(Wnd
->style
& WS_VISIBLE
))
423 Wnd
->state
&= ~(WNDS_SENDNCPAINT
|WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
428 if (Wnd
->hrgnUpdate
== NULL
)
430 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
433 if (Wnd
->head
.pti
== PsGetCurrentThreadWin32Thread())
435 if (Wnd
->state
& WNDS_SENDNCPAINT
)
437 TempRegion
= IntGetNCUpdateRgn(Wnd
, TRUE
);
439 IntSendNCPaint(Wnd
, TempRegion
);
441 if (TempRegion
> HRGN_WINDOW
&& GreIsHandleValid(TempRegion
))
443 /* NOTE: The region can already be deleted! */
444 GreDeleteObject(TempRegion
);
448 if (Wnd
->state
& WNDS_SENDERASEBACKGROUND
)
450 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
453 hDC
= UserGetDCEx( Wnd
,
455 DCX_CACHE
|DCX_USESTYLE
|DCX_INTERSECTRGN
|DCX_KEEPCLIPRGN
);
457 if (Wnd
->head
.pti
->ppi
!= pti
->ppi
)
459 ERR("Sending DC to another Process!!!\n");
462 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
463 // Kill the loop, so Clear before we send.
464 if (!co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
466 Wnd
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
468 UserReleaseDC(Wnd
, hDC
, FALSE
);
477 * Check that the window is still valid at this point
479 if (!IntIsWindow(hWnd
))
485 * Paint child windows.
488 if (!(Flags
& RDW_NOCHILDREN
) &&
489 !(Wnd
->style
& WS_MINIMIZE
) &&
490 ( Flags
& RDW_ALLCHILDREN
||
491 (Flags
& RDW_CLIPCHILDREN
&& Wnd
->style
& WS_CLIPCHILDREN
) ) )
494 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
496 if ((List
= IntWinListChildren(Wnd
)))
498 for (phWnd
= List
; *phWnd
; ++phWnd
)
500 if ((Wnd
= UserGetWindowObject(*phWnd
)) == NULL
)
503 if (Wnd
->head
.pti
!= pti
&& Wnd
->style
& WS_CHILD
)
506 if (Wnd
->style
& WS_VISIBLE
)
508 USER_REFERENCE_ENTRY Ref
;
509 UserRefObjectCo(Wnd
, &Ref
);
510 co_IntPaintWindows(Wnd
, Flags
, TRUE
);
511 UserDerefObjectCo(Wnd
);
514 ExFreePoolWithTag(List
, USERTAG_WINDOWLIST
);
522 * Internal function used by IntRedrawWindow, simplecall.
526 co_IntUpdateWindows(PWND Wnd
, ULONG Flags
, BOOL Recurse
)
528 HWND hWnd
= Wnd
->head
.h
;
530 if ( Wnd
->hrgnUpdate
!= NULL
|| Wnd
->state
& WNDS_INTERNALPAINT
)
534 if (!IntValidateParents(Wnd
, Recurse
))
540 if (Wnd
->state
& WNDS_INTERNALPAINT
)
542 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
544 if (Wnd
->hrgnUpdate
== NULL
)
545 MsqDecPaintCountQueue(Wnd
->head
.pti
);
548 Wnd
->state
|= WNDS_PAINTNOTPROCESSED
;
549 Wnd
->state
&= ~WNDS_UPDATEDIRTY
;
551 Wnd
->state2
|= WNDS2_WMPAINTSENT
;
552 co_IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
554 if (Wnd
->state
& WNDS_PAINTNOTPROCESSED
)
556 USER_REFERENCE_ENTRY Ref
;
557 UserRefObjectCo(Wnd
, &Ref
);
558 co_IntPaintWindows(Wnd
, RDW_NOCHILDREN
, FALSE
);
559 UserDerefObjectCo(Wnd
);
563 // Force flags as a toggle. Fixes msg:test_paint_messages:WmChildPaintNc.
564 Flags
= (Flags
& RDW_NOCHILDREN
) ? RDW_NOCHILDREN
: RDW_ALLCHILDREN
; // All children is the default.
567 * Update child windows.
570 if (!(Flags
& RDW_NOCHILDREN
) &&
571 (Flags
& RDW_ALLCHILDREN
) &&
572 !UserIsDesktopWindow(Wnd
))
576 for (Child
= Wnd
->spwndChild
; Child
; Child
= Child
->spwndNext
)
578 /* transparent window, check for non-transparent sibling to paint first, then skip it */
579 if ( Child
->ExStyle
& WS_EX_TRANSPARENT
&&
580 ( Child
->hrgnUpdate
!= NULL
|| Child
->state
& WNDS_INTERNALPAINT
) )
582 PWND Next
= Child
->spwndNext
;
585 if ( Next
->hrgnUpdate
!= NULL
|| Next
->state
& WNDS_INTERNALPAINT
) break;
587 Next
= Next
->spwndNext
;
593 if (Child
->style
& WS_VISIBLE
)
595 USER_REFERENCE_ENTRY Ref
;
596 UserRefObjectCo(Child
, &Ref
);
597 co_IntUpdateWindows(Child
, Flags
, TRUE
);
598 UserDerefObjectCo(Child
);
605 UserUpdateWindows(PWND pWnd
, ULONG Flags
)
607 // If transparent and any sibling windows below needs to be painted, leave.
608 if (pWnd
->ExStyle
& WS_EX_TRANSPARENT
)
610 PWND Next
= pWnd
->spwndNext
;
614 if ( Next
->head
.pti
== pWnd
->head
.pti
&&
615 ( Next
->hrgnUpdate
!= NULL
|| Next
->state
& WNDS_INTERNALPAINT
) )
620 Next
= Next
->spwndNext
;
623 co_IntUpdateWindows(pWnd
, Flags
, FALSE
);
627 UserSyncAndPaintWindows(PWND pWnd
, ULONG Flags
)
630 // Find parent, if it needs to be painted, leave.
633 if ((Parent
= Parent
->spwndParent
) == NULL
) break;
634 if ( Parent
->style
& WS_CLIPCHILDREN
) break;
635 if ( Parent
->hrgnUpdate
!= NULL
|| Parent
->state
& WNDS_INTERNALPAINT
) return;
638 IntSendSyncPaint(pWnd
, Flags
);
639 co_IntPaintWindows(pWnd
, Flags
, FALSE
);
643 * IntInvalidateWindows
645 * Internal function used by IntRedrawWindow, UserRedrawDesktop,
646 * co_WinPosSetWindowPos, co_UserRedrawWindow.
649 IntInvalidateWindows(PWND Wnd
, PREGION Rgn
, ULONG Flags
)
651 INT RgnType
= NULLREGION
;
652 BOOL HadPaintMessage
;
654 TRACE("IntInvalidateWindows start Rgn %p\n",Rgn
);
656 if ( Rgn
> PRGN_WINDOW
)
659 * If the nonclient is not to be redrawn, clip the region to the client
662 if ((Flags
& RDW_INVALIDATE
) != 0 && (Flags
& RDW_FRAME
) == 0)
666 RgnClient
= IntSysCreateRectpRgnIndirect(&Wnd
->rcClient
);
669 RgnType
= IntGdiCombineRgn(Rgn
, Rgn
, RgnClient
, RGN_AND
);
670 REGION_Delete(RgnClient
);
675 * Clip the given region with window rectangle (or region)
678 if (!Wnd
->hrgnClip
|| (Wnd
->style
& WS_MINIMIZE
))
680 PREGION RgnWindow
= IntSysCreateRectpRgnIndirect(&Wnd
->rcWindow
);
683 RgnType
= IntGdiCombineRgn(Rgn
, Rgn
, RgnWindow
, RGN_AND
);
684 REGION_Delete(RgnWindow
);
689 PREGION RgnClip
= REGION_LockRgn(Wnd
->hrgnClip
);
692 REGION_bOffsetRgn(Rgn
,
695 RgnType
= IntGdiCombineRgn(Rgn
, Rgn
, RgnClip
, RGN_AND
);
696 REGION_bOffsetRgn(Rgn
,
699 REGION_UnlockRgn(RgnClip
);
705 RgnType
= NULLREGION
;
709 * Save current state of pending updates
712 HadPaintMessage
= IntIsWindowDirty(Wnd
);
715 * Update the region and flags
718 // The following flags are used to invalidate the window.
719 if (Flags
& (RDW_INVALIDATE
|RDW_INTERNALPAINT
|RDW_ERASE
|RDW_FRAME
))
721 if (Flags
& RDW_INTERNALPAINT
)
723 Wnd
->state
|= WNDS_INTERNALPAINT
;
726 if (Flags
& RDW_INVALIDATE
)
730 Wnd
->state
&= ~WNDS_NONCPAINT
;
732 /* If not the same thread set it dirty. */
733 if (Wnd
->head
.pti
!= PsGetCurrentThreadWin32Thread())
735 Wnd
->state
|= WNDS_UPDATEDIRTY
;
736 if (Wnd
->state2
& WNDS2_WMPAINTSENT
)
737 Wnd
->state2
|= WNDS2_ENDPAINTINVALIDATE
;
740 if (Flags
& RDW_FRAME
)
741 Wnd
->state
|= WNDS_SENDNCPAINT
;
743 if (Flags
& RDW_ERASE
)
744 Wnd
->state
|= WNDS_SENDERASEBACKGROUND
;
746 if (RgnType
!= NULLREGION
&& Rgn
> PRGN_WINDOW
)
748 if (Wnd
->hrgnUpdate
== NULL
)
750 Wnd
->hrgnUpdate
= NtGdiCreateRectRgn(0, 0, 0, 0);
751 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_PUBLIC
);
754 if (Wnd
->hrgnUpdate
!= HRGN_WINDOW
)
756 RgnUpdate
= REGION_LockRgn(Wnd
->hrgnUpdate
);
759 RgnType
= IntGdiCombineRgn(RgnUpdate
, RgnUpdate
, Rgn
, RGN_OR
);
760 REGION_UnlockRgn(RgnUpdate
);
761 if (RgnType
== NULLREGION
)
763 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
764 GreDeleteObject(Wnd
->hrgnUpdate
);
765 Wnd
->hrgnUpdate
= NULL
;
771 Flags
|= RDW_ERASE
|RDW_FRAME
; // For children.
775 if (!HadPaintMessage
&& IntIsWindowDirty(Wnd
))
777 MsqIncPaintCountQueue(Wnd
->head
.pti
);
780 } // The following flags are used to validate the window.
781 else if (Flags
& (RDW_VALIDATE
|RDW_NOINTERNALPAINT
|RDW_NOERASE
|RDW_NOFRAME
))
783 if (Wnd
->state
& WNDS_UPDATEDIRTY
&& !(Flags
& RDW_NOUPDATEDIRTY
))
786 if (Flags
& RDW_NOINTERNALPAINT
)
788 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
791 if (Flags
& RDW_VALIDATE
)
793 if (Flags
& RDW_NOFRAME
)
794 Wnd
->state
&= ~WNDS_SENDNCPAINT
;
796 if (Flags
& RDW_NOERASE
)
797 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
799 if (Wnd
->hrgnUpdate
> HRGN_WINDOW
&& RgnType
!= NULLREGION
&& Rgn
> PRGN_WINDOW
)
801 PREGION RgnUpdate
= REGION_LockRgn(Wnd
->hrgnUpdate
);
805 RgnType
= IntGdiCombineRgn(RgnUpdate
, RgnUpdate
, Rgn
, RGN_DIFF
);
806 REGION_UnlockRgn(RgnUpdate
);
808 if (RgnType
== NULLREGION
)
810 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
811 GreDeleteObject(Wnd
->hrgnUpdate
);
812 Wnd
->hrgnUpdate
= NULL
;
816 // If update is null, do not erase.
817 if (Wnd
->hrgnUpdate
== NULL
)
819 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
823 if (HadPaintMessage
&& !IntIsWindowDirty(Wnd
))
825 MsqDecPaintCountQueue(Wnd
->head
.pti
);
830 * Process children if needed
833 if (!(Flags
& RDW_NOCHILDREN
) &&
834 !(Wnd
->style
& WS_MINIMIZE
) &&
835 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)))
839 for (Child
= Wnd
->spwndChild
; Child
; Child
= Child
->spwndNext
)
841 if (Child
->style
& WS_VISIBLE
)
844 * Recursive call to update children hrgnUpdate
846 PREGION RgnTemp
= IntSysCreateRectpRgn(0, 0, 0, 0);
849 if (Rgn
> PRGN_WINDOW
) IntGdiCombineRgn(RgnTemp
, Rgn
, 0, RGN_COPY
);
850 IntInvalidateWindows(Child
, ((Rgn
> PRGN_WINDOW
)?RgnTemp
:Rgn
), Flags
);
851 REGION_Delete(RgnTemp
);
856 TRACE("IntInvalidateWindows exit\n");
860 * IntIsWindowDrawable
863 * Window is drawable when it is visible and all parents are not
868 IntIsWindowDrawable(PWND Wnd
)
872 for (WndObject
= Wnd
; WndObject
!= NULL
; WndObject
= WndObject
->spwndParent
)
874 if ( WndObject
->state2
& WNDS2_INDESTROY
||
875 WndObject
->state
& WNDS_DESTROYED
||
877 !(WndObject
->style
& WS_VISIBLE
) ||
878 ((WndObject
->style
& WS_MINIMIZE
) && (WndObject
!= Wnd
)))
890 * Internal version of NtUserRedrawWindow that takes WND as
897 const RECTL
* UpdateRect
,
901 PREGION TmpRgn
= NULL
;
902 TRACE("co_UserRedrawWindow start Rgn %p\n",UpdateRgn
);
906 * Validation of passed parameters.
909 if (!IntIsWindowDrawable(Window
))
911 return TRUE
; // Just do nothing!!!
916 Window
= UserGetDesktopWindow();
921 * Transform the parameters UpdateRgn and UpdateRect into
922 * a region hRgn specified in screen coordinates.
925 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
)) // Both are OKAY!
927 /* We can't hold lock on GDI objects while doing roundtrips to user mode,
928 * so use a copy instead */
931 TmpRgn
= IntSysCreateRectpRgn(0, 0, 0, 0);
933 if (UpdateRgn
> PRGN_WINDOW
)
935 IntGdiCombineRgn(TmpRgn
, UpdateRgn
, NULL
, RGN_COPY
);
938 if (Window
!= UserGetDesktopWindow())
940 REGION_bOffsetRgn(TmpRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
945 if (UpdateRect
!= NULL
)
947 if (Window
== UserGetDesktopWindow())
949 TmpRgn
= IntSysCreateRectpRgnIndirect(UpdateRect
);
953 TmpRgn
= IntSysCreateRectpRgn(Window
->rcClient
.left
+ UpdateRect
->left
,
954 Window
->rcClient
.top
+ UpdateRect
->top
,
955 Window
->rcClient
.left
+ UpdateRect
->right
,
956 Window
->rcClient
.top
+ UpdateRect
->bottom
);
961 if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
962 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
964 if (!RECTL_bIsEmptyRect(&Window
->rcWindow
))
965 TmpRgn
= IntSysCreateRectpRgnIndirect(&Window
->rcWindow
);
969 if (!RECTL_bIsEmptyRect(&Window
->rcClient
))
970 TmpRgn
= IntSysCreateRectpRgnIndirect(&Window
->rcClient
);
976 /* Fixes test RDW_INTERNALPAINT behavior */
979 TmpRgn
= PRGN_WINDOW
; // Need a region so the bits can be set!!!
984 * Adjust the window update region depending on hRgn and flags.
987 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
) &&
990 IntInvalidateWindows(Window
, TmpRgn
, Flags
);
995 * Repaint and erase windows if needed.
998 if (Flags
& RDW_UPDATENOW
)
1000 UserUpdateWindows(Window
, Flags
);
1002 else if (Flags
& RDW_ERASENOW
)
1004 if ((Flags
& (RDW_NOCHILDREN
|RDW_ALLCHILDREN
)) == 0)
1005 Flags
|= RDW_CLIPCHILDREN
;
1007 UserSyncAndPaintWindows(Window
, Flags
);
1015 if (TmpRgn
> PRGN_WINDOW
)
1017 REGION_Delete(TmpRgn
);
1019 TRACE("co_UserRedrawWindow exit\n");
1025 PaintSuspendedWindow(PWND pwnd
, HRGN hrgnOrig
)
1027 if (pwnd
->hrgnUpdate
)
1030 INT Flags
= DC_NC
|DC_NOSENDMSG
;
1036 if (pwnd
->hrgnUpdate
> HRGN_WINDOW
)
1038 hrgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
1039 type
= NtGdiCombineRgn( hrgnTemp
, pwnd
->hrgnUpdate
, 0, RGN_COPY
);
1042 GreDeleteObject(hrgnTemp
);
1043 hrgnTemp
= HRGN_WINDOW
;
1048 hrgnTemp
= GreCreateRectRgnIndirect(&pwnd
->rcWindow
);
1052 hrgnTemp
> HRGN_WINDOW
&&
1053 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnOrig
, RGN_AND
) == NULLREGION
)
1055 GreDeleteObject(hrgnTemp
);
1059 hDC
= UserGetDCEx(pwnd
, hrgnTemp
, DCX_WINDOW
|DCX_INTERSECTRGN
|DCX_USESTYLE
|DCX_KEEPCLIPRGN
);
1061 Rect
= pwnd
->rcWindow
;
1062 RECTL_vOffsetRect(&Rect
, -pwnd
->rcWindow
.left
, -pwnd
->rcWindow
.top
);
1064 // Clear out client area!
1065 FillRect(hDC
, &Rect
, IntGetSysColorBrush(COLOR_WINDOW
));
1067 NC_DoNCPaint(pwnd
, hDC
, Flags
); // Redraw without MENUs.
1069 UserReleaseDC(pwnd
, hDC
, FALSE
);
1071 prgn
= REGION_LockRgn(hrgnTemp
);
1072 IntInvalidateWindows(pwnd
, prgn
, RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ALLCHILDREN
);
1073 REGION_UnlockRgn(prgn
);
1075 // Set updates for this window.
1076 pwnd
->state
|= WNDS_SENDNCPAINT
|WNDS_SENDERASEBACKGROUND
|WNDS_UPDATEDIRTY
;
1078 // DCX_KEEPCLIPRGN is set. Check it anyway.
1079 if (hrgnTemp
> HRGN_WINDOW
&& GreIsHandleValid(hrgnTemp
)) GreDeleteObject(hrgnTemp
);
1084 UpdateTheadChildren(PWND pWnd
, HRGN hRgn
)
1086 PaintSuspendedWindow( pWnd
, hRgn
);
1088 if (!(pWnd
->style
& WS_CLIPCHILDREN
))
1091 pWnd
= pWnd
->spwndChild
; // invalidate children if any.
1094 UpdateTheadChildren( pWnd
, hRgn
);
1095 pWnd
= pWnd
->spwndNext
;
1100 UpdateThreadWindows(PWND pWnd
, PTHREADINFO pti
, HRGN hRgn
)
1104 for ( pwndTemp
= pWnd
;
1106 pwndTemp
= pwndTemp
->spwndNext
)
1108 if (pwndTemp
->head
.pti
== pti
)
1110 UserUpdateWindows(pwndTemp
, RDW_ALLCHILDREN
);
1114 if (IsThreadSuspended(pwndTemp
->head
.pti
) || MsqIsHung(pwndTemp
->head
.pti
))
1116 UpdateTheadChildren(pwndTemp
, hRgn
);
1119 UserUpdateWindows(pwndTemp
, RDW_ALLCHILDREN
);
1125 IntIsWindowDirty(PWND Wnd
)
1127 return ( Wnd
->style
& WS_VISIBLE
&&
1128 ( Wnd
->hrgnUpdate
!= NULL
||
1129 Wnd
->state
& WNDS_INTERNALPAINT
) );
1133 Conditions to paint any window:
1135 1. Update region is not null.
1136 2. Internal paint flag is set.
1137 3. Paint count is not zero.
1141 IntFindWindowToRepaint(PWND Window
, PTHREADINFO Thread
)
1146 for (; Window
!= NULL
; Window
= Window
->spwndNext
)
1148 if (IntWndBelongsToThread(Window
, Thread
))
1150 if (IntIsWindowDirty(Window
))
1152 /* Make sure all non-transparent siblings are already drawn. */
1153 if (Window
->ExStyle
& WS_EX_TRANSPARENT
)
1155 for (TempWindow
= Window
->spwndNext
; TempWindow
!= NULL
;
1156 TempWindow
= TempWindow
->spwndNext
)
1158 if (!(TempWindow
->ExStyle
& WS_EX_TRANSPARENT
) &&
1159 IntWndBelongsToThread(TempWindow
, Thread
) &&
1160 IntIsWindowDirty(TempWindow
))
1169 /* find a child of the specified window that needs repainting */
1170 if (Window
->spwndChild
)
1172 hChild
= IntFindWindowToRepaint(Window
->spwndChild
, Thread
);
1181 // Internal painting of windows.
1184 IntPaintWindow( PWND Window
)
1186 // Handle normal painting.
1187 co_IntPaintWindows( Window
, RDW_NOCHILDREN
, FALSE
);
1199 PWND PaintWnd
, StartWnd
;
1201 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
1202 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
1205 if (Thread
->TIF_flags
& TIF_SYSTEMTHREAD
)
1207 ERR("WM_PAINT is in a System Thread!\n");
1210 StartWnd
= UserGetDesktopWindow();
1211 PaintWnd
= IntFindWindowToRepaint(StartWnd
, Thread
);
1213 Message
->hwnd
= PaintWnd
? UserHMGetHandle(PaintWnd
) : NULL
;
1215 if (Message
->hwnd
== NULL
&& Thread
->cPaintsReady
)
1217 // Find note in window.c:"PAINTING BUG".
1218 ERR("WARNING SOMETHING HAS GONE WRONG: Thread marked as containing dirty windows, but no dirty windows found! Counts %u\n",Thread
->cPaintsReady
);
1219 /* Hack to stop spamming the debug log ! */
1220 Thread
->cPaintsReady
= 0;
1224 if (Message
->hwnd
== NULL
)
1227 if (!(Window
== NULL
||
1228 PaintWnd
== Window
||
1229 IntIsChildWindow(Window
, PaintWnd
))) /* check that it is a child of the specified parent */
1232 if (PaintWnd
->state
& WNDS_INTERNALPAINT
)
1234 PaintWnd
->state
&= ~WNDS_INTERNALPAINT
;
1235 if (!PaintWnd
->hrgnUpdate
)
1236 MsqDecPaintCountQueue(Thread
);
1238 PaintWnd
->state2
&= ~WNDS2_STARTPAINT
;
1239 PaintWnd
->state
&= ~WNDS_UPDATEDIRTY
;
1242 while (Window
&& !UserIsDesktopWindow(Window
))
1244 // Role back and check for clip children, do not set if any.
1245 if (Window
->spwndParent
&& !(Window
->spwndParent
->style
& WS_CLIPCHILDREN
))
1247 PaintWnd
->state2
|= WNDS2_WMPAINTSENT
;
1249 Window
= Window
->spwndParent
;
1252 Message
->wParam
= Message
->lParam
= 0;
1253 Message
->message
= WM_PAINT
;
1265 INT cx
, cy
, xSrc
, ySrc
;
1267 if ( nFlags
& PW_CLIENTONLY
)
1269 cx
= pwnd
->rcClient
.right
- pwnd
->rcClient
.left
;
1270 cy
= pwnd
->rcClient
.bottom
- pwnd
->rcClient
.top
;
1271 xSrc
= pwnd
->rcClient
.left
- pwnd
->rcWindow
.left
;
1272 ySrc
= pwnd
->rcClient
.top
- pwnd
->rcWindow
.top
;
1276 cx
= pwnd
->rcWindow
.right
- pwnd
->rcWindow
.left
;
1277 cy
= pwnd
->rcWindow
.bottom
- pwnd
->rcWindow
.top
;
1282 // TODO: Setup Redirection for Print.
1285 /* Update the window just incase. */
1286 co_IntUpdateWindows( pwnd
, RDW_ALLCHILDREN
, FALSE
);
1288 hdcSrc
= UserGetDCEx( pwnd
, NULL
, DCX_CACHE
|DCX_WINDOW
);
1289 /* Print window to printer context. */
1290 NtGdiBitBlt( hdcBlt
,
1302 UserReleaseDC( pwnd
, hdcSrc
, FALSE
);
1304 // TODO: Release Redirection from Print.
1311 IntFlashWindowEx(PWND pWnd
, PFLASHWINFO pfwi
)
1313 DWORD_PTR FlashState
;
1314 UINT uCount
= pfwi
->uCount
;
1315 BOOL Activate
= FALSE
, Ret
= FALSE
;
1319 FlashState
= (DWORD_PTR
)UserGetProp(pWnd
, AtomFlashWndState
, TRUE
);
1321 if (FlashState
== FLASHW_FINISHED
)
1323 // Cycle has finished, kill timer and set this to Stop.
1324 FlashState
|= FLASHW_KILLSYSTIMER
;
1325 pfwi
->dwFlags
= FLASHW_STOP
;
1331 if (pfwi
->dwFlags
== FLASHW_SYSTIMER
)
1333 // Called from system timer, restore flags, counts and state.
1334 pfwi
->dwFlags
= LOWORD(FlashState
);
1335 uCount
= HIWORD(FlashState
);
1336 FlashState
= MAKELONG(LOWORD(FlashState
),0);
1340 // Clean out the trash! Fix SeaMonkey crash after restart.
1345 if (FlashState
== 0)
1346 { // First time in cycle, setup flash state.
1347 if ( pWnd
->state
& WNDS_ACTIVEFRAME
||
1348 (pfwi
->dwFlags
& FLASHW_CAPTION
&& pWnd
->style
& (WS_BORDER
|WS_DLGFRAME
)))
1350 FlashState
= FLASHW_STARTED
|FLASHW_ACTIVE
;
1354 // Set previous window state.
1355 Ret
= !!(FlashState
& FLASHW_ACTIVE
);
1357 if ( (pfwi
->dwFlags
& FLASHW_TIMERNOFG
) == FLASHW_TIMERNOFG
&&
1358 gpqForeground
== pWnd
->head
.pti
->MessageQueue
)
1360 // Flashing until foreground, set this to Stop.
1361 pfwi
->dwFlags
= FLASHW_STOP
;
1365 // Toggle activate flag.
1366 if ( pfwi
->dwFlags
== FLASHW_STOP
)
1368 if (gpqForeground
&& gpqForeground
->spwndActive
== pWnd
)
1375 Activate
= (FlashState
& FLASHW_ACTIVE
) == 0;
1378 if ( pfwi
->dwFlags
== FLASHW_STOP
|| pfwi
->dwFlags
& FLASHW_CAPTION
)
1380 co_IntSendMessage(UserHMGetHandle(pWnd
), WM_NCACTIVATE
, Activate
, 0);
1383 // FIXME: Check for a Stop Sign here.
1384 if ( pfwi
->dwFlags
& FLASHW_TRAY
)
1386 // Need some shell work here too.
1387 TRACE("FIXME: Flash window no Tray support!\n");
1390 if ( pfwi
->dwFlags
== FLASHW_STOP
)
1392 if (FlashState
& FLASHW_KILLSYSTIMER
)
1394 IntKillTimer(pWnd
, ID_EVENT_SYSTIMER_FLASHWIN
, TRUE
);
1397 UserRemoveProp(pWnd
, AtomFlashWndState
, TRUE
);
1400 { // Have a count and started, set timer.
1403 FlashState
|= FLASHW_COUNT
;
1405 if (!(Activate
^ !!(FlashState
& FLASHW_STARTED
)))
1408 if (!(FlashState
& FLASHW_KILLSYSTIMER
))
1409 pfwi
->dwFlags
|= FLASHW_TIMER
;
1412 if (pfwi
->dwFlags
& FLASHW_TIMER
)
1414 FlashState
|= FLASHW_KILLSYSTIMER
;
1417 ID_EVENT_SYSTIMER_FLASHWIN
,
1418 pfwi
->dwTimeout
? pfwi
->dwTimeout
: gpsi
->dtCaretBlink
,
1423 if (FlashState
& FLASHW_COUNT
&& uCount
== 0)
1425 // Keep spinning? Nothing else to do.
1426 FlashState
= FLASHW_FINISHED
;
1430 // Save state and flags so this can be restored next time through.
1431 FlashState
^= (FlashState
^ -!!(Activate
)) & FLASHW_ACTIVE
;
1432 FlashState
^= (FlashState
^ pfwi
->dwFlags
) & (FLASHW_MASK
& ~FLASHW_TIMER
);
1434 FlashState
= MAKELONG(LOWORD(FlashState
),uCount
);
1435 UserSetProp(pWnd
, AtomFlashWndState
, (HANDLE
)FlashState
, TRUE
);
1441 IntBeginPaint(PWND Window
, PPAINTSTRUCT Ps
)
1447 co_UserHideCaret(Window
);
1449 Window
->state2
|= WNDS2_STARTPAINT
;
1450 Window
->state
&= ~WNDS_PAINTNOTPROCESSED
;
1452 if (Window
->state
& WNDS_SENDNCPAINT
)
1455 // Application can keep update dirty.
1458 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1459 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
1460 IntSendNCPaint(Window
, hRgn
);
1461 if (hRgn
> HRGN_WINDOW
&& GreIsHandleValid(hRgn
))
1463 /* NOTE: The region can already be deleted! */
1464 GreDeleteObject(hRgn
);
1467 while(Window
->state
& WNDS_UPDATEDIRTY
);
1471 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1474 RtlZeroMemory(Ps
, sizeof(PAINTSTRUCT
));
1476 if (Window
->state2
& WNDS2_ENDPAINTINVALIDATE
)
1478 ERR("BP: Another thread invalidated this window\n");
1481 Ps
->hdc
= UserGetDCEx( Window
,
1483 DCX_INTERSECTRGN
| DCX_USESTYLE
);
1489 // If set, always clear flags out due to the conditions later on for sending the message.
1490 if (Window
->state
& WNDS_SENDERASEBACKGROUND
)
1492 Window
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
1496 if (Window
->hrgnUpdate
!= NULL
)
1498 MsqDecPaintCountQueue(Window
->head
.pti
);
1499 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
1500 /* The region is part of the dc now and belongs to the process! */
1501 Window
->hrgnUpdate
= NULL
;
1505 if (Window
->state
& WNDS_INTERNALPAINT
)
1506 MsqDecPaintCountQueue(Window
->head
.pti
);
1509 type
= GdiGetClipBox(Ps
->hdc
, &Ps
->rcPaint
);
1511 IntGetClientRect(Window
, &Rect
);
1513 Window
->state
&= ~WNDS_INTERNALPAINT
;
1515 if ( Erase
&& // Set to erase,
1516 type
!= NULLREGION
&& // don't erase if the clip box is empty,
1517 (!(Window
->pcls
->style
& CS_PARENTDC
) || // not parent dc or
1518 RECTL_bIntersectRect( &Rect
, &Rect
, &Ps
->rcPaint
) ) ) // intersecting.
1520 Ps
->fErase
= !co_IntSendMessage(UserHMGetHandle(Window
), WM_ERASEBKGND
, (WPARAM
)Ps
->hdc
, 0);
1523 Window
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
1531 IntSendChildNCPaint(Window
);
1537 IntEndPaint(PWND Wnd
, PPAINTSTRUCT Ps
)
1543 UserReleaseDC(Wnd
, hdc
, TRUE
);
1545 if (Wnd
->state2
& WNDS2_ENDPAINTINVALIDATE
)
1547 ERR("EP: Another thread invalidated this window\n");
1548 Wnd
->state2
&= ~WNDS2_ENDPAINTINVALIDATE
;
1551 Wnd
->state2
&= ~(WNDS2_WMPAINTSENT
|WNDS2_STARTPAINT
);
1553 co_UserShowCaret(Wnd
);
1559 IntFillWindow(PWND pWndParent
,
1570 type
= GdiGetClipBox(hDC
, &Rect
);
1572 IntGetClientRect(pWnd
, &Rect1
);
1574 if ( type
!= NULLREGION
&& // Clip box is not empty,
1575 (!(pWnd
->pcls
->style
& CS_PARENTDC
) || // not parent dc or
1576 RECTL_bIntersectRect( &Rect
, &Rect
, &Rect1
) ) ) // intersecting.
1581 if (!UserIsDesktopWindow(pWndParent
))
1583 x
= pWndParent
->rcClient
.left
- pWnd
->rcClient
.left
;
1584 y
= pWndParent
->rcClient
.top
- pWnd
->rcClient
.top
;
1587 GreSetBrushOrg(hDC
, x
, y
, &ppt
);
1589 if ( hBrush
< (HBRUSH
)CTLCOLOR_MAX
)
1590 hBrush
= GetControlColor( pWndParent
, pWnd
, hDC
, HandleToUlong(hBrush
) + WM_CTLCOLORMSGBOX
);
1592 FillRect(hDC
, &Rect
, hBrush
);
1594 GreSetBrushOrg(hDC
, ppt
.x
, ppt
.y
, NULL
);
1602 /* PUBLIC FUNCTIONS ***********************************************************/
1612 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
1618 USER_REFERENCE_ENTRY Ref
;
1619 DECLARE_RETURN(HDC
);
1621 TRACE("Enter NtUserBeginPaint\n");
1622 UserEnterExclusive();
1624 if (!(Window
= UserGetWindowObject(hWnd
)))
1629 UserRefObjectCo(Window
, &Ref
);
1631 hDC
= IntBeginPaint(Window
, &Ps
);
1633 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
1634 if (! NT_SUCCESS(Status
))
1636 SetLastNtError(Status
);
1643 if (Window
) UserDerefObjectCo(Window
);
1645 TRACE("Leave NtUserBeginPaint, ret=%p\n",_ret_
);
1659 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* pUnsafePs
)
1661 NTSTATUS Status
= STATUS_SUCCESS
;
1664 USER_REFERENCE_ENTRY Ref
;
1665 DECLARE_RETURN(BOOL
);
1667 TRACE("Enter NtUserEndPaint\n");
1668 UserEnterExclusive();
1670 if (!(Window
= UserGetWindowObject(hWnd
)))
1675 UserRefObjectCo(Window
, &Ref
); // Here for the exception.
1679 ProbeForRead(pUnsafePs
, sizeof(*pUnsafePs
), 1);
1680 RtlCopyMemory(&Ps
, pUnsafePs
, sizeof(PAINTSTRUCT
));
1682 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1684 Status
= _SEH2_GetExceptionCode();
1687 if (!NT_SUCCESS(Status
))
1692 RETURN(IntEndPaint(Window
, &Ps
));
1695 if (Window
) UserDerefObjectCo(Window
);
1697 TRACE("Leave NtUserEndPaint, ret=%i\n",_ret_
);
1703 * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND.
1709 NtUserFillWindow(HWND hWndParent
,
1715 PWND pWnd
, pWndParent
= NULL
;
1716 USER_REFERENCE_ENTRY Ref
;
1718 TRACE("Enter NtUserFillWindow\n");
1719 UserEnterExclusive();
1726 if (!(pWnd
= UserGetWindowObject(hWnd
)))
1731 if (hWndParent
&& !(pWndParent
= UserGetWindowObject(hWndParent
)))
1736 UserRefObjectCo(pWnd
, &Ref
);
1737 ret
= IntFillWindow( pWndParent
, pWnd
, hDC
, hBrush
);
1738 UserDerefObjectCo(pWnd
);
1741 TRACE("Leave NtUserFillWindow, ret=%i\n",ret
);
1750 NtUserFlashWindowEx(IN PFLASHWINFO pfwi
)
1753 FLASHWINFO finfo
= {0};
1756 UserEnterExclusive();
1760 ProbeForRead(pfwi
, sizeof(FLASHWINFO
), 1);
1761 RtlCopyMemory(&finfo
, pfwi
, sizeof(FLASHWINFO
));
1763 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1765 SetLastNtError(_SEH2_GetExceptionCode());
1766 _SEH2_YIELD(goto Exit
);
1770 if (!( pWnd
= ValidateHwndNoErr(finfo
.hwnd
)) ||
1771 finfo
.cbSize
!= sizeof(FLASHWINFO
) ||
1772 finfo
.dwFlags
& ~(FLASHW_ALL
|FLASHW_TIMER
|FLASHW_TIMERNOFG
) )
1774 EngSetLastError(ERROR_INVALID_PARAMETER
);
1778 Ret
= IntFlashWindowEx(pWnd
, &finfo
);
1786 GetUpdateRgn, this fails the same as the old one.
1789 co_UserGetUpdateRgn(PWND Window
, HRGN hRgn
, BOOL bErase
)
1795 ASSERT_REFS_CO(Window
);
1799 USER_REFERENCE_ENTRY Ref
;
1800 UserRefObjectCo(Window
, &Ref
);
1801 co_IntPaintWindows(Window
, RDW_NOCHILDREN
, FALSE
);
1802 UserDerefObjectCo(Window
);
1805 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1807 if (Window
->hrgnUpdate
== NULL
)
1809 NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0);
1813 Rect
= Window
->rcClient
;
1814 Type
= IntIntersectWithParents(Window
, &Rect
);
1816 if (Window
->hrgnUpdate
== HRGN_WINDOW
)
1819 ERR("GURn: Caller is passing Window Region 1\n");
1822 NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0);
1826 RegionType
= SIMPLEREGION
;
1828 if (!UserIsDesktopWindow(Window
))
1830 RECTL_vOffsetRect(&Rect
,
1831 -Window
->rcClient
.left
,
1832 -Window
->rcClient
.top
);
1834 GreSetRectRgnIndirect(hRgn
, &Rect
);
1838 HRGN hrgnTemp
= GreCreateRectRgnIndirect(&Rect
);
1840 RegionType
= NtGdiCombineRgn(hRgn
, hrgnTemp
, Window
->hrgnUpdate
, RGN_AND
);
1842 if (RegionType
== ERROR
|| RegionType
== NULLREGION
)
1844 if (hrgnTemp
) GreDeleteObject(hrgnTemp
);
1845 NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0);
1849 if (!UserIsDesktopWindow(Window
))
1851 NtGdiOffsetRgn(hRgn
,
1852 -Window
->rcClient
.left
,
1853 -Window
->rcClient
.top
);
1855 if (hrgnTemp
) GreDeleteObject(hrgnTemp
);
1861 co_UserGetUpdateRect(PWND Window
, PRECT pRect
, BOOL bErase
)
1868 USER_REFERENCE_ENTRY Ref
;
1869 UserRefObjectCo(Window
, &Ref
);
1870 co_IntPaintWindows(Window
, RDW_NOCHILDREN
, FALSE
);
1871 UserDerefObjectCo(Window
);
1874 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1876 if (Window
->hrgnUpdate
== NULL
)
1878 pRect
->left
= pRect
->top
= pRect
->right
= pRect
->bottom
= 0;
1883 /* Get the update region bounding box. */
1884 if (Window
->hrgnUpdate
== HRGN_WINDOW
)
1886 *pRect
= Window
->rcClient
;
1887 ERR("GURt: Caller is retrieving Window Region 1\n");
1891 RegionType
= IntGdiGetRgnBox(Window
->hrgnUpdate
, pRect
);
1893 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
1894 RECTL_bIntersectRect(pRect
, pRect
, &Window
->rcClient
);
1897 if (IntIntersectWithParents(Window
, pRect
))
1899 if (!UserIsDesktopWindow(Window
))
1901 RECTL_vOffsetRect(pRect
,
1902 -Window
->rcClient
.left
,
1903 -Window
->rcClient
.top
);
1905 if (Window
->pcls
->style
& CS_OWNDC
)
1909 hdc
= UserGetDCEx(Window
, NULL
, DCX_USESTYLE
);
1910 //layout = NtGdiSetLayout(hdc, -1, 0);
1911 //IntMapWindowPoints( 0, Window, (LPPOINT)pRect, 2 );
1912 GreDPtoLP( hdc
, (LPPOINT
)pRect
, 2 );
1913 //NtGdiSetLayout(hdc, -1, layout);
1914 UserReleaseDC(Window
, hdc
, FALSE
);
1919 pRect
->left
= pRect
->top
= pRect
->right
= pRect
->bottom
= 0;
1926 * NtUserGetUpdateRgn
1933 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
1935 DECLARE_RETURN(INT
);
1939 TRACE("Enter NtUserGetUpdateRgn\n");
1940 UserEnterExclusive();
1942 if (!(Window
= UserGetWindowObject(hWnd
)))
1947 ret
= co_UserGetUpdateRgn(Window
, hRgn
, bErase
);
1952 TRACE("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
1958 * NtUserGetUpdateRect
1965 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
1971 DECLARE_RETURN(BOOL
);
1973 TRACE("Enter NtUserGetUpdateRect\n");
1974 UserEnterExclusive();
1976 if (!(Window
= UserGetWindowObject(hWnd
)))
1981 Ret
= co_UserGetUpdateRect(Window
, &Rect
, bErase
);
1983 if (UnsafeRect
!= NULL
)
1985 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECTL
));
1986 if (!NT_SUCCESS(Status
))
1988 EngSetLastError(ERROR_INVALID_PARAMETER
);
1996 TRACE("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
2002 * NtUserRedrawWindow
2011 CONST RECT
*lprcUpdate
,
2015 RECTL SafeUpdateRect
;
2018 USER_REFERENCE_ENTRY Ref
;
2019 NTSTATUS Status
= STATUS_SUCCESS
;
2020 PREGION RgnUpdate
= NULL
;
2021 DECLARE_RETURN(BOOL
);
2023 TRACE("Enter NtUserRedrawWindow\n");
2024 UserEnterExclusive();
2026 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
2035 ProbeForRead(lprcUpdate
, sizeof(RECTL
), 1);
2036 RtlCopyMemory(&SafeUpdateRect
, lprcUpdate
, sizeof(RECTL
));
2038 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2040 Status
= _SEH2_GetExceptionCode();
2043 if (!NT_SUCCESS(Status
))
2045 EngSetLastError(RtlNtStatusToDosError(Status
));
2050 if ( flags
& ~(RDW_ERASE
|RDW_FRAME
|RDW_INTERNALPAINT
|RDW_INVALIDATE
|
2051 RDW_NOERASE
|RDW_NOFRAME
|RDW_NOINTERNALPAINT
|RDW_VALIDATE
|
2052 RDW_ERASENOW
|RDW_UPDATENOW
|RDW_ALLCHILDREN
|RDW_NOCHILDREN
) )
2054 /* RedrawWindow fails only in case that flags are invalid */
2055 EngSetLastError(ERROR_INVALID_FLAGS
);
2059 /* We can't hold lock on GDI objects while doing roundtrips to user mode,
2060 * so it will be copied.
2062 if (hrgnUpdate
> HRGN_WINDOW
)
2064 RgnUpdate
= REGION_LockRgn(hrgnUpdate
);
2067 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2070 REGION_UnlockRgn(RgnUpdate
);
2072 else if (hrgnUpdate
== HRGN_WINDOW
) // Trap it out.
2074 ERR("NTRW: Caller is passing Window Region 1\n");
2077 UserRefObjectCo(Wnd
, &Ref
);
2079 Ret
= co_UserRedrawWindow( Wnd
,
2080 lprcUpdate
? &SafeUpdateRect
: NULL
,
2084 UserDerefObjectCo(Wnd
);
2089 TRACE("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
2095 UserDrawCaptionText(
2098 const PUNICODE_STRING Text
,
2103 HFONT hOldFont
= NULL
;
2104 COLORREF OldTextColor
;
2105 NONCLIENTMETRICSW nclm
;
2107 BOOLEAN bDeleteFont
= FALSE
;
2110 ULONG fit
= 0, Length
;
2113 TRACE("UserDrawCaptionText: %wZ\n", Text
);
2115 nclm
.cbSize
= sizeof(nclm
);
2116 if (!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
, nclm
.cbSize
, &nclm
, 0))
2118 ERR("UserSystemParametersInfo() failed!\n");
2124 if(uFlags
& DC_SMALLCAP
)
2125 Status
= TextIntCreateFontIndirect(&nclm
.lfSmCaptionFont
, &hFont
);
2127 Status
= TextIntCreateFontIndirect(&nclm
.lfCaptionFont
, &hFont
);
2129 if(!NT_SUCCESS(Status
))
2131 ERR("TextIntCreateFontIndirect() failed! Status: 0x%x\n", Status
);
2138 IntGdiSetBkMode(hDc
, TRANSPARENT
);
2140 hOldFont
= NtGdiSelectFont(hDc
, hFont
);
2142 if(uFlags
& DC_INBUTTON
)
2143 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(COLOR_BTNTEXT
));
2145 OldTextColor
= IntGdiSetTextColor(hDc
,
2146 IntGetSysColor(uFlags
& DC_ACTIVE
? COLOR_CAPTIONTEXT
: COLOR_INACTIVECAPTIONTEXT
));
2148 // Adjust for system menu.
2149 if (pWnd
&& pWnd
->style
& WS_SYSMENU
)
2151 r
.right
-= UserGetSystemMetrics(SM_CYCAPTION
) - 1;
2152 if ((pWnd
->style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
)) && !(pWnd
->ExStyle
& WS_EX_TOOLWINDOW
))
2154 r
.right
-= UserGetSystemMetrics(SM_CXSIZE
) + 1;
2155 r
.right
-= UserGetSystemMetrics(SM_CXSIZE
) + 1;
2159 GreGetTextExtentExW(hDc
, Text
->Buffer
, Text
->Length
/sizeof(WCHAR
), r
.right
- r
.left
, &fit
, 0, &Size
, 0);
2161 Length
= (Text
->Length
/sizeof(WCHAR
) == fit
? fit
: fit
+1);
2163 if (Text
->Length
/sizeof(WCHAR
) > Length
)
2169 { // Faster while in setup.
2170 GreExtTextOutW( hDc
,
2172 lpRc
->top
+ (lpRc
->bottom
- lpRc
->top
) / 2 - Size
.cy
/ 2, // DT_SINGLELINE && DT_VCENTER
2184 Text
->Length
/sizeof(WCHAR
),
2186 DT_END_ELLIPSIS
|DT_SINGLELINE
|DT_VCENTER
|DT_NOPREFIX
|DT_LEFT
);
2189 IntGdiSetTextColor(hDc
, OldTextColor
);
2192 NtGdiSelectFont(hDc
, hOldFont
);
2195 GreDeleteObject(hFont
);
2201 // This draws Buttons, Icons and Text...
2203 BOOL
UserDrawCaption(
2209 const PUNICODE_STRING Str
,
2213 HBRUSH hBgBrush
, hOldBrush
= NULL
;
2217 RECTL_vMakeWellOrdered(lpRc
);
2219 /* Determine whether the icon needs to be displayed */
2220 if (!hIcon
&& pWnd
!= NULL
)
2222 HasIcon
= (uFlags
& DC_ICON
) && !(uFlags
& DC_SMALLCAP
) &&
2223 (pWnd
->style
& WS_SYSMENU
) && !(pWnd
->ExStyle
& WS_EX_TOOLWINDOW
);
2226 HasIcon
= (hIcon
!= NULL
);
2228 // Draw the caption background
2229 if((uFlags
& DC_GRADIENT
) && !(uFlags
& DC_INBUTTON
))
2231 static GRADIENT_RECT gcap
= {0, 1};
2232 TRIVERTEX Vertices
[2];
2235 Colors
[0] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
2236 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
2238 Colors
[1] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
2239 COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
2241 Vertices
[0].x
= Rect
.left
;
2242 Vertices
[0].y
= Rect
.top
;
2243 Vertices
[0].Red
= (WORD
)Colors
[0]<<8;
2244 Vertices
[0].Green
= (WORD
)Colors
[0] & 0xFF00;
2245 Vertices
[0].Blue
= (WORD
)(Colors
[0]>>8) & 0xFF00;
2246 Vertices
[0].Alpha
= 0;
2248 Vertices
[1].x
= Rect
.right
;
2249 Vertices
[1].y
= Rect
.bottom
;
2250 Vertices
[1].Red
= (WORD
)Colors
[1]<<8;
2251 Vertices
[1].Green
= (WORD
)Colors
[1] & 0xFF00;
2252 Vertices
[1].Blue
= (WORD
)(Colors
[1]>>8) & 0xFF00;
2253 Vertices
[1].Alpha
= 0;
2255 if(!GreGradientFill(hDc
, Vertices
, 2, &gcap
, 1, GRADIENT_FILL_RECT_H
))
2257 ERR("GreGradientFill() failed!\n");
2263 if(uFlags
& DC_INBUTTON
)
2264 hBgBrush
= IntGetSysColorBrush(COLOR_3DFACE
);
2265 else if(uFlags
& DC_ACTIVE
)
2266 hBgBrush
= IntGetSysColorBrush(COLOR_ACTIVECAPTION
);
2268 hBgBrush
= IntGetSysColorBrush(COLOR_INACTIVECAPTION
);
2270 hOldBrush
= NtGdiSelectBrush(hDc
, hBgBrush
);
2274 ERR("NtGdiSelectBrush() failed!\n");
2278 if(!NtGdiPatBlt(hDc
, Rect
.left
, Rect
.top
,
2279 Rect
.right
- Rect
.left
,
2280 Rect
.bottom
- Rect
.top
,
2283 ERR("NtGdiPatBlt() failed!\n");
2291 PCURICON_OBJECT pIcon
= NULL
;
2295 pIcon
= UserGetCurIconObject(hIcon
);
2299 pIcon
= NC_IconForWindow(pWnd
);
2300 // FIXME: NC_IconForWindow should reference it for us */
2302 UserReferenceObject(pIcon
);
2307 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
2308 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
2309 LONG x
= Rect
.left
- cx
/2 + 1 + (Rect
.bottom
- Rect
.top
)/2; // this is really what Window does
2310 LONG y
= (Rect
.top
+ Rect
.bottom
- cy
)/2; // center
2311 UserDrawIconEx(hDc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
2312 UserDereferenceObject(pIcon
);
2321 Rect
.left
+= Rect
.bottom
- Rect
.top
;
2323 if((uFlags
& DC_TEXT
))
2329 Set
= UserDrawCaptionText(pWnd
, hDc
, Str
, &Rect
, uFlags
, hFont
);
2330 else if (pWnd
!= NULL
) // FIXME: Windows does not do that
2332 UNICODE_STRING ustr
;
2333 ustr
.Buffer
= pWnd
->strName
.Buffer
; // FIXME: LARGE_STRING truncated!
2334 ustr
.Length
= (USHORT
)min(pWnd
->strName
.Length
, MAXUSHORT
);
2335 ustr
.MaximumLength
= (USHORT
)min(pWnd
->strName
.MaximumLength
, MAXUSHORT
);
2336 Set
= UserDrawCaptionText(pWnd
, hDc
, &ustr
, &Rect
, uFlags
, hFont
);
2341 pWnd
->state2
&= ~WNDS2_CAPTIONTEXTTRUNCATED
;
2343 pWnd
->state2
|= WNDS2_CAPTIONTEXTTRUNCATED
;
2350 if (hOldBrush
) NtGdiSelectBrush(hDc
, hOldBrush
);
2357 UserRealizePalette(HDC hdc
)
2359 HWND hWnd
, hWndDesktop
;
2362 Ret
= IntGdiRealizePalette(hdc
);
2363 if (Ret
) // There was a change.
2365 hWnd
= IntWindowFromDC(hdc
);
2366 if (hWnd
) // Send broadcast if dc is associated with a window.
2367 { // FYI: Thread locked in CallOneParam.
2368 hWndDesktop
= IntGetDesktopWindow();
2369 if ( hWndDesktop
!= hWnd
)
2371 PWND pWnd
= UserGetWindowObject(hWndDesktop
);
2372 ERR("RealizePalette Desktop.");
2373 hdc
= UserGetWindowDC(pWnd
);
2374 IntPaintDesktop(hdc
);
2375 UserReleaseDC(pWnd
,hdc
,FALSE
);
2377 UserSendNotifyMessage((HWND
)HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0);
2385 NtUserDrawCaptionTemp(
2391 const PUNICODE_STRING str
,
2395 UNICODE_STRING SafeStr
= {0};
2396 NTSTATUS Status
= STATUS_SUCCESS
;
2400 UserEnterExclusive();
2404 if(!(pWnd
= UserGetWindowObject(hWnd
)))
2413 ProbeForRead(lpRc
, sizeof(RECTL
), sizeof(ULONG
));
2414 RtlCopyMemory(&SafeRect
, lpRc
, sizeof(RECTL
));
2417 SafeStr
= ProbeForReadUnicodeString(str
);
2418 if (SafeStr
.Length
!= 0)
2420 ProbeForRead( SafeStr
.Buffer
,
2426 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2428 Status
= _SEH2_GetExceptionCode();
2432 if (Status
!= STATUS_SUCCESS
)
2434 SetLastNtError(Status
);
2440 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, &SafeStr
, uFlags
);
2443 if ( RECTL_bIsEmptyRect(&SafeRect
) && hFont
== 0 && hIcon
== 0 )
2446 if (uFlags
& DC_DRAWCAPTIONMD
)
2448 ERR("NC Caption Mode\n");
2449 UserDrawCaptionBar(pWnd
, hDC
, uFlags
);
2452 else if (uFlags
& DC_DRAWFRAMEMD
)
2454 ERR("NC Paint Mode\n");
2455 NC_DoNCPaint(pWnd
, hDC
, uFlags
); // Update Menus too!
2459 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, NULL
, uFlags
);
2468 NtUserDrawCaption(HWND hWnd
,
2473 return NtUserDrawCaptionTemp(hWnd
, hDC
, lpRc
, 0, 0, NULL
, uFlags
);
2477 co_UserExcludeUpdateRgn(HDC hDC
, PWND Window
)
2482 if (Window
->hrgnUpdate
)
2484 if (Window
->hrgnUpdate
== HRGN_WINDOW
)
2486 return NtGdiIntersectClipRect(hDC
, 0, 0, 0, 0);
2491 HRGN hrgn
= NtGdiCreateRectRgn(0,0,0,0);
2493 if ( hrgn
&& GreGetDCPoint( hDC
, GdiGetDCOrg
, &pt
) )
2495 if ( NtGdiGetRandomRgn( hDC
, hrgn
, CLIPRGN
) == NULLREGION
)
2497 NtGdiOffsetRgn(hrgn
, pt
.x
, pt
.y
);
2502 PMONITOR pm
= UserGetPrimaryMonitor();
2503 hrgnScreen
= NtGdiCreateRectRgn(0,0,0,0);
2504 NtGdiCombineRgn(hrgnScreen
, hrgnScreen
, pm
->hrgnMonitor
, RGN_OR
);
2506 NtGdiCombineRgn(hrgn
, hrgnScreen
, NULL
, RGN_COPY
);
2508 GreDeleteObject(hrgnScreen
);
2511 NtGdiCombineRgn(hrgn
, hrgn
, Window
->hrgnUpdate
, RGN_DIFF
);
2513 NtGdiOffsetRgn(hrgn
, -pt
.x
, -pt
.y
);
2515 ret
= NtGdiExtSelectClipRgn(hDC
, hrgn
, RGN_COPY
);
2517 GreDeleteObject(hrgn
);
2524 return GdiGetClipBox( hDC
, &rc
);
2530 NtUserExcludeUpdateRgn(
2537 TRACE("Enter NtUserExcludeUpdateRgn\n");
2538 UserEnterExclusive();
2540 pWnd
= UserGetWindowObject(hWnd
);
2543 ret
= co_UserExcludeUpdateRgn(hDC
, pWnd
);
2545 TRACE("Leave NtUserExcludeUpdateRgn, ret=%i\n", ret
);
2553 NtUserInvalidateRect(
2555 CONST RECT
*lpUnsafeRect
,
2558 UINT flags
= RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0);
2561 flags
= RDW_ALLCHILDREN
| RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ERASENOW
;
2562 lpUnsafeRect
= NULL
;
2564 return NtUserRedrawWindow(hWnd
, lpUnsafeRect
, NULL
, flags
);
2569 NtUserInvalidateRgn(
2576 EngSetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2579 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2592 UserEnterExclusive();
2596 if (!(Window
= UserGetWindowObject(hwnd
)) ||
2597 UserIsDesktopWindow(Window
) || UserIsMessageWindow(Window
))
2604 /* Validate flags and check it as a mask for 0 or 1. */
2605 if ( (nFlags
& PW_CLIENTONLY
) == nFlags
)
2606 Ret
= IntPrintWindow( Window
, hdcBlt
, nFlags
);
2608 EngSetLastError(ERROR_INVALID_PARAMETER
);
2616 /* ValidateRect gets redirected to NtUserValidateRect:
2617 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */
2624 UINT flags
= RDW_VALIDATE
;
2627 flags
= RDW_ALLCHILDREN
| RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ERASENOW
;
2630 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, flags
);