return Result;
}
+DWORD
+FASTCALL
+IntScrollWindowEx(
+ PWND Window,
+ INT dx,
+ INT dy,
+ const RECT *prcScroll,
+ const RECT *prcClip,
+ HRGN hrgnUpdate,
+ LPRECT prcUpdate,
+ UINT flags)
+{
+ RECTL rcScroll, rcClip, rcCaret;
+ INT Result;
+ PWND CaretWnd;
+ HDC hDC;
+ PREGION RgnUpdate = NULL, RgnTemp, RgnWinupd = NULL;
+ HWND hwndCaret;
+ DWORD dcxflags = 0;
+ int rdw_flags;
+ USER_REFERENCE_ENTRY CaretRef;
+
+ IntGetClientRect(Window, &rcClip);
+
+ if (prcScroll)
+ {
+ RECTL_bIntersectRect(&rcScroll, &rcClip, prcScroll);
+ }
+ else
+ rcScroll = rcClip;
+
+ if (prcClip)
+ {
+ RECTL_bIntersectRect(&rcClip, &rcClip, prcClip);
+ }
+
+ if (rcClip.right <= rcClip.left || rcClip.bottom <= rcClip.top ||
+ (dx == 0 && dy == 0))
+ {
+ return NULLREGION;
+ }
+
+ /* We must use a copy of the region, as we can't hold an exclusive lock
+ * on it while doing callouts to user-mode */
+ RgnUpdate = IntSysCreateRectpRgn(0, 0, 0, 0);
+ if(!RgnUpdate)
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return ERROR;
+ }
+
+ if (hrgnUpdate)
+ {
+ RgnTemp = REGION_LockRgn(hrgnUpdate);
+ if (!RgnTemp)
+ {
+ EngSetLastError(ERROR_INVALID_HANDLE);
+ return ERROR;
+ }
+ IntGdiCombineRgn(RgnUpdate, RgnTemp, NULL, RGN_COPY);
+ REGION_UnlockRgn(RgnTemp);
+ }
+
+ /* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
+ if (flags & SW_SCROLLWNDDCE)
+ {
+ dcxflags = DCX_USESTYLE;
+
+ if (!(Window->pcls->style & (CS_OWNDC|CS_CLASSDC)))
+ dcxflags |= DCX_CACHE; // AH??? wine~ If not Powned or with Class go Cheap!
+
+ if (flags & SW_SCROLLCHILDREN && Window->style & WS_CLIPCHILDREN)
+ dcxflags |= DCX_CACHE|DCX_NOCLIPCHILDREN;
+ }
+ else
+ {
+ /* So in this case ScrollWindowEx uses Cache DC. */
+ dcxflags = DCX_CACHE|DCX_USESTYLE;
+ if (flags & SW_SCROLLCHILDREN) dcxflags |= DCX_NOCLIPCHILDREN;
+ }
+
+ hDC = UserGetDCEx(Window, 0, dcxflags);
+ if (!hDC)
+ {
+ /* FIXME: SetLastError? */
+ return ERROR;
+ }
+
+ rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ? RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE ;
+
+ rcCaret = rcScroll;
+ hwndCaret = co_IntFixCaret(Window, &rcCaret, flags);
+
+ Result = UserScrollDC( hDC,
+ dx,
+ dy,
+ &rcScroll,
+ &rcClip,
+ NULL,
+ RgnUpdate,
+ prcUpdate);
+
+ UserReleaseDC(Window, hDC, FALSE);
+
+ /*
+ * Take into account the fact that some damage may have occurred during
+ * the scroll. Keep a copy in hrgnWinupd to be added to hrngUpdate at the end.
+ */
+
+ RgnTemp = IntSysCreateRectpRgn(0, 0, 0, 0);
+ if (!RgnTemp)
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return ERROR;
+ }
+
+ if (co_IntGetUpdateRgn(Window, RgnTemp, FALSE) != NULLREGION)
+ {
+ PREGION RgnClip = IntSysCreateRectpRgnIndirect(&rcClip);
+ if (RgnClip)
+ {
+ if (hrgnUpdate)
+ {
+ RgnWinupd = IntSysCreateRectpRgn( 0, 0, 0, 0);
+ IntGdiCombineRgn( RgnWinupd, RgnTemp, 0, RGN_COPY);
+ }
+
+ REGION_bOffsetRgn(RgnTemp, dx, dy);
+
+ IntGdiCombineRgn(RgnTemp, RgnTemp, RgnClip, RGN_AND);
+
+ if (hrgnUpdate)
+ IntGdiCombineRgn( RgnWinupd, RgnWinupd, RgnTemp, RGN_OR );
+
+ co_UserRedrawWindow(Window, NULL, RgnTemp, rdw_flags );
+
+ REGION_Delete(RgnClip);
+ }
+ }
+ REGION_Delete(RgnTemp);
+
+ if (flags & SW_SCROLLCHILDREN)
+ {
+ PWND Child;
+ RECTL rcChild;
+ POINT ClientOrigin;
+ USER_REFERENCE_ENTRY WndRef;
+ RECTL rcDummy;
+ LPARAM lParam;
+
+ IntGetClientOrigin(Window, &ClientOrigin);
+
+ for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
+ {
+ rcChild = Child->rcWindow;
+ rcChild.left -= ClientOrigin.x;
+ rcChild.top -= ClientOrigin.y;
+ rcChild.right -= ClientOrigin.x;
+ rcChild.bottom -= ClientOrigin.y;
+
+ if (!prcScroll || RECTL_bIntersectRect(&rcDummy, &rcChild, &rcScroll))
+ {
+ UserRefObjectCo(Child, &WndRef);
+
+ if (Window->spwndParent == UserGetDesktopWindow()) // Window->spwndParent->fnid == FNID_DESKTOP )
+ lParam = MAKELONG(Child->rcClient.left, Child->rcClient.top);
+ else
+ lParam = MAKELONG(rcChild.left + dx, rcChild.top + dy);
+
+ /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
+ /* windows sometimes a WM_MOVE */
+ co_IntSendMessage(UserHMGetHandle(Child), WM_MOVE, 0, lParam);
+
+ UserDerefObjectCo(Child);
+ }
+ }
+ }
+
+ if (flags & (SW_INVALIDATE | SW_ERASE))
+ {
+ co_UserRedrawWindow( Window,
+ NULL,
+ RgnUpdate,
+ rdw_flags | /* HACK */
+ ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : RDW_NOCHILDREN) );
+ }
+
+ if (hwndCaret && (CaretWnd = UserGetWindowObject(hwndCaret)))
+ {
+ UserRefObjectCo(CaretWnd, &CaretRef);
+
+ co_IntSetCaretPos(rcCaret.left + dx, rcCaret.top + dy);
+ co_UserShowCaret(CaretWnd);
+
+ UserDerefObjectCo(CaretWnd);
+ }
+
+ if (hrgnUpdate && (Result != ERROR))
+ {
+ /* Give everything back to the caller */
+ RgnTemp = REGION_LockRgn(hrgnUpdate);
+ /* The handle should still be valid */
+ ASSERT(RgnTemp);
+ if (RgnWinupd)
+ IntGdiCombineRgn(RgnTemp, RgnUpdate, RgnWinupd, RGN_OR);
+ else
+ IntGdiCombineRgn(RgnTemp, RgnUpdate, NULL, RGN_COPY);
+ REGION_UnlockRgn(RgnTemp);
+ }
+
+ if (RgnWinupd)
+ {
+ REGION_Delete(RgnWinupd);
+ }
+
+ if (RgnUpdate)
+ {
+ REGION_Delete(RgnUpdate);
+ }
+
+ return Result;
+}
+
+
+BOOL FASTCALL
+IntScrollWindow(PWND pWnd,
+ int dx,
+ int dy,
+ CONST RECT *lpRect,
+ CONST RECT *prcClip)
+{
+ return IntScrollWindowEx( pWnd, dx, dy, lpRect, prcClip, 0, NULL,
+ (lpRect ? 0 : SW_SCROLLCHILDREN) | (SW_ERASE|SW_INVALIDATE|SW_SCROLLWNDDCE)) != ERROR;
+}
+
/*
* NtUserScrollDC
*