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 #define RDW_CLIPCHILDREN 4096
13 #define RDW_NOUPDATEDIRTY 32768
15 /* PRIVATE FUNCTIONS **********************************************************/
18 * @name IntIntersectWithParents
20 * Intersect window rectangle with all parent client rectangles.
23 * Pointer to child window to start intersecting from.
25 * Pointer to rectangle that we want to intersect in screen
26 * coordinates on input and intersected rectangle on output (if TRUE
30 * If any parent is minimized or invisible or the resulting rectangle
31 * is empty then FALSE is returned. Otherwise TRUE is returned.
35 IntIntersectWithParents(PWND Child
, RECTL
*WindowRect
)
39 if (Child
->ExStyle
& WS_EX_REDIRECTED
)
42 ParentWnd
= Child
->spwndParent
;
43 while (ParentWnd
!= NULL
)
45 if (!(ParentWnd
->style
& WS_VISIBLE
) ||
46 (ParentWnd
->style
& WS_MINIMIZE
) ||
47 !RECTL_bIntersectRect(WindowRect
, WindowRect
, &ParentWnd
->rcClient
) )
52 if (ParentWnd
->ExStyle
& WS_EX_REDIRECTED
)
55 ParentWnd
= ParentWnd
->spwndParent
;
62 IntValidateParents(PWND Child
, BOOL Recurse
)
64 RECTL ParentRect
, Rect
;
65 BOOL Start
, Ret
= TRUE
;
66 PWND ParentWnd
= Child
;
69 if (ParentWnd
->style
& WS_CHILD
)
72 ParentWnd
= ParentWnd
->spwndParent
;
73 while (ParentWnd
->style
& WS_CHILD
);
76 // No pending nonclient paints.
77 if (!(ParentWnd
->state
& WNDS_SYNCPAINTPENDING
)) Recurse
= FALSE
;
80 ParentWnd
= Child
->spwndParent
;
83 if (ParentWnd
->style
& WS_CLIPCHILDREN
)
86 if (ParentWnd
->hrgnUpdate
!= 0)
93 // Start with child clipping.
98 Rect
= Child
->rcWindow
;
100 if (!IntIntersectWithParents(Child
, &Rect
)) break;
102 Rgn
= IntSysCreateRectpRgnIndirect(&Rect
);
106 PREGION RgnClip
= REGION_LockRgn(Child
->hrgnClip
);
107 IntGdiCombineRgn(Rgn
, Rgn
, RgnClip
, RGN_AND
);
108 REGION_UnlockRgn(RgnClip
);
112 ParentRect
= ParentWnd
->rcWindow
;
114 if (!IntIntersectWithParents(ParentWnd
, &ParentRect
)) break;
116 IntInvalidateWindows( ParentWnd
,
118 RDW_VALIDATE
| RDW_NOCHILDREN
| RDW_NOUPDATEDIRTY
);
120 ParentWnd
= ParentWnd
->spwndParent
;
123 if (Rgn
) REGION_Delete(Rgn
);
129 Synchronize painting to the top-level windows of other threads.
132 IntSendSyncPaint(PWND Wnd
, ULONG Flags
)
134 PTHREADINFO ptiCur
, ptiWnd
;
135 PUSER_SENT_MESSAGE Message
;
139 ptiWnd
= Wnd
->head
.pti
;
140 ptiCur
= PsGetCurrentThreadWin32Thread();
142 Not the current thread, Wnd is in send Nonclient paint also in send erase background and it is visiable.
144 if ( Wnd
->head
.pti
!= ptiCur
&&
145 Wnd
->state
& WNDS_SENDNCPAINT
&&
146 Wnd
->state
& WNDS_SENDERASEBACKGROUND
&&
147 Wnd
->style
& WS_VISIBLE
)
149 // For testing, if you see this, break out the Champagne and have a party!
150 TRACE("SendSyncPaint Wnd in State!\n");
151 if (!IsListEmpty(&ptiWnd
->SentMessagesListHead
))
153 // Scan sent queue messages to see if we received sync paint messages.
154 Entry
= ptiWnd
->SentMessagesListHead
.Flink
;
155 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
159 if (Message
->Msg
.message
== WM_SYNCPAINT
&&
160 Message
->Msg
.hwnd
== UserHMGetHandle(Wnd
))
161 { // Already received so exit out.
162 ERR("SendSyncPaint Found one in the Sent Msg Queue!\n");
166 Entry
= Message
->ListEntry
.Flink
;
167 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
169 while (Entry
!= &ptiWnd
->SentMessagesListHead
);
173 TRACE("Sending WM_SYNCPAINT\n");
174 // This message has no parameters. But it does! Pass Flags along.
175 co_IntSendMessageNoWait(UserHMGetHandle(Wnd
), WM_SYNCPAINT
, Flags
, 0);
176 Wnd
->state
|= WNDS_SYNCPAINTPENDING
;
180 // Send to all the children if this is the desktop window.
181 if ( Wnd
== UserGetDesktopWindow() )
183 if ( Flags
& RDW_ALLCHILDREN
||
184 ( !(Flags
& RDW_NOCHILDREN
) && Wnd
->style
& WS_CLIPCHILDREN
))
186 PWND spwndChild
= Wnd
->spwndChild
;
189 if ( spwndChild
->style
& WS_CHILD
&&
190 spwndChild
->head
.pti
!= ptiCur
)
192 spwndChild
= spwndChild
->spwndNext
;
195 IntSendSyncPaint( spwndChild
, Flags
);
196 spwndChild
= spwndChild
->spwndNext
;
203 * @name IntCalcWindowRgn
205 * Get a window or client region.
209 IntCalcWindowRgn(PWND Wnd
, BOOL Client
)
215 hRgnWindow
= NtGdiCreateRectRgn(
219 Wnd
->rcClient
.bottom
);
223 hRgnWindow
= NtGdiCreateRectRgn(
227 Wnd
->rcWindow
.bottom
);
230 if (Wnd
->hrgnClip
!= NULL
&& !(Wnd
->style
& WS_MINIMIZE
))
232 NtGdiOffsetRgn(hRgnWindow
,
235 NtGdiCombineRgn(hRgnWindow
, hRgnWindow
, Wnd
->hrgnClip
, RGN_AND
);
236 NtGdiOffsetRgn(hRgnWindow
,
245 * @name IntGetNCUpdateRgn
247 * Get non-client update region of a window and optionally validate it.
250 * Pointer to window to get the NC update region from.
252 * Set to TRUE to force validating the NC update region.
255 * Handle to NC update region. The caller is responsible for deleting
260 IntGetNCUpdateRgn(PWND Window
, BOOL Validate
)
264 UINT RgnType
, NcType
;
267 if (Window
->hrgnUpdate
!= NULL
&&
268 Window
->hrgnUpdate
!= HRGN_WINDOW
)
270 hRgnNonClient
= IntCalcWindowRgn(Window
, FALSE
);
273 * If region creation fails it's safe to fallback to whole
276 if (hRgnNonClient
== NULL
)
281 hRgnWindow
= IntCalcWindowRgn(Window
, TRUE
);
282 if (hRgnWindow
== NULL
)
284 GreDeleteObject(hRgnNonClient
);
288 NcType
= IntGdiGetRgnBox(hRgnNonClient
, &update
);
290 RgnType
= NtGdiCombineRgn(hRgnNonClient
, hRgnNonClient
, hRgnWindow
, RGN_DIFF
);
292 if (RgnType
== ERROR
)
294 GreDeleteObject(hRgnWindow
);
295 GreDeleteObject(hRgnNonClient
);
298 else if (RgnType
== NULLREGION
)
300 GreDeleteObject(hRgnWindow
);
301 GreDeleteObject(hRgnNonClient
);
302 Window
->state
&= ~WNDS_UPDATEDIRTY
;
307 * Remove the nonclient region from the standard update region if
308 * we were asked for it.
313 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
, hRgnWindow
, RGN_AND
) == NULLREGION
)
315 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
316 GreDeleteObject(Window
->hrgnUpdate
);
317 Window
->state
&= ~WNDS_UPDATEDIRTY
;
318 Window
->hrgnUpdate
= NULL
;
319 if (!(Window
->state
& WNDS_INTERNALPAINT
))
320 MsqDecPaintCountQueue(Window
->head
.pti
);
324 /* check if update rgn contains complete nonclient area */
325 if (NcType
== SIMPLEREGION
)
328 IntGetWindowRect( Window
, &window
);
330 if (IntEqualRect( &window
, &update
))
332 GreDeleteObject(hRgnNonClient
);
333 hRgnNonClient
= HRGN_WINDOW
;
337 GreDeleteObject(hRgnWindow
);
339 return hRgnNonClient
;
343 return Window
->hrgnUpdate
;
348 IntSendNCPaint(PWND pWnd
, HRGN hRgn
)
350 pWnd
->state
&= ~WNDS_SENDNCPAINT
;
352 if ( pWnd
== GetW32ThreadInfo()->MessageQueue
->spwndActive
&&
353 !(pWnd
->state
& WNDS_ACTIVEFRAME
))
355 pWnd
->state
|= WNDS_ACTIVEFRAME
;
356 pWnd
->state
&= ~WNDS_NONCPAINT
;
360 if (pWnd
->state2
& WNDS2_FORCEFULLNCPAINTCLIPRGN
)
362 pWnd
->state2
&= ~WNDS2_FORCEFULLNCPAINTCLIPRGN
;
366 if (hRgn
) co_IntSendMessage(UserHMGetHandle(pWnd
), WM_NCPAINT
, (WPARAM
)hRgn
, 0);
370 IntSendChildNCPaint(PWND pWnd
)
372 pWnd
= pWnd
->spwndChild
;
375 if (pWnd
->hrgnUpdate
== NULL
&& pWnd
->state
& WNDS_SENDNCPAINT
)
377 USER_REFERENCE_ENTRY Ref
;
378 UserRefObjectCo(pWnd
, &Ref
);
379 IntSendNCPaint(pWnd
, HRGN_WINDOW
);
380 UserDerefObjectCo(pWnd
);
382 pWnd
= pWnd
->spwndNext
;
389 * Internal function used by IntRedrawWindow.
393 co_IntPaintWindows(PWND Wnd
, ULONG Flags
, BOOL Recurse
)
396 HWND hWnd
= Wnd
->head
.h
;
397 HRGN TempRegion
= NULL
;
399 Wnd
->state
&= ~WNDS_PAINTNOTPROCESSED
;
401 if (Wnd
->state
& WNDS_SENDNCPAINT
||
402 Wnd
->state
& WNDS_SENDERASEBACKGROUND
)
404 if (!(Wnd
->style
& WS_VISIBLE
))
406 Wnd
->state
&= ~(WNDS_SENDNCPAINT
|WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
411 if (Wnd
->hrgnUpdate
== NULL
)
413 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
416 if (Wnd
->head
.pti
== PsGetCurrentThreadWin32Thread())
418 if (Wnd
->state
& WNDS_SENDNCPAINT
)
420 TempRegion
= IntGetNCUpdateRgn(Wnd
, TRUE
);
422 IntSendNCPaint(Wnd
, TempRegion
);
424 if (TempRegion
> HRGN_WINDOW
&& GreIsHandleValid(TempRegion
))
426 /* NOTE: The region can already be deleted! */
427 GreDeleteObject(TempRegion
);
431 if (Wnd
->state
& WNDS_SENDERASEBACKGROUND
)
433 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
436 hDC
= UserGetDCEx( Wnd
,
438 DCX_CACHE
|DCX_USESTYLE
|DCX_INTERSECTRGN
|DCX_KEEPCLIPRGN
);
440 if (Wnd
->head
.pti
->ppi
!= pti
->ppi
)
442 ERR("Sending DC to another Process!!!\n");
445 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
446 // Kill the loop, so Clear before we send.
447 if (!co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
449 Wnd
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
451 UserReleaseDC(Wnd
, hDC
, FALSE
);
460 * Check that the window is still valid at this point
462 if (!IntIsWindow(hWnd
))
468 * Paint child windows.
471 if (!(Flags
& RDW_NOCHILDREN
) &&
472 !(Wnd
->style
& WS_MINIMIZE
) &&
473 ( Flags
& RDW_ALLCHILDREN
||
474 (Flags
& RDW_CLIPCHILDREN
&& Wnd
->style
& WS_CLIPCHILDREN
) ) )
477 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
479 if ((List
= IntWinListChildren(Wnd
)))
481 for (phWnd
= List
; *phWnd
; ++phWnd
)
483 if ((Wnd
= UserGetWindowObject(*phWnd
)) == NULL
)
486 if (Wnd
->head
.pti
!= pti
&& Wnd
->style
& WS_CHILD
)
489 if (Wnd
->style
& WS_VISIBLE
)
491 USER_REFERENCE_ENTRY Ref
;
492 UserRefObjectCo(Wnd
, &Ref
);
493 co_IntPaintWindows(Wnd
, Flags
, TRUE
);
494 UserDerefObjectCo(Wnd
);
497 ExFreePoolWithTag(List
, USERTAG_WINDOWLIST
);
505 * Internal function used by IntRedrawWindow, simplecall.
509 co_IntUpdateWindows(PWND Wnd
, ULONG Flags
, BOOL Recurse
)
511 HWND hWnd
= Wnd
->head
.h
;
513 if ((Wnd
->hrgnUpdate
!= NULL
|| Wnd
->state
& WNDS_INTERNALPAINT
))
517 if (!IntValidateParents(Wnd
, Recurse
))
523 if (Wnd
->state
& WNDS_INTERNALPAINT
)
525 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
527 if (Wnd
->hrgnUpdate
== NULL
)
528 MsqDecPaintCountQueue(Wnd
->head
.pti
);
531 Wnd
->state
|= WNDS_PAINTNOTPROCESSED
;
532 Wnd
->state
&= ~WNDS_UPDATEDIRTY
;
534 Wnd
->state2
|= WNDS2_WMPAINTSENT
;
535 co_IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
537 if (Wnd
->state
& WNDS_PAINTNOTPROCESSED
)
539 USER_REFERENCE_ENTRY Ref
;
540 UserRefObjectCo(Wnd
, &Ref
);
541 co_IntPaintWindows(Wnd
, RDW_NOCHILDREN
, FALSE
);
542 UserDerefObjectCo(Wnd
);
546 // Force flags as a toggle. Fixes msg:test_paint_messages:WmChildPaintNc.
547 Flags
= (Flags
& RDW_NOCHILDREN
) ? RDW_NOCHILDREN
: RDW_ALLCHILDREN
; // All children is the default.
550 * Update child windows.
553 if (!(Flags
& RDW_NOCHILDREN
) &&
554 Flags
& RDW_ALLCHILDREN
&&
555 Wnd
!= UserGetDesktopWindow() )
559 for (Child
= Wnd
->spwndChild
; Child
; Child
= Child
->spwndNext
)
561 /* transparent window, check for non-transparent sibling to paint first, then skip it */
562 if ( Child
->ExStyle
& WS_EX_TRANSPARENT
&&
563 ( Child
->hrgnUpdate
!= NULL
|| Child
->state
& WNDS_INTERNALPAINT
) )
565 PWND Next
= Child
->spwndNext
;
568 if ( Next
->hrgnUpdate
!= NULL
|| Next
->state
& WNDS_INTERNALPAINT
) break;
570 Next
= Next
->spwndNext
;
576 if ( Child
->style
& WS_VISIBLE
)
578 USER_REFERENCE_ENTRY Ref
;
579 UserRefObjectCo(Child
, &Ref
);
580 co_IntUpdateWindows(Child
, Flags
, TRUE
);
581 UserDerefObjectCo(Child
);
588 UserUpdateWindows(PWND pWnd
, ULONG Flags
)
590 // If transparent and any sibling windows below needs to be painted, leave.
591 if (pWnd
->ExStyle
& WS_EX_TRANSPARENT
)
593 PWND Next
= pWnd
->spwndNext
;
597 if ( Next
->head
.pti
== pWnd
->head
.pti
&&
598 ( Next
->hrgnUpdate
!= NULL
|| Next
->state
& WNDS_INTERNALPAINT
) )
603 Next
= Next
->spwndNext
;
606 co_IntUpdateWindows(pWnd
, Flags
, FALSE
);
610 UserSyncAndPaintWindows(PWND pWnd
, ULONG Flags
)
613 // Find parent, if it needs to be painted, leave.
616 if ((Parent
= Parent
->spwndParent
) == NULL
) break;
617 if ( Parent
->style
& WS_CLIPCHILDREN
) break;
618 if ( Parent
->hrgnUpdate
!= NULL
|| Parent
->state
& WNDS_INTERNALPAINT
) return;
621 IntSendSyncPaint(pWnd
, Flags
);
622 co_IntPaintWindows(pWnd
, Flags
, FALSE
);
626 * IntInvalidateWindows
628 * Internal function used by IntRedrawWindow, UserRedrawDesktop,
629 * co_WinPosSetWindowPos, co_UserRedrawWindow.
632 IntInvalidateWindows(PWND Wnd
, PREGION Rgn
, ULONG Flags
)
634 INT RgnType
= NULLREGION
;
635 BOOL HadPaintMessage
;
637 TRACE("IntInvalidateWindows start Rgn %p\n",Rgn
);
639 if ( Rgn
> PRGN_WINDOW
)
642 * If the nonclient is not to be redrawn, clip the region to the client
645 if ((Flags
& RDW_INVALIDATE
) != 0 && (Flags
& RDW_FRAME
) == 0)
649 RgnClient
= IntSysCreateRectpRgnIndirect(&Wnd
->rcClient
);
652 RgnType
= IntGdiCombineRgn(Rgn
, Rgn
, RgnClient
, RGN_AND
);
653 REGION_Delete(RgnClient
);
658 * Clip the given region with window rectangle (or region)
661 if (!Wnd
->hrgnClip
|| (Wnd
->style
& WS_MINIMIZE
))
663 PREGION RgnWindow
= IntSysCreateRectpRgnIndirect(&Wnd
->rcWindow
);
666 RgnType
= IntGdiCombineRgn(Rgn
, Rgn
, RgnWindow
, RGN_AND
);
667 REGION_Delete(RgnWindow
);
672 PREGION RgnClip
= REGION_LockRgn(Wnd
->hrgnClip
);
675 REGION_bOffsetRgn(Rgn
,
678 RgnType
= IntGdiCombineRgn(Rgn
, Rgn
, RgnClip
, RGN_AND
);
679 REGION_bOffsetRgn(Rgn
,
682 REGION_UnlockRgn(RgnClip
);
688 RgnType
= NULLREGION
;
692 * Save current state of pending updates
695 HadPaintMessage
= IntIsWindowDirty(Wnd
);
698 * Update the region and flags
701 // The following flags are used to invalidate the window.
702 if (Flags
& (RDW_INVALIDATE
|RDW_INTERNALPAINT
|RDW_ERASE
|RDW_FRAME
))
704 if (Flags
& RDW_INTERNALPAINT
)
706 Wnd
->state
|= WNDS_INTERNALPAINT
;
709 if (Flags
& RDW_INVALIDATE
)
713 Wnd
->state
&= ~WNDS_NONCPAINT
;
715 /* If not the same thread set it dirty. */
716 if (Wnd
->head
.pti
!= PsGetCurrentThreadWin32Thread())
718 Wnd
->state
|= WNDS_UPDATEDIRTY
;
719 if (Wnd
->state2
& WNDS2_WMPAINTSENT
)
720 Wnd
->state2
|= WNDS2_ENDPAINTINVALIDATE
;
723 if (Flags
& RDW_FRAME
)
724 Wnd
->state
|= WNDS_SENDNCPAINT
;
726 if (Flags
& RDW_ERASE
)
727 Wnd
->state
|= WNDS_SENDERASEBACKGROUND
;
729 if (RgnType
!= NULLREGION
&& Rgn
> PRGN_WINDOW
)
731 if (Wnd
->hrgnUpdate
== NULL
)
733 Wnd
->hrgnUpdate
= NtGdiCreateRectRgn(0, 0, 0, 0);
734 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_PUBLIC
);
737 if (Wnd
->hrgnUpdate
!= HRGN_WINDOW
)
739 RgnUpdate
= REGION_LockRgn(Wnd
->hrgnUpdate
);
742 RgnType
= IntGdiCombineRgn(RgnUpdate
, RgnUpdate
, Rgn
, RGN_OR
);
743 REGION_UnlockRgn(RgnUpdate
);
744 if (RgnType
== NULLREGION
)
746 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
747 GreDeleteObject(Wnd
->hrgnUpdate
);
748 Wnd
->hrgnUpdate
= NULL
;
754 Flags
|= RDW_ERASE
|RDW_FRAME
; // For children.
758 if (!HadPaintMessage
&& IntIsWindowDirty(Wnd
))
760 MsqIncPaintCountQueue(Wnd
->head
.pti
);
763 } // The following flags are used to validate the window.
764 else if (Flags
& (RDW_VALIDATE
|RDW_NOINTERNALPAINT
|RDW_NOERASE
|RDW_NOFRAME
))
766 if (Wnd
->state
& WNDS_UPDATEDIRTY
&& !(Flags
& RDW_NOUPDATEDIRTY
))
769 if (Flags
& RDW_NOINTERNALPAINT
)
771 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
774 if (Flags
& RDW_VALIDATE
)
776 if (Flags
& RDW_NOFRAME
)
777 Wnd
->state
&= ~WNDS_SENDNCPAINT
;
779 if (Flags
& RDW_NOERASE
)
780 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
782 if (Wnd
->hrgnUpdate
> HRGN_WINDOW
&& RgnType
!= NULLREGION
&& Rgn
> PRGN_WINDOW
)
784 PREGION RgnUpdate
= REGION_LockRgn(Wnd
->hrgnUpdate
);
788 RgnType
= IntGdiCombineRgn(RgnUpdate
, RgnUpdate
, Rgn
, RGN_DIFF
);
789 REGION_UnlockRgn(RgnUpdate
);
791 if (RgnType
== NULLREGION
)
793 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
794 GreDeleteObject(Wnd
->hrgnUpdate
);
795 Wnd
->hrgnUpdate
= NULL
;
799 // If update is null, do not erase.
800 if (Wnd
->hrgnUpdate
== NULL
)
802 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
806 if (HadPaintMessage
&& !IntIsWindowDirty(Wnd
))
808 MsqDecPaintCountQueue(Wnd
->head
.pti
);
813 * Process children if needed
816 if (!(Flags
& RDW_NOCHILDREN
) &&
817 !(Wnd
->style
& WS_MINIMIZE
) &&
818 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)))
822 for (Child
= Wnd
->spwndChild
; Child
; Child
= Child
->spwndNext
)
824 if (Child
->style
& WS_VISIBLE
)
827 * Recursive call to update children hrgnUpdate
829 PREGION RgnTemp
= IntSysCreateRectpRgn(0, 0, 0, 0);
832 if (Rgn
> PRGN_WINDOW
) IntGdiCombineRgn(RgnTemp
, Rgn
, 0, RGN_COPY
);
833 IntInvalidateWindows(Child
, ((Rgn
> PRGN_WINDOW
)?RgnTemp
:Rgn
), Flags
);
834 REGION_Delete(RgnTemp
);
839 TRACE("IntInvalidateWindows exit\n");
843 * IntIsWindowDrawable
846 * Window is drawable when it is visible and all parents are not
851 IntIsWindowDrawable(PWND Wnd
)
855 for (WndObject
= Wnd
; WndObject
!= NULL
; WndObject
= WndObject
->spwndParent
)
857 if ( WndObject
->state2
& WNDS2_INDESTROY
||
858 WndObject
->state
& WNDS_DESTROYED
||
860 !(WndObject
->style
& WS_VISIBLE
) ||
861 ((WndObject
->style
& WS_MINIMIZE
) && (WndObject
!= Wnd
)))
873 * Internal version of NtUserRedrawWindow that takes WND as
880 const RECTL
* UpdateRect
,
884 PREGION TmpRgn
= NULL
;
885 TRACE("co_UserRedrawWindow start Rgn %p\n",UpdateRgn
);
889 * Validation of passed parameters.
892 if (!IntIsWindowDrawable(Window
))
894 return TRUE
; // Just do nothing!!!
899 Window
= UserGetDesktopWindow();
904 * Transform the parameters UpdateRgn and UpdateRect into
905 * a region hRgn specified in screen coordinates.
908 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
)) // Both are OKAY!
910 /* We can't hold lock on GDI objects while doing roundtrips to user mode,
911 * so use a copy instead */
914 TmpRgn
= IntSysCreateRectpRgn(0, 0, 0, 0);
916 if (UpdateRgn
> PRGN_WINDOW
)
918 IntGdiCombineRgn(TmpRgn
, UpdateRgn
, NULL
, RGN_COPY
);
921 if (Window
!= UserGetDesktopWindow())
923 REGION_bOffsetRgn(TmpRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
928 if (UpdateRect
!= NULL
)
930 if (Window
== UserGetDesktopWindow())
932 TmpRgn
= IntSysCreateRectpRgnIndirect(UpdateRect
);
936 TmpRgn
= IntSysCreateRectpRgn(Window
->rcClient
.left
+ UpdateRect
->left
,
937 Window
->rcClient
.top
+ UpdateRect
->top
,
938 Window
->rcClient
.left
+ UpdateRect
->right
,
939 Window
->rcClient
.top
+ UpdateRect
->bottom
);
944 if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
945 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
947 if (!RECTL_bIsEmptyRect(&Window
->rcWindow
))
948 TmpRgn
= IntSysCreateRectpRgnIndirect(&Window
->rcWindow
);
952 if (!RECTL_bIsEmptyRect(&Window
->rcClient
))
953 TmpRgn
= IntSysCreateRectpRgnIndirect(&Window
->rcClient
);
959 /* Fixes test RDW_INTERNALPAINT behavior */
962 TmpRgn
= PRGN_WINDOW
; // Need a region so the bits can be set!!!
967 * Adjust the window update region depending on hRgn and flags.
970 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
) &&
973 IntInvalidateWindows(Window
, TmpRgn
, Flags
);
978 * Repaint and erase windows if needed.
981 if (Flags
& RDW_UPDATENOW
)
983 UserUpdateWindows(Window
, Flags
);
985 else if (Flags
& RDW_ERASENOW
)
987 if ((Flags
& (RDW_NOCHILDREN
|RDW_ALLCHILDREN
)) == 0)
988 Flags
|= RDW_CLIPCHILDREN
;
990 UserSyncAndPaintWindows(Window
, Flags
);
998 if (TmpRgn
> PRGN_WINDOW
)
1000 REGION_Delete(TmpRgn
);
1002 TRACE("co_UserRedrawWindow exit\n");
1008 IntIsWindowDirty(PWND Wnd
)
1010 return ( Wnd
->style
& WS_VISIBLE
&&
1011 ( Wnd
->hrgnUpdate
!= NULL
||
1012 Wnd
->state
& WNDS_INTERNALPAINT
) );
1016 Conditions to paint any window:
1018 1. Update region is not null.
1019 2. Internal paint flag is set.
1020 3. Paint count is not zero.
1024 IntFindWindowToRepaint(PWND Window
, PTHREADINFO Thread
)
1029 for (; Window
!= NULL
; Window
= Window
->spwndNext
)
1031 if (IntWndBelongsToThread(Window
, Thread
))
1033 if (IntIsWindowDirty(Window
))
1035 /* Make sure all non-transparent siblings are already drawn. */
1036 if (Window
->ExStyle
& WS_EX_TRANSPARENT
)
1038 for (TempWindow
= Window
->spwndNext
; TempWindow
!= NULL
;
1039 TempWindow
= TempWindow
->spwndNext
)
1041 if (!(TempWindow
->ExStyle
& WS_EX_TRANSPARENT
) &&
1042 IntWndBelongsToThread(TempWindow
, Thread
) &&
1043 IntIsWindowDirty(TempWindow
))
1052 /* find a child of the specified window that needs repainting */
1053 if (Window
->spwndChild
)
1055 hChild
= IntFindWindowToRepaint(Window
->spwndChild
, Thread
);
1072 PWND PaintWnd
, StartWnd
;
1074 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
1075 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
1078 if (Thread
->TIF_flags
& TIF_SYSTEMTHREAD
)
1080 ERR("WM_PAINT is in a System Thread!\n");
1083 StartWnd
= UserGetDesktopWindow();
1084 PaintWnd
= IntFindWindowToRepaint(StartWnd
, Thread
);
1086 Message
->hwnd
= PaintWnd
? UserHMGetHandle(PaintWnd
) : NULL
;
1088 if (Message
->hwnd
== NULL
&& Thread
->cPaintsReady
)
1090 // Find note in window.c:"PAINTING BUG".
1091 ERR("WARNING SOMETHING HAS GONE WRONG: Thread marked as containing dirty windows, but no dirty windows found! Counts %u\n",Thread
->cPaintsReady
);
1092 /* Hack to stop spamming the debug log ! */
1093 Thread
->cPaintsReady
= 0;
1097 if (Message
->hwnd
== NULL
)
1100 if (!(Window
== NULL
||
1101 PaintWnd
== Window
||
1102 IntIsChildWindow(Window
, PaintWnd
))) /* check that it is a child of the specified parent */
1105 if (PaintWnd
->state
& WNDS_INTERNALPAINT
)
1107 PaintWnd
->state
&= ~WNDS_INTERNALPAINT
;
1108 if (!PaintWnd
->hrgnUpdate
)
1109 MsqDecPaintCountQueue(Thread
);
1111 PaintWnd
->state2
&= ~WNDS2_STARTPAINT
;
1112 PaintWnd
->state
&= ~WNDS_UPDATEDIRTY
;
1115 while( Window
&& Window
!= UserGetDesktopWindow())
1117 // Role back and check for clip children, do not set if any.
1118 if (Window
->spwndParent
&& !(Window
->spwndParent
->style
& WS_CLIPCHILDREN
))
1120 PaintWnd
->state2
|= WNDS2_WMPAINTSENT
;
1122 Window
= Window
->spwndParent
;
1125 Message
->wParam
= Message
->lParam
= 0;
1126 Message
->message
= WM_PAINT
;
1138 INT cx
, cy
, xSrc
, ySrc
;
1140 if ( nFlags
& PW_CLIENTONLY
)
1142 cx
= pwnd
->rcClient
.right
- pwnd
->rcClient
.left
;
1143 cy
= pwnd
->rcClient
.bottom
- pwnd
->rcClient
.top
;
1144 xSrc
= pwnd
->rcClient
.left
- pwnd
->rcWindow
.left
;
1145 ySrc
= pwnd
->rcClient
.top
- pwnd
->rcWindow
.top
;
1149 cx
= pwnd
->rcWindow
.right
- pwnd
->rcWindow
.left
;
1150 cy
= pwnd
->rcWindow
.bottom
- pwnd
->rcWindow
.top
;
1155 // TODO: Setup Redirection for Print.
1158 /* Update the window just incase. */
1159 co_IntUpdateWindows( pwnd
, RDW_ALLCHILDREN
, FALSE
);
1161 hdcSrc
= UserGetDCEx( pwnd
, NULL
, DCX_CACHE
|DCX_WINDOW
);
1162 /* Print window to printer context. */
1163 NtGdiBitBlt( hdcBlt
,
1175 UserReleaseDC( pwnd
, hdcSrc
, FALSE
);
1177 // TODO: Release Redirection from Print.
1184 IntFlashWindowEx(PWND pWnd
, PFLASHWINFO pfwi
)
1187 UINT uCount
= pfwi
->uCount
;
1188 BOOL Activate
= FALSE
, Ret
= FALSE
;
1192 FlashState
= (DWORD
)UserGetProp(pWnd
, AtomFlashWndState
);
1194 if (FlashState
== FLASHW_FINISHED
)
1196 // Cycle has finished, kill timer and set this to Stop.
1197 FlashState
|= FLASHW_KILLSYSTIMER
;
1198 pfwi
->dwFlags
= FLASHW_STOP
;
1204 if (pfwi
->dwFlags
== FLASHW_SYSTIMER
)
1206 // Called from system timer, restore flags, counts and state.
1207 pfwi
->dwFlags
= LOWORD(FlashState
);
1208 uCount
= HIWORD(FlashState
);
1209 FlashState
= MAKELONG(LOWORD(FlashState
),0);
1213 // Clean out the trash! Fix SeaMonkey crash after restart.
1218 if (FlashState
== 0)
1219 { // First time in cycle, setup flash state.
1220 if ( pWnd
->state
& WNDS_ACTIVEFRAME
||
1221 (pfwi
->dwFlags
& FLASHW_CAPTION
&& pWnd
->style
& (WS_BORDER
|WS_DLGFRAME
)))
1223 FlashState
= FLASHW_STARTED
|FLASHW_ACTIVE
;
1227 // Set previous window state.
1228 Ret
= !!(FlashState
& FLASHW_ACTIVE
);
1230 if ( pfwi
->dwFlags
& FLASHW_TIMERNOFG
&&
1231 gpqForeground
== pWnd
->head
.pti
->MessageQueue
)
1233 // Flashing until foreground, set this to Stop.
1234 pfwi
->dwFlags
= FLASHW_STOP
;
1238 // Toggle activate flag.
1239 if ( pfwi
->dwFlags
== FLASHW_STOP
)
1241 if (gpqForeground
&& gpqForeground
->spwndActive
== pWnd
)
1248 Activate
= (FlashState
& FLASHW_ACTIVE
) == 0;
1251 if ( pfwi
->dwFlags
== FLASHW_STOP
|| pfwi
->dwFlags
& FLASHW_CAPTION
)
1253 co_IntSendMessage(UserHMGetHandle(pWnd
), WM_NCACTIVATE
, Activate
, 0);
1256 // FIXME: Check for a Stop Sign here.
1257 if ( pfwi
->dwFlags
& FLASHW_TRAY
)
1259 // Need some shell work here too.
1260 TRACE("FIXME: Flash window no Tray support!\n");
1263 if ( pfwi
->dwFlags
== FLASHW_STOP
)
1265 if (FlashState
& FLASHW_KILLSYSTIMER
)
1267 IntKillTimer(pWnd
, ID_EVENT_SYSTIMER_FLASHWIN
, TRUE
);
1270 IntRemoveProp(pWnd
, AtomFlashWndState
);
1273 { // Have a count and started, set timer.
1276 FlashState
|= FLASHW_COUNT
;
1278 if (!(Activate
^ !!(FlashState
& FLASHW_STARTED
)))
1281 if (!(FlashState
& FLASHW_KILLSYSTIMER
))
1282 pfwi
->dwFlags
|= FLASHW_TIMER
;
1285 if (pfwi
->dwFlags
& FLASHW_TIMER
)
1287 FlashState
|= FLASHW_KILLSYSTIMER
;
1290 ID_EVENT_SYSTIMER_FLASHWIN
,
1291 pfwi
->dwTimeout
? pfwi
->dwTimeout
: gpsi
->dtCaretBlink
,
1296 if (FlashState
& FLASHW_COUNT
&& uCount
== 0)
1298 // Keep spinning? Nothing else to do.
1299 FlashState
= FLASHW_FINISHED
;
1303 // Save state and flags so this can be restored next time through.
1304 FlashState
^= (FlashState
^ -!!(Activate
)) & FLASHW_ACTIVE
;
1305 FlashState
^= (FlashState
^ pfwi
->dwFlags
) & (FLASHW_MASK
& ~FLASHW_TIMER
);
1307 FlashState
= MAKELONG(LOWORD(FlashState
),uCount
);
1308 IntSetProp(pWnd
, AtomFlashWndState
, (HANDLE
) FlashState
);
1314 IntBeginPaint(PWND Window
, PPAINTSTRUCT Ps
)
1320 co_UserHideCaret(Window
);
1322 Window
->state2
|= WNDS2_STARTPAINT
;
1323 Window
->state
&= ~WNDS_PAINTNOTPROCESSED
;
1325 if (Window
->state
& WNDS_SENDNCPAINT
)
1328 // Application can keep update dirty.
1331 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1332 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
1333 IntSendNCPaint(Window
, hRgn
);
1334 if (hRgn
> HRGN_WINDOW
&& GreIsHandleValid(hRgn
))
1336 /* NOTE: The region can already be deleted! */
1337 GreDeleteObject(hRgn
);
1340 while(Window
->state
& WNDS_UPDATEDIRTY
);
1344 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1347 RtlZeroMemory(Ps
, sizeof(PAINTSTRUCT
));
1349 if (Window
->state2
& WNDS2_ENDPAINTINVALIDATE
)
1351 ERR("BP: Another thread invalidated this window\n");
1354 Ps
->hdc
= UserGetDCEx( Window
,
1356 DCX_INTERSECTRGN
| DCX_USESTYLE
);
1362 // If set, always clear flags out due to the conditions later on for sending the message.
1363 if (Window
->state
& WNDS_SENDERASEBACKGROUND
)
1365 Window
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
1369 if (Window
->hrgnUpdate
!= NULL
)
1371 MsqDecPaintCountQueue(Window
->head
.pti
);
1372 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
1373 /* The region is part of the dc now and belongs to the process! */
1374 Window
->hrgnUpdate
= NULL
;
1378 if (Window
->state
& WNDS_INTERNALPAINT
)
1379 MsqDecPaintCountQueue(Window
->head
.pti
);
1382 type
= GdiGetClipBox(Ps
->hdc
, &Ps
->rcPaint
);
1384 IntGetClientRect(Window
, &Rect
);
1386 Window
->state
&= ~WNDS_INTERNALPAINT
;
1388 if ( Erase
&& // Set to erase,
1389 type
!= NULLREGION
&& // don't erase if the clip box is empty,
1390 (!(Window
->pcls
->style
& CS_PARENTDC
) || // not parent dc or
1391 RECTL_bIntersectRect( &Rect
, &Rect
, &Ps
->rcPaint
) ) ) // intersecting.
1393 Ps
->fErase
= !co_IntSendMessage(UserHMGetHandle(Window
), WM_ERASEBKGND
, (WPARAM
)Ps
->hdc
, 0);
1396 Window
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
1404 IntSendChildNCPaint(Window
);
1410 IntEndPaint(PWND Wnd
, PPAINTSTRUCT Ps
)
1416 UserReleaseDC(Wnd
, hdc
, TRUE
);
1418 if (Wnd
->state2
& WNDS2_ENDPAINTINVALIDATE
)
1420 ERR("EP: Another thread invalidated this window\n");
1421 Wnd
->state2
&= ~WNDS2_ENDPAINTINVALIDATE
;
1424 Wnd
->state2
&= ~(WNDS2_WMPAINTSENT
|WNDS2_STARTPAINT
);
1426 co_UserShowCaret(Wnd
);
1431 /* PUBLIC FUNCTIONS ***********************************************************/
1441 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
1447 USER_REFERENCE_ENTRY Ref
;
1448 DECLARE_RETURN(HDC
);
1450 TRACE("Enter NtUserBeginPaint\n");
1451 UserEnterExclusive();
1453 if (!(Window
= UserGetWindowObject(hWnd
)))
1458 UserRefObjectCo(Window
, &Ref
);
1460 hDC
= IntBeginPaint(Window
, &Ps
);
1462 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
1463 if (! NT_SUCCESS(Status
))
1465 SetLastNtError(Status
);
1472 if (Window
) UserDerefObjectCo(Window
);
1474 TRACE("Leave NtUserBeginPaint, ret=%p\n",_ret_
);
1488 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* pUnsafePs
)
1490 NTSTATUS Status
= STATUS_SUCCESS
;
1493 USER_REFERENCE_ENTRY Ref
;
1494 DECLARE_RETURN(BOOL
);
1496 TRACE("Enter NtUserEndPaint\n");
1497 UserEnterExclusive();
1499 if (!(Window
= UserGetWindowObject(hWnd
)))
1504 UserRefObjectCo(Window
, &Ref
); // Here for the exception.
1508 ProbeForRead(pUnsafePs
, sizeof(*pUnsafePs
), 1);
1509 RtlCopyMemory(&Ps
, pUnsafePs
, sizeof(PAINTSTRUCT
));
1511 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1513 Status
= _SEH2_GetExceptionCode();
1516 if (!NT_SUCCESS(Status
))
1521 RETURN(IntEndPaint(Window
, &Ps
));
1524 if (Window
) UserDerefObjectCo(Window
);
1526 TRACE("Leave NtUserEndPaint, ret=%i\n",_ret_
);
1535 NtUserFlashWindowEx(IN PFLASHWINFO pfwi
)
1538 FLASHWINFO finfo
= {0};
1541 UserEnterExclusive();
1545 ProbeForRead(pfwi
, sizeof(FLASHWINFO
), sizeof(ULONG
));
1546 RtlCopyMemory(&finfo
, pfwi
, sizeof(FLASHWINFO
));
1548 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1550 SetLastNtError(_SEH2_GetExceptionCode());
1555 if (!Ret
) goto Exit
;
1557 if (!( pWnd
= (PWND
)UserGetObject(gHandleTable
, finfo
.hwnd
, TYPE_WINDOW
)) ||
1558 finfo
.cbSize
!= sizeof(FLASHWINFO
) ||
1559 finfo
.dwFlags
& ~(FLASHW_ALL
|FLASHW_TIMER
|FLASHW_TIMERNOFG
) )
1561 EngSetLastError(ERROR_INVALID_PARAMETER
);
1566 Ret
= IntFlashWindowEx(pWnd
, &finfo
);
1574 GetUpdateRgn, this fails the same as the old one.
1577 co_UserGetUpdateRgn(PWND Window
, HRGN hRgn
, BOOL bErase
)
1583 ASSERT_REFS_CO(Window
);
1587 USER_REFERENCE_ENTRY Ref
;
1588 UserRefObjectCo(Window
, &Ref
);
1589 co_IntPaintWindows(Window
, RDW_NOCHILDREN
, FALSE
);
1590 UserDerefObjectCo(Window
);
1593 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1595 if (Window
->hrgnUpdate
== NULL
)
1597 NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0);
1601 Rect
= Window
->rcClient
;
1602 Type
= IntIntersectWithParents(Window
, &Rect
);
1604 if (Window
->hrgnUpdate
== HRGN_WINDOW
)
1607 ERR("GURn: Caller is passing Window Region 1\n");
1610 NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0);
1614 RegionType
= SIMPLEREGION
;
1616 if (Window
!= UserGetDesktopWindow()) // Window->fnid == FNID_DESKTOP
1618 RECTL_vOffsetRect(&Rect
,
1619 -Window
->rcClient
.left
,
1620 -Window
->rcClient
.top
);
1622 GreSetRectRgnIndirect(hRgn
, &Rect
);
1626 HRGN hrgnTemp
= GreCreateRectRgnIndirect(&Rect
);
1628 RegionType
= NtGdiCombineRgn(hRgn
, hrgnTemp
, Window
->hrgnUpdate
, RGN_AND
);
1630 if (RegionType
== ERROR
|| RegionType
== NULLREGION
)
1632 if (hrgnTemp
) GreDeleteObject(hrgnTemp
);
1633 NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0);
1637 if (Window
!= UserGetDesktopWindow()) // Window->fnid == FNID_DESKTOP
1639 NtGdiOffsetRgn(hRgn
,
1640 -Window
->rcClient
.left
,
1641 -Window
->rcClient
.top
);
1643 if (hrgnTemp
) GreDeleteObject(hrgnTemp
);
1649 co_UserGetUpdateRect(PWND Window
, PRECT pRect
, BOOL bErase
)
1656 USER_REFERENCE_ENTRY Ref
;
1657 UserRefObjectCo(Window
, &Ref
);
1658 co_IntPaintWindows(Window
, RDW_NOCHILDREN
, FALSE
);
1659 UserDerefObjectCo(Window
);
1662 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1664 if (Window
->hrgnUpdate
== NULL
)
1666 pRect
->left
= pRect
->top
= pRect
->right
= pRect
->bottom
= 0;
1671 /* Get the update region bounding box. */
1672 if (Window
->hrgnUpdate
== HRGN_WINDOW
)
1674 *pRect
= Window
->rcClient
;
1675 ERR("GURt: Caller is retrieving Window Region 1\n");
1679 RegionType
= IntGdiGetRgnBox(Window
->hrgnUpdate
, pRect
);
1681 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
1682 RECTL_bIntersectRect(pRect
, pRect
, &Window
->rcClient
);
1685 if (IntIntersectWithParents(Window
, pRect
))
1687 RECTL_vOffsetRect(pRect
,
1688 -Window
->rcClient
.left
,
1689 -Window
->rcClient
.top
);
1693 pRect
->left
= pRect
->top
= pRect
->right
= pRect
->bottom
= 0;
1700 * NtUserGetUpdateRgn
1707 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
1709 DECLARE_RETURN(INT
);
1713 TRACE("Enter NtUserGetUpdateRgn\n");
1714 UserEnterExclusive();
1716 if (!(Window
= UserGetWindowObject(hWnd
)))
1721 ret
= co_UserGetUpdateRgn(Window
, hRgn
, bErase
);
1726 TRACE("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
1732 * NtUserGetUpdateRect
1739 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
1745 DECLARE_RETURN(BOOL
);
1747 TRACE("Enter NtUserGetUpdateRect\n");
1748 UserEnterExclusive();
1750 if (!(Window
= UserGetWindowObject(hWnd
)))
1755 Ret
= co_UserGetUpdateRect(Window
, &Rect
, bErase
);
1757 if (UnsafeRect
!= NULL
)
1759 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECTL
));
1760 if (!NT_SUCCESS(Status
))
1762 EngSetLastError(ERROR_INVALID_PARAMETER
);
1770 TRACE("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1776 * NtUserRedrawWindow
1785 CONST RECT
*lprcUpdate
,
1789 RECTL SafeUpdateRect
;
1792 USER_REFERENCE_ENTRY Ref
;
1793 NTSTATUS Status
= STATUS_SUCCESS
;
1794 PREGION RgnUpdate
= NULL
;
1795 DECLARE_RETURN(BOOL
);
1797 TRACE("Enter NtUserRedrawWindow\n");
1798 UserEnterExclusive();
1800 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1809 ProbeForRead(lprcUpdate
, sizeof(RECTL
), 1);
1810 RtlCopyMemory(&SafeUpdateRect
, lprcUpdate
, sizeof(RECTL
));
1812 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1814 Status
= _SEH2_GetExceptionCode();
1817 if (!NT_SUCCESS(Status
))
1819 EngSetLastError(RtlNtStatusToDosError(Status
));
1824 if ( flags
& ~(RDW_ERASE
|RDW_FRAME
|RDW_INTERNALPAINT
|RDW_INVALIDATE
|
1825 RDW_NOERASE
|RDW_NOFRAME
|RDW_NOINTERNALPAINT
|RDW_VALIDATE
|
1826 RDW_ERASENOW
|RDW_UPDATENOW
|RDW_ALLCHILDREN
|RDW_NOCHILDREN
) )
1828 /* RedrawWindow fails only in case that flags are invalid */
1829 EngSetLastError(ERROR_INVALID_FLAGS
);
1833 /* We can't hold lock on GDI objects while doing roundtrips to user mode,
1834 * so it will be copied.
1836 if (hrgnUpdate
> HRGN_WINDOW
)
1838 RgnUpdate
= REGION_LockRgn(hrgnUpdate
);
1841 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1844 REGION_UnlockRgn(RgnUpdate
);
1846 else if (hrgnUpdate
== HRGN_WINDOW
) // Trap it out.
1848 ERR("NTRW: Caller is passing Window Region 1\n");
1851 UserRefObjectCo(Wnd
, &Ref
);
1853 Ret
= co_UserRedrawWindow( Wnd
,
1854 lprcUpdate
? &SafeUpdateRect
: NULL
,
1858 UserDerefObjectCo(Wnd
);
1863 TRACE("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1869 UserDrawCaptionText(
1872 const PUNICODE_STRING Text
,
1877 HFONT hOldFont
= NULL
;
1878 COLORREF OldTextColor
;
1879 NONCLIENTMETRICSW nclm
;
1881 BOOLEAN bDeleteFont
= FALSE
;
1884 ULONG fit
= 0, Length
;
1887 TRACE("UserDrawCaptionText: %wZ\n", Text
);
1889 nclm
.cbSize
= sizeof(nclm
);
1890 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICS
), &nclm
, 0))
1892 ERR("UserSystemParametersInfo() failed!\n");
1898 if(uFlags
& DC_SMALLCAP
)
1899 Status
= TextIntCreateFontIndirect(&nclm
.lfSmCaptionFont
, &hFont
);
1901 Status
= TextIntCreateFontIndirect(&nclm
.lfCaptionFont
, &hFont
);
1903 if(!NT_SUCCESS(Status
))
1905 ERR("TextIntCreateFontIndirect() failed! Status: 0x%x\n", Status
);
1912 IntGdiSetBkMode(hDc
, TRANSPARENT
);
1914 hOldFont
= NtGdiSelectFont(hDc
, hFont
);
1916 if(uFlags
& DC_INBUTTON
)
1917 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(COLOR_BTNTEXT
));
1919 OldTextColor
= IntGdiSetTextColor(hDc
,
1920 IntGetSysColor(uFlags
& DC_ACTIVE
? COLOR_CAPTIONTEXT
: COLOR_INACTIVECAPTIONTEXT
));
1922 // Adjust for system menu.
1923 if (pWnd
&& pWnd
->style
& WS_SYSMENU
)
1925 r
.right
-= UserGetSystemMetrics(SM_CYCAPTION
) - 1;
1926 if ((pWnd
->style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
)) && !(pWnd
->ExStyle
& WS_EX_TOOLWINDOW
))
1928 r
.right
-= UserGetSystemMetrics(SM_CXSIZE
) + 1;
1929 r
.right
-= UserGetSystemMetrics(SM_CXSIZE
) + 1;
1933 GreGetTextExtentExW(hDc
, Text
->Buffer
, Text
->Length
/sizeof(WCHAR
), r
.right
- r
.left
, &fit
, 0, &Size
, 0);
1935 Length
= (Text
->Length
/sizeof(WCHAR
) == fit
? fit
: fit
+1);
1937 if (Text
->Length
/sizeof(WCHAR
) > Length
)
1943 { // Faster while in setup.
1944 GreExtTextOutW( hDc
,
1946 lpRc
->top
+ (lpRc
->bottom
- lpRc
->top
) / 2 - Size
.cy
/ 2, // DT_SINGLELINE && DT_VCENTER
1958 Text
->Length
/sizeof(WCHAR
),
1960 DT_END_ELLIPSIS
|DT_SINGLELINE
|DT_VCENTER
|DT_NOPREFIX
|DT_LEFT
);
1963 IntGdiSetTextColor(hDc
, OldTextColor
);
1966 NtGdiSelectFont(hDc
, hOldFont
);
1969 GreDeleteObject(hFont
);
1975 // This draws Buttons, Icons and Text...
1977 BOOL
UserDrawCaption(
1983 const PUNICODE_STRING Str
,
1987 HBRUSH hBgBrush
, hOldBrush
= NULL
;
1991 RECTL_vMakeWellOrdered(lpRc
);
1993 if (!hIcon
&& pWnd
!= NULL
)
1995 HasIcon
= (uFlags
& DC_ICON
) && (pWnd
->style
& WS_SYSMENU
)
1996 && !(uFlags
& DC_SMALLCAP
) && !(pWnd
->ExStyle
& WS_EX_DLGMODALFRAME
)
1997 && !(pWnd
->ExStyle
& WS_EX_TOOLWINDOW
);
2000 HasIcon
= (hIcon
!= 0);
2002 // Draw the caption background
2003 if((uFlags
& DC_GRADIENT
) && !(uFlags
& DC_INBUTTON
))
2005 static GRADIENT_RECT gcap
= {0, 1};
2006 TRIVERTEX Vertices
[2];
2009 Colors
[0] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
2010 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
2012 Colors
[1] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
2013 COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
2015 Vertices
[0].x
= Rect
.left
;
2016 Vertices
[0].y
= Rect
.top
;
2017 Vertices
[0].Red
= (WORD
)Colors
[0]<<8;
2018 Vertices
[0].Green
= (WORD
)Colors
[0] & 0xFF00;
2019 Vertices
[0].Blue
= (WORD
)(Colors
[0]>>8) & 0xFF00;
2020 Vertices
[0].Alpha
= 0;
2022 Vertices
[1].x
= Rect
.right
;
2023 Vertices
[1].y
= Rect
.bottom
;
2024 Vertices
[1].Red
= (WORD
)Colors
[1]<<8;
2025 Vertices
[1].Green
= (WORD
)Colors
[1] & 0xFF00;
2026 Vertices
[1].Blue
= (WORD
)(Colors
[1]>>8) & 0xFF00;
2027 Vertices
[1].Alpha
= 0;
2029 if(!GreGradientFill(hDc
, Vertices
, 2, &gcap
, 1, GRADIENT_FILL_RECT_H
))
2031 ERR("GreGradientFill() failed!\n");
2037 if(uFlags
& DC_INBUTTON
)
2038 hBgBrush
= IntGetSysColorBrush(COLOR_3DFACE
);
2039 else if(uFlags
& DC_ACTIVE
)
2040 hBgBrush
= IntGetSysColorBrush(COLOR_ACTIVECAPTION
);
2042 hBgBrush
= IntGetSysColorBrush(COLOR_INACTIVECAPTION
);
2044 hOldBrush
= NtGdiSelectBrush(hDc
, hBgBrush
);
2048 ERR("NtGdiSelectBrush() failed!\n");
2052 if(!NtGdiPatBlt(hDc
, Rect
.left
, Rect
.top
,
2053 Rect
.right
- Rect
.left
,
2054 Rect
.bottom
- Rect
.top
,
2057 ERR("NtGdiPatBlt() failed!\n");
2065 PCURICON_OBJECT pIcon
= NULL
;
2069 pIcon
= UserGetCurIconObject(hIcon
);
2073 pIcon
= NC_IconForWindow(pWnd
);
2074 // FIXME: NC_IconForWindow should reference it for us */
2076 UserReferenceObject(pIcon
);
2081 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
2082 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
2083 LONG x
= Rect
.left
- cx
/2 + 1 + (Rect
.bottom
- Rect
.top
)/2; // this is really what Window does
2084 LONG y
= (Rect
.top
+ Rect
.bottom
)/2 - cy
/2; // center
2085 UserDrawIconEx(hDc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
2086 UserDereferenceObject(pIcon
);
2095 Rect
.left
+= Rect
.bottom
- Rect
.top
;
2097 if((uFlags
& DC_TEXT
))
2103 Set
= UserDrawCaptionText(pWnd
, hDc
, Str
, &Rect
, uFlags
, hFont
);
2104 else if (pWnd
!= NULL
) // FIXME: Windows does not do that
2106 UNICODE_STRING ustr
;
2107 ustr
.Buffer
= pWnd
->strName
.Buffer
; // FIXME: LARGE_STRING truncated!
2108 ustr
.Length
= (USHORT
)min(pWnd
->strName
.Length
, MAXUSHORT
);
2109 ustr
.MaximumLength
= (USHORT
)min(pWnd
->strName
.MaximumLength
, MAXUSHORT
);
2110 Set
= UserDrawCaptionText(pWnd
, hDc
, &ustr
, &Rect
, uFlags
, hFont
);
2115 pWnd
->state2
&= ~WNDS2_CAPTIONTEXTTRUNCATED
;
2117 pWnd
->state2
|= WNDS2_CAPTIONTEXTTRUNCATED
;
2124 if (hOldBrush
) NtGdiSelectBrush(hDc
, hOldBrush
);
2131 UserRealizePalette(HDC hdc
)
2133 HWND hWnd
, hWndDesktop
;
2136 Ret
= IntGdiRealizePalette(hdc
);
2137 if (Ret
) // There was a change.
2139 hWnd
= IntWindowFromDC(hdc
);
2140 if (hWnd
) // Send broadcast if dc is associated with a window.
2141 { // FYI: Thread locked in CallOneParam.
2142 hWndDesktop
= IntGetDesktopWindow();
2143 if ( hWndDesktop
!= hWnd
)
2145 PWND pWnd
= UserGetWindowObject(hWndDesktop
);
2146 ERR("RealizePalette Desktop.");
2147 hdc
= UserGetWindowDC(pWnd
);
2148 IntPaintDesktop(hdc
);
2149 UserReleaseDC(pWnd
,hdc
,FALSE
);
2151 UserSendNotifyMessage((HWND
)HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0);
2159 NtUserDrawCaptionTemp(
2165 const PUNICODE_STRING str
,
2169 UNICODE_STRING SafeStr
= {0};
2170 NTSTATUS Status
= STATUS_SUCCESS
;
2174 UserEnterExclusive();
2178 if(!(pWnd
= UserGetWindowObject(hWnd
)))
2187 ProbeForRead(lpRc
, sizeof(RECTL
), sizeof(ULONG
));
2188 RtlCopyMemory(&SafeRect
, lpRc
, sizeof(RECTL
));
2191 SafeStr
= ProbeForReadUnicodeString(str
);
2192 if (SafeStr
.Length
!= 0)
2194 ProbeForRead( SafeStr
.Buffer
,
2200 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2202 Status
= _SEH2_GetExceptionCode();
2206 if (Status
!= STATUS_SUCCESS
)
2208 SetLastNtError(Status
);
2214 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, &SafeStr
, uFlags
);
2217 if ( RECTL_bIsEmptyRect(&SafeRect
) && hFont
== 0 && hIcon
== 0 )
2220 if (uFlags
& DC_DRAWCAPTIONMD
)
2222 ERR("NC Caption Mode\n");
2223 UserDrawCaptionBar(pWnd
, hDC
, uFlags
);
2226 else if (uFlags
& DC_DRAWFRAMEMD
)
2228 ERR("NC Paint Mode\n");
2229 NC_DoNCPaint(pWnd
, hDC
, uFlags
); // Update Menus too!
2233 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, NULL
, uFlags
);
2242 NtUserDrawCaption(HWND hWnd
,
2247 return NtUserDrawCaptionTemp(hWnd
, hDC
, lpRc
, 0, 0, NULL
, uFlags
);
2252 NtUserInvalidateRect(
2254 CONST RECT
*lpUnsafeRect
,
2257 UINT flags
= RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0);
2260 flags
= RDW_ALLCHILDREN
| RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ERASENOW
;
2261 lpUnsafeRect
= NULL
;
2263 return NtUserRedrawWindow(hWnd
, lpUnsafeRect
, NULL
, flags
);
2268 NtUserInvalidateRgn(
2275 EngSetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2278 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2291 UserEnterExclusive();
2295 if (!(Window
= UserGetWindowObject(hwnd
)) || // FIXME:
2296 Window
== UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2297 Window
== UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2304 /* Validate flags and check it as a mask for 0 or 1. */
2305 if ( (nFlags
& PW_CLIENTONLY
) == nFlags
)
2306 Ret
= IntPrintWindow( Window
, hdcBlt
, nFlags
);
2308 EngSetLastError(ERROR_INVALID_PARAMETER
);
2316 /* ValidateRect gets redirected to NtUserValidateRect:
2317 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */
2324 UINT flags
= RDW_VALIDATE
;
2327 flags
= RDW_ALLCHILDREN
| RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ERASENOW
;
2330 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, flags
);