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
= REGION_LockRgn(Wnd
->hrgnUpdate
);
320 if (!IntValidateParent(Wnd
, RgnUpdate
, Recurse
))
322 REGION_UnlockRgn(RgnUpdate
);
325 REGION_UnlockRgn(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
)
422 INT RgnType
= NULLREGION
;
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
= REGION_LockRgn(Wnd
->hrgnClip
);
463 REGION_bOffsetRgn(Rgn
,
466 RgnType
= IntGdiCombineRgn(Rgn
, Rgn
, RgnClip
, RGN_AND
);
467 REGION_bOffsetRgn(Rgn
,
470 REGION_UnlockRgn(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
= REGION_LockRgn(Wnd
->hrgnUpdate
);
520 RgnType
= IntGdiCombineRgn(RgnUpdate
, RgnUpdate
, Rgn
, RGN_OR
);
521 REGION_UnlockRgn(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
= REGION_LockRgn(Wnd
->hrgnUpdate
);
554 RgnType
= IntGdiCombineRgn(RgnUpdate
, RgnUpdate
, Rgn
, RGN_DIFF
);
555 REGION_UnlockRgn(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 REGION_bOffsetRgn(TmpRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
688 else if (UpdateRect
!= NULL
)
690 if (!RECTL_bIsEmptyRect(UpdateRect
))
692 TmpRgn
= IntSysCreateRectpRgnIndirect(UpdateRect
);
693 REGION_bOffsetRgn(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
)
946 UINT uCount
= pfwi
->uCount
;
947 BOOL Activate
= FALSE
, Ret
= FALSE
;
951 FlashState
= (DWORD
)UserGetProp(pWnd
, AtomFlashWndState
);
953 if (FlashState
== FLASHW_FINISHED
)
955 // Cycle has finished, kill timer and set this to Stop.
956 FlashState
|= FLASHW_KILLSYSTIMER
;
957 pfwi
->dwFlags
= FLASHW_STOP
;
963 if (pfwi
->dwFlags
== FLASHW_SYSTIMER
)
965 // Called from system timer, restore flags, counts and state.
966 pfwi
->dwFlags
= LOWORD(FlashState
);
967 uCount
= HIWORD(FlashState
);
968 FlashState
= MAKELONG(LOWORD(FlashState
),0);
972 // Clean out the trash! Fix SeaMonkey crash after restart.
978 { // First time in cycle, setup flash state.
979 if ( pWnd
->state
& WNDS_ACTIVEFRAME
||
980 (pfwi
->dwFlags
& FLASHW_CAPTION
&& pWnd
->style
& (WS_BORDER
|WS_DLGFRAME
)))
982 FlashState
= FLASHW_STARTED
|FLASHW_ACTIVE
;
986 // Set previous window state.
987 Ret
= !!(FlashState
& FLASHW_ACTIVE
);
989 if ( pfwi
->dwFlags
& FLASHW_TIMERNOFG
&&
990 gpqForeground
== pWnd
->head
.pti
->MessageQueue
)
992 // Flashing until foreground, set this to Stop.
993 pfwi
->dwFlags
= FLASHW_STOP
;
997 // Toggle activate flag.
998 if ( pfwi
->dwFlags
== FLASHW_STOP
)
1000 if (gpqForeground
&& gpqForeground
->spwndActive
== pWnd
)
1007 Activate
= (FlashState
& FLASHW_ACTIVE
) == 0;
1010 if ( pfwi
->dwFlags
== FLASHW_STOP
|| pfwi
->dwFlags
& FLASHW_CAPTION
)
1012 co_IntSendMessage(UserHMGetHandle(pWnd
), WM_NCACTIVATE
, Activate
, 0);
1015 // FIXME: Check for a Stop Sign here.
1016 if ( pfwi
->dwFlags
& FLASHW_TRAY
)
1018 // Need some shell work here too.
1019 TRACE("FIXME: Flash window no Tray support!\n");
1022 if ( pfwi
->dwFlags
== FLASHW_STOP
)
1024 if (FlashState
& FLASHW_KILLSYSTIMER
)
1026 IntKillTimer(pWnd
, ID_EVENT_SYSTIMER_FLASHWIN
, TRUE
);
1029 IntRemoveProp(pWnd
, AtomFlashWndState
);
1032 { // Have a count and started, set timer.
1035 FlashState
|= FLASHW_COUNT
;
1037 if (!(Activate
^ !!(FlashState
& FLASHW_STARTED
)))
1040 if (!(FlashState
& FLASHW_KILLSYSTIMER
))
1041 pfwi
->dwFlags
|= FLASHW_TIMER
;
1044 if (pfwi
->dwFlags
& FLASHW_TIMER
)
1046 FlashState
|= FLASHW_KILLSYSTIMER
;
1049 ID_EVENT_SYSTIMER_FLASHWIN
,
1050 pfwi
->dwTimeout
? pfwi
->dwTimeout
: gpsi
->dtCaretBlink
,
1055 if (FlashState
& FLASHW_COUNT
&& uCount
== 0)
1057 // Keep spinning? Nothing else to do.
1058 FlashState
= FLASHW_FINISHED
;
1062 // Save state and flags so this can be restored next time through.
1063 FlashState
^= (FlashState
^ -!!(Activate
)) & FLASHW_ACTIVE
;
1064 FlashState
^= (FlashState
^ pfwi
->dwFlags
) & (FLASHW_MASK
& ~FLASHW_TIMER
);
1066 FlashState
= MAKELONG(LOWORD(FlashState
),uCount
);
1067 IntSetProp(pWnd
, AtomFlashWndState
, (HANDLE
) FlashState
);
1073 IntBeginPaint(PWND Window
, PPAINTSTRUCT Ps
)
1075 co_UserHideCaret(Window
);
1077 Window
->state2
|= WNDS2_STARTPAINT
;
1078 Window
->state
&= ~WNDS_PAINTNOTPROCESSED
;
1080 if (Window
->state
& WNDS_SENDNCPAINT
)
1084 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1085 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
1086 Window
->state
&= ~WNDS_SENDNCPAINT
;
1087 co_IntSendMessage(UserHMGetHandle(Window
), WM_NCPAINT
, (WPARAM
)hRgn
, 0);
1088 if (hRgn
!= HRGN_WINDOW
&& hRgn
!= NULL
&& GreIsHandleValid(hRgn
))
1090 /* NOTE: The region can already be deleted! */
1091 GreDeleteObject(hRgn
);
1096 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1099 RtlZeroMemory(Ps
, sizeof(PAINTSTRUCT
));
1101 Ps
->hdc
= UserGetDCEx( Window
,
1103 DCX_INTERSECTRGN
| DCX_USESTYLE
);
1109 if (Window
->hrgnUpdate
!= NULL
)
1111 MsqDecPaintCountQueue(Window
->head
.pti
);
1112 GdiGetClipBox(Ps
->hdc
, &Ps
->rcPaint
);
1113 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
1114 /* The region is part of the dc now and belongs to the process! */
1115 Window
->hrgnUpdate
= NULL
;
1119 if (Window
->state
& WNDS_INTERNALPAINT
)
1120 MsqDecPaintCountQueue(Window
->head
.pti
);
1122 IntGetClientRect(Window
, &Ps
->rcPaint
);
1125 Window
->state
&= ~WNDS_INTERNALPAINT
;
1127 if (Window
->state
& WNDS_SENDERASEBACKGROUND
)
1129 Window
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
1130 Ps
->fErase
= !co_IntSendMessage(UserHMGetHandle(Window
), WM_ERASEBKGND
, (WPARAM
)Ps
->hdc
, 0);
1133 Window
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
1140 if (Window
->hrgnUpdate
)
1142 if (!(Window
->style
& WS_CLIPCHILDREN
))
1145 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
1147 if (Child
->hrgnUpdate
== NULL
&& Child
->state
& WNDS_SENDNCPAINT
) // Helped fixing test_redrawnow.
1148 IntInvalidateWindows(Child
, NULL
, RDW_FRAME
| RDW_ERASE
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
1156 IntEndPaint(PWND Wnd
, PPAINTSTRUCT Ps
)
1162 UserReleaseDC(Wnd
, hdc
, TRUE
);
1164 Wnd
->state2
&= ~(WNDS2_WMPAINTSENT
|WNDS2_STARTPAINT
);
1166 co_UserShowCaret(Wnd
);
1171 /* PUBLIC FUNCTIONS ***********************************************************/
1181 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
1187 USER_REFERENCE_ENTRY Ref
;
1188 DECLARE_RETURN(HDC
);
1190 TRACE("Enter NtUserBeginPaint\n");
1191 UserEnterExclusive();
1193 if (!(Window
= UserGetWindowObject(hWnd
)))
1198 UserRefObjectCo(Window
, &Ref
);
1200 hDC
= IntBeginPaint(Window
, &Ps
);
1202 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
1203 if (! NT_SUCCESS(Status
))
1205 SetLastNtError(Status
);
1212 if (Window
) UserDerefObjectCo(Window
);
1214 TRACE("Leave NtUserBeginPaint, ret=%p\n",_ret_
);
1228 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* pUnsafePs
)
1230 NTSTATUS Status
= STATUS_SUCCESS
;
1233 USER_REFERENCE_ENTRY Ref
;
1234 DECLARE_RETURN(BOOL
);
1236 TRACE("Enter NtUserEndPaint\n");
1237 UserEnterExclusive();
1239 if (!(Window
= UserGetWindowObject(hWnd
)))
1244 UserRefObjectCo(Window
, &Ref
); // Here for the exception.
1248 ProbeForRead(pUnsafePs
, sizeof(*pUnsafePs
), 1);
1249 RtlCopyMemory(&Ps
, pUnsafePs
, sizeof(PAINTSTRUCT
));
1251 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1253 Status
= _SEH2_GetExceptionCode();
1256 if (!NT_SUCCESS(Status
))
1261 RETURN(IntEndPaint(Window
, &Ps
));
1264 if (Window
) UserDerefObjectCo(Window
);
1266 TRACE("Leave NtUserEndPaint, ret=%i\n",_ret_
);
1275 NtUserFlashWindowEx(IN PFLASHWINFO pfwi
)
1278 FLASHWINFO finfo
= {0};
1281 UserEnterExclusive();
1285 ProbeForRead(pfwi
, sizeof(FLASHWINFO
), sizeof(ULONG
));
1286 RtlCopyMemory(&finfo
, pfwi
, sizeof(FLASHWINFO
));
1288 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1290 SetLastNtError(_SEH2_GetExceptionCode());
1295 if (!Ret
) goto Exit
;
1297 if (!( pWnd
= (PWND
)UserGetObject(gHandleTable
, finfo
.hwnd
, TYPE_WINDOW
)) ||
1298 finfo
.cbSize
!= sizeof(FLASHWINFO
) ||
1299 finfo
.dwFlags
& ~(FLASHW_ALL
|FLASHW_TIMER
|FLASHW_TIMERNOFG
) )
1301 EngSetLastError(ERROR_INVALID_PARAMETER
);
1306 Ret
= IntFlashWindowEx(pWnd
, &finfo
);
1314 co_UserGetUpdateRgn(PWND Window
, PREGION Rgn
, BOOL bErase
)
1320 ASSERT_REFS_CO(Window
);
1322 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1324 if (Window
->hrgnUpdate
== NULL
)
1326 REGION_SetRectRgn(Rgn
, 0, 0, 0, 0);
1330 UpdateRgn
= REGION_LockRgn(Window
->hrgnUpdate
);
1334 Rect
= Window
->rcClient
;
1335 IntIntersectWithParents(Window
, &Rect
);
1336 REGION_SetRectRgn(Rgn
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
1337 RegionType
= IntGdiCombineRgn(Rgn
, Rgn
, UpdateRgn
, RGN_AND
);
1338 REGION_bOffsetRgn(Rgn
, -Window
->rcClient
.left
, -Window
->rcClient
.top
);
1339 REGION_UnlockRgn(UpdateRgn
);
1341 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
1343 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1350 * NtUserGetUpdateRgn
1357 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
1359 DECLARE_RETURN(INT
);
1362 USER_REFERENCE_ENTRY Ref
;
1365 TRACE("Enter NtUserGetUpdateRgn\n");
1366 UserEnterExclusive();
1368 if (!(Window
= UserGetWindowObject(hWnd
)))
1373 /* Use a system region, we can't hold GDI locks when doing roundtrips to user mode */
1374 Rgn
= IntSysCreateRectpRgn(0, 0, 0, 0);
1378 UserRefObjectCo(Window
, &Ref
);
1379 ret
= co_UserGetUpdateRgn(Window
, Rgn
, bErase
);
1380 UserDerefObjectCo(Window
);
1385 if (Rgn
&& (_ret_
!= ERROR
))
1387 PREGION TheRgn
= REGION_LockRgn(hRgn
);
1390 EngSetLastError(ERROR_INVALID_HANDLE
);
1395 IntGdiCombineRgn(TheRgn
, Rgn
, NULL
, RGN_COPY
);
1396 REGION_UnlockRgn(TheRgn
);
1403 TRACE("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
1409 * NtUserGetUpdateRect
1416 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
1423 DECLARE_RETURN(BOOL
);
1425 TRACE("Enter NtUserGetUpdateRect\n");
1426 UserEnterExclusive();
1428 if (!(Window
= UserGetWindowObject(hWnd
)))
1433 Window
->state
&= ~WNDS_UPDATEDIRTY
;
1435 if (Window
->hrgnUpdate
== NULL
)
1437 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1441 /* Get the update region bounding box. */
1442 if (Window
->hrgnUpdate
== HRGN_WINDOW
)
1444 Rect
= Window
->rcClient
;
1448 RgnData
= REGION_LockRgn(Window
->hrgnUpdate
);
1449 ASSERT(RgnData
!= NULL
);
1450 RegionType
= REGION_GetRgnBox(RgnData
, &Rect
);
1451 REGION_UnlockRgn(RgnData
);
1453 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
1454 RECTL_bIntersectRect(&Rect
, &Rect
, &Window
->rcClient
);
1457 if (IntIntersectWithParents(Window
, &Rect
))
1459 RECTL_vOffsetRect(&Rect
,
1460 -Window
->rcClient
.left
,
1461 -Window
->rcClient
.top
);
1464 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1468 if (bErase
&& !RECTL_bIsEmptyRect(&Rect
))
1470 USER_REFERENCE_ENTRY Ref
;
1471 UserRefObjectCo(Window
, &Ref
);
1472 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1473 UserDerefObjectCo(Window
);
1476 if (UnsafeRect
!= NULL
)
1478 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECTL
));
1479 if (!NT_SUCCESS(Status
))
1481 EngSetLastError(ERROR_INVALID_PARAMETER
);
1486 RETURN(!RECTL_bIsEmptyRect(&Rect
));
1489 TRACE("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1495 * NtUserRedrawWindow
1504 CONST RECT
*lprcUpdate
,
1508 RECTL SafeUpdateRect
;
1511 USER_REFERENCE_ENTRY Ref
;
1512 NTSTATUS Status
= STATUS_SUCCESS
;
1513 PREGION RgnUpdate
= NULL
;
1514 DECLARE_RETURN(BOOL
);
1516 TRACE("Enter NtUserRedrawWindow\n");
1517 UserEnterExclusive();
1519 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1528 ProbeForRead(lprcUpdate
, sizeof(RECTL
), 1);
1529 RtlCopyMemory(&SafeUpdateRect
, lprcUpdate
, sizeof(RECTL
));
1531 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1533 Status
= _SEH2_GetExceptionCode();
1536 if (!NT_SUCCESS(Status
))
1538 EngSetLastError(RtlNtStatusToDosError(Status
));
1543 if ( flags
& ~(RDW_ERASE
|RDW_FRAME
|RDW_INTERNALPAINT
|RDW_INVALIDATE
|
1544 RDW_NOERASE
|RDW_NOFRAME
|RDW_NOINTERNALPAINT
|RDW_VALIDATE
|
1545 RDW_ERASENOW
|RDW_UPDATENOW
|RDW_ALLCHILDREN
|RDW_NOCHILDREN
) )
1547 /* RedrawWindow fails only in case that flags are invalid */
1548 EngSetLastError(ERROR_INVALID_FLAGS
);
1552 /* We can't hold lock on GDI obects while doing roundtrips to user mode,
1553 * so use a copy instead */
1558 RgnUpdate
= IntSysCreateRectpRgn(0, 0, 0, 0);
1561 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1565 RgnTemp
= REGION_LockRgn(hrgnUpdate
);
1568 EngSetLastError(ERROR_INVALID_HANDLE
);
1571 IntGdiCombineRgn(RgnUpdate
, RgnTemp
, NULL
, RGN_COPY
);
1572 REGION_UnlockRgn(RgnTemp
);
1575 UserRefObjectCo(Wnd
, &Ref
);
1577 Ret
= co_UserRedrawWindow( Wnd
,
1578 lprcUpdate
? &SafeUpdateRect
: NULL
,
1582 UserDerefObjectCo(Wnd
);
1588 REGION_Delete(RgnUpdate
);
1589 TRACE("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1600 const RECTL
*prcScroll
,
1601 const RECTL
*prcClip
,
1607 RECTL rcScroll
, rcClip
, rcSrc
, rcDst
;
1610 if (GdiGetClipBox(hDC
, &rcClip
) == ERROR
)
1612 ERR("GdiGetClipBox failed for HDC %p\n", hDC
);
1619 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcClip
);
1624 rcScroll
= *prcScroll
;
1625 RECTL_bIntersectRect(&rcSrc
, &rcClip
, prcScroll
);
1633 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1634 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1636 if (!NtGdiBitBlt( hDC
,
1639 rcDst
.right
- rcDst
.left
,
1640 rcDst
.bottom
- rcDst
.top
,
1651 /* Calculate the region that was invalidated by moving or
1652 could not be copied, because it was not visible */
1653 if (RgnUpdate
|| hrgnUpdate
|| prcUpdate
)
1655 PREGION RgnOwn
, RgnTmp
;
1657 pDC
= DC_LockDc(hDC
);
1665 NT_ASSERT(RgnUpdate
== NULL
);
1666 RgnUpdate
= REGION_LockRgn(hrgnUpdate
);
1674 /* Begin with the shifted and then clipped scroll rect */
1676 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1677 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1681 REGION_SetRectRgn(RgnOwn
, rcDst
.left
, rcDst
.top
, rcDst
.right
, rcDst
.bottom
);
1685 RgnOwn
= IntSysCreateRectpRgnIndirect(&rcDst
);
1688 /* Add the source rect */
1689 RgnTmp
= IntSysCreateRectpRgnIndirect(&rcSrc
);
1690 IntGdiCombineRgn(RgnOwn
, RgnOwn
, RgnTmp
, RGN_OR
);
1692 /* Substract the part of the dest that was visible in source */
1693 IntGdiCombineRgn(RgnTmp
, RgnTmp
, pDC
->prgnVis
, RGN_AND
);
1694 REGION_bOffsetRgn(RgnTmp
, dx
, dy
);
1695 Result
= IntGdiCombineRgn(RgnOwn
, RgnOwn
, RgnTmp
, RGN_DIFF
);
1697 /* DO NOT Unlock DC while messing with prgnVis! */
1700 REGION_Delete(RgnTmp
);
1704 REGION_GetRgnBox(RgnOwn
, prcUpdate
);
1709 REGION_UnlockRgn(RgnUpdate
);
1711 else if (!RgnUpdate
)
1713 REGION_Delete(RgnOwn
);
1717 Result
= NULLREGION
;
1733 const RECT
*prcUnsafeScroll
,
1734 const RECT
*prcUnsafeClip
,
1736 LPRECT prcUnsafeUpdate
)
1738 DECLARE_RETURN(DWORD
);
1739 RECTL rcScroll
, rcClip
, rcUpdate
;
1740 NTSTATUS Status
= STATUS_SUCCESS
;
1743 TRACE("Enter NtUserScrollDC\n");
1744 UserEnterExclusive();
1748 if (prcUnsafeScroll
)
1750 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1751 rcScroll
= *prcUnsafeScroll
;
1755 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1756 rcClip
= *prcUnsafeClip
;
1758 if (prcUnsafeUpdate
)
1760 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1763 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1765 Status
= _SEH2_GetExceptionCode();
1768 if (!NT_SUCCESS(Status
))
1770 SetLastNtError(Status
);
1774 Result
= UserScrollDC( hDC
,
1777 prcUnsafeScroll
? &rcScroll
: 0,
1778 prcUnsafeClip
? &rcClip
: 0,
1781 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1784 /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
1788 if (prcUnsafeUpdate
)
1792 *prcUnsafeUpdate
= rcUpdate
;
1794 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1796 Status
= _SEH2_GetExceptionCode();
1799 if (!NT_SUCCESS(Status
))
1801 /* FIXME: SetLastError? */
1802 /* FIXME: correct? We have already scrolled! */
1810 TRACE("Leave NtUserScrollDC, ret=%lu\n",_ret_
);
1816 * NtUserScrollWindowEx
1823 NtUserScrollWindowEx(
1827 const RECT
*prcUnsafeScroll
,
1828 const RECT
*prcUnsafeClip
,
1830 LPRECT prcUnsafeUpdate
,
1833 RECTL rcScroll
, rcClip
, rcCaret
, rcUpdate
;
1835 PWND Window
= NULL
, CaretWnd
;
1837 PREGION RgnUpdate
= NULL
, RgnTemp
, RgnWinupd
= NULL
;
1841 NTSTATUS Status
= STATUS_SUCCESS
;
1842 DECLARE_RETURN(DWORD
);
1843 USER_REFERENCE_ENTRY Ref
, CaretRef
;
1845 TRACE("Enter NtUserScrollWindowEx\n");
1846 UserEnterExclusive();
1848 Window
= UserGetWindowObject(hWnd
);
1849 if (!Window
|| !IntIsWindowDrawable(Window
))
1851 Window
= NULL
; /* prevent deref at cleanup */
1854 UserRefObjectCo(Window
, &Ref
);
1856 IntGetClientRect(Window
, &rcClip
);
1860 if (prcUnsafeScroll
)
1862 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1863 RECTL_bIntersectRect(&rcScroll
, &rcClip
, prcUnsafeScroll
);
1870 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1871 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcUnsafeClip
);
1874 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1876 Status
= _SEH2_GetExceptionCode();
1880 if (!NT_SUCCESS(Status
))
1882 SetLastNtError(Status
);
1886 if (rcClip
.right
<= rcClip
.left
|| rcClip
.bottom
<= rcClip
.top
||
1887 (dx
== 0 && dy
== 0))
1892 /* We must use a copy of the region, as we can't hold an exclusive lock
1893 * on it while doing callouts to user-mode */
1894 RgnUpdate
= IntSysCreateRectpRgn(0, 0, 0, 0);
1897 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1903 RgnTemp
= REGION_LockRgn(hrgnUpdate
);
1906 EngSetLastError(ERROR_INVALID_HANDLE
);
1909 IntGdiCombineRgn(RgnUpdate
, RgnTemp
, NULL
, RGN_COPY
);
1910 REGION_UnlockRgn(RgnTemp
);
1913 /* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
1914 if (flags
& SW_SCROLLWNDDCE
)
1916 dcxflags
= DCX_USESTYLE
;
1918 if (!(Window
->pcls
->style
& (CS_OWNDC
|CS_CLASSDC
)))
1919 dcxflags
|= DCX_CACHE
; // AH??? wine~ If not Powned or with Class go Cheap!
1921 if (flags
& SW_SCROLLCHILDREN
&& Window
->style
& WS_CLIPCHILDREN
)
1922 dcxflags
|= DCX_CACHE
|DCX_NOCLIPCHILDREN
;
1926 /* So in this case ScrollWindowEx uses Cache DC. */
1927 dcxflags
= DCX_CACHE
|DCX_USESTYLE
;
1928 if (flags
& SW_SCROLLCHILDREN
) dcxflags
|= DCX_NOCLIPCHILDREN
;
1931 hDC
= UserGetDCEx(Window
, 0, dcxflags
);
1934 /* FIXME: SetLastError? */
1938 rdw_flags
= (flags
& SW_ERASE
) && (flags
& SW_INVALIDATE
) ? RDW_INVALIDATE
| RDW_ERASE
: RDW_INVALIDATE
;
1941 hwndCaret
= co_IntFixCaret(Window
, &rcCaret
, flags
);
1943 Result
= UserScrollDC( hDC
,
1950 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1952 UserReleaseDC(Window
, hDC
, FALSE
);
1955 * Take into account the fact that some damage may have occurred during
1956 * the scroll. Keep a copy in hrgnWinupd to be added to hrngUpdate at the end.
1959 RgnTemp
= IntSysCreateRectpRgn(0, 0, 0, 0);
1962 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1966 if (co_UserGetUpdateRgn(Window
, RgnTemp
, FALSE
) != NULLREGION
)
1968 PREGION RgnClip
= IntSysCreateRectpRgnIndirect(&rcClip
);
1973 RgnWinupd
= IntSysCreateRectpRgn( 0, 0, 0, 0);
1974 IntGdiCombineRgn( RgnWinupd
, RgnTemp
, 0, RGN_COPY
);
1976 REGION_bOffsetRgn(RgnTemp
, dx
, dy
);
1977 IntGdiCombineRgn(RgnTemp
, RgnTemp
, RgnClip
, RGN_AND
);
1979 IntGdiCombineRgn( RgnWinupd
, RgnWinupd
, RgnTemp
, RGN_OR
);
1980 co_UserRedrawWindow(Window
, NULL
, RgnTemp
, rdw_flags
);
1981 REGION_Delete(RgnClip
);
1984 REGION_Delete(RgnTemp
);
1986 if (flags
& SW_SCROLLCHILDREN
)
1991 USER_REFERENCE_ENTRY WndRef
;
1994 IntGetClientOrigin(Window
, &ClientOrigin
);
1995 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
1997 rcChild
= Child
->rcWindow
;
1998 rcChild
.left
-= ClientOrigin
.x
;
1999 rcChild
.top
-= ClientOrigin
.y
;
2000 rcChild
.right
-= ClientOrigin
.x
;
2001 rcChild
.bottom
-= ClientOrigin
.y
;
2003 if (! prcUnsafeScroll
|| RECTL_bIntersectRect(&rcDummy
, &rcChild
, &rcScroll
))
2005 UserRefObjectCo(Child
, &WndRef
);
2006 co_WinPosSetWindowPos(Child
, 0, rcChild
.left
+ dx
, rcChild
.top
+ dy
, 0, 0,
2007 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
2008 SWP_NOREDRAW
| SWP_DEFERERASE
);
2009 UserDerefObjectCo(Child
);
2014 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
2016 co_UserRedrawWindow(Window
, NULL
, RgnUpdate
, rdw_flags
|
2017 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
2018 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
2021 if (hwndCaret
&& (CaretWnd
= UserGetWindowObject(hwndCaret
)))
2023 UserRefObjectCo(CaretWnd
, &CaretRef
);
2025 co_IntSetCaretPos(rcCaret
.left
+ dx
, rcCaret
.top
+ dy
);
2026 co_UserShowCaret(CaretWnd
);
2028 UserDerefObjectCo(CaretWnd
);
2031 if (prcUnsafeUpdate
)
2035 /* Probe here, to not fail on invalid pointer before scrolling */
2036 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
2037 *prcUnsafeUpdate
= rcUpdate
;
2039 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2041 Status
= _SEH2_GetExceptionCode();
2045 if (!NT_SUCCESS(Status
))
2047 SetLastNtError(Status
);
2055 if (hrgnUpdate
&& (_ret_
!= ERROR
))
2057 /* Give everything back to the caller */
2058 RgnTemp
= REGION_LockRgn(hrgnUpdate
);
2059 /* The handle should still be valid */
2062 IntGdiCombineRgn(RgnTemp
, RgnUpdate
, RgnWinupd
, RGN_OR
);
2064 IntGdiCombineRgn(RgnTemp
, RgnUpdate
, NULL
, RGN_COPY
);
2065 REGION_UnlockRgn(RgnTemp
);
2070 REGION_Delete(RgnWinupd
);
2075 REGION_Delete(RgnUpdate
);
2079 UserDerefObjectCo(Window
);
2081 TRACE("Leave NtUserScrollWindowEx, ret=%lu\n",_ret_
);
2087 UserDrawCaptionText(
2089 const PUNICODE_STRING Text
,
2094 HFONT hOldFont
= NULL
;
2095 COLORREF OldTextColor
;
2096 NONCLIENTMETRICSW nclm
;
2098 BOOLEAN bDeleteFont
= FALSE
;
2101 TRACE("UserDrawCaptionText: %wZ\n", Text
);
2103 nclm
.cbSize
= sizeof(nclm
);
2104 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
2105 sizeof(NONCLIENTMETRICS
), &nclm
, 0))
2107 ERR("UserSystemParametersInfo() failed!\n");
2113 if(uFlags
& DC_SMALLCAP
)
2114 Status
= TextIntCreateFontIndirect(&nclm
.lfSmCaptionFont
, &hFont
);
2116 Status
= TextIntCreateFontIndirect(&nclm
.lfCaptionFont
, &hFont
);
2118 if(!NT_SUCCESS(Status
))
2120 ERR("TextIntCreateFontIndirect() failed! Status: 0x%x\n", Status
);
2127 IntGdiSetBkMode(hDc
, TRANSPARENT
);
2129 hOldFont
= NtGdiSelectFont(hDc
, hFont
);
2132 ERR("SelectFont() failed!\n");
2136 if(uFlags
& DC_INBUTTON
)
2137 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(COLOR_BTNTEXT
));
2139 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(uFlags
& DC_ACTIVE
2140 ? COLOR_CAPTIONTEXT
: COLOR_INACTIVECAPTIONTEXT
));
2142 // FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
2143 GreGetTextExtentW(hDc
, Text
->Buffer
, Text
->Length
/sizeof(WCHAR
), &Size
, 0);
2145 lpRc
->left
, (lpRc
->top
+ lpRc
->bottom
)/2 - Size
.cy
/2,
2146 0, NULL
, Text
->Buffer
, Text
->Length
/sizeof(WCHAR
), NULL
, 0);
2148 IntGdiSetTextColor(hDc
, OldTextColor
);
2150 NtGdiSelectFont(hDc
, hOldFont
);
2152 GreDeleteObject(hFont
);
2157 BOOL
UserDrawCaption(
2163 const PUNICODE_STRING Str
,
2167 HBRUSH hBgBrush
, hOldBrush
= NULL
;
2171 RECTL_vMakeWellOrdered(lpRc
);
2173 if (!hIcon
&& pWnd
!= NULL
)
2175 HasIcon
= (uFlags
& DC_ICON
) && (pWnd
->style
& WS_SYSMENU
)
2176 && !(uFlags
& DC_SMALLCAP
) && !(pWnd
->ExStyle
& WS_EX_DLGMODALFRAME
)
2177 && !(pWnd
->ExStyle
& WS_EX_TOOLWINDOW
);
2180 HasIcon
= (hIcon
!= 0);
2182 // Draw the caption background
2183 if((uFlags
& DC_GRADIENT
) && !(uFlags
& DC_INBUTTON
))
2185 static GRADIENT_RECT gcap
= {0, 1};
2186 TRIVERTEX Vertices
[2];
2189 Colors
[0] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
2190 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
2192 Colors
[1] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
2193 COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
2195 Vertices
[0].x
= Rect
.left
;
2196 Vertices
[0].y
= Rect
.top
;
2197 Vertices
[0].Red
= (WORD
)Colors
[0]<<8;
2198 Vertices
[0].Green
= (WORD
)Colors
[0] & 0xFF00;
2199 Vertices
[0].Blue
= (WORD
)(Colors
[0]>>8) & 0xFF00;
2200 Vertices
[0].Alpha
= 0;
2202 Vertices
[1].x
= Rect
.right
;
2203 Vertices
[1].y
= Rect
.bottom
;
2204 Vertices
[1].Red
= (WORD
)Colors
[1]<<8;
2205 Vertices
[1].Green
= (WORD
)Colors
[1] & 0xFF00;
2206 Vertices
[1].Blue
= (WORD
)(Colors
[1]>>8) & 0xFF00;
2207 Vertices
[1].Alpha
= 0;
2209 if(!GreGradientFill(hDc
, Vertices
, 2, &gcap
, 1, GRADIENT_FILL_RECT_H
))
2211 ERR("GreGradientFill() failed!\n");
2217 if(uFlags
& DC_INBUTTON
)
2218 hBgBrush
= IntGetSysColorBrush(COLOR_3DFACE
);
2219 else if(uFlags
& DC_ACTIVE
)
2220 hBgBrush
= IntGetSysColorBrush(COLOR_ACTIVECAPTION
);
2222 hBgBrush
= IntGetSysColorBrush(COLOR_INACTIVECAPTION
);
2224 hOldBrush
= NtGdiSelectBrush(hDc
, hBgBrush
);
2228 ERR("NtGdiSelectBrush() failed!\n");
2232 if(!NtGdiPatBlt(hDc
, Rect
.left
, Rect
.top
,
2233 Rect
.right
- Rect
.left
,
2234 Rect
.bottom
- Rect
.top
,
2237 ERR("NtGdiPatBlt() failed!\n");
2245 PCURICON_OBJECT pIcon
= NULL
;
2249 pIcon
= UserGetCurIconObject(hIcon
);
2253 pIcon
= NC_IconForWindow(pWnd
);
2254 // FIXME: NC_IconForWindow should reference it for us */
2256 UserReferenceObject(pIcon
);
2261 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
2262 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
2263 LONG x
= Rect
.left
- cx
/2 + 1 + (Rect
.bottom
- Rect
.top
)/2; // this is really what Window does
2264 LONG y
= (Rect
.top
+ Rect
.bottom
)/2 - cy
/2; // center
2265 UserDrawIconEx(hDc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
2266 UserDereferenceObject(pIcon
);
2275 Rect
.left
+= Rect
.bottom
- Rect
.top
;
2277 if((uFlags
& DC_TEXT
))
2282 UserDrawCaptionText(hDc
, Str
, &Rect
, uFlags
, hFont
);
2283 else if (pWnd
!= NULL
) // FIXME: Windows does not do that
2285 UNICODE_STRING ustr
;
2286 ustr
.Buffer
= pWnd
->strName
.Buffer
; // FIXME: LARGE_STRING truncated!
2287 ustr
.Length
= (USHORT
)min(pWnd
->strName
.Length
, MAXUSHORT
);
2288 ustr
.MaximumLength
= (USHORT
)min(pWnd
->strName
.MaximumLength
, MAXUSHORT
);
2289 UserDrawCaptionText(hDc
, &ustr
, &Rect
, uFlags
, hFont
);
2296 if (hOldBrush
) NtGdiSelectBrush(hDc
, hOldBrush
);
2303 UserRealizePalette(HDC hdc
)
2305 HWND hWnd
, hWndDesktop
;
2308 Ret
= IntGdiRealizePalette(hdc
);
2309 if (Ret
) // There was a change.
2311 hWnd
= IntWindowFromDC(hdc
);
2312 if (hWnd
) // Send broadcast if dc is associated with a window.
2313 { // FYI: Thread locked in CallOneParam.
2314 hWndDesktop
= IntGetDesktopWindow();
2315 if ( hWndDesktop
!= hWnd
)
2317 PWND pWnd
= UserGetWindowObject(hWndDesktop
);
2318 ERR("RealizePalette Desktop.");
2319 hdc
= UserGetWindowDC(pWnd
);
2320 IntPaintDesktop(hdc
);
2321 UserReleaseDC(pWnd
,hdc
,FALSE
);
2323 UserSendNotifyMessage((HWND
)HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0);
2331 NtUserDrawCaptionTemp(
2337 const PUNICODE_STRING str
,
2341 UNICODE_STRING SafeStr
= {0};
2342 NTSTATUS Status
= STATUS_SUCCESS
;
2346 UserEnterExclusive();
2350 if(!(pWnd
= UserGetWindowObject(hWnd
)))
2359 ProbeForRead(lpRc
, sizeof(RECTL
), sizeof(ULONG
));
2360 RtlCopyMemory(&SafeRect
, lpRc
, sizeof(RECTL
));
2363 SafeStr
= ProbeForReadUnicodeString(str
);
2364 if (SafeStr
.Length
!= 0)
2366 ProbeForRead( SafeStr
.Buffer
,
2372 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2374 Status
= _SEH2_GetExceptionCode();
2378 if (Status
!= STATUS_SUCCESS
)
2380 SetLastNtError(Status
);
2386 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, &SafeStr
, uFlags
);
2388 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, NULL
, uFlags
);
2396 NtUserDrawCaption(HWND hWnd
,
2401 return NtUserDrawCaptionTemp(hWnd
, hDC
, lpRc
, 0, 0, NULL
, uFlags
);
2406 NtUserInvalidateRect(
2408 CONST RECT
*lpUnsafeRect
,
2411 UINT flags
= RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0);
2414 flags
= RDW_ALLCHILDREN
| RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ERASENOW
;
2415 lpUnsafeRect
= NULL
;
2417 return NtUserRedrawWindow(hWnd
, lpUnsafeRect
, NULL
, flags
);
2422 NtUserInvalidateRgn(
2429 EngSetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2432 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2445 UserEnterExclusive();
2449 if (!(Window
= UserGetWindowObject(hwnd
)) || // FIXME:
2450 Window
== UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2451 Window
== UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2458 /* Validate flags and check it as a mask for 0 or 1. */
2459 if ( (nFlags
& PW_CLIENTONLY
) == nFlags
)
2460 Ret
= IntPrintWindow( Window
, hdcBlt
, nFlags
);
2462 EngSetLastError(ERROR_INVALID_PARAMETER
);
2470 /* ValidateRect gets redirected to NtUserValidateRect:
2471 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */
2478 UINT flags
= RDW_VALIDATE
;
2481 flags
= RDW_ALLCHILDREN
| RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ERASENOW
;
2484 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, flags
);