2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window painting function
5 * FILE: subsystems/win32/win32k/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 ParentWnd
= Child
->spwndParent
;
37 while (ParentWnd
!= NULL
)
39 if (!(ParentWnd
->style
& WS_VISIBLE
) ||
40 (ParentWnd
->style
& WS_MINIMIZE
))
45 if (!RECTL_bIntersectRect(WindowRect
, WindowRect
, &ParentWnd
->rcClient
))
50 /* FIXME: Layered windows. */
52 ParentWnd
= ParentWnd
->spwndParent
;
59 IntValidateParent(PWND Child
, PREGION ValidateRgn
, BOOL Recurse
)
61 PWND ParentWnd
= Child
;
63 if (ParentWnd
->style
& WS_CHILD
)
66 ParentWnd
= ParentWnd
->spwndParent
;
67 while (ParentWnd
->style
& WS_CHILD
);
69 // Hax out for drawing issues.
70 // if (!(ParentWnd->state & WNDS_SYNCPAINTPENDING)) Recurse = FALSE;
72 ParentWnd
= Child
->spwndParent
;
75 if (ParentWnd
->style
& WS_CLIPCHILDREN
)
78 if (ParentWnd
->hrgnUpdate
!= 0)
83 IntInvalidateWindows( ParentWnd
,
85 RDW_VALIDATE
| RDW_NOCHILDREN
);
88 ParentWnd
= ParentWnd
->spwndParent
;
95 Synchronize painting to the top-level windows of other threads.
98 IntSendSyncPaint(PWND Wnd
, ULONG Flags
)
100 PTHREADINFO ptiCur
, ptiWnd
;
101 PUSER_SENT_MESSAGE Message
;
105 ptiWnd
= Wnd
->head
.pti
;
106 ptiCur
= PsGetCurrentThreadWin32Thread();
108 Not the current thread, Wnd is in send Nonclient paint also in send erase background and it is visiable.
110 if ( Wnd
->head
.pti
!= ptiCur
&&
111 Wnd
->state
& WNDS_SENDNCPAINT
&&
112 Wnd
->state
& WNDS_SENDERASEBACKGROUND
&&
113 Wnd
->style
& WS_VISIBLE
)
115 // For testing, if you see this, break out the Champagne and have a party!
116 ERR("SendSyncPaint Wnd in State!\n");
117 if (!IsListEmpty(&ptiWnd
->SentMessagesListHead
))
119 // Scan sent queue messages to see if we received sync paint messages.
120 Entry
= ptiWnd
->SentMessagesListHead
.Flink
;
121 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
125 if (Message
->Msg
.message
== WM_SYNCPAINT
&&
126 Message
->Msg
.hwnd
== UserHMGetHandle(Wnd
))
127 { // Already received so exit out.
128 ERR("SendSyncPaint Found one in the Sent Msg Queue!\n");
132 Entry
= Message
->ListEntry
.Flink
;
133 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
135 while (Entry
!= &ptiWnd
->SentMessagesListHead
);
139 ERR("Sending WM_SYNCPAINT\n");
140 // This message has no parameters. But it does! Pass Flags along.
141 co_IntSendMessageNoWait(UserHMGetHandle(Wnd
), WM_SYNCPAINT
, Flags
, 0);
142 Wnd
->state
|= WNDS_SYNCPAINTPENDING
;
146 // Send to all the children if this is the desktop window.
147 if ( Wnd
== UserGetDesktopWindow() )
149 if ( Flags
& RDW_ALLCHILDREN
||
150 ( !(Flags
& RDW_NOCHILDREN
) && Wnd
->style
& WS_CLIPCHILDREN
))
152 PWND spwndChild
= Wnd
->spwndChild
;
155 if ( spwndChild
->style
& WS_CHILD
&&
156 spwndChild
->head
.pti
!= ptiCur
)
158 spwndChild
= spwndChild
->spwndNext
;
161 IntSendSyncPaint( spwndChild
, Flags
);
162 spwndChild
= spwndChild
->spwndNext
;
169 * @name IntCalcWindowRgn
171 * Get a window or client region.
175 IntCalcWindowRgn(PWND Wnd
, BOOL Client
)
181 hRgnWindow
= NtGdiCreateRectRgn(
185 Wnd
->rcClient
.bottom
);
189 hRgnWindow
= NtGdiCreateRectRgn(
193 Wnd
->rcWindow
.bottom
);
196 if (Wnd
->hrgnClip
!= NULL
&& !(Wnd
->style
& WS_MINIMIZE
))
198 NtGdiOffsetRgn(hRgnWindow
,
201 NtGdiCombineRgn(hRgnWindow
, hRgnWindow
, Wnd
->hrgnClip
, RGN_AND
);
202 NtGdiOffsetRgn(hRgnWindow
,
211 * @name IntGetNCUpdateRgn
213 * Get non-client update region of a window and optionally validate it.
216 * Pointer to window to get the NC update region from.
218 * Set to TRUE to force validating the NC update region.
221 * Handle to NC update region. The caller is responsible for deleting
226 IntGetNCUpdateRgn(PWND Window
, BOOL Validate
)
232 if (Window
->hrgnUpdate
!= NULL
&&
233 Window
->hrgnUpdate
!= HRGN_WINDOW
)
235 hRgnNonClient
= IntCalcWindowRgn(Window
, FALSE
);
238 * If region creation fails it's safe to fallback to whole
241 if (hRgnNonClient
== NULL
)
246 hRgnWindow
= IntCalcWindowRgn(Window
, TRUE
);
247 if (hRgnWindow
== NULL
)
249 GreDeleteObject(hRgnNonClient
);
253 RgnType
= NtGdiCombineRgn(hRgnNonClient
, hRgnNonClient
,
254 hRgnWindow
, RGN_DIFF
);
255 if (RgnType
== ERROR
)
257 GreDeleteObject(hRgnWindow
);
258 GreDeleteObject(hRgnNonClient
);
261 else if (RgnType
== NULLREGION
)
263 GreDeleteObject(hRgnWindow
);
264 GreDeleteObject(hRgnNonClient
);
265 Window
->state
&= ~WNDS_UPDATEDIRTY
;
270 * Remove the nonclient region from the standard update region if
271 * we were asked for it.
276 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
,
277 hRgnWindow
, RGN_AND
) == NULLREGION
)
279 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
280 GreDeleteObject(Window
->hrgnUpdate
);
281 Window
->state
&= ~WNDS_UPDATEDIRTY
;
282 Window
->hrgnUpdate
= NULL
;
283 if (!(Window
->state
& WNDS_INTERNALPAINT
))
284 MsqDecPaintCountQueue(Window
->head
.pti
);
288 GreDeleteObject(hRgnWindow
);
290 return hRgnNonClient
;
294 return Window
->hrgnUpdate
;
301 * Internal function used by IntRedrawWindow.
305 co_IntPaintWindows(PWND Wnd
, ULONG Flags
, BOOL Recurse
)
308 HWND hWnd
= Wnd
->head
.h
;
311 Wnd
->state
&= ~WNDS_PAINTNOTPROCESSED
;
313 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
317 PREGION RgnUpdate
= RGNOBJAPI_Lock(Wnd
->hrgnUpdate
, NULL
);
320 if (!IntValidateParent(Wnd
, RgnUpdate
, Recurse
))
322 RGNOBJAPI_Unlock(RgnUpdate
);
325 RGNOBJAPI_Unlock(RgnUpdate
);
329 if (Flags
& RDW_UPDATENOW
)
331 if ((Wnd
->hrgnUpdate
!= NULL
||
332 Wnd
->state
& WNDS_INTERNALPAINT
))
334 Wnd
->state2
|= WNDS2_WMPAINTSENT
;
335 co_IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
338 else if (Wnd
->head
.pti
== PsGetCurrentThreadWin32Thread())
340 if (Wnd
->state
& WNDS_SENDNCPAINT
)
342 TempRegion
= IntGetNCUpdateRgn(Wnd
, TRUE
);
343 Wnd
->state
&= ~WNDS_SENDNCPAINT
;
344 if ( Wnd
== GetW32ThreadInfo()->MessageQueue
->spwndActive
&&
345 !(Wnd
->state
& WNDS_ACTIVEFRAME
))
347 Wnd
->state
|= WNDS_ACTIVEFRAME
;
348 Wnd
->state
&= ~WNDS_NONCPAINT
;
350 if (TempRegion
) co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)TempRegion
, 0);
353 if (Wnd
->state
& WNDS_SENDERASEBACKGROUND
)
357 hDC
= UserGetDCEx( Wnd
,
359 DCX_CACHE
|DCX_USESTYLE
|DCX_INTERSECTRGN
|DCX_KEEPCLIPRGN
);
361 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
362 // Kill the loop, so Clear before we send.
363 if (!co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
365 Wnd
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
367 UserReleaseDC(Wnd
, hDC
, FALSE
);
374 Wnd
->state
&= ~(WNDS_SENDNCPAINT
|WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
378 * Check that the window is still valid at this point
380 if (!IntIsWindow(hWnd
))
386 * Paint child windows.
388 if (!(Flags
& RDW_NOCHILDREN
) &&
389 !(Wnd
->style
& WS_MINIMIZE
) &&
390 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)) )
394 if ((List
= IntWinListChildren(Wnd
)))
396 /* FIXME: Handle WS_EX_TRANSPARENT */
397 for (phWnd
= List
; *phWnd
; ++phWnd
)
399 Wnd
= UserGetWindowObject(*phWnd
);
400 if (Wnd
&& (Wnd
->style
& WS_VISIBLE
))
402 USER_REFERENCE_ENTRY Ref
;
403 UserRefObjectCo(Wnd
, &Ref
);
404 co_IntPaintWindows(Wnd
, Flags
, TRUE
);
405 UserDerefObjectCo(Wnd
);
408 ExFreePoolWithTag(List
, USERTAG_WINDOWLIST
);
414 * IntInvalidateWindows
416 * Internal function used by IntRedrawWindow, UserRedrawDesktop,
417 * co_WinPosSetWindowPos, IntValidateParent, co_UserRedrawWindow.
420 IntInvalidateWindows(PWND Wnd
, PREGION Rgn
, ULONG Flags
)
423 BOOL HadPaintMessage
;
425 TRACE("IntInvalidateWindows start\n");
427 Wnd
->state
|= WNDS_PAINTNOTPROCESSED
;
430 * If the nonclient is not to be redrawn, clip the region to the client
433 if (0 != (Flags
& RDW_INVALIDATE
) && 0 == (Flags
& RDW_FRAME
))
437 RgnClient
= IntSysCreateRectpRgnIndirect(&Wnd
->rcClient
);
440 RgnType
= IntGdiCombineRgn(Rgn
, Rgn
, RgnClient
, RGN_AND
);
441 REGION_Delete(RgnClient
);
446 * Clip the given region with window rectangle (or region)
449 if (!Wnd
->hrgnClip
|| (Wnd
->style
& WS_MINIMIZE
))
451 PREGION RgnWindow
= IntSysCreateRectpRgnIndirect(&Wnd
->rcWindow
);
454 RgnType
= IntGdiCombineRgn(Rgn
, Rgn
, RgnWindow
, RGN_AND
);
455 REGION_Delete(RgnWindow
);
460 PREGION RgnClip
= RGNOBJAPI_Lock(Wnd
->hrgnClip
, NULL
);
463 IntGdiOffsetRgn( Rgn
,
466 RgnType
= IntGdiCombineRgn(Rgn
, Rgn
, RgnClip
, RGN_AND
);
467 IntGdiOffsetRgn( Rgn
,
470 RGNOBJAPI_Unlock(RgnClip
);
475 * Save current state of pending updates
478 HadPaintMessage
= IntIsWindowDirty(Wnd
);
481 * Update the region and flags
484 // The following flags are used to invalidate the window.
485 if (Flags
& (RDW_INVALIDATE
|RDW_INTERNALPAINT
|RDW_ERASE
|RDW_FRAME
))
487 if (Flags
& RDW_INTERNALPAINT
)
489 Wnd
->state
|= WNDS_INTERNALPAINT
;
492 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
496 Wnd
->state
&= ~WNDS_NONCPAINT
;
498 /* If not the same thread set it dirty. */
499 if (Wnd
->head
.pti
!= PsGetCurrentThreadWin32Thread())
501 Wnd
->state
|= WNDS_UPDATEDIRTY
;
502 if (Wnd
->state2
& WNDS2_WMPAINTSENT
)
503 Wnd
->state2
|= WNDS2_ENDPAINTINVALIDATE
;
506 if (Flags
& RDW_FRAME
)
507 Wnd
->state
|= WNDS_SENDNCPAINT
;
508 if (Flags
& RDW_ERASE
)
509 Wnd
->state
|= WNDS_SENDERASEBACKGROUND
;
511 if (Wnd
->hrgnUpdate
== NULL
)
513 Wnd
->hrgnUpdate
= NtGdiCreateRectRgn(0, 0, 0, 0);
514 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_PUBLIC
);
517 RgnUpdate
= RGNOBJAPI_Lock(Wnd
->hrgnUpdate
, NULL
);
520 RgnType
= IntGdiCombineRgn(RgnUpdate
, RgnUpdate
, Rgn
, RGN_OR
);
521 RGNOBJAPI_Unlock(RgnUpdate
);
522 if (RgnType
== NULLREGION
)
524 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
525 GreDeleteObject(Wnd
->hrgnUpdate
);
526 Wnd
->hrgnUpdate
= NULL
;
529 Flags
|= RDW_FRAME
; // For children.
531 } // The following flags are used to validate the window.
532 else if (Flags
& (RDW_VALIDATE
|RDW_NOINTERNALPAINT
|RDW_NOERASE
|RDW_NOFRAME
))
534 /* FIXME: Handle WNDS_UPDATEDIRTY */
536 if (Flags
& RDW_NOINTERNALPAINT
)
538 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
541 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
543 if (Flags
& RDW_NOFRAME
)
544 Wnd
->state
&= ~WNDS_SENDNCPAINT
;
545 if (Flags
& RDW_NOERASE
)
546 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
548 if (Wnd
->hrgnUpdate
!= NULL
)
550 PREGION RgnUpdate
= RGNOBJAPI_Lock(Wnd
->hrgnUpdate
, NULL
);
554 RgnType
= IntGdiCombineRgn(RgnUpdate
, RgnUpdate
, Rgn
, RGN_DIFF
);
555 RGNOBJAPI_Unlock(RgnUpdate
);
557 if(RgnType
== NULLREGION
)
559 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
560 GreDeleteObject(Wnd
->hrgnUpdate
);
561 Wnd
->hrgnUpdate
= NULL
;
566 if (Wnd
->hrgnUpdate
== NULL
)
567 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
572 * Process children if needed
575 if (!(Flags
& RDW_NOCHILDREN
) && !(Wnd
->style
& WS_MINIMIZE
) &&
576 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)))
580 for (Child
= Wnd
->spwndChild
; Child
; Child
= Child
->spwndNext
)
582 if (Child
->style
& WS_VISIBLE
)
585 * Recursive call to update children hrgnUpdate
587 PREGION RgnTemp
= IntSysCreateRectpRgn(0, 0, 0, 0);
590 IntGdiCombineRgn(RgnTemp
, Rgn
, 0, RGN_COPY
);
591 IntInvalidateWindows(Child
, RgnTemp
, Flags
);
592 REGION_Delete(RgnTemp
);
599 * Fake post paint messages to window message queue if needed
602 if (HadPaintMessage
!= IntIsWindowDirty(Wnd
))
605 MsqDecPaintCountQueue(Wnd
->head
.pti
);
607 MsqIncPaintCountQueue(Wnd
->head
.pti
);
609 TRACE("IntInvalidateWindows exit\n");
613 * IntIsWindowDrawable
616 * Window is drawable when it is visible and all parents are not
621 IntIsWindowDrawable(PWND Wnd
)
625 for (WndObject
= Wnd
; WndObject
!= NULL
; WndObject
= WndObject
->spwndParent
)
627 if ( WndObject
->state2
& WNDS2_INDESTROY
||
628 WndObject
->state
& WNDS_DESTROYED
||
630 !(WndObject
->style
& WS_VISIBLE
) ||
631 ((WndObject
->style
& WS_MINIMIZE
) && (WndObject
!= Wnd
)))
643 * Internal version of NtUserRedrawWindow that takes WND as
650 const RECTL
* UpdateRect
,
654 PREGION TmpRgn
= NULL
;
655 TRACE("co_UserRedrawWindow start\n");
659 * Validation of passed parameters.
662 if (!IntIsWindowDrawable(Window
))
664 return TRUE
; // Just do nothing!!!
669 * Transform the parameters UpdateRgn and UpdateRect into
670 * a region hRgn specified in screen coordinates.
673 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
)) // Both are OKAY!
677 TmpRgn
= IntSysCreateRectpRgn(0, 0, 0, 0);
678 if (IntGdiCombineRgn(TmpRgn
, UpdateRgn
, NULL
, RGN_COPY
) == NULLREGION
)
680 REGION_Delete(TmpRgn
);
685 IntGdiOffsetRgn(TmpRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
688 else if (UpdateRect
!= NULL
)
690 if (!RECTL_bIsEmptyRect(UpdateRect
))
692 TmpRgn
= IntSysCreateRectpRgnIndirect(UpdateRect
);
693 IntGdiOffsetRgn(TmpRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
696 else if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
697 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
699 if (!RECTL_bIsEmptyRect(&Window
->rcWindow
))
700 TmpRgn
= IntSysCreateRectpRgnIndirect(&Window
->rcWindow
);
704 if (!RECTL_bIsEmptyRect(&Window
->rcClient
))
705 TmpRgn
= IntSysCreateRectpRgnIndirect(&Window
->rcClient
);
711 * Adjust the window update region depending on hRgn and flags.
714 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
) &&
717 IntInvalidateWindows(Window
, TmpRgn
, Flags
);
722 * Repaint and erase windows if needed.
725 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
727 if (Flags
& RDW_ERASENOW
) IntSendSyncPaint(Window
, Flags
);
728 co_IntPaintWindows(Window
, Flags
, FALSE
);
738 REGION_Delete(TmpRgn
);
740 TRACE("co_UserRedrawWindow exit\n");
746 IntIsWindowDirty(PWND Wnd
)
748 return ( Wnd
->style
& WS_VISIBLE
&&
749 ( Wnd
->hrgnUpdate
!= NULL
||
750 Wnd
->state
& WNDS_INTERNALPAINT
) );
754 IntFindWindowToRepaint(PWND Window
, PTHREADINFO Thread
)
759 for (; Window
!= NULL
; Window
= Window
->spwndNext
)
761 if (IntWndBelongsToThread(Window
, Thread
) &&
762 IntIsWindowDirty(Window
))
764 /* Make sure all non-transparent siblings are already drawn. */
765 if (Window
->ExStyle
& WS_EX_TRANSPARENT
)
767 for (TempWindow
= Window
->spwndNext
; TempWindow
!= NULL
;
768 TempWindow
= TempWindow
->spwndNext
)
770 if (!(TempWindow
->ExStyle
& WS_EX_TRANSPARENT
) &&
771 IntWndBelongsToThread(TempWindow
, Thread
) &&
772 IntIsWindowDirty(TempWindow
))
782 if (Window
->spwndChild
)
784 hChild
= IntFindWindowToRepaint(Window
->spwndChild
, Thread
);
803 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
804 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
807 if (Thread
->TIF_flags
& TIF_SYSTEMTHREAD
)
809 ERR("WM_PAINT is in a System Thread!\n");
812 PaintWnd
= IntFindWindowToRepaint(UserGetDesktopWindow(), Thread
);
814 Message
->hwnd
= PaintWnd
? UserHMGetHandle(PaintWnd
) : NULL
;
816 if (Message
->hwnd
== NULL
)
818 ERR("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found! Counts %u\n",Thread
->cPaintsReady
);
819 /* Hack to stop spamming the debuglog ! */
820 Thread
->cPaintsReady
= 0;
824 if (Window
!= NULL
&& PaintWnd
!= Window
)
827 if (PaintWnd
->state
& WNDS_INTERNALPAINT
)
829 PaintWnd
->state
&= ~WNDS_INTERNALPAINT
;
830 if (!PaintWnd
->hrgnUpdate
)
831 MsqDecPaintCountQueue(Thread
);
833 PaintWnd
->state2
&= ~WNDS2_WMPAINTSENT
;
834 PaintWnd
->state
&= ~WNDS_UPDATEDIRTY
;
835 Message
->wParam
= Message
->lParam
= 0;
836 Message
->message
= WM_PAINT
;
842 co_IntFixCaret(PWND Window
, RECTL
*lprc
, UINT flags
)
845 PTHRDCARETINFO CaretInfo
;
847 PUSER_MESSAGE_QUEUE ActiveMessageQueue
;
851 ASSERT_REFS_CO(Window
);
853 pti
= PsGetCurrentThreadWin32Thread();
854 Desktop
= pti
->rpdesk
;
855 ActiveMessageQueue
= Desktop
->ActiveMessageQueue
;
856 if (!ActiveMessageQueue
) return 0;
857 CaretInfo
= ActiveMessageQueue
->CaretInfo
;
858 hWndCaret
= CaretInfo
->hWnd
;
860 WndCaret
= ValidateHwndNoErr(hWndCaret
);
862 // FIXME: Check for WndCaret can be NULL
863 if (WndCaret
== Window
||
864 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(Window
, WndCaret
)))
866 POINT pt
, FromOffset
, ToOffset
;
869 pt
.x
= CaretInfo
->Pos
.x
;
870 pt
.y
= CaretInfo
->Pos
.y
;
871 IntGetClientOrigin(WndCaret
, &FromOffset
);
872 IntGetClientOrigin(Window
, &ToOffset
);
875 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
876 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
877 if (RECTL_bIntersectRect(lprc
, lprc
, &rcCaret
))
897 INT cx
, cy
, xSrc
, ySrc
;
899 if ( nFlags
& PW_CLIENTONLY
)
901 cx
= pwnd
->rcClient
.right
- pwnd
->rcClient
.left
;
902 cy
= pwnd
->rcClient
.bottom
- pwnd
->rcClient
.top
;
903 xSrc
= pwnd
->rcClient
.left
- pwnd
->rcWindow
.left
;
904 ySrc
= pwnd
->rcClient
.top
- pwnd
->rcWindow
.top
;
908 cx
= pwnd
->rcWindow
.right
- pwnd
->rcWindow
.left
;
909 cy
= pwnd
->rcWindow
.bottom
- pwnd
->rcWindow
.top
;
914 // TODO: Setup Redirection for Print.
917 /* Update the window just incase. */
918 co_IntPaintWindows( pwnd
, RDW_ERASENOW
|RDW_UPDATENOW
, FALSE
);
920 hdcSrc
= UserGetDCEx( pwnd
, NULL
, DCX_CACHE
|DCX_WINDOW
);
921 /* Print window to printer context. */
934 UserReleaseDC( pwnd
, hdcSrc
, FALSE
);
936 // TODO: Release Redirection from Print.
943 IntFlashWindowEx(PWND pWnd
, PFLASHWINFO pfwi
)
949 pprop
= IntGetProp(pWnd
, AtomFlashWndState
);
952 FlashState
= pfwi
->dwFlags
;
953 IntSetProp(pWnd
, AtomFlashWndState
, (HANDLE
) FlashState
);
957 FlashState
= (DWORD
)pprop
->Data
;
958 if ( pfwi
->dwFlags
== FLASHW_STOP
)
960 IntRemoveProp(pWnd
, AtomFlashWndState
);
967 IntBeginPaint(PWND Window
, PPAINTSTRUCT Ps
)
969 co_UserHideCaret(Window
);
971 Window
->state2
|= WNDS2_STARTPAINT
;
972 Window
->state
&= ~WNDS_PAINTNOTPROCESSED
;
974 if (Window
->state
& WNDS_SENDNCPAINT
)
978 Window
->state
&= ~WNDS_UPDATEDIRTY
;
979 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
980 Window
->state
&= ~WNDS_SENDNCPAINT
;
981 co_IntSendMessage(UserHMGetHandle(Window
), WM_NCPAINT
, (WPARAM
)hRgn
, 0);
982 if (hRgn
!= HRGN_WINDOW
&& hRgn
!= NULL
&& GreIsHandleValid(hRgn
))
984 /* NOTE: The region can already be deleted! */
985 GreDeleteObject(hRgn
);
990 Window
->state
&= ~WNDS_UPDATEDIRTY
;
993 RtlZeroMemory(Ps
, sizeof(PAINTSTRUCT
));
995 Ps
->hdc
= UserGetDCEx( Window
,
997 DCX_INTERSECTRGN
| DCX_USESTYLE
);
1003 if (Window
->hrgnUpdate
!= NULL
)
1005 MsqDecPaintCountQueue(Window
->head
.pti
);
1006 GdiGetClipBox(Ps
->hdc
, &Ps
->rcPaint
);
1007 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
1008 /* The region is part of the dc now and belongs to the process! */
1009 Window
->hrgnUpdate
= NULL
;
1013 if (Window
->state
& WNDS_INTERNALPAINT
)
1014 MsqDecPaintCountQueue(Window
->head
.pti
);
1016 IntGetClientRect(Window
, &Ps
->rcPaint
);
1019 Window
->state
&= ~WNDS_INTERNALPAINT
;
1021 if (Window
->state
& WNDS_SENDERASEBACKGROUND
)
1023 Window
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
1024 Ps
->fErase
= !co_IntSendMessage(UserHMGetHandle(Window
), WM_ERASEBKGND
, (WPARAM
)Ps
->hdc
, 0);
1027 Window
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
1034 if (Window
->hrgnUpdate
)
1036 if (!(Window
->style
& WS_CLIPCHILDREN
))
1039 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
1041 if (Child
->hrgnUpdate
== NULL
&& Child
->state
& WNDS_SENDNCPAINT
) // Helped fixing test_redrawnow.
1042 IntInvalidateWindows(Child
, NULL
, RDW_FRAME
| RDW_ERASE
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
1050 IntEndPaint(PWND Wnd
, PPAINTSTRUCT Ps
)
1056 UserReleaseDC(Wnd
, hdc
, TRUE
);
1058 Wnd
->state2
&= ~(WNDS2_WMPAINTSENT
|WNDS2_STARTPAINT
);
1060 co_UserShowCaret(Wnd
);
1065 /* PUBLIC FUNCTIONS ***********************************************************/
1075 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
1081 USER_REFERENCE_ENTRY Ref
;
1082 DECLARE_RETURN(HDC
);
1084 TRACE("Enter NtUserBeginPaint\n");
1085 UserEnterExclusive();
1087 if (!(Window
= UserGetWindowObject(hWnd
)))
1092 UserRefObjectCo(Window
, &Ref
);
1094 hDC
= IntBeginPaint(Window
, &Ps
);
1096 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
1097 if (! NT_SUCCESS(Status
))
1099 SetLastNtError(Status
);
1106 if (Window
) UserDerefObjectCo(Window
);
1108 TRACE("Leave NtUserBeginPaint, ret=%p\n",_ret_
);
1122 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* pUnsafePs
)
1124 NTSTATUS Status
= STATUS_SUCCESS
;
1127 USER_REFERENCE_ENTRY Ref
;
1128 DECLARE_RETURN(BOOL
);
1130 TRACE("Enter NtUserEndPaint\n");
1131 UserEnterExclusive();
1133 if (!(Window
= UserGetWindowObject(hWnd
)))
1138 UserRefObjectCo(Window
, &Ref
); // Here for the exception.
1142 ProbeForRead(pUnsafePs
, sizeof(*pUnsafePs
), 1);
1143 RtlCopyMemory(&Ps
, pUnsafePs
, sizeof(PAINTSTRUCT
));
1145 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1147 Status
= _SEH2_GetExceptionCode();
1150 if (!NT_SUCCESS(Status
))
1155 RETURN(IntEndPaint(Window
, &Ps
));
1158 if (Window
) UserDerefObjectCo(Window
);
1160 TRACE("Leave NtUserEndPaint, ret=%i\n",_ret_
);
1169 NtUserFlashWindowEx(IN PFLASHWINFO pfwi
)
1172 FLASHWINFO finfo
= {0};
1175 UserEnterExclusive();
1179 ProbeForRead(pfwi
, sizeof(FLASHWINFO
), sizeof(ULONG
));
1180 RtlCopyMemory(&finfo
, pfwi
, sizeof(FLASHWINFO
));
1182 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1184 SetLastNtError(_SEH2_GetExceptionCode());
1189 if (!Ret
) goto Exit
;
1191 if (!( pWnd
= (PWND
)UserGetObject(gHandleTable
, finfo
.hwnd
, TYPE_WINDOW
)) ||
1192 finfo
.cbSize
!= sizeof(FLASHWINFO
) ||
1193 finfo
.dwFlags
& ~(FLASHW_ALL
|FLASHW_TIMER
|FLASHW_TIMERNOFG
) )
1195 EngSetLastError(ERROR_INVALID_PARAMETER
);
1200 Ret
= IntFlashWindowEx(pWnd
, &finfo
);
1208 co_UserGetUpdateRgn(PWND Window
, PREGION Rgn
, BOOL bErase
)
1214 ASSERT_REFS_CO(Window
);
1216 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1218 if (Window
->hrgnUpdate
== NULL
)
1220 REGION_SetRectRgn(Rgn
, 0, 0, 0, 0);
1224 UpdateRgn
= RGNOBJAPI_Lock(Window
->hrgnUpdate
, NULL
);
1228 Rect
= Window
->rcClient
;
1229 IntIntersectWithParents(Window
, &Rect
);
1230 REGION_SetRectRgn(Rgn
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
1231 RegionType
= IntGdiCombineRgn(Rgn
, Rgn
, UpdateRgn
, RGN_AND
);
1232 IntGdiOffsetRgn(Rgn
, -Window
->rcClient
.left
, -Window
->rcClient
.top
);
1233 RGNOBJAPI_Unlock(UpdateRgn
);
1235 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
1237 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1244 * NtUserGetUpdateRgn
1251 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
1253 DECLARE_RETURN(INT
);
1256 USER_REFERENCE_ENTRY Ref
;
1259 TRACE("Enter NtUserGetUpdateRgn\n");
1260 UserEnterExclusive();
1262 if (!(Window
= UserGetWindowObject(hWnd
)))
1267 /* Use a system region, we can't hold GDI locks when doing roundtrips to user mode */
1268 Rgn
= IntSysCreateRectpRgn(0, 0, 0, 0);
1272 UserRefObjectCo(Window
, &Ref
);
1273 ret
= co_UserGetUpdateRgn(Window
, Rgn
, bErase
);
1274 UserDerefObjectCo(Window
);
1279 if (Rgn
&& (_ret_
!= ERROR
))
1281 PREGION TheRgn
= RGNOBJAPI_Lock(hRgn
, NULL
);
1284 EngSetLastError(ERROR_INVALID_HANDLE
);
1287 IntGdiCombineRgn(TheRgn
, Rgn
, NULL
, RGN_COPY
);
1288 RGNOBJAPI_Unlock(TheRgn
);
1294 TRACE("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
1300 * NtUserGetUpdateRect
1307 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
1312 PROSRGNDATA RgnData
;
1314 DECLARE_RETURN(BOOL
);
1316 TRACE("Enter NtUserGetUpdateRect\n");
1317 UserEnterExclusive();
1319 if (!(Window
= UserGetWindowObject(hWnd
)))
1324 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1326 if (Window
->hrgnUpdate
== NULL
)
1328 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1332 /* Get the update region bounding box. */
1333 if (Window
->hrgnUpdate
== HRGN_WINDOW
)
1335 Rect
= Window
->rcClient
;
1339 RgnData
= RGNOBJAPI_Lock(Window
->hrgnUpdate
, NULL
);
1340 ASSERT(RgnData
!= NULL
);
1341 RegionType
= REGION_GetRgnBox(RgnData
, &Rect
);
1342 RGNOBJAPI_Unlock(RgnData
);
1344 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
1345 RECTL_bIntersectRect(&Rect
, &Rect
, &Window
->rcClient
);
1348 if (IntIntersectWithParents(Window
, &Rect
))
1350 RECTL_vOffsetRect(&Rect
,
1351 -Window
->rcClient
.left
,
1352 -Window
->rcClient
.top
);
1355 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1359 if (bErase
&& !RECTL_bIsEmptyRect(&Rect
))
1361 USER_REFERENCE_ENTRY Ref
;
1362 UserRefObjectCo(Window
, &Ref
);
1363 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1364 UserDerefObjectCo(Window
);
1367 if (UnsafeRect
!= NULL
)
1369 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECTL
));
1370 if (!NT_SUCCESS(Status
))
1372 EngSetLastError(ERROR_INVALID_PARAMETER
);
1377 RETURN(!RECTL_bIsEmptyRect(&Rect
));
1380 TRACE("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1386 * NtUserRedrawWindow
1395 CONST RECT
*lprcUpdate
,
1399 RECTL SafeUpdateRect
;
1402 USER_REFERENCE_ENTRY Ref
;
1403 NTSTATUS Status
= STATUS_SUCCESS
;
1404 PREGION RgnUpdate
= NULL
;
1405 DECLARE_RETURN(BOOL
);
1407 TRACE("Enter NtUserRedrawWindow\n");
1408 UserEnterExclusive();
1410 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1419 ProbeForRead(lprcUpdate
, sizeof(RECTL
), 1);
1420 RtlCopyMemory(&SafeUpdateRect
, lprcUpdate
, sizeof(RECTL
));
1422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1424 Status
= _SEH2_GetExceptionCode();
1427 if (!NT_SUCCESS(Status
))
1429 EngSetLastError(RtlNtStatusToDosError(Status
));
1434 if ( flags
& ~(RDW_ERASE
|RDW_FRAME
|RDW_INTERNALPAINT
|RDW_INVALIDATE
|
1435 RDW_NOERASE
|RDW_NOFRAME
|RDW_NOINTERNALPAINT
|RDW_VALIDATE
|
1436 RDW_ERASENOW
|RDW_UPDATENOW
|RDW_ALLCHILDREN
|RDW_NOCHILDREN
) )
1438 /* RedrawWindow fails only in case that flags are invalid */
1439 EngSetLastError(ERROR_INVALID_FLAGS
);
1443 /* We can't hold lock on GDI obects while doing roundtrips to user mode,
1444 * so use a copy instead */
1449 RgnUpdate
= IntSysCreateRectpRgn(0, 0, 0, 0);
1452 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1456 RgnTemp
= RGNOBJAPI_Lock(hrgnUpdate
, NULL
);
1459 EngSetLastError(ERROR_INVALID_HANDLE
);
1462 IntGdiCombineRgn(RgnUpdate
, RgnTemp
, NULL
, RGN_COPY
);
1463 RGNOBJAPI_Unlock(RgnTemp
);
1466 UserRefObjectCo(Wnd
, &Ref
);
1468 Ret
= co_UserRedrawWindow( Wnd
,
1469 lprcUpdate
? &SafeUpdateRect
: NULL
,
1473 UserDerefObjectCo(Wnd
);
1479 REGION_Delete(RgnUpdate
);
1480 TRACE("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1491 const RECTL
*prcScroll
,
1492 const RECTL
*prcClip
,
1497 RECTL rcScroll
, rcClip
, rcSrc
, rcDst
;
1500 GdiGetClipBox(hDC
, &rcClip
);
1504 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcClip
);
1509 rcScroll
= *prcScroll
;
1510 RECTL_bIntersectRect(&rcSrc
, &rcClip
, prcScroll
);
1518 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1519 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1521 if (!NtGdiBitBlt( hDC
,
1524 rcDst
.right
- rcDst
.left
,
1525 rcDst
.bottom
- rcDst
.top
,
1536 /* Calculate the region that was invalidated by moving or
1537 could not be copied, because it was not visible */
1538 if (RgnUpdate
|| prcUpdate
)
1540 PREGION RgnOwn
, RgnTmp
;
1542 pDC
= DC_LockDc(hDC
);
1548 /* Begin with the shifted and then clipped scroll rect */
1550 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1551 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1555 REGION_SetRectRgn(RgnOwn
, rcDst
.left
, rcDst
.top
, rcDst
.right
, rcDst
.bottom
);
1559 RgnOwn
= IntSysCreateRectpRgnIndirect(&rcDst
);
1562 /* Add the source rect */
1563 RgnTmp
= IntSysCreateRectpRgnIndirect(&rcSrc
);
1564 IntGdiCombineRgn(RgnOwn
, RgnOwn
, RgnTmp
, RGN_OR
);
1566 /* Substract the part of the dest that was visible in source */
1567 IntGdiCombineRgn(RgnTmp
, RgnTmp
, pDC
->prgnVis
, RGN_AND
);
1568 IntGdiOffsetRgn(RgnTmp
, dx
, dy
);
1569 Result
= IntGdiCombineRgn(RgnOwn
, RgnOwn
, RgnTmp
, RGN_DIFF
);
1571 /* DO NOT Unlock DC while messing with prgnVis! */
1574 REGION_Delete(RgnTmp
);
1578 REGION_GetRgnBox(RgnOwn
, prcUpdate
);
1583 REGION_Delete(RgnOwn
);
1587 Result
= NULLREGION
;
1603 const RECT
*prcUnsafeScroll
,
1604 const RECT
*prcUnsafeClip
,
1606 LPRECT prcUnsafeUpdate
)
1608 DECLARE_RETURN(DWORD
);
1609 RECTL rcScroll
, rcClip
, rcUpdate
;
1610 NTSTATUS Status
= STATUS_SUCCESS
;
1612 PREGION RgnUpdate
= NULL
;
1614 TRACE("Enter NtUserScrollDC\n");
1615 UserEnterExclusive();
1619 if (prcUnsafeScroll
)
1621 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1622 rcScroll
= *prcUnsafeScroll
;
1626 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1627 rcClip
= *prcUnsafeClip
;
1629 if (prcUnsafeUpdate
)
1631 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1634 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1636 Status
= _SEH2_GetExceptionCode();
1639 if (!NT_SUCCESS(Status
))
1641 SetLastNtError(Status
);
1647 RgnUpdate
= RGNOBJAPI_Lock(hrgnUpdate
, NULL
);
1652 Result
= UserScrollDC( hDC
,
1655 prcUnsafeScroll
? &rcScroll
: 0,
1656 prcUnsafeClip
? &rcClip
: 0,
1658 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1661 /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
1665 if (prcUnsafeUpdate
)
1669 *prcUnsafeUpdate
= rcUpdate
;
1671 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1673 Status
= _SEH2_GetExceptionCode();
1676 if (!NT_SUCCESS(Status
))
1678 /* FIXME: SetLastError? */
1679 /* FIXME: correct? We have already scrolled! */
1688 RGNOBJAPI_Unlock(RgnUpdate
);
1689 TRACE("Leave NtUserScrollDC, ret=%lu\n",_ret_
);
1695 * NtUserScrollWindowEx
1702 NtUserScrollWindowEx(
1706 const RECT
*prcUnsafeScroll
,
1707 const RECT
*prcUnsafeClip
,
1709 LPRECT prcUnsafeUpdate
,
1712 RECTL rcScroll
, rcClip
, rcCaret
, rcUpdate
;
1714 PWND Window
= NULL
, CaretWnd
;
1716 PREGION RgnUpdate
= NULL
, RgnTemp
, RgnWinupd
= NULL
;
1720 NTSTATUS Status
= STATUS_SUCCESS
;
1721 DECLARE_RETURN(DWORD
);
1722 USER_REFERENCE_ENTRY Ref
, CaretRef
;
1724 TRACE("Enter NtUserScrollWindowEx\n");
1725 UserEnterExclusive();
1727 Window
= UserGetWindowObject(hWnd
);
1728 if (!Window
|| !IntIsWindowDrawable(Window
))
1730 Window
= NULL
; /* prevent deref at cleanup */
1733 UserRefObjectCo(Window
, &Ref
);
1735 IntGetClientRect(Window
, &rcClip
);
1739 if (prcUnsafeScroll
)
1741 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1742 RECTL_bIntersectRect(&rcScroll
, &rcClip
, prcUnsafeScroll
);
1749 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1750 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcUnsafeClip
);
1753 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1755 Status
= _SEH2_GetExceptionCode();
1759 if (!NT_SUCCESS(Status
))
1761 SetLastNtError(Status
);
1765 if (rcClip
.right
<= rcClip
.left
|| rcClip
.bottom
<= rcClip
.top
||
1766 (dx
== 0 && dy
== 0))
1771 /* We must use a copy of the region, as we can't hold an exclusive lock
1772 * on it while doing callouts to user-mode */
1773 RgnUpdate
= IntSysCreateRectpRgn(0, 0, 0, 0);
1776 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1782 RgnTemp
= RGNOBJAPI_Lock(hrgnUpdate
, NULL
);
1785 EngSetLastError(ERROR_INVALID_HANDLE
);
1788 IntGdiCombineRgn(RgnUpdate
, RgnTemp
, NULL
, RGN_COPY
);
1789 RGNOBJAPI_Unlock(RgnTemp
);
1792 /* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
1793 if (flags
& SW_SCROLLWNDDCE
)
1795 dcxflags
= DCX_USESTYLE
;
1797 if (!(Window
->pcls
->style
& (CS_OWNDC
|CS_CLASSDC
)))
1798 dcxflags
|= DCX_CACHE
; // AH??? wine~ If not Powned or with Class go Cheap!
1800 if (flags
& SW_SCROLLCHILDREN
&& Window
->style
& WS_CLIPCHILDREN
)
1801 dcxflags
|= DCX_CACHE
|DCX_NOCLIPCHILDREN
;
1805 /* So in this case ScrollWindowEx uses Cache DC. */
1806 dcxflags
= DCX_CACHE
|DCX_USESTYLE
;
1807 if (flags
& SW_SCROLLCHILDREN
) dcxflags
|= DCX_NOCLIPCHILDREN
;
1810 hDC
= UserGetDCEx(Window
, 0, dcxflags
);
1813 /* FIXME: SetLastError? */
1817 rdw_flags
= (flags
& SW_ERASE
) && (flags
& SW_INVALIDATE
) ? RDW_INVALIDATE
| RDW_ERASE
: RDW_INVALIDATE
;
1820 hwndCaret
= co_IntFixCaret(Window
, &rcCaret
, flags
);
1822 Result
= UserScrollDC( hDC
,
1828 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1830 UserReleaseDC(Window
, hDC
, FALSE
);
1833 * Take into account the fact that some damage may have occurred during
1834 * the scroll. Keep a copy in hrgnWinupd to be added to hrngUpdate at the end.
1837 RgnTemp
= IntSysCreateRectpRgn(0, 0, 0, 0);
1840 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1844 if (co_UserGetUpdateRgn(Window
, RgnTemp
, FALSE
) != NULLREGION
)
1846 PREGION RgnClip
= IntSysCreateRectpRgnIndirect(&rcClip
);
1851 RgnWinupd
= IntSysCreateRectpRgn( 0, 0, 0, 0);
1852 IntGdiCombineRgn( RgnWinupd
, RgnTemp
, 0, RGN_COPY
);
1854 IntGdiOffsetRgn(RgnTemp
, dx
, dy
);
1855 IntGdiCombineRgn(RgnTemp
, RgnTemp
, RgnClip
, RGN_AND
);
1857 IntGdiCombineRgn( RgnWinupd
, RgnWinupd
, RgnTemp
, RGN_OR
);
1858 co_UserRedrawWindow(Window
, NULL
, RgnTemp
, rdw_flags
);
1859 REGION_Delete(RgnClip
);
1862 REGION_Delete(RgnTemp
);
1864 if (flags
& SW_SCROLLCHILDREN
)
1869 USER_REFERENCE_ENTRY WndRef
;
1872 IntGetClientOrigin(Window
, &ClientOrigin
);
1873 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
1875 rcChild
= Child
->rcWindow
;
1876 rcChild
.left
-= ClientOrigin
.x
;
1877 rcChild
.top
-= ClientOrigin
.y
;
1878 rcChild
.right
-= ClientOrigin
.x
;
1879 rcChild
.bottom
-= ClientOrigin
.y
;
1881 if (! prcUnsafeScroll
|| RECTL_bIntersectRect(&rcDummy
, &rcChild
, &rcScroll
))
1883 UserRefObjectCo(Child
, &WndRef
);
1884 co_WinPosSetWindowPos(Child
, 0, rcChild
.left
+ dx
, rcChild
.top
+ dy
, 0, 0,
1885 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1886 SWP_NOREDRAW
| SWP_DEFERERASE
);
1887 UserDerefObjectCo(Child
);
1892 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1894 co_UserRedrawWindow(Window
, NULL
, RgnUpdate
, rdw_flags
|
1895 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1896 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1899 if (hwndCaret
&& (CaretWnd
= UserGetWindowObject(hwndCaret
)))
1901 UserRefObjectCo(CaretWnd
, &CaretRef
);
1903 co_IntSetCaretPos(rcCaret
.left
+ dx
, rcCaret
.top
+ dy
);
1904 co_UserShowCaret(CaretWnd
);
1906 UserDerefObjectCo(CaretWnd
);
1909 if (prcUnsafeUpdate
)
1913 /* Probe here, to not fail on invalid pointer before scrolling */
1914 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1915 *prcUnsafeUpdate
= rcUpdate
;
1917 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1919 Status
= _SEH2_GetExceptionCode();
1923 if (!NT_SUCCESS(Status
))
1925 SetLastNtError(Status
);
1933 if (hrgnUpdate
&& (_ret_
!= ERROR
))
1935 /* Give everything back to the caller */
1936 RgnTemp
= RGNOBJAPI_Lock(hrgnUpdate
, NULL
);
1937 /* The handle should still be valid */
1940 IntGdiCombineRgn(RgnTemp
, RgnUpdate
, RgnWinupd
, RGN_OR
);
1942 IntGdiCombineRgn(RgnTemp
, RgnUpdate
, NULL
, RGN_COPY
);
1943 RGNOBJAPI_Unlock(RgnTemp
);
1948 REGION_Delete(RgnWinupd
);
1953 REGION_Delete(RgnUpdate
);
1957 UserDerefObjectCo(Window
);
1959 TRACE("Leave NtUserScrollWindowEx, ret=%lu\n",_ret_
);
1965 UserDrawCaptionText(
1967 const PUNICODE_STRING Text
,
1972 HFONT hOldFont
= NULL
;
1973 COLORREF OldTextColor
;
1974 NONCLIENTMETRICSW nclm
;
1976 BOOLEAN bDeleteFont
= FALSE
;
1979 TRACE("UserDrawCaptionText: %wZ\n", Text
);
1981 nclm
.cbSize
= sizeof(nclm
);
1982 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1983 sizeof(NONCLIENTMETRICS
), &nclm
, 0))
1985 ERR("UserSystemParametersInfo() failed!\n");
1991 if(uFlags
& DC_SMALLCAP
)
1992 Status
= TextIntCreateFontIndirect(&nclm
.lfSmCaptionFont
, &hFont
);
1994 Status
= TextIntCreateFontIndirect(&nclm
.lfCaptionFont
, &hFont
);
1996 if(!NT_SUCCESS(Status
))
1998 ERR("TextIntCreateFontIndirect() failed! Status: 0x%x\n", Status
);
2005 IntGdiSetBkMode(hDc
, TRANSPARENT
);
2007 hOldFont
= NtGdiSelectFont(hDc
, hFont
);
2010 ERR("SelectFont() failed!\n");
2014 if(uFlags
& DC_INBUTTON
)
2015 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(COLOR_BTNTEXT
));
2017 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(uFlags
& DC_ACTIVE
2018 ? COLOR_CAPTIONTEXT
: COLOR_INACTIVECAPTIONTEXT
));
2020 // FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
2021 GreGetTextExtentW(hDc
, Text
->Buffer
, Text
->Length
/sizeof(WCHAR
), &Size
, 0);
2023 lpRc
->left
, (lpRc
->top
+ lpRc
->bottom
)/2 - Size
.cy
/2,
2024 0, NULL
, Text
->Buffer
, Text
->Length
/sizeof(WCHAR
), NULL
, 0);
2026 IntGdiSetTextColor(hDc
, OldTextColor
);
2028 NtGdiSelectFont(hDc
, hOldFont
);
2030 GreDeleteObject(hFont
);
2035 BOOL
UserDrawCaption(
2041 const PUNICODE_STRING Str
,
2045 HBRUSH hBgBrush
, hOldBrush
= NULL
;
2049 RECTL_vMakeWellOrdered(lpRc
);
2051 if (!hIcon
&& pWnd
!= NULL
)
2053 HasIcon
= (uFlags
& DC_ICON
) && (pWnd
->style
& WS_SYSMENU
)
2054 && !(uFlags
& DC_SMALLCAP
) && !(pWnd
->ExStyle
& WS_EX_DLGMODALFRAME
)
2055 && !(pWnd
->ExStyle
& WS_EX_TOOLWINDOW
);
2058 HasIcon
= (hIcon
!= 0);
2060 // Draw the caption background
2061 if((uFlags
& DC_GRADIENT
) && !(uFlags
& DC_INBUTTON
))
2063 static GRADIENT_RECT gcap
= {0, 1};
2064 TRIVERTEX Vertices
[2];
2067 Colors
[0] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
2068 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
2070 Colors
[1] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
2071 COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
2073 Vertices
[0].x
= Rect
.left
;
2074 Vertices
[0].y
= Rect
.top
;
2075 Vertices
[0].Red
= (WORD
)Colors
[0]<<8;
2076 Vertices
[0].Green
= (WORD
)Colors
[0] & 0xFF00;
2077 Vertices
[0].Blue
= (WORD
)(Colors
[0]>>8) & 0xFF00;
2078 Vertices
[0].Alpha
= 0;
2080 Vertices
[1].x
= Rect
.right
;
2081 Vertices
[1].y
= Rect
.bottom
;
2082 Vertices
[1].Red
= (WORD
)Colors
[1]<<8;
2083 Vertices
[1].Green
= (WORD
)Colors
[1] & 0xFF00;
2084 Vertices
[1].Blue
= (WORD
)(Colors
[1]>>8) & 0xFF00;
2085 Vertices
[1].Alpha
= 0;
2087 if(!GreGradientFill(hDc
, Vertices
, 2, &gcap
, 1, GRADIENT_FILL_RECT_H
))
2089 ERR("GreGradientFill() failed!\n");
2095 if(uFlags
& DC_INBUTTON
)
2096 hBgBrush
= IntGetSysColorBrush(COLOR_3DFACE
);
2097 else if(uFlags
& DC_ACTIVE
)
2098 hBgBrush
= IntGetSysColorBrush(COLOR_ACTIVECAPTION
);
2100 hBgBrush
= IntGetSysColorBrush(COLOR_INACTIVECAPTION
);
2102 hOldBrush
= NtGdiSelectBrush(hDc
, hBgBrush
);
2106 ERR("NtGdiSelectBrush() failed!\n");
2110 if(!NtGdiPatBlt(hDc
, Rect
.left
, Rect
.top
,
2111 Rect
.right
- Rect
.left
,
2112 Rect
.bottom
- Rect
.top
,
2115 ERR("NtGdiPatBlt() failed!\n");
2123 PCURICON_OBJECT pIcon
= NULL
;
2127 pIcon
= UserGetCurIconObject(hIcon
);
2131 pIcon
= NC_IconForWindow(pWnd
);
2132 // FIXME: NC_IconForWindow should reference it for us */
2134 UserReferenceObject(pIcon
);
2139 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
2140 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
2141 LONG x
= Rect
.left
- cx
/2 + 1 + (Rect
.bottom
- Rect
.top
)/2; // this is really what Window does
2142 LONG y
= (Rect
.top
+ Rect
.bottom
)/2 - cy
/2; // center
2143 UserDrawIconEx(hDc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
2144 UserDereferenceObject(pIcon
);
2153 Rect
.left
+= Rect
.bottom
- Rect
.top
;
2155 if((uFlags
& DC_TEXT
))
2160 UserDrawCaptionText(hDc
, Str
, &Rect
, uFlags
, hFont
);
2161 else if (pWnd
!= NULL
) // FIXME: Windows does not do that
2163 UNICODE_STRING ustr
;
2164 ustr
.Buffer
= pWnd
->strName
.Buffer
; // FIXME: LARGE_STRING truncated!
2165 ustr
.Length
= (USHORT
)min(pWnd
->strName
.Length
, MAXUSHORT
);
2166 ustr
.MaximumLength
= (USHORT
)min(pWnd
->strName
.MaximumLength
, MAXUSHORT
);
2167 UserDrawCaptionText(hDc
, &ustr
, &Rect
, uFlags
, hFont
);
2174 if (hOldBrush
) NtGdiSelectBrush(hDc
, hOldBrush
);
2181 UserRealizePalette(HDC hdc
)
2183 HWND hWnd
, hWndDesktop
;
2186 Ret
= IntGdiRealizePalette(hdc
);
2187 if (Ret
) // There was a change.
2189 hWnd
= IntWindowFromDC(hdc
);
2190 if (hWnd
) // Send broadcast if dc is associated with a window.
2191 { // FYI: Thread locked in CallOneParam.
2192 hWndDesktop
= IntGetDesktopWindow();
2193 if ( hWndDesktop
!= hWnd
)
2195 PWND pWnd
= UserGetWindowObject(hWndDesktop
);
2196 ERR("RealizePalette Desktop.");
2197 hdc
= UserGetWindowDC(pWnd
);
2198 IntPaintDesktop(hdc
);
2199 UserReleaseDC(pWnd
,hdc
,FALSE
);
2201 UserSendNotifyMessage((HWND
)HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0);
2209 NtUserDrawCaptionTemp(
2215 const PUNICODE_STRING str
,
2219 UNICODE_STRING SafeStr
= {0};
2220 NTSTATUS Status
= STATUS_SUCCESS
;
2224 UserEnterExclusive();
2228 if(!(pWnd
= UserGetWindowObject(hWnd
)))
2237 ProbeForRead(lpRc
, sizeof(RECTL
), sizeof(ULONG
));
2238 RtlCopyMemory(&SafeRect
, lpRc
, sizeof(RECTL
));
2241 SafeStr
= ProbeForReadUnicodeString(str
);
2242 if (SafeStr
.Length
!= 0)
2244 ProbeForRead( SafeStr
.Buffer
,
2250 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2252 Status
= _SEH2_GetExceptionCode();
2256 if (Status
!= STATUS_SUCCESS
)
2258 SetLastNtError(Status
);
2264 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, &SafeStr
, uFlags
);
2266 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, NULL
, uFlags
);
2274 NtUserDrawCaption(HWND hWnd
,
2279 return NtUserDrawCaptionTemp(hWnd
, hDC
, lpRc
, 0, 0, NULL
, uFlags
);
2284 NtUserInvalidateRect(
2286 CONST RECT
*lpUnsafeRect
,
2289 UINT flags
= RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0);
2292 flags
= RDW_ALLCHILDREN
| RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ERASENOW
;
2293 lpUnsafeRect
= NULL
;
2295 return NtUserRedrawWindow(hWnd
, lpUnsafeRect
, NULL
, flags
);
2300 NtUserInvalidateRgn(
2307 EngSetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2310 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2323 UserEnterExclusive();
2327 if (!(Window
= UserGetWindowObject(hwnd
)) || // FIXME:
2328 Window
== UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2329 Window
== UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2336 /* Validate flags and check it as a mask for 0 or 1. */
2337 if ( (nFlags
& PW_CLIENTONLY
) == nFlags
)
2338 Ret
= IntPrintWindow( Window
, hdcBlt
, nFlags
);
2340 EngSetLastError(ERROR_INVALID_PARAMETER
);
2348 /* ValidateRect gets redirected to NtUserValidateRect:
2349 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */
2356 UINT flags
= RDW_VALIDATE
;
2359 flags
= RDW_ALLCHILDREN
| RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ERASENOW
;
2362 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, flags
);