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
)
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
)
180 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcClient
);
182 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcWindow
);
184 if (Wnd
->hrgnClip
!= NULL
&& !(Wnd
->style
& WS_MINIMIZE
))
186 NtGdiOffsetRgn(hRgnWindow
,
189 NtGdiCombineRgn(hRgnWindow
, hRgnWindow
, Wnd
->hrgnClip
, RGN_AND
);
190 NtGdiOffsetRgn(hRgnWindow
,
199 * @name IntGetNCUpdateRgn
201 * Get non-client update region of a window and optionally validate it.
204 * Pointer to window to get the NC update region from.
206 * Set to TRUE to force validating the NC update region.
209 * Handle to NC update region. The caller is responsible for deleting
214 IntGetNCUpdateRgn(PWND Window
, BOOL Validate
)
220 if (Window
->hrgnUpdate
!= NULL
&&
221 Window
->hrgnUpdate
!= HRGN_WINDOW
)
223 hRgnNonClient
= IntCalcWindowRgn(Window
, FALSE
);
226 * If region creation fails it's safe to fallback to whole
229 if (hRgnNonClient
== NULL
)
234 hRgnWindow
= IntCalcWindowRgn(Window
, TRUE
);
235 if (hRgnWindow
== NULL
)
237 GreDeleteObject(hRgnNonClient
);
241 RgnType
= NtGdiCombineRgn(hRgnNonClient
, hRgnNonClient
,
242 hRgnWindow
, RGN_DIFF
);
243 if (RgnType
== ERROR
)
245 GreDeleteObject(hRgnWindow
);
246 GreDeleteObject(hRgnNonClient
);
249 else if (RgnType
== NULLREGION
)
251 GreDeleteObject(hRgnWindow
);
252 GreDeleteObject(hRgnNonClient
);
253 Window
->state
&= ~WNDS_UPDATEDIRTY
;
258 * Remove the nonclient region from the standard update region if
259 * we were asked for it.
264 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
,
265 hRgnWindow
, RGN_AND
) == NULLREGION
)
267 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
268 GreDeleteObject(Window
->hrgnUpdate
);
269 Window
->state
&= ~WNDS_UPDATEDIRTY
;
270 Window
->hrgnUpdate
= NULL
;
271 if (!(Window
->state
& WNDS_INTERNALPAINT
))
272 MsqDecPaintCountQueue(Window
->head
.pti
);
276 GreDeleteObject(hRgnWindow
);
278 return hRgnNonClient
;
282 return Window
->hrgnUpdate
;
289 * Internal function used by IntRedrawWindow.
293 co_IntPaintWindows(PWND Wnd
, ULONG Flags
, BOOL Recurse
)
296 HWND hWnd
= Wnd
->head
.h
;
299 Wnd
->state
&= ~WNDS_PAINTNOTPROCESSED
;
301 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
305 if (!IntValidateParent(Wnd
, Wnd
->hrgnUpdate
, Recurse
))
309 if (Flags
& RDW_UPDATENOW
)
311 if ((Wnd
->hrgnUpdate
!= NULL
||
312 Wnd
->state
& WNDS_INTERNALPAINT
))
314 Wnd
->state2
|= WNDS2_WMPAINTSENT
;
315 co_IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
318 else if (Wnd
->head
.pti
== PsGetCurrentThreadWin32Thread())
320 if (Wnd
->state
& WNDS_SENDNCPAINT
)
322 TempRegion
= IntGetNCUpdateRgn(Wnd
, TRUE
);
323 Wnd
->state
&= ~WNDS_SENDNCPAINT
;
324 if ( Wnd
== GetW32ThreadInfo()->MessageQueue
->spwndActive
&&
325 !(Wnd
->state
& WNDS_ACTIVEFRAME
))
327 Wnd
->state
|= WNDS_ACTIVEFRAME
;
328 Wnd
->state
&= ~WNDS_NONCPAINT
;
330 if (TempRegion
) co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)TempRegion
, 0);
333 if (Wnd
->state
& WNDS_SENDERASEBACKGROUND
)
337 hDC
= UserGetDCEx( Wnd
,
339 DCX_CACHE
|DCX_USESTYLE
|DCX_INTERSECTRGN
|DCX_KEEPCLIPRGN
);
341 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
342 // Kill the loop, so Clear before we send.
343 if (!co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
345 Wnd
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
347 UserReleaseDC(Wnd
, hDC
, FALSE
);
354 Wnd
->state
&= ~(WNDS_SENDNCPAINT
|WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
358 * Check that the window is still valid at this point
360 if (!IntIsWindow(hWnd
))
366 * Paint child windows.
368 if (!(Flags
& RDW_NOCHILDREN
) &&
369 !(Wnd
->style
& WS_MINIMIZE
) &&
370 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)) )
374 if ((List
= IntWinListChildren(Wnd
)))
376 /* FIXME: Handle WS_EX_TRANSPARENT */
377 for (phWnd
= List
; *phWnd
; ++phWnd
)
379 Wnd
= UserGetWindowObject(*phWnd
);
380 if (Wnd
&& (Wnd
->style
& WS_VISIBLE
))
382 USER_REFERENCE_ENTRY Ref
;
383 UserRefObjectCo(Wnd
, &Ref
);
384 co_IntPaintWindows(Wnd
, Flags
, TRUE
);
385 UserDerefObjectCo(Wnd
);
388 ExFreePoolWithTag(List
, USERTAG_WINDOWLIST
);
394 * IntInvalidateWindows
396 * Internal function used by IntRedrawWindow, UserRedrawDesktop,
397 * co_WinPosSetWindowPos, IntValidateParent, co_UserRedrawWindow.
400 IntInvalidateWindows(PWND Wnd
, HRGN hRgn
, ULONG Flags
)
403 BOOL HadPaintMessage
;
405 TRACE("IntInvalidateWindows start\n");
407 Wnd
->state
|= WNDS_PAINTNOTPROCESSED
;
410 * If the nonclient is not to be redrawn, clip the region to the client
413 if (0 != (Flags
& RDW_INVALIDATE
) && 0 == (Flags
& RDW_FRAME
))
417 hRgnClient
= IntSysCreateRectRgnIndirect(&Wnd
->rcClient
);
418 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnClient
, RGN_AND
);
419 GreDeleteObject(hRgnClient
);
423 * Clip the given region with window rectangle (or region)
426 if (!Wnd
->hrgnClip
|| (Wnd
->style
& WS_MINIMIZE
))
430 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcWindow
);
431 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
432 GreDeleteObject(hRgnWindow
);
436 NtGdiOffsetRgn( hRgn
,
439 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Wnd
->hrgnClip
, RGN_AND
);
440 NtGdiOffsetRgn( hRgn
,
446 * Save current state of pending updates
449 HadPaintMessage
= IntIsWindowDirty(Wnd
);
452 * Update the region and flags
455 // The following flags are used to invalidate the window.
456 if (Flags
& (RDW_INVALIDATE
|RDW_INTERNALPAINT
|RDW_ERASE
|RDW_FRAME
))
458 if (Flags
& RDW_INTERNALPAINT
)
460 Wnd
->state
|= WNDS_INTERNALPAINT
;
463 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
465 Wnd
->state
&= ~WNDS_NONCPAINT
;
467 /* If not the same thread set it dirty. */
468 if (Wnd
->head
.pti
!= PsGetCurrentThreadWin32Thread())
470 Wnd
->state
|= WNDS_UPDATEDIRTY
;
471 if (Wnd
->state2
& WNDS2_WMPAINTSENT
)
472 Wnd
->state2
|= WNDS2_ENDPAINTINVALIDATE
;
475 if (Flags
& RDW_FRAME
)
476 Wnd
->state
|= WNDS_SENDNCPAINT
;
477 if (Flags
& RDW_ERASE
)
478 Wnd
->state
|= WNDS_SENDERASEBACKGROUND
;
480 if (Wnd
->hrgnUpdate
== NULL
)
482 Wnd
->hrgnUpdate
= IntSysCreateRectRgn(0, 0, 0, 0);
483 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_PUBLIC
);
486 if (NtGdiCombineRgn(Wnd
->hrgnUpdate
, Wnd
->hrgnUpdate
,
487 hRgn
, RGN_OR
) == NULLREGION
)
489 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
490 GreDeleteObject(Wnd
->hrgnUpdate
);
491 Wnd
->hrgnUpdate
= NULL
;
493 Flags
|= RDW_FRAME
; // For children.
495 } // The following flags are used to validate the window.
496 else if (Flags
& (RDW_VALIDATE
|RDW_NOINTERNALPAINT
|RDW_NOERASE
|RDW_NOFRAME
))
498 /* FIXME: Handle WNDS_UPDATEDIRTY */
500 if (Flags
& RDW_NOINTERNALPAINT
)
502 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
505 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
507 if (Flags
& RDW_NOFRAME
)
508 Wnd
->state
&= ~WNDS_SENDNCPAINT
;
509 if (Flags
& RDW_NOERASE
)
510 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
512 if (Wnd
->hrgnUpdate
!= NULL
)
514 if (NtGdiCombineRgn(Wnd
->hrgnUpdate
, Wnd
->hrgnUpdate
,
515 hRgn
, RGN_DIFF
) == NULLREGION
)
517 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
518 GreDeleteObject(Wnd
->hrgnUpdate
);
519 Wnd
->hrgnUpdate
= NULL
;
523 if (Wnd
->hrgnUpdate
== NULL
)
524 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
529 * Process children if needed
532 if (!(Flags
& RDW_NOCHILDREN
) && !(Wnd
->style
& WS_MINIMIZE
) &&
533 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)))
537 for (Child
= Wnd
->spwndChild
; Child
; Child
= Child
->spwndNext
)
539 if (Child
->style
& WS_VISIBLE
)
542 * Recursive call to update children hrgnUpdate
544 HRGN hRgnTemp
= IntSysCreateRectRgn(0, 0, 0, 0);
545 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
546 IntInvalidateWindows(Child
, hRgnTemp
, Flags
);
547 GreDeleteObject(hRgnTemp
);
553 * Fake post paint messages to window message queue if needed
556 if (HadPaintMessage
!= IntIsWindowDirty(Wnd
))
559 MsqDecPaintCountQueue(Wnd
->head
.pti
);
561 MsqIncPaintCountQueue(Wnd
->head
.pti
);
563 TRACE("IntInvalidateWindows exit\n");
567 * IntIsWindowDrawable
570 * Window is drawable when it is visible and all parents are not
575 IntIsWindowDrawable(PWND Wnd
)
579 for (WndObject
= Wnd
; WndObject
!= NULL
; WndObject
= WndObject
->spwndParent
)
581 if ( WndObject
->state2
& WNDS2_INDESTROY
||
582 WndObject
->state
& WNDS_DESTROYED
||
584 !(WndObject
->style
& WS_VISIBLE
) ||
585 ((WndObject
->style
& WS_MINIMIZE
) && (WndObject
!= Wnd
)))
597 * Internal version of NtUserRedrawWindow that takes WND as
604 const RECTL
* UpdateRect
,
609 TRACE("co_UserRedrawWindow start\n");
613 * Validation of passed parameters.
616 if (!IntIsWindowDrawable(Window
))
618 return TRUE
; // Just do nothing!!!
623 * Transform the parameters UpdateRgn and UpdateRect into
624 * a region hRgn specified in screen coordinates.
627 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
)) // Both are OKAY!
629 if (UpdateRgn
!= NULL
)
631 hRgn
= IntSysCreateRectRgn(0, 0, 0, 0);
632 if (NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
) == NULLREGION
)
634 GreDeleteObject(hRgn
);
638 NtGdiOffsetRgn(hRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
640 else if (UpdateRect
!= NULL
)
642 if (!RECTL_bIsEmptyRect(UpdateRect
))
644 hRgn
= IntSysCreateRectRgnIndirect((RECTL
*)UpdateRect
);
645 NtGdiOffsetRgn(hRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
648 else if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
649 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
651 if (!RECTL_bIsEmptyRect(&Window
->rcWindow
))
652 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcWindow
);
656 if (!RECTL_bIsEmptyRect(&Window
->rcClient
))
657 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcClient
);
663 * Adjust the window update region depending on hRgn and flags.
666 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
) &&
669 IntInvalidateWindows(Window
, hRgn
, Flags
);
674 * Repaint and erase windows if needed.
677 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
679 if (Flags
& RDW_ERASENOW
) IntSendSyncPaint(Window
, Flags
);
680 co_IntPaintWindows(Window
, Flags
, FALSE
);
690 GreDeleteObject(hRgn
);
692 TRACE("co_UserRedrawWindow exit\n");
698 IntIsWindowDirty(PWND Wnd
)
700 return ( Wnd
->style
& WS_VISIBLE
&&
701 ( Wnd
->hrgnUpdate
!= NULL
||
702 Wnd
->state
& WNDS_INTERNALPAINT
) );
706 IntFindWindowToRepaint(PWND Window
, PTHREADINFO Thread
)
711 for (; Window
!= NULL
; Window
= Window
->spwndNext
)
713 if (IntWndBelongsToThread(Window
, Thread
) &&
714 IntIsWindowDirty(Window
))
716 /* Make sure all non-transparent siblings are already drawn. */
717 if (Window
->ExStyle
& WS_EX_TRANSPARENT
)
719 for (TempWindow
= Window
->spwndNext
; TempWindow
!= NULL
;
720 TempWindow
= TempWindow
->spwndNext
)
722 if (!(TempWindow
->ExStyle
& WS_EX_TRANSPARENT
) &&
723 IntWndBelongsToThread(TempWindow
, Thread
) &&
724 IntIsWindowDirty(TempWindow
))
734 if (Window
->spwndChild
)
736 hChild
= IntFindWindowToRepaint(Window
->spwndChild
, Thread
);
755 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
756 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
759 if (Thread
->TIF_flags
& TIF_SYSTEMTHREAD
)
761 ERR("WM_PAINT is in a System Thread!\n");
764 PaintWnd
= IntFindWindowToRepaint(UserGetDesktopWindow(), Thread
);
766 Message
->hwnd
= PaintWnd
? UserHMGetHandle(PaintWnd
) : NULL
;
768 if (Message
->hwnd
== NULL
)
770 ERR("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found! Counts %u\n",Thread
->cPaintsReady
);
771 /* Hack to stop spamming the debuglog ! */
772 Thread
->cPaintsReady
= 0;
776 if (Window
!= NULL
&& PaintWnd
!= Window
)
779 if (PaintWnd
->state
& WNDS_INTERNALPAINT
)
781 PaintWnd
->state
&= ~WNDS_INTERNALPAINT
;
782 if (!PaintWnd
->hrgnUpdate
)
783 MsqDecPaintCountQueue(Thread
);
785 PaintWnd
->state2
&= ~WNDS2_WMPAINTSENT
;
786 PaintWnd
->state
&= ~WNDS_UPDATEDIRTY
;
787 Message
->wParam
= Message
->lParam
= 0;
788 Message
->message
= WM_PAINT
;
794 co_IntFixCaret(PWND Window
, RECTL
*lprc
, UINT flags
)
797 PTHRDCARETINFO CaretInfo
;
799 PUSER_MESSAGE_QUEUE ActiveMessageQueue
;
803 ASSERT_REFS_CO(Window
);
805 pti
= PsGetCurrentThreadWin32Thread();
806 Desktop
= pti
->rpdesk
;
807 ActiveMessageQueue
= Desktop
->ActiveMessageQueue
;
808 if (!ActiveMessageQueue
) return 0;
809 CaretInfo
= ActiveMessageQueue
->CaretInfo
;
810 hWndCaret
= CaretInfo
->hWnd
;
812 WndCaret
= ValidateHwndNoErr(hWndCaret
);
814 // FIXME: Check for WndCaret can be NULL
815 if (WndCaret
== Window
||
816 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(Window
, WndCaret
)))
818 POINT pt
, FromOffset
, ToOffset
;
821 pt
.x
= CaretInfo
->Pos
.x
;
822 pt
.y
= CaretInfo
->Pos
.y
;
823 IntGetClientOrigin(WndCaret
, &FromOffset
);
824 IntGetClientOrigin(Window
, &ToOffset
);
827 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
828 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
829 if (RECTL_bIntersectRect(lprc
, lprc
, &rcCaret
))
849 INT cx
, cy
, xSrc
, ySrc
;
851 if ( nFlags
& PW_CLIENTONLY
)
853 cx
= pwnd
->rcClient
.right
- pwnd
->rcClient
.left
;
854 cy
= pwnd
->rcClient
.bottom
- pwnd
->rcClient
.top
;
855 xSrc
= pwnd
->rcClient
.left
- pwnd
->rcWindow
.left
;
856 ySrc
= pwnd
->rcClient
.top
- pwnd
->rcWindow
.top
;
860 cx
= pwnd
->rcWindow
.right
- pwnd
->rcWindow
.left
;
861 cy
= pwnd
->rcWindow
.bottom
- pwnd
->rcWindow
.top
;
866 // TODO: Setup Redirection for Print.
869 /* Update the window just incase. */
870 co_IntPaintWindows( pwnd
, RDW_ERASENOW
|RDW_UPDATENOW
, FALSE
);
872 hdcSrc
= UserGetDCEx( pwnd
, NULL
, DCX_CACHE
|DCX_WINDOW
);
873 /* Print window to printer context. */
886 UserReleaseDC( pwnd
, hdcSrc
, FALSE
);
888 // TODO: Release Redirection from Print.
895 IntFlashWindowEx(PWND pWnd
, PFLASHWINFO pfwi
)
901 pprop
= IntGetProp(pWnd
, AtomFlashWndState
);
904 FlashState
= pfwi
->dwFlags
;
905 IntSetProp(pWnd
, AtomFlashWndState
, (HANDLE
) FlashState
);
909 FlashState
= (DWORD
)pprop
->Data
;
910 if ( pfwi
->dwFlags
== FLASHW_STOP
)
912 IntRemoveProp(pWnd
, AtomFlashWndState
);
919 IntBeginPaint(PWND Window
, PPAINTSTRUCT Ps
)
921 co_UserHideCaret(Window
);
923 Window
->state2
|= WNDS2_STARTPAINT
;
924 Window
->state
&= ~WNDS_PAINTNOTPROCESSED
;
926 if (Window
->state
& WNDS_SENDNCPAINT
)
930 Window
->state
&= ~WNDS_UPDATEDIRTY
;
931 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
932 Window
->state
&= ~WNDS_SENDNCPAINT
;
933 co_IntSendMessage(UserHMGetHandle(Window
), WM_NCPAINT
, (WPARAM
)hRgn
, 0);
934 if (hRgn
!= HRGN_WINDOW
&& hRgn
!= NULL
&& GreIsHandleValid(hRgn
))
936 /* NOTE: The region can already be deleted! */
937 GreDeleteObject(hRgn
);
942 Window
->state
&= ~WNDS_UPDATEDIRTY
;
945 RtlZeroMemory(Ps
, sizeof(PAINTSTRUCT
));
947 Ps
->hdc
= UserGetDCEx( Window
,
949 DCX_INTERSECTRGN
| DCX_USESTYLE
);
955 if (Window
->hrgnUpdate
!= NULL
)
957 MsqDecPaintCountQueue(Window
->head
.pti
);
958 GdiGetClipBox(Ps
->hdc
, &Ps
->rcPaint
);
959 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
960 /* The region is part of the dc now and belongs to the process! */
961 Window
->hrgnUpdate
= NULL
;
965 if (Window
->state
& WNDS_INTERNALPAINT
)
966 MsqDecPaintCountQueue(Window
->head
.pti
);
968 IntGetClientRect(Window
, &Ps
->rcPaint
);
971 Window
->state
&= ~WNDS_INTERNALPAINT
;
973 if (Window
->state
& WNDS_SENDERASEBACKGROUND
)
975 Window
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
976 Ps
->fErase
= !co_IntSendMessage(UserHMGetHandle(Window
), WM_ERASEBKGND
, (WPARAM
)Ps
->hdc
, 0);
979 Window
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
986 if (Window
->hrgnUpdate
)
988 if (!(Window
->style
& WS_CLIPCHILDREN
))
991 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
993 if (Child
->hrgnUpdate
== NULL
&& Child
->state
& WNDS_SENDNCPAINT
) // Helped fixing test_redrawnow.
994 IntInvalidateWindows(Child
, Window
->hrgnUpdate
, RDW_FRAME
| RDW_ERASE
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
1002 IntEndPaint(PWND Wnd
, PPAINTSTRUCT Ps
)
1008 UserReleaseDC(Wnd
, hdc
, TRUE
);
1010 Wnd
->state2
&= ~(WNDS2_WMPAINTSENT
|WNDS2_STARTPAINT
);
1012 co_UserShowCaret(Wnd
);
1017 /* PUBLIC FUNCTIONS ***********************************************************/
1027 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
1033 USER_REFERENCE_ENTRY Ref
;
1034 DECLARE_RETURN(HDC
);
1036 TRACE("Enter NtUserBeginPaint\n");
1037 UserEnterExclusive();
1039 if (!(Window
= UserGetWindowObject(hWnd
)))
1044 UserRefObjectCo(Window
, &Ref
);
1046 hDC
= IntBeginPaint(Window
, &Ps
);
1048 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
1049 if (! NT_SUCCESS(Status
))
1051 SetLastNtError(Status
);
1058 if (Window
) UserDerefObjectCo(Window
);
1060 TRACE("Leave NtUserBeginPaint, ret=%p\n",_ret_
);
1074 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* pUnsafePs
)
1076 NTSTATUS Status
= STATUS_SUCCESS
;
1079 USER_REFERENCE_ENTRY Ref
;
1080 DECLARE_RETURN(BOOL
);
1082 TRACE("Enter NtUserEndPaint\n");
1083 UserEnterExclusive();
1085 if (!(Window
= UserGetWindowObject(hWnd
)))
1090 UserRefObjectCo(Window
, &Ref
); // Here for the exception.
1094 ProbeForRead(pUnsafePs
, sizeof(*pUnsafePs
), 1);
1095 RtlCopyMemory(&Ps
, pUnsafePs
, sizeof(PAINTSTRUCT
));
1097 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1099 Status
= _SEH2_GetExceptionCode();
1102 if (!NT_SUCCESS(Status
))
1107 RETURN(IntEndPaint(Window
, &Ps
));
1110 if (Window
) UserDerefObjectCo(Window
);
1112 TRACE("Leave NtUserEndPaint, ret=%i\n",_ret_
);
1121 NtUserFlashWindowEx(IN PFLASHWINFO pfwi
)
1124 FLASHWINFO finfo
= {0};
1127 UserEnterExclusive();
1131 ProbeForRead(pfwi
, sizeof(FLASHWINFO
), sizeof(ULONG
));
1132 RtlCopyMemory(&finfo
, pfwi
, sizeof(FLASHWINFO
));
1134 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1136 SetLastNtError(_SEH2_GetExceptionCode());
1141 if (!Ret
) goto Exit
;
1143 if (!( pWnd
= (PWND
)UserGetObject(gHandleTable
, finfo
.hwnd
, TYPE_WINDOW
)) ||
1144 finfo
.cbSize
!= sizeof(FLASHWINFO
) ||
1145 finfo
.dwFlags
& ~(FLASHW_ALL
|FLASHW_TIMER
|FLASHW_TIMERNOFG
) )
1147 EngSetLastError(ERROR_INVALID_PARAMETER
);
1152 Ret
= IntFlashWindowEx(pWnd
, &finfo
);
1160 co_UserGetUpdateRgn(PWND Window
, HRGN hRgn
, BOOL bErase
)
1165 ASSERT_REFS_CO(Window
);
1167 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1169 if (Window
->hrgnUpdate
== NULL
)
1171 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
1175 Rect
= Window
->rcClient
;
1176 IntIntersectWithParents(Window
, &Rect
);
1177 NtGdiSetRectRgn(hRgn
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
1178 RegionType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->hrgnUpdate
, RGN_AND
);
1179 NtGdiOffsetRgn(hRgn
, -Window
->rcClient
.left
, -Window
->rcClient
.top
);
1182 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
1184 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1191 * NtUserGetUpdateRgn
1198 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
1200 DECLARE_RETURN(INT
);
1203 USER_REFERENCE_ENTRY Ref
;
1205 TRACE("Enter NtUserGetUpdateRgn\n");
1206 UserEnterExclusive();
1208 if (!(Window
= UserGetWindowObject(hWnd
)))
1213 UserRefObjectCo(Window
, &Ref
);
1214 ret
= co_UserGetUpdateRgn(Window
, hRgn
, bErase
);
1215 UserDerefObjectCo(Window
);
1220 TRACE("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
1226 * NtUserGetUpdateRect
1233 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
1238 PROSRGNDATA RgnData
;
1240 DECLARE_RETURN(BOOL
);
1242 TRACE("Enter NtUserGetUpdateRect\n");
1243 UserEnterExclusive();
1245 if (!(Window
= UserGetWindowObject(hWnd
)))
1250 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1252 if (Window
->hrgnUpdate
== NULL
)
1254 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1258 /* Get the update region bounding box. */
1259 if (Window
->hrgnUpdate
== HRGN_WINDOW
)
1261 Rect
= Window
->rcClient
;
1265 RgnData
= RGNOBJAPI_Lock(Window
->hrgnUpdate
, NULL
);
1266 ASSERT(RgnData
!= NULL
);
1267 RegionType
= REGION_GetRgnBox(RgnData
, &Rect
);
1268 RGNOBJAPI_Unlock(RgnData
);
1270 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
1271 RECTL_bIntersectRect(&Rect
, &Rect
, &Window
->rcClient
);
1274 if (IntIntersectWithParents(Window
, &Rect
))
1276 RECTL_vOffsetRect(&Rect
,
1277 -Window
->rcClient
.left
,
1278 -Window
->rcClient
.top
);
1281 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1285 if (bErase
&& !RECTL_bIsEmptyRect(&Rect
))
1287 USER_REFERENCE_ENTRY Ref
;
1288 UserRefObjectCo(Window
, &Ref
);
1289 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1290 UserDerefObjectCo(Window
);
1293 if (UnsafeRect
!= NULL
)
1295 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECTL
));
1296 if (!NT_SUCCESS(Status
))
1298 EngSetLastError(ERROR_INVALID_PARAMETER
);
1303 RETURN(!RECTL_bIsEmptyRect(&Rect
));
1306 TRACE("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1312 * NtUserRedrawWindow
1321 CONST RECT
*lprcUpdate
,
1325 RECTL SafeUpdateRect
;
1328 USER_REFERENCE_ENTRY Ref
;
1329 NTSTATUS Status
= STATUS_SUCCESS
;
1330 DECLARE_RETURN(BOOL
);
1332 TRACE("Enter NtUserRedrawWindow\n");
1333 UserEnterExclusive();
1335 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1344 ProbeForRead(lprcUpdate
, sizeof(RECTL
), 1);
1345 RtlCopyMemory(&SafeUpdateRect
, lprcUpdate
, sizeof(RECTL
));
1347 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1349 Status
= _SEH2_GetExceptionCode();
1352 if (!NT_SUCCESS(Status
))
1354 EngSetLastError(RtlNtStatusToDosError(Status
));
1359 if ( flags
& ~(RDW_ERASE
|RDW_FRAME
|RDW_INTERNALPAINT
|RDW_INVALIDATE
|
1360 RDW_NOERASE
|RDW_NOFRAME
|RDW_NOINTERNALPAINT
|RDW_VALIDATE
|
1361 RDW_ERASENOW
|RDW_UPDATENOW
|RDW_ALLCHILDREN
|RDW_NOCHILDREN
) )
1363 /* RedrawWindow fails only in case that flags are invalid */
1364 EngSetLastError(ERROR_INVALID_FLAGS
);
1368 UserRefObjectCo(Wnd
, &Ref
);
1370 Ret
= co_UserRedrawWindow( Wnd
,
1371 lprcUpdate
? &SafeUpdateRect
: NULL
,
1375 UserDerefObjectCo(Wnd
);
1380 TRACE("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1391 const RECTL
*prcScroll
,
1392 const RECTL
*prcClip
,
1397 RECTL rcScroll
, rcClip
, rcSrc
, rcDst
;
1400 GdiGetClipBox(hDC
, &rcClip
);
1404 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcClip
);
1409 rcScroll
= *prcScroll
;
1410 RECTL_bIntersectRect(&rcSrc
, &rcClip
, prcScroll
);
1418 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1419 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1421 if (!NtGdiBitBlt( hDC
,
1424 rcDst
.right
- rcDst
.left
,
1425 rcDst
.bottom
- rcDst
.top
,
1436 /* Calculate the region that was invalidated by moving or
1437 could not be copied, because it was not visible */
1438 if (hrgnUpdate
|| prcUpdate
)
1440 HRGN hrgnOwn
, hrgnTmp
;
1443 pDC
= DC_LockDc(hDC
);
1449 /* Begin with the shifted and then clipped scroll rect */
1451 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1452 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1455 hrgnOwn
= hrgnUpdate
;
1456 if (!NtGdiSetRectRgn(hrgnOwn
, rcDst
.left
, rcDst
.top
, rcDst
.right
, rcDst
.bottom
))
1464 hrgnOwn
= IntSysCreateRectRgnIndirect(&rcDst
);
1467 /* Add the source rect */
1468 hrgnTmp
= IntSysCreateRectRgnIndirect(&rcSrc
);
1469 NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_OR
);
1471 /* Substract the part of the dest that was visible in source */
1472 prgnTmp
= RGNOBJAPI_Lock(hrgnTmp
, NULL
);
1473 IntGdiCombineRgn(prgnTmp
, prgnTmp
, pDC
->prgnVis
, RGN_AND
);
1474 RGNOBJAPI_Unlock(prgnTmp
);
1475 NtGdiOffsetRgn(hrgnTmp
, dx
, dy
);
1476 Result
= NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_DIFF
);
1478 /* DO NOT Unlock DC while messing with prgnVis! */
1481 GreDeleteObject(hrgnTmp
);
1485 IntGdiGetRgnBox(hrgnOwn
, prcUpdate
);
1490 GreDeleteObject(hrgnOwn
);
1494 Result
= NULLREGION
;
1510 const RECT
*prcUnsafeScroll
,
1511 const RECT
*prcUnsafeClip
,
1513 LPRECT prcUnsafeUpdate
)
1515 DECLARE_RETURN(DWORD
);
1516 RECTL rcScroll
, rcClip
, rcUpdate
;
1517 NTSTATUS Status
= STATUS_SUCCESS
;
1520 TRACE("Enter NtUserScrollDC\n");
1521 UserEnterExclusive();
1525 if (prcUnsafeScroll
)
1527 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1528 rcScroll
= *prcUnsafeScroll
;
1532 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1533 rcClip
= *prcUnsafeClip
;
1535 if (prcUnsafeUpdate
)
1537 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1540 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1542 Status
= _SEH2_GetExceptionCode();
1545 if (!NT_SUCCESS(Status
))
1547 SetLastNtError(Status
);
1551 Result
= UserScrollDC( hDC
,
1554 prcUnsafeScroll
? &rcScroll
: 0,
1555 prcUnsafeClip
? &rcClip
: 0,
1557 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1560 /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
1564 if (prcUnsafeUpdate
)
1568 *prcUnsafeUpdate
= rcUpdate
;
1570 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1572 Status
= _SEH2_GetExceptionCode();
1575 if (!NT_SUCCESS(Status
))
1577 /* FIXME: SetLastError? */
1578 /* FIXME: correct? We have already scrolled! */
1586 TRACE("Leave NtUserScrollDC, ret=%lu\n",_ret_
);
1592 * NtUserScrollWindowEx
1599 NtUserScrollWindowEx(
1603 const RECT
*prcUnsafeScroll
,
1604 const RECT
*prcUnsafeClip
,
1606 LPRECT prcUnsafeUpdate
,
1609 RECTL rcScroll
, rcClip
, rcCaret
, rcUpdate
;
1611 PWND Window
= NULL
, CaretWnd
;
1613 HRGN hrgnOwn
= NULL
, hrgnTemp
, hrgnWinupd
= NULL
;
1617 BOOL bOwnRgn
= TRUE
;
1618 NTSTATUS Status
= STATUS_SUCCESS
;
1619 DECLARE_RETURN(DWORD
);
1620 USER_REFERENCE_ENTRY Ref
, CaretRef
;
1622 TRACE("Enter NtUserScrollWindowEx\n");
1623 UserEnterExclusive();
1625 Window
= UserGetWindowObject(hWnd
);
1626 if (!Window
|| !IntIsWindowDrawable(Window
))
1628 Window
= NULL
; /* prevent deref at cleanup */
1631 UserRefObjectCo(Window
, &Ref
);
1633 IntGetClientRect(Window
, &rcClip
);
1637 if (prcUnsafeScroll
)
1639 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1640 RECTL_bIntersectRect(&rcScroll
, &rcClip
, prcUnsafeScroll
);
1647 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1648 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcUnsafeClip
);
1651 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1653 Status
= _SEH2_GetExceptionCode();
1657 if (!NT_SUCCESS(Status
))
1659 SetLastNtError(Status
);
1663 if (rcClip
.right
<= rcClip
.left
|| rcClip
.bottom
<= rcClip
.top
||
1664 (dx
== 0 && dy
== 0))
1671 hrgnOwn
= hrgnUpdate
;
1675 hrgnOwn
= IntSysCreateRectRgn(0, 0, 0, 0);
1677 /* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
1678 if (flags
& SW_SCROLLWNDDCE
)
1680 dcxflags
= DCX_USESTYLE
;
1682 if (!(Window
->pcls
->style
& (CS_OWNDC
|CS_CLASSDC
)))
1683 dcxflags
|= DCX_CACHE
; // AH??? wine~ If not Powned or with Class go Cheap!
1685 if (flags
& SW_SCROLLCHILDREN
&& Window
->style
& WS_CLIPCHILDREN
)
1686 dcxflags
|= DCX_CACHE
|DCX_NOCLIPCHILDREN
;
1690 /* So in this case ScrollWindowEx uses Cache DC. */
1691 dcxflags
= DCX_CACHE
|DCX_USESTYLE
;
1692 if (flags
& SW_SCROLLCHILDREN
) dcxflags
|= DCX_NOCLIPCHILDREN
;
1695 hDC
= UserGetDCEx(Window
, 0, dcxflags
);
1698 /* FIXME: SetLastError? */
1702 rdw_flags
= (flags
& SW_ERASE
) && (flags
& SW_INVALIDATE
) ? RDW_INVALIDATE
| RDW_ERASE
: RDW_INVALIDATE
;
1705 hwndCaret
= co_IntFixCaret(Window
, &rcCaret
, flags
);
1707 Result
= UserScrollDC( hDC
,
1713 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1715 UserReleaseDC(Window
, hDC
, FALSE
);
1718 * Take into account the fact that some damage may have occurred during
1719 * the scroll. Keep a copy in hrgnWinupd to be added to hrngUpdate at the end.
1722 hrgnTemp
= IntSysCreateRectRgn(0, 0, 0, 0);
1723 if (co_UserGetUpdateRgn(Window
, hrgnTemp
, FALSE
) != NULLREGION
)
1725 HRGN hrgnClip
= IntSysCreateRectRgnIndirect(&rcClip
);
1728 hrgnWinupd
= IntSysCreateRectRgn( 0, 0, 0, 0);
1729 NtGdiCombineRgn( hrgnWinupd
, hrgnTemp
, 0, RGN_COPY
);
1731 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1732 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1733 if (!bOwnRgn
) NtGdiCombineRgn( hrgnWinupd
, hrgnWinupd
, hrgnTemp
, RGN_OR
);
1734 co_UserRedrawWindow(Window
, NULL
, hrgnTemp
, rdw_flags
);
1735 GreDeleteObject(hrgnClip
);
1737 GreDeleteObject(hrgnTemp
);
1739 if (flags
& SW_SCROLLCHILDREN
)
1744 USER_REFERENCE_ENTRY WndRef
;
1747 IntGetClientOrigin(Window
, &ClientOrigin
);
1748 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
1750 rcChild
= Child
->rcWindow
;
1751 rcChild
.left
-= ClientOrigin
.x
;
1752 rcChild
.top
-= ClientOrigin
.y
;
1753 rcChild
.right
-= ClientOrigin
.x
;
1754 rcChild
.bottom
-= ClientOrigin
.y
;
1756 if (! prcUnsafeScroll
|| RECTL_bIntersectRect(&rcDummy
, &rcChild
, &rcScroll
))
1758 UserRefObjectCo(Child
, &WndRef
);
1759 co_WinPosSetWindowPos(Child
, 0, rcChild
.left
+ dx
, rcChild
.top
+ dy
, 0, 0,
1760 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1761 SWP_NOREDRAW
| SWP_DEFERERASE
);
1762 UserDerefObjectCo(Child
);
1767 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1769 co_UserRedrawWindow(Window
, NULL
, hrgnOwn
, rdw_flags
|
1770 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1771 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1774 if (hwndCaret
&& (CaretWnd
= UserGetWindowObject(hwndCaret
)))
1776 UserRefObjectCo(CaretWnd
, &CaretRef
);
1778 co_IntSetCaretPos(rcCaret
.left
+ dx
, rcCaret
.top
+ dy
);
1779 co_UserShowCaret(CaretWnd
);
1781 UserDerefObjectCo(CaretWnd
);
1784 if (prcUnsafeUpdate
)
1788 /* Probe here, to not fail on invalid pointer before scrolling */
1789 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1790 *prcUnsafeUpdate
= rcUpdate
;
1792 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1794 Status
= _SEH2_GetExceptionCode();
1798 if (!NT_SUCCESS(Status
))
1800 SetLastNtError(Status
);
1808 if (hrgnWinupd
&& !bOwnRgn
)
1810 NtGdiCombineRgn( hrgnOwn
, hrgnOwn
, hrgnWinupd
, RGN_OR
);
1811 GreDeleteObject(hrgnWinupd
);
1814 if (hrgnOwn
&& !hrgnUpdate
)
1816 GreDeleteObject(hrgnOwn
);
1820 UserDerefObjectCo(Window
);
1822 TRACE("Leave NtUserScrollWindowEx, ret=%lu\n",_ret_
);
1828 UserDrawCaptionText(
1830 const PUNICODE_STRING Text
,
1835 HFONT hOldFont
= NULL
;
1836 COLORREF OldTextColor
;
1837 NONCLIENTMETRICSW nclm
;
1839 BOOLEAN bDeleteFont
= FALSE
;
1842 TRACE("UserDrawCaptionText: %wZ\n", Text
);
1844 nclm
.cbSize
= sizeof(nclm
);
1845 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1846 sizeof(NONCLIENTMETRICS
), &nclm
, 0))
1848 ERR("UserSystemParametersInfo() failed!\n");
1854 if(uFlags
& DC_SMALLCAP
)
1855 Status
= TextIntCreateFontIndirect(&nclm
.lfSmCaptionFont
, &hFont
);
1857 Status
= TextIntCreateFontIndirect(&nclm
.lfCaptionFont
, &hFont
);
1859 if(!NT_SUCCESS(Status
))
1861 ERR("TextIntCreateFontIndirect() failed! Status: 0x%x\n", Status
);
1868 IntGdiSetBkMode(hDc
, TRANSPARENT
);
1870 hOldFont
= NtGdiSelectFont(hDc
, hFont
);
1873 ERR("SelectFont() failed!\n");
1877 if(uFlags
& DC_INBUTTON
)
1878 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(COLOR_BTNTEXT
));
1880 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(uFlags
& DC_ACTIVE
1881 ? COLOR_CAPTIONTEXT
: COLOR_INACTIVECAPTIONTEXT
));
1883 // FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
1884 GreGetTextExtentW(hDc
, Text
->Buffer
, Text
->Length
/sizeof(WCHAR
), &Size
, 0);
1886 lpRc
->left
, (lpRc
->top
+ lpRc
->bottom
)/2 - Size
.cy
/2,
1887 0, NULL
, Text
->Buffer
, Text
->Length
/sizeof(WCHAR
), NULL
, 0);
1889 IntGdiSetTextColor(hDc
, OldTextColor
);
1891 NtGdiSelectFont(hDc
, hOldFont
);
1893 GreDeleteObject(hFont
);
1898 BOOL
UserDrawCaption(
1904 const PUNICODE_STRING Str
,
1908 HBRUSH hBgBrush
, hOldBrush
= NULL
;
1912 RECTL_vMakeWellOrdered(lpRc
);
1914 if (!hIcon
&& pWnd
!= NULL
)
1916 HasIcon
= (uFlags
& DC_ICON
) && (pWnd
->style
& WS_SYSMENU
)
1917 && !(uFlags
& DC_SMALLCAP
) && !(pWnd
->ExStyle
& WS_EX_DLGMODALFRAME
)
1918 && !(pWnd
->ExStyle
& WS_EX_TOOLWINDOW
);
1921 HasIcon
= (hIcon
!= 0);
1923 // Draw the caption background
1924 if((uFlags
& DC_GRADIENT
) && !(uFlags
& DC_INBUTTON
))
1926 static GRADIENT_RECT gcap
= {0, 1};
1927 TRIVERTEX Vertices
[2];
1930 Colors
[0] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1931 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
1933 Colors
[1] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1934 COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
1936 Vertices
[0].x
= Rect
.left
;
1937 Vertices
[0].y
= Rect
.top
;
1938 Vertices
[0].Red
= (WORD
)Colors
[0]<<8;
1939 Vertices
[0].Green
= (WORD
)Colors
[0] & 0xFF00;
1940 Vertices
[0].Blue
= (WORD
)(Colors
[0]>>8) & 0xFF00;
1941 Vertices
[0].Alpha
= 0;
1943 Vertices
[1].x
= Rect
.right
;
1944 Vertices
[1].y
= Rect
.bottom
;
1945 Vertices
[1].Red
= (WORD
)Colors
[1]<<8;
1946 Vertices
[1].Green
= (WORD
)Colors
[1] & 0xFF00;
1947 Vertices
[1].Blue
= (WORD
)(Colors
[1]>>8) & 0xFF00;
1948 Vertices
[1].Alpha
= 0;
1950 if(!GreGradientFill(hDc
, Vertices
, 2, &gcap
, 1, GRADIENT_FILL_RECT_H
))
1952 ERR("GreGradientFill() failed!\n");
1958 if(uFlags
& DC_INBUTTON
)
1959 hBgBrush
= IntGetSysColorBrush(COLOR_3DFACE
);
1960 else if(uFlags
& DC_ACTIVE
)
1961 hBgBrush
= IntGetSysColorBrush(COLOR_ACTIVECAPTION
);
1963 hBgBrush
= IntGetSysColorBrush(COLOR_INACTIVECAPTION
);
1965 hOldBrush
= NtGdiSelectBrush(hDc
, hBgBrush
);
1969 ERR("NtGdiSelectBrush() failed!\n");
1973 if(!NtGdiPatBlt(hDc
, Rect
.left
, Rect
.top
,
1974 Rect
.right
- Rect
.left
,
1975 Rect
.bottom
- Rect
.top
,
1978 ERR("NtGdiPatBlt() failed!\n");
1986 PCURICON_OBJECT pIcon
= NULL
;
1990 hIcon
= NC_IconForWindow( pWnd
);
1994 pIcon
= UserGetCurIconObject(hIcon
);
1998 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
1999 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
2000 LONG x
= Rect
.left
- cx
/2 + 1 + (Rect
.bottom
- Rect
.top
)/2; // this is really what Window does
2001 LONG y
= (Rect
.top
+ Rect
.bottom
)/2 - cy
/2; // center
2002 UserDrawIconEx(hDc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
2003 UserDereferenceObject(pIcon
);
2008 Rect
.left
+= Rect
.bottom
- Rect
.top
;
2010 if((uFlags
& DC_TEXT
))
2015 UserDrawCaptionText(hDc
, Str
, &Rect
, uFlags
, hFont
);
2016 else if (pWnd
!= NULL
) // FIXME: Windows does not do that
2018 UNICODE_STRING ustr
;
2019 ustr
.Buffer
= pWnd
->strName
.Buffer
; // FIXME: LARGE_STRING truncated!
2020 ustr
.Length
= (USHORT
)min(pWnd
->strName
.Length
, MAXUSHORT
);
2021 ustr
.MaximumLength
= (USHORT
)min(pWnd
->strName
.MaximumLength
, MAXUSHORT
);
2022 UserDrawCaptionText(hDc
, &ustr
, &Rect
, uFlags
, hFont
);
2029 if (hOldBrush
) NtGdiSelectBrush(hDc
, hOldBrush
);
2036 UserRealizePalette(HDC hdc
)
2038 HWND hWnd
, hWndDesktop
;
2041 Ret
= IntGdiRealizePalette(hdc
);
2042 if (Ret
) // There was a change.
2044 hWnd
= IntWindowFromDC(hdc
);
2045 if (hWnd
) // Send broadcast if dc is associated with a window.
2046 { // FYI: Thread locked in CallOneParam.
2047 hWndDesktop
= IntGetDesktopWindow();
2048 if ( hWndDesktop
!= hWnd
)
2050 PWND pWnd
= UserGetWindowObject(hWndDesktop
);
2051 ERR("RealizePalette Desktop.");
2052 hdc
= UserGetWindowDC(pWnd
);
2053 IntPaintDesktop(hdc
);
2054 UserReleaseDC(pWnd
,hdc
,FALSE
);
2056 UserSendNotifyMessage((HWND
)HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0);
2064 NtUserDrawCaptionTemp(
2070 const PUNICODE_STRING str
,
2074 UNICODE_STRING SafeStr
= {0};
2075 NTSTATUS Status
= STATUS_SUCCESS
;
2079 UserEnterExclusive();
2083 if(!(pWnd
= UserGetWindowObject(hWnd
)))
2092 ProbeForRead(lpRc
, sizeof(RECTL
), sizeof(ULONG
));
2093 RtlCopyMemory(&SafeRect
, lpRc
, sizeof(RECTL
));
2096 SafeStr
= ProbeForReadUnicodeString(str
);
2097 if (SafeStr
.Length
!= 0)
2099 ProbeForRead( SafeStr
.Buffer
,
2105 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2107 Status
= _SEH2_GetExceptionCode();
2111 if (Status
!= STATUS_SUCCESS
)
2113 SetLastNtError(Status
);
2119 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, &SafeStr
, uFlags
);
2121 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, NULL
, uFlags
);
2129 NtUserDrawCaption(HWND hWnd
,
2134 return NtUserDrawCaptionTemp(hWnd
, hDC
, lpRc
, 0, 0, NULL
, uFlags
);
2139 NtUserInvalidateRect(
2141 CONST RECT
*lpUnsafeRect
,
2144 return NtUserRedrawWindow(hWnd
, lpUnsafeRect
, NULL
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2149 NtUserInvalidateRgn(
2154 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2167 UserEnterExclusive();
2171 if (!(Window
= UserGetWindowObject(hwnd
)) || // FIXME:
2172 Window
== UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2173 Window
== UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2180 /* Validate flags and check it as a mask for 0 or 1. */
2181 if ( (nFlags
& PW_CLIENTONLY
) == nFlags
)
2182 Ret
= IntPrintWindow( Window
, hdcBlt
, nFlags
);
2184 EngSetLastError(ERROR_INVALID_PARAMETER
);
2192 /* ValidateRect gets redirected to NtUserValidateRect:
2193 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */
2202 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, RDW_VALIDATE
);
2204 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, RDW_INVALIDATE
|RDW_ERASE
|RDW_ERASENOW
|RDW_ALLCHILDREN
);