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
, HRGN hValidateRgn
, 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
)
101 PUSER_MESSAGE_QUEUE MessageQueue
;
102 PUSER_SENT_MESSAGE Message
;
106 MessageQueue
= Wnd
->head
.pti
->MessageQueue
;
107 ptiCur
= PsGetCurrentThreadWin32Thread();
109 Not the current thread, Wnd is in send Nonclient paint also in send erase background and it is visiable.
111 if ( Wnd
->head
.pti
!= ptiCur
&&
112 Wnd
->state
& WNDS_SENDNCPAINT
&&
113 Wnd
->state
& WNDS_SENDERASEBACKGROUND
&&
114 Wnd
->style
& WS_VISIBLE
)
116 // For testing, if you see this, break out the Champagne and have a party!
117 ERR("SendSyncPaint Wnd in State!\n");
118 if (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
120 // Scan sent queue messages to see if we received sync paint messages.
121 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
122 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
126 if (Message
->Msg
.message
== WM_SYNCPAINT
&&
127 Message
->Msg
.hwnd
== UserHMGetHandle(Wnd
))
128 { // Already received so exit out.
129 ERR("SendSyncPaint Found one in the Sent Msg Queue!\n");
133 Entry
= Message
->ListEntry
.Flink
;
134 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
136 while (Entry
!= &MessageQueue
->SentMessagesListHead
);
140 ERR("Sending WM_SYNCPAINT\n");
141 // This message has no parameters. But it does! Pass Flags along.
142 co_IntSendMessageNoWait(UserHMGetHandle(Wnd
), WM_SYNCPAINT
, Flags
, 0);
143 Wnd
->state
|= WNDS_SYNCPAINTPENDING
;
147 // Send to all the children if this is the desktop window.
148 if ( Wnd
== UserGetDesktopWindow() )
150 if ( Flags
& RDW_ALLCHILDREN
||
151 ( !(Flags
& RDW_NOCHILDREN
) && Wnd
->style
& WS_CLIPCHILDREN
))
153 PWND spwndChild
= Wnd
->spwndChild
;
156 if ( spwndChild
->style
& WS_CHILD
&&
157 spwndChild
->head
.pti
!= ptiCur
)
159 spwndChild
= spwndChild
->spwndNext
;
162 IntSendSyncPaint( spwndChild
, Flags
);
163 spwndChild
= spwndChild
->spwndNext
;
170 * @name IntCalcWindowRgn
172 * Get a window or client region.
176 IntCalcWindowRgn(PWND Wnd
, BOOL Client
)
181 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcClient
);
183 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcWindow
);
185 if (Wnd
->hrgnClip
!= NULL
&& !(Wnd
->style
& WS_MINIMIZE
))
187 NtGdiOffsetRgn(hRgnWindow
,
190 NtGdiCombineRgn(hRgnWindow
, hRgnWindow
, Wnd
->hrgnClip
, RGN_AND
);
191 NtGdiOffsetRgn(hRgnWindow
,
200 * @name IntGetNCUpdateRgn
202 * Get non-client update region of a window and optionally validate it.
205 * Pointer to window to get the NC update region from.
207 * Set to TRUE to force validating the NC update region.
210 * Handle to NC update region. The caller is responsible for deleting
215 IntGetNCUpdateRgn(PWND Window
, BOOL Validate
)
221 if (Window
->hrgnUpdate
!= NULL
&&
222 Window
->hrgnUpdate
!= HRGN_WINDOW
)
224 hRgnNonClient
= IntCalcWindowRgn(Window
, FALSE
);
227 * If region creation fails it's safe to fallback to whole
230 if (hRgnNonClient
== NULL
)
235 hRgnWindow
= IntCalcWindowRgn(Window
, TRUE
);
236 if (hRgnWindow
== NULL
)
238 GreDeleteObject(hRgnNonClient
);
242 RgnType
= NtGdiCombineRgn(hRgnNonClient
, hRgnNonClient
,
243 hRgnWindow
, RGN_DIFF
);
244 if (RgnType
== ERROR
)
246 GreDeleteObject(hRgnWindow
);
247 GreDeleteObject(hRgnNonClient
);
250 else if (RgnType
== NULLREGION
)
252 GreDeleteObject(hRgnWindow
);
253 GreDeleteObject(hRgnNonClient
);
254 Window
->state
&= ~WNDS_UPDATEDIRTY
;
259 * Remove the nonclient region from the standard update region if
260 * we were asked for it.
265 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
,
266 hRgnWindow
, RGN_AND
) == NULLREGION
)
268 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
269 GreDeleteObject(Window
->hrgnUpdate
);
270 Window
->state
&= ~WNDS_UPDATEDIRTY
;
271 Window
->hrgnUpdate
= NULL
;
272 if (!(Window
->state
& WNDS_INTERNALPAINT
))
273 MsqDecPaintCountQueue(Window
->head
.pti
->MessageQueue
);
277 GreDeleteObject(hRgnWindow
);
279 return hRgnNonClient
;
283 return Window
->hrgnUpdate
;
290 * Internal function used by IntRedrawWindow.
294 co_IntPaintWindows(PWND Wnd
, ULONG Flags
, BOOL Recurse
)
297 HWND hWnd
= Wnd
->head
.h
;
300 Wnd
->state
&= ~WNDS_PAINTNOTPROCESSED
;
302 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
306 if (!IntValidateParent(Wnd
, Wnd
->hrgnUpdate
, Recurse
))
310 if (Flags
& RDW_UPDATENOW
)
312 if ((Wnd
->hrgnUpdate
!= NULL
||
313 Wnd
->state
& WNDS_INTERNALPAINT
))
315 Wnd
->state2
|= WNDS2_WMPAINTSENT
;
316 co_IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
319 else if (Wnd
->head
.pti
== PsGetCurrentThreadWin32Thread())
321 if (Wnd
->state
& WNDS_SENDNCPAINT
)
323 TempRegion
= IntGetNCUpdateRgn(Wnd
, TRUE
);
324 Wnd
->state
&= ~WNDS_SENDNCPAINT
;
325 if ( Wnd
== GetW32ThreadInfo()->MessageQueue
->spwndActive
&&
326 !(Wnd
->state
& WNDS_ACTIVEFRAME
))
328 Wnd
->state
|= WNDS_ACTIVEFRAME
;
329 Wnd
->state
&= ~WNDS_NONCPAINT
;
331 if (TempRegion
) co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)TempRegion
, 0);
334 if (Wnd
->state
& WNDS_SENDERASEBACKGROUND
)
338 hDC
= UserGetDCEx( Wnd
,
340 DCX_CACHE
|DCX_USESTYLE
|DCX_INTERSECTRGN
|DCX_KEEPCLIPRGN
);
342 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
343 // Kill the loop, so Clear before we send.
344 if (!co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
346 Wnd
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
348 UserReleaseDC(Wnd
, hDC
, FALSE
);
355 Wnd
->state
&= ~(WNDS_SENDNCPAINT
|WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
359 * Check that the window is still valid at this point
361 if (!IntIsWindow(hWnd
))
367 * Paint child windows.
369 if (!(Flags
& RDW_NOCHILDREN
) &&
370 !(Wnd
->style
& WS_MINIMIZE
) &&
371 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)) )
375 if ((List
= IntWinListChildren(Wnd
)))
377 /* FIXME: Handle WS_EX_TRANSPARENT */
378 for (phWnd
= List
; *phWnd
; ++phWnd
)
380 Wnd
= UserGetWindowObject(*phWnd
);
381 if (Wnd
&& (Wnd
->style
& WS_VISIBLE
))
383 USER_REFERENCE_ENTRY Ref
;
384 UserRefObjectCo(Wnd
, &Ref
);
385 co_IntPaintWindows(Wnd
, Flags
, TRUE
);
386 UserDerefObjectCo(Wnd
);
389 ExFreePoolWithTag(List
, USERTAG_WINDOWLIST
);
395 * IntInvalidateWindows
397 * Internal function used by IntRedrawWindow, UserRedrawDesktop,
398 * co_WinPosSetWindowPos, IntValidateParent, co_UserRedrawWindow.
401 IntInvalidateWindows(PWND Wnd
, HRGN hRgn
, ULONG Flags
)
404 BOOL HadPaintMessage
;
406 TRACE("IntInvalidateWindows start\n");
408 Wnd
->state
|= WNDS_PAINTNOTPROCESSED
;
411 * If the nonclient is not to be redrawn, clip the region to the client
414 if (0 != (Flags
& RDW_INVALIDATE
) && 0 == (Flags
& RDW_FRAME
))
418 hRgnClient
= IntSysCreateRectRgnIndirect(&Wnd
->rcClient
);
419 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnClient
, RGN_AND
);
420 GreDeleteObject(hRgnClient
);
424 * Clip the given region with window rectangle (or region)
427 if (!Wnd
->hrgnClip
|| (Wnd
->style
& WS_MINIMIZE
))
431 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcWindow
);
432 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
433 GreDeleteObject(hRgnWindow
);
437 NtGdiOffsetRgn( hRgn
,
440 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Wnd
->hrgnClip
, RGN_AND
);
441 NtGdiOffsetRgn( hRgn
,
447 * Save current state of pending updates
450 HadPaintMessage
= IntIsWindowDirty(Wnd
);
453 * Update the region and flags
456 // The following flags are used to invalidate the window.
457 if (Flags
& (RDW_INVALIDATE
|RDW_INTERNALPAINT
|RDW_ERASE
|RDW_FRAME
))
459 if (Flags
& RDW_INTERNALPAINT
)
461 Wnd
->state
|= WNDS_INTERNALPAINT
;
464 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
466 Wnd
->state
&= ~WNDS_NONCPAINT
;
468 /* If not the same thread set it dirty. */
469 if (Wnd
->head
.pti
!= PsGetCurrentThreadWin32Thread())
471 Wnd
->state
|= WNDS_UPDATEDIRTY
;
472 if (Wnd
->state2
& WNDS2_WMPAINTSENT
)
473 Wnd
->state2
|= WNDS2_ENDPAINTINVALIDATE
;
476 if (Flags
& RDW_FRAME
)
477 Wnd
->state
|= WNDS_SENDNCPAINT
;
478 if (Flags
& RDW_ERASE
)
479 Wnd
->state
|= WNDS_SENDERASEBACKGROUND
;
481 if (Wnd
->hrgnUpdate
== NULL
)
483 Wnd
->hrgnUpdate
= IntSysCreateRectRgn(0, 0, 0, 0);
484 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_PUBLIC
);
487 if (NtGdiCombineRgn(Wnd
->hrgnUpdate
, Wnd
->hrgnUpdate
,
488 hRgn
, RGN_OR
) == NULLREGION
)
490 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
491 GreDeleteObject(Wnd
->hrgnUpdate
);
492 Wnd
->hrgnUpdate
= NULL
;
494 Flags
|= RDW_FRAME
; // For children.
496 } // The following flags are used to validate the window.
497 else if (Flags
& (RDW_VALIDATE
|RDW_NOINTERNALPAINT
|RDW_NOERASE
|RDW_NOFRAME
))
499 /* FIXME: Handle WNDS_UPDATEDIRTY */
501 if (Flags
& RDW_NOINTERNALPAINT
)
503 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
506 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
508 if (Flags
& RDW_NOFRAME
)
509 Wnd
->state
&= ~WNDS_SENDNCPAINT
;
510 if (Flags
& RDW_NOERASE
)
511 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
513 if (Wnd
->hrgnUpdate
!= NULL
)
515 if (NtGdiCombineRgn(Wnd
->hrgnUpdate
, Wnd
->hrgnUpdate
,
516 hRgn
, RGN_DIFF
) == NULLREGION
)
518 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
519 GreDeleteObject(Wnd
->hrgnUpdate
);
520 Wnd
->hrgnUpdate
= NULL
;
524 if (Wnd
->hrgnUpdate
== NULL
)
525 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
530 * Process children if needed
533 if (!(Flags
& RDW_NOCHILDREN
) && !(Wnd
->style
& WS_MINIMIZE
) &&
534 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)))
538 for (Child
= Wnd
->spwndChild
; Child
; Child
= Child
->spwndNext
)
540 if (Child
->style
& WS_VISIBLE
)
543 * Recursive call to update children hrgnUpdate
545 HRGN hRgnTemp
= IntSysCreateRectRgn(0, 0, 0, 0);
546 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
547 IntInvalidateWindows(Child
, hRgnTemp
, Flags
);
548 GreDeleteObject(hRgnTemp
);
554 * Fake post paint messages to window message queue if needed
557 if (HadPaintMessage
!= IntIsWindowDirty(Wnd
))
560 MsqDecPaintCountQueue(Wnd
->head
.pti
->MessageQueue
);
562 MsqIncPaintCountQueue(Wnd
->head
.pti
->MessageQueue
);
564 TRACE("IntInvalidateWindows exit\n");
568 * IntIsWindowDrawable
571 * Window is drawable when it is visible and all parents are not
576 IntIsWindowDrawable(PWND Wnd
)
580 for (WndObject
= Wnd
; WndObject
!= NULL
; WndObject
= WndObject
->spwndParent
)
582 if ( WndObject
->state2
& WNDS2_INDESTROY
||
583 WndObject
->state
& WNDS_DESTROYED
||
585 !(WndObject
->style
& WS_VISIBLE
) ||
586 ((WndObject
->style
& WS_MINIMIZE
) && (WndObject
!= Wnd
)))
598 * Internal version of NtUserRedrawWindow that takes WND as
605 const RECTL
* UpdateRect
,
610 TRACE("co_UserRedrawWindow start\n");
614 * Validation of passed parameters.
617 if (!IntIsWindowDrawable(Window
))
619 return TRUE
; // Just do nothing!!!
624 * Transform the parameters UpdateRgn and UpdateRect into
625 * a region hRgn specified in screen coordinates.
628 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
)) // Both are OKAY!
630 if (UpdateRgn
!= NULL
)
632 hRgn
= IntSysCreateRectRgn(0, 0, 0, 0);
633 if (NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
) == NULLREGION
)
635 GreDeleteObject(hRgn
);
639 NtGdiOffsetRgn(hRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
641 else if (UpdateRect
!= NULL
)
643 if (!RECTL_bIsEmptyRect(UpdateRect
))
645 hRgn
= IntSysCreateRectRgnIndirect((RECTL
*)UpdateRect
);
646 NtGdiOffsetRgn(hRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
649 else if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
650 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
652 if (!RECTL_bIsEmptyRect(&Window
->rcWindow
))
653 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcWindow
);
657 if (!RECTL_bIsEmptyRect(&Window
->rcClient
))
658 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcClient
);
664 * Adjust the window update region depending on hRgn and flags.
667 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
) &&
670 IntInvalidateWindows(Window
, hRgn
, Flags
);
675 * Repaint and erase windows if needed.
678 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
680 if (Flags
& RDW_ERASENOW
) IntSendSyncPaint(Window
, Flags
);
681 co_IntPaintWindows(Window
, Flags
, FALSE
);
691 GreDeleteObject(hRgn
);
693 TRACE("co_UserRedrawWindow exit\n");
699 IntIsWindowDirty(PWND Wnd
)
701 return ( Wnd
->style
& WS_VISIBLE
&&
702 ( Wnd
->hrgnUpdate
!= NULL
||
703 Wnd
->state
& WNDS_INTERNALPAINT
) );
707 IntFindWindowToRepaint(PWND Window
, PTHREADINFO Thread
)
712 for (; Window
!= NULL
; Window
= Window
->spwndNext
)
714 if (IntWndBelongsToThread(Window
, Thread
) &&
715 IntIsWindowDirty(Window
))
717 /* Make sure all non-transparent siblings are already drawn. */
718 if (Window
->ExStyle
& WS_EX_TRANSPARENT
)
720 for (TempWindow
= Window
->spwndNext
; TempWindow
!= NULL
;
721 TempWindow
= TempWindow
->spwndNext
)
723 if (!(TempWindow
->ExStyle
& WS_EX_TRANSPARENT
) &&
724 IntWndBelongsToThread(TempWindow
, Thread
) &&
725 IntIsWindowDirty(TempWindow
))
735 if (Window
->spwndChild
)
737 hChild
= IntFindWindowToRepaint(Window
->spwndChild
, Thread
);
756 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
757 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
760 if (Thread
->TIF_flags
& TIF_SYSTEMTHREAD
)
762 ERR("WM_PAINT is in a System Thread!\n");
765 PaintWnd
= IntFindWindowToRepaint(UserGetDesktopWindow(), Thread
);
767 Message
->hwnd
= PaintWnd
? UserHMGetHandle(PaintWnd
) : NULL
;
769 if (Message
->hwnd
== NULL
)
771 ERR("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found! Counts %d\n",Thread
->cPaintsReady
);
772 /* Hack to stop spamming the debuglog ! */
773 Thread
->cPaintsReady
= 0;
777 if (Window
!= NULL
&& PaintWnd
!= Window
)
780 if (PaintWnd
->state
& WNDS_INTERNALPAINT
)
782 PaintWnd
->state
&= ~WNDS_INTERNALPAINT
;
783 if (!PaintWnd
->hrgnUpdate
)
784 MsqDecPaintCountQueue(Thread
->MessageQueue
);
786 PaintWnd
->state2
&= ~WNDS2_WMPAINTSENT
;
787 PaintWnd
->state
&= ~WNDS_UPDATEDIRTY
;
788 Message
->wParam
= Message
->lParam
= 0;
789 Message
->message
= WM_PAINT
;
795 co_IntFixCaret(PWND Window
, RECTL
*lprc
, UINT flags
)
798 PTHRDCARETINFO CaretInfo
;
800 PUSER_MESSAGE_QUEUE ActiveMessageQueue
;
804 ASSERT_REFS_CO(Window
);
806 pti
= PsGetCurrentThreadWin32Thread();
807 Desktop
= pti
->rpdesk
;
808 ActiveMessageQueue
= Desktop
->ActiveMessageQueue
;
809 if (!ActiveMessageQueue
) return 0;
810 CaretInfo
= ActiveMessageQueue
->CaretInfo
;
811 hWndCaret
= CaretInfo
->hWnd
;
813 WndCaret
= ValidateHwndNoErr(hWndCaret
);
815 // FIXME: Check for WndCaret can be NULL
816 if (WndCaret
== Window
||
817 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(Window
, WndCaret
)))
819 POINT pt
, FromOffset
, ToOffset
;
822 pt
.x
= CaretInfo
->Pos
.x
;
823 pt
.y
= CaretInfo
->Pos
.y
;
824 IntGetClientOrigin(WndCaret
, &FromOffset
);
825 IntGetClientOrigin(Window
, &ToOffset
);
828 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
829 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
830 if (RECTL_bIntersectRect(lprc
, lprc
, &rcCaret
))
850 INT cx
, cy
, xSrc
, ySrc
;
852 if ( nFlags
& PW_CLIENTONLY
)
854 cx
= pwnd
->rcClient
.right
- pwnd
->rcClient
.left
;
855 cy
= pwnd
->rcClient
.bottom
- pwnd
->rcClient
.top
;
856 xSrc
= pwnd
->rcClient
.left
- pwnd
->rcWindow
.left
;
857 ySrc
= pwnd
->rcClient
.top
- pwnd
->rcWindow
.top
;
861 cx
= pwnd
->rcWindow
.right
- pwnd
->rcWindow
.left
;
862 cy
= pwnd
->rcWindow
.bottom
- pwnd
->rcWindow
.top
;
867 // TODO: Setup Redirection for Print.
870 /* Update the window just incase. */
871 co_IntPaintWindows( pwnd
, RDW_ERASENOW
|RDW_UPDATENOW
, FALSE
);
873 hdcSrc
= UserGetDCEx( pwnd
, NULL
, DCX_CACHE
|DCX_WINDOW
);
874 /* Print window to printer context. */
887 UserReleaseDC( pwnd
, hdcSrc
, FALSE
);
889 // TODO: Release Redirection from Print.
896 IntFlashWindowEx(PWND pWnd
, PFLASHWINFO pfwi
)
902 pprop
= IntGetProp(pWnd
, AtomFlashWndState
);
905 FlashState
= pfwi
->dwFlags
;
906 IntSetProp(pWnd
, AtomFlashWndState
, (HANDLE
) FlashState
);
910 FlashState
= (DWORD
)pprop
->Data
;
911 if ( pfwi
->dwFlags
== FLASHW_STOP
)
913 IntRemoveProp(pWnd
, AtomFlashWndState
);
920 IntBeginPaint(PWND Window
, PPAINTSTRUCT Ps
)
922 co_UserHideCaret(Window
);
924 Window
->state2
|= WNDS2_STARTPAINT
;
925 Window
->state
&= ~WNDS_PAINTNOTPROCESSED
;
927 if (Window
->state
& WNDS_SENDNCPAINT
)
931 Window
->state
&= ~WNDS_UPDATEDIRTY
;
932 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
933 Window
->state
&= ~WNDS_SENDNCPAINT
;
934 co_IntSendMessage(UserHMGetHandle(Window
), WM_NCPAINT
, (WPARAM
)hRgn
, 0);
935 if (hRgn
!= HRGN_WINDOW
&& hRgn
!= NULL
&& GreIsHandleValid(hRgn
))
937 /* NOTE: The region can already be deleted! */
938 GreDeleteObject(hRgn
);
943 Window
->state
&= ~WNDS_UPDATEDIRTY
;
946 RtlZeroMemory(Ps
, sizeof(PAINTSTRUCT
));
948 Ps
->hdc
= UserGetDCEx( Window
,
950 DCX_INTERSECTRGN
| DCX_USESTYLE
);
956 if (Window
->hrgnUpdate
!= NULL
)
958 MsqDecPaintCountQueue(Window
->head
.pti
->MessageQueue
);
959 GdiGetClipBox(Ps
->hdc
, &Ps
->rcPaint
);
960 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
961 /* The region is part of the dc now and belongs to the process! */
962 Window
->hrgnUpdate
= NULL
;
966 if (Window
->state
& WNDS_INTERNALPAINT
)
967 MsqDecPaintCountQueue(Window
->head
.pti
->MessageQueue
);
969 IntGetClientRect(Window
, &Ps
->rcPaint
);
972 Window
->state
&= ~WNDS_INTERNALPAINT
;
974 if (Window
->state
& WNDS_SENDERASEBACKGROUND
)
976 Window
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
977 Ps
->fErase
= !co_IntSendMessage(UserHMGetHandle(Window
), WM_ERASEBKGND
, (WPARAM
)Ps
->hdc
, 0);
980 Window
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
987 if (Window
->hrgnUpdate
)
989 if (!(Window
->style
& WS_CLIPCHILDREN
))
992 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
994 if (Child
->hrgnUpdate
== NULL
&& Child
->state
& WNDS_SENDNCPAINT
) // Helped fixing test_redrawnow.
995 IntInvalidateWindows(Child
, Window
->hrgnUpdate
, RDW_FRAME
| RDW_ERASE
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
1003 IntEndPaint(PWND Wnd
, PPAINTSTRUCT Ps
)
1009 UserReleaseDC(Wnd
, hdc
, TRUE
);
1011 Wnd
->state2
&= ~(WNDS2_WMPAINTSENT
|WNDS2_STARTPAINT
);
1013 co_UserShowCaret(Wnd
);
1018 /* PUBLIC FUNCTIONS ***********************************************************/
1028 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
1034 USER_REFERENCE_ENTRY Ref
;
1035 DECLARE_RETURN(HDC
);
1037 TRACE("Enter NtUserBeginPaint\n");
1038 UserEnterExclusive();
1040 if (!(Window
= UserGetWindowObject(hWnd
)))
1045 UserRefObjectCo(Window
, &Ref
);
1047 hDC
= IntBeginPaint(Window
, &Ps
);
1049 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
1050 if (! NT_SUCCESS(Status
))
1052 SetLastNtError(Status
);
1059 if (Window
) UserDerefObjectCo(Window
);
1061 TRACE("Leave NtUserBeginPaint, ret=%p\n",_ret_
);
1075 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* pUnsafePs
)
1077 NTSTATUS Status
= STATUS_SUCCESS
;
1080 USER_REFERENCE_ENTRY Ref
;
1081 DECLARE_RETURN(BOOL
);
1083 TRACE("Enter NtUserEndPaint\n");
1084 UserEnterExclusive();
1086 if (!(Window
= UserGetWindowObject(hWnd
)))
1091 UserRefObjectCo(Window
, &Ref
); // Here for the exception.
1095 ProbeForRead(pUnsafePs
, sizeof(*pUnsafePs
), 1);
1096 RtlCopyMemory(&Ps
, pUnsafePs
, sizeof(PAINTSTRUCT
));
1098 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1100 Status
= _SEH2_GetExceptionCode();
1103 if (!NT_SUCCESS(Status
))
1108 RETURN(IntEndPaint(Window
, &Ps
));
1111 if (Window
) UserDerefObjectCo(Window
);
1113 TRACE("Leave NtUserEndPaint, ret=%i\n",_ret_
);
1122 NtUserFlashWindowEx(IN PFLASHWINFO pfwi
)
1125 FLASHWINFO finfo
= {0};
1128 UserEnterExclusive();
1132 ProbeForRead(pfwi
, sizeof(FLASHWINFO
), sizeof(ULONG
));
1133 RtlCopyMemory(&finfo
, pfwi
, sizeof(FLASHWINFO
));
1135 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1137 SetLastNtError(_SEH2_GetExceptionCode());
1142 if (!Ret
) goto Exit
;
1144 if (!( pWnd
= (PWND
)UserGetObject(gHandleTable
, finfo
.hwnd
, TYPE_WINDOW
)) ||
1145 finfo
.cbSize
!= sizeof(FLASHWINFO
) ||
1146 finfo
.dwFlags
& ~(FLASHW_ALL
|FLASHW_TIMER
|FLASHW_TIMERNOFG
) )
1148 EngSetLastError(ERROR_INVALID_PARAMETER
);
1153 Ret
= IntFlashWindowEx(pWnd
, &finfo
);
1161 co_UserGetUpdateRgn(PWND Window
, HRGN hRgn
, BOOL bErase
)
1166 ASSERT_REFS_CO(Window
);
1168 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1170 if (Window
->hrgnUpdate
== NULL
)
1172 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
1176 Rect
= Window
->rcClient
;
1177 IntIntersectWithParents(Window
, &Rect
);
1178 NtGdiSetRectRgn(hRgn
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
1179 RegionType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->hrgnUpdate
, RGN_AND
);
1180 NtGdiOffsetRgn(hRgn
, -Window
->rcClient
.left
, -Window
->rcClient
.top
);
1183 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
1185 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1192 * NtUserGetUpdateRgn
1199 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
1201 DECLARE_RETURN(INT
);
1204 USER_REFERENCE_ENTRY Ref
;
1206 TRACE("Enter NtUserGetUpdateRgn\n");
1207 UserEnterExclusive();
1209 if (!(Window
= UserGetWindowObject(hWnd
)))
1214 UserRefObjectCo(Window
, &Ref
);
1215 ret
= co_UserGetUpdateRgn(Window
, hRgn
, bErase
);
1216 UserDerefObjectCo(Window
);
1221 TRACE("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
1227 * NtUserGetUpdateRect
1234 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
1239 PROSRGNDATA RgnData
;
1241 DECLARE_RETURN(BOOL
);
1243 TRACE("Enter NtUserGetUpdateRect\n");
1244 UserEnterExclusive();
1246 if (!(Window
= UserGetWindowObject(hWnd
)))
1251 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1253 if (Window
->hrgnUpdate
== NULL
)
1255 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1259 /* Get the update region bounding box. */
1260 if (Window
->hrgnUpdate
== HRGN_WINDOW
)
1262 Rect
= Window
->rcClient
;
1266 RgnData
= RGNOBJAPI_Lock(Window
->hrgnUpdate
, NULL
);
1267 ASSERT(RgnData
!= NULL
);
1268 RegionType
= REGION_GetRgnBox(RgnData
, &Rect
);
1269 RGNOBJAPI_Unlock(RgnData
);
1271 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
1272 RECTL_bIntersectRect(&Rect
, &Rect
, &Window
->rcClient
);
1275 if (IntIntersectWithParents(Window
, &Rect
))
1277 RECTL_vOffsetRect(&Rect
,
1278 -Window
->rcClient
.left
,
1279 -Window
->rcClient
.top
);
1282 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1286 if (bErase
&& !RECTL_bIsEmptyRect(&Rect
))
1288 USER_REFERENCE_ENTRY Ref
;
1289 UserRefObjectCo(Window
, &Ref
);
1290 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1291 UserDerefObjectCo(Window
);
1294 if (UnsafeRect
!= NULL
)
1296 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECTL
));
1297 if (!NT_SUCCESS(Status
))
1299 EngSetLastError(ERROR_INVALID_PARAMETER
);
1304 RETURN(!RECTL_bIsEmptyRect(&Rect
));
1307 TRACE("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1313 * NtUserRedrawWindow
1322 CONST RECT
*lprcUpdate
,
1326 RECTL SafeUpdateRect
;
1329 USER_REFERENCE_ENTRY Ref
;
1330 NTSTATUS Status
= STATUS_SUCCESS
;
1331 DECLARE_RETURN(BOOL
);
1333 TRACE("Enter NtUserRedrawWindow\n");
1334 UserEnterExclusive();
1336 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1345 ProbeForRead(lprcUpdate
, sizeof(RECTL
), 1);
1346 RtlCopyMemory(&SafeUpdateRect
, lprcUpdate
, sizeof(RECTL
));
1348 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1350 Status
= _SEH2_GetExceptionCode();
1353 if (!NT_SUCCESS(Status
))
1355 EngSetLastError(RtlNtStatusToDosError(Status
));
1360 if ( flags
& ~(RDW_ERASE
|RDW_FRAME
|RDW_INTERNALPAINT
|RDW_INVALIDATE
|
1361 RDW_NOERASE
|RDW_NOFRAME
|RDW_NOINTERNALPAINT
|RDW_VALIDATE
|
1362 RDW_ERASENOW
|RDW_UPDATENOW
|RDW_ALLCHILDREN
|RDW_NOCHILDREN
) )
1364 /* RedrawWindow fails only in case that flags are invalid */
1365 EngSetLastError(ERROR_INVALID_FLAGS
);
1369 UserRefObjectCo(Wnd
, &Ref
);
1371 Ret
= co_UserRedrawWindow( Wnd
,
1372 lprcUpdate
? &SafeUpdateRect
: NULL
,
1376 UserDerefObjectCo(Wnd
);
1381 TRACE("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1392 const RECTL
*prcScroll
,
1393 const RECTL
*prcClip
,
1398 RECTL rcScroll
, rcClip
, rcSrc
, rcDst
;
1401 GdiGetClipBox(hDC
, &rcClip
);
1405 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcClip
);
1410 rcScroll
= *prcScroll
;
1411 RECTL_bIntersectRect(&rcSrc
, &rcClip
, prcScroll
);
1419 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1420 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1422 if (!NtGdiBitBlt( hDC
,
1425 rcDst
.right
- rcDst
.left
,
1426 rcDst
.bottom
- rcDst
.top
,
1437 /* Calculate the region that was invalidated by moving or
1438 could not be copied, because it was not visible */
1439 if (hrgnUpdate
|| prcUpdate
)
1441 HRGN hrgnOwn
, hrgnTmp
;
1444 pDC
= DC_LockDc(hDC
);
1450 /* Begin with the shifted and then clipped scroll rect */
1452 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1453 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1456 hrgnOwn
= hrgnUpdate
;
1457 if (!NtGdiSetRectRgn(hrgnOwn
, rcDst
.left
, rcDst
.top
, rcDst
.right
, rcDst
.bottom
))
1465 hrgnOwn
= IntSysCreateRectRgnIndirect(&rcDst
);
1468 /* Add the source rect */
1469 hrgnTmp
= IntSysCreateRectRgnIndirect(&rcSrc
);
1470 NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_OR
);
1472 /* Substract the part of the dest that was visible in source */
1473 prgnTmp
= RGNOBJAPI_Lock(hrgnTmp
, NULL
);
1474 IntGdiCombineRgn(prgnTmp
, prgnTmp
, pDC
->prgnVis
, RGN_AND
);
1475 RGNOBJAPI_Unlock(prgnTmp
);
1476 NtGdiOffsetRgn(hrgnTmp
, dx
, dy
);
1477 Result
= NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_DIFF
);
1479 /* DO NOT Unlock DC while messing with prgnVis! */
1482 GreDeleteObject(hrgnTmp
);
1486 IntGdiGetRgnBox(hrgnOwn
, prcUpdate
);
1491 GreDeleteObject(hrgnOwn
);
1495 Result
= NULLREGION
;
1511 const RECT
*prcUnsafeScroll
,
1512 const RECT
*prcUnsafeClip
,
1514 LPRECT prcUnsafeUpdate
)
1516 DECLARE_RETURN(DWORD
);
1517 RECTL rcScroll
, rcClip
, rcUpdate
;
1518 NTSTATUS Status
= STATUS_SUCCESS
;
1521 TRACE("Enter NtUserScrollDC\n");
1522 UserEnterExclusive();
1526 if (prcUnsafeScroll
)
1528 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1529 rcScroll
= *prcUnsafeScroll
;
1533 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1534 rcClip
= *prcUnsafeClip
;
1536 if (prcUnsafeUpdate
)
1538 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1541 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1543 Status
= _SEH2_GetExceptionCode();
1546 if (!NT_SUCCESS(Status
))
1548 SetLastNtError(Status
);
1552 Result
= UserScrollDC( hDC
,
1555 prcUnsafeScroll
? &rcScroll
: 0,
1556 prcUnsafeClip
? &rcClip
: 0,
1558 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1561 /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
1565 if (prcUnsafeUpdate
)
1569 *prcUnsafeUpdate
= rcUpdate
;
1571 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1573 Status
= _SEH2_GetExceptionCode();
1576 if (!NT_SUCCESS(Status
))
1578 /* FIXME: SetLastError? */
1579 /* FIXME: correct? We have already scrolled! */
1587 TRACE("Leave NtUserScrollDC, ret=%i\n",_ret_
);
1593 * NtUserScrollWindowEx
1600 NtUserScrollWindowEx(
1604 const RECT
*prcUnsafeScroll
,
1605 const RECT
*prcUnsafeClip
,
1607 LPRECT prcUnsafeUpdate
,
1610 RECTL rcScroll
, rcClip
, rcCaret
, rcUpdate
;
1612 PWND Window
= NULL
, CaretWnd
;
1614 HRGN hrgnOwn
= NULL
, hrgnTemp
, hrgnWinupd
= NULL
;
1618 BOOL bOwnRgn
= TRUE
;
1619 NTSTATUS Status
= STATUS_SUCCESS
;
1620 DECLARE_RETURN(DWORD
);
1621 USER_REFERENCE_ENTRY Ref
, CaretRef
;
1623 TRACE("Enter NtUserScrollWindowEx\n");
1624 UserEnterExclusive();
1626 Window
= UserGetWindowObject(hWnd
);
1627 if (!Window
|| !IntIsWindowDrawable(Window
))
1629 Window
= NULL
; /* prevent deref at cleanup */
1632 UserRefObjectCo(Window
, &Ref
);
1634 IntGetClientRect(Window
, &rcClip
);
1638 if (prcUnsafeScroll
)
1640 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1641 RECTL_bIntersectRect(&rcScroll
, &rcClip
, prcUnsafeScroll
);
1648 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1649 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcUnsafeClip
);
1652 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1654 Status
= _SEH2_GetExceptionCode();
1658 if (!NT_SUCCESS(Status
))
1660 SetLastNtError(Status
);
1664 if (rcClip
.right
<= rcClip
.left
|| rcClip
.bottom
<= rcClip
.top
||
1665 (dx
== 0 && dy
== 0))
1672 hrgnOwn
= hrgnUpdate
;
1676 hrgnOwn
= IntSysCreateRectRgn(0, 0, 0, 0);
1678 /* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
1679 if (flags
& SW_SCROLLWNDDCE
)
1681 dcxflags
= DCX_USESTYLE
;
1683 if (!(Window
->pcls
->style
& (CS_OWNDC
|CS_CLASSDC
)))
1684 dcxflags
|= DCX_CACHE
; // AH??? wine~ If not Powned or with Class go Cheap!
1686 if (flags
& SW_SCROLLCHILDREN
&& Window
->style
& WS_CLIPCHILDREN
)
1687 dcxflags
|= DCX_CACHE
|DCX_NOCLIPCHILDREN
;
1691 /* So in this case ScrollWindowEx uses Cache DC. */
1692 dcxflags
= DCX_CACHE
|DCX_USESTYLE
;
1693 if (flags
& SW_SCROLLCHILDREN
) dcxflags
|= DCX_NOCLIPCHILDREN
;
1696 hDC
= UserGetDCEx(Window
, 0, dcxflags
);
1699 /* FIXME: SetLastError? */
1703 rdw_flags
= (flags
& SW_ERASE
) && (flags
& SW_INVALIDATE
) ? RDW_INVALIDATE
| RDW_ERASE
: RDW_INVALIDATE
;
1706 hwndCaret
= co_IntFixCaret(Window
, &rcCaret
, flags
);
1708 Result
= UserScrollDC( hDC
,
1714 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1716 UserReleaseDC(Window
, hDC
, FALSE
);
1719 * Take into account the fact that some damage may have occurred during
1720 * the scroll. Keep a copy in hrgnWinupd to be added to hrngUpdate at the end.
1723 hrgnTemp
= IntSysCreateRectRgn(0, 0, 0, 0);
1724 if (co_UserGetUpdateRgn(Window
, hrgnTemp
, FALSE
) != NULLREGION
)
1726 HRGN hrgnClip
= IntSysCreateRectRgnIndirect(&rcClip
);
1729 hrgnWinupd
= IntSysCreateRectRgn( 0, 0, 0, 0);
1730 NtGdiCombineRgn( hrgnWinupd
, hrgnTemp
, 0, RGN_COPY
);
1732 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1733 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1734 if (!bOwnRgn
) NtGdiCombineRgn( hrgnWinupd
, hrgnWinupd
, hrgnTemp
, RGN_OR
);
1735 co_UserRedrawWindow(Window
, NULL
, hrgnTemp
, rdw_flags
);
1736 GreDeleteObject(hrgnClip
);
1738 GreDeleteObject(hrgnTemp
);
1740 if (flags
& SW_SCROLLCHILDREN
)
1745 USER_REFERENCE_ENTRY WndRef
;
1748 IntGetClientOrigin(Window
, &ClientOrigin
);
1749 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
1751 rcChild
= Child
->rcWindow
;
1752 rcChild
.left
-= ClientOrigin
.x
;
1753 rcChild
.top
-= ClientOrigin
.y
;
1754 rcChild
.right
-= ClientOrigin
.x
;
1755 rcChild
.bottom
-= ClientOrigin
.y
;
1757 if (! prcUnsafeScroll
|| RECTL_bIntersectRect(&rcDummy
, &rcChild
, &rcScroll
))
1759 UserRefObjectCo(Child
, &WndRef
);
1760 co_WinPosSetWindowPos(Child
, 0, rcChild
.left
+ dx
, rcChild
.top
+ dy
, 0, 0,
1761 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1762 SWP_NOREDRAW
| SWP_DEFERERASE
);
1763 UserDerefObjectCo(Child
);
1768 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1770 co_UserRedrawWindow(Window
, NULL
, hrgnOwn
, rdw_flags
|
1771 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1772 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1775 if (hwndCaret
&& (CaretWnd
= UserGetWindowObject(hwndCaret
)))
1777 UserRefObjectCo(CaretWnd
, &CaretRef
);
1779 co_IntSetCaretPos(rcCaret
.left
+ dx
, rcCaret
.top
+ dy
);
1780 co_UserShowCaret(CaretWnd
);
1782 UserDerefObjectCo(CaretWnd
);
1785 if (prcUnsafeUpdate
)
1789 /* Probe here, to not fail on invalid pointer before scrolling */
1790 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1791 *prcUnsafeUpdate
= rcUpdate
;
1793 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1795 Status
= _SEH2_GetExceptionCode();
1799 if (!NT_SUCCESS(Status
))
1801 SetLastNtError(Status
);
1809 if (hrgnWinupd
&& !bOwnRgn
)
1811 NtGdiCombineRgn( hrgnOwn
, hrgnOwn
, hrgnWinupd
, RGN_OR
);
1812 GreDeleteObject(hrgnWinupd
);
1815 if (hrgnOwn
&& !hrgnUpdate
)
1817 GreDeleteObject(hrgnOwn
);
1821 UserDerefObjectCo(Window
);
1823 TRACE("Leave NtUserScrollWindowEx, ret=%i\n",_ret_
);
1829 UserDrawCaptionText(
1831 const PUNICODE_STRING Text
,
1836 HFONT hOldFont
= NULL
;
1837 COLORREF OldTextColor
;
1838 NONCLIENTMETRICSW nclm
;
1840 BOOLEAN bDeleteFont
= FALSE
;
1843 TRACE("UserDrawCaptionText: %wZ\n", Text
);
1845 nclm
.cbSize
= sizeof(nclm
);
1846 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1847 sizeof(NONCLIENTMETRICS
), &nclm
, 0))
1849 ERR("UserSystemParametersInfo() failed!\n");
1855 if(uFlags
& DC_SMALLCAP
)
1856 Status
= TextIntCreateFontIndirect(&nclm
.lfSmCaptionFont
, &hFont
);
1858 Status
= TextIntCreateFontIndirect(&nclm
.lfCaptionFont
, &hFont
);
1860 if(!NT_SUCCESS(Status
))
1862 ERR("TextIntCreateFontIndirect() failed! Status: 0x%x\n", Status
);
1869 IntGdiSetBkMode(hDc
, TRANSPARENT
);
1871 hOldFont
= NtGdiSelectFont(hDc
, hFont
);
1874 ERR("SelectFont() failed!\n");
1878 if(uFlags
& DC_INBUTTON
)
1879 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(COLOR_BTNTEXT
));
1881 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(uFlags
& DC_ACTIVE
1882 ? COLOR_CAPTIONTEXT
: COLOR_INACTIVECAPTIONTEXT
));
1884 // FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
1885 GreGetTextExtentW(hDc
, Text
->Buffer
, Text
->Length
/sizeof(WCHAR
), &Size
, 0);
1887 lpRc
->left
, (lpRc
->top
+ lpRc
->bottom
)/2 - Size
.cy
/2,
1888 0, NULL
, Text
->Buffer
, Text
->Length
/sizeof(WCHAR
), NULL
, 0);
1890 IntGdiSetTextColor(hDc
, OldTextColor
);
1892 NtGdiSelectFont(hDc
, hOldFont
);
1894 GreDeleteObject(hFont
);
1899 BOOL
UserDrawCaption(
1905 const PUNICODE_STRING Str
,
1909 HBRUSH hBgBrush
, hOldBrush
= NULL
;
1913 RECTL_vMakeWellOrdered(lpRc
);
1915 if (!hIcon
&& pWnd
!= NULL
)
1917 HasIcon
= (uFlags
& DC_ICON
) && (pWnd
->style
& WS_SYSMENU
)
1918 && !(uFlags
& DC_SMALLCAP
) && !(pWnd
->ExStyle
& WS_EX_DLGMODALFRAME
)
1919 && !(pWnd
->ExStyle
& WS_EX_TOOLWINDOW
);
1922 HasIcon
= (hIcon
!= 0);
1924 // Draw the caption background
1925 if((uFlags
& DC_GRADIENT
) && !(uFlags
& DC_INBUTTON
))
1927 static GRADIENT_RECT gcap
= {0, 1};
1928 TRIVERTEX Vertices
[2];
1931 Colors
[0] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1932 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
1934 Colors
[1] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1935 COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
1937 Vertices
[0].x
= Rect
.left
;
1938 Vertices
[0].y
= Rect
.top
;
1939 Vertices
[0].Red
= (WORD
)Colors
[0]<<8;
1940 Vertices
[0].Green
= (WORD
)Colors
[0] & 0xFF00;
1941 Vertices
[0].Blue
= (WORD
)(Colors
[0]>>8) & 0xFF00;
1942 Vertices
[0].Alpha
= 0;
1944 Vertices
[1].x
= Rect
.right
;
1945 Vertices
[1].y
= Rect
.bottom
;
1946 Vertices
[1].Red
= (WORD
)Colors
[1]<<8;
1947 Vertices
[1].Green
= (WORD
)Colors
[1] & 0xFF00;
1948 Vertices
[1].Blue
= (WORD
)(Colors
[1]>>8) & 0xFF00;
1949 Vertices
[1].Alpha
= 0;
1951 if(!GreGradientFill(hDc
, Vertices
, 2, &gcap
, 1, GRADIENT_FILL_RECT_H
))
1953 ERR("GreGradientFill() failed!\n");
1959 if(uFlags
& DC_INBUTTON
)
1960 hBgBrush
= IntGetSysColorBrush(COLOR_3DFACE
);
1961 else if(uFlags
& DC_ACTIVE
)
1962 hBgBrush
= IntGetSysColorBrush(COLOR_ACTIVECAPTION
);
1964 hBgBrush
= IntGetSysColorBrush(COLOR_INACTIVECAPTION
);
1966 hOldBrush
= NtGdiSelectBrush(hDc
, hBgBrush
);
1970 ERR("NtGdiSelectBrush() failed!\n");
1974 if(!NtGdiPatBlt(hDc
, Rect
.left
, Rect
.top
,
1975 Rect
.right
- Rect
.left
,
1976 Rect
.bottom
- Rect
.top
,
1979 ERR("NtGdiPatBlt() failed!\n");
1987 PCURICON_OBJECT pIcon
= NULL
;
1991 hIcon
= pWnd
->pcls
->hIconSm
; // FIXME: Windows does not do that
1993 hIcon
= pWnd
->pcls
->hIcon
;
1997 pIcon
= UserGetCurIconObject(hIcon
);
2001 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
2002 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
2003 LONG x
= Rect
.left
- cx
/2 + 1 + (Rect
.bottom
- Rect
.top
)/2; // this is really what Window does
2004 LONG y
= (Rect
.top
+ Rect
.bottom
)/2 - cy
/2; // center
2005 UserDrawIconEx(hDc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
2006 UserDereferenceObject(pIcon
);
2011 Rect
.left
+= Rect
.bottom
- Rect
.top
;
2013 if((uFlags
& DC_TEXT
))
2018 UserDrawCaptionText(hDc
, Str
, &Rect
, uFlags
, hFont
);
2019 else if (pWnd
!= NULL
) // FIXME: Windows does not do that
2021 UNICODE_STRING ustr
;
2022 ustr
.Buffer
= pWnd
->strName
.Buffer
; // FIXME: LARGE_STRING truncated!
2023 ustr
.Length
= (USHORT
)min(pWnd
->strName
.Length
, MAXUSHORT
);
2024 ustr
.MaximumLength
= (USHORT
)min(pWnd
->strName
.MaximumLength
, MAXUSHORT
);
2025 UserDrawCaptionText(hDc
, &ustr
, &Rect
, uFlags
, hFont
);
2032 if (hOldBrush
) NtGdiSelectBrush(hDc
, hOldBrush
);
2039 UserRealizePalette(HDC hdc
)
2041 HWND hWnd
, hWndDesktop
;
2044 Ret
= IntGdiRealizePalette(hdc
);
2045 if (Ret
) // There was a change.
2047 hWnd
= IntWindowFromDC(hdc
);
2048 if (hWnd
) // Send broadcast if dc is associated with a window.
2049 { // FYI: Thread locked in CallOneParam.
2050 hWndDesktop
= IntGetDesktopWindow();
2051 if ( hWndDesktop
!= hWnd
)
2053 PWND pWnd
= UserGetWindowObject(hWndDesktop
);
2054 ERR("RealizePalette Desktop.");
2055 hdc
= UserGetWindowDC(pWnd
);
2056 IntPaintDesktop(hdc
);
2057 UserReleaseDC(pWnd
,hdc
,FALSE
);
2059 UserSendNotifyMessage((HWND
)HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0);
2067 NtUserDrawCaptionTemp(
2073 const PUNICODE_STRING str
,
2077 UNICODE_STRING SafeStr
= {0};
2078 NTSTATUS Status
= STATUS_SUCCESS
;
2082 UserEnterExclusive();
2086 if(!(pWnd
= UserGetWindowObject(hWnd
)))
2095 ProbeForRead(lpRc
, sizeof(RECTL
), sizeof(ULONG
));
2096 RtlCopyMemory(&SafeRect
, lpRc
, sizeof(RECTL
));
2099 SafeStr
= ProbeForReadUnicodeString(str
);
2100 if (SafeStr
.Length
!= 0)
2102 ProbeForRead( SafeStr
.Buffer
,
2108 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2110 Status
= _SEH2_GetExceptionCode();
2114 if (Status
!= STATUS_SUCCESS
)
2116 SetLastNtError(Status
);
2122 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, &SafeStr
, uFlags
);
2124 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, NULL
, uFlags
);
2132 NtUserDrawCaption(HWND hWnd
,
2137 return NtUserDrawCaptionTemp(hWnd
, hDC
, lpRc
, 0, 0, NULL
, uFlags
);
2142 NtUserInvalidateRect(
2144 CONST RECT
*lpUnsafeRect
,
2147 return NtUserRedrawWindow(hWnd
, lpUnsafeRect
, NULL
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2152 NtUserInvalidateRgn(
2157 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2170 UserEnterExclusive();
2174 if (!(Window
= UserGetWindowObject(hwnd
)) || // FIXME:
2175 Window
== UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2176 Window
== UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2183 /* Validate flags and check it as a mask for 0 or 1. */
2184 if ( (nFlags
& PW_CLIENTONLY
) == nFlags
)
2185 Ret
= IntPrintWindow( Window
, hdcBlt
, nFlags
);
2187 EngSetLastError(ERROR_INVALID_PARAMETER
);
2195 /* ValidateRect gets redirected to NtUserValidateRect:
2196 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */
2205 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, RDW_VALIDATE
);
2207 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, RDW_INVALIDATE
|RDW_ERASE
|RDW_ERASENOW
|RDW_ALLCHILDREN
);