From: Jacek Caban jacek@codeweavers.com
Signed-off-by: Jacek Caban jacek@codeweavers.com --- dlls/user32/edit.c | 4 +- dlls/user32/listbox.c | 8 +- dlls/user32/mdi.c | 8 +- dlls/user32/painting.c | 240 +---------------------------------- dlls/user32/user32.spec | 2 +- dlls/win32u/dce.c | 204 +++++++++++++++++++++++++++++ dlls/win32u/gdiobj.c | 1 + dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 4 + dlls/win32u/window.c | 2 +- dlls/win32u/wrappers.c | 9 ++ include/ntuser.h | 6 + 12 files changed, 239 insertions(+), 251 deletions(-)
diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c index b7eaf2b9ddf..70f105b9a0a 100644 --- a/dlls/user32/edit.c +++ b/dlls/user32/edit.c @@ -1708,8 +1708,8 @@ static BOOL EDIT_EM_LineScroll_internal(EDITSTATE *es, INT dx, INT dy)
GetClientRect(es->hwndSelf, &rc1); IntersectRect(&rc, &rc1, &es->format_rect); - ScrollWindowEx(es->hwndSelf, -dx, dy, - NULL, &rc, NULL, NULL, SW_INVALIDATE); + NtUserScrollWindowEx(es->hwndSelf, -dx, dy, + NULL, &rc, NULL, NULL, SW_INVALIDATE); /* force scroll info update */ EDIT_UpdateScrollInfo(es); } diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c index 0eed2fdfe65..b8f127c0963 100644 --- a/dlls/user32/listbox.c +++ b/dlls/user32/listbox.c @@ -439,8 +439,8 @@ static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index, BOOL scroll ) else dy = (descr->top_item - index) * descr->item_height;
- ScrollWindowEx( descr->self, dx, dy, NULL, NULL, 0, NULL, - SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); + NtUserScrollWindowEx( descr->self, dx, dy, NULL, NULL, 0, NULL, + SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); } else InvalidateRect( descr->self, NULL, TRUE ); @@ -1340,8 +1340,8 @@ static void LISTBOX_SetHorizontalPos( LB_DESCR *descr, INT pos ) /* Invalidate the focused item so it will be repainted correctly */ if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1) InvalidateRect( descr->self, &rect, TRUE ); - ScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL, - SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); + NtUserScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL, + SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); } else InvalidateRect( descr->self, NULL, TRUE ); diff --git a/dlls/user32/mdi.c b/dlls/user32/mdi.c index e5a52012413..26772aed763 100644 --- a/dlls/user32/mdi.c +++ b/dlls/user32/mdi.c @@ -1822,11 +1822,11 @@ void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam, SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
if( uMsg == WM_VSCROLL ) - ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL, - SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); + NtUserScrollWindowEx( hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL, + SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); else - ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL, - SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); + NtUserScrollWindowEx( hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL, + SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); done: SetThreadDpiAwarenessContext( context ); } diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c index e7be362773a..419c952d998 100644 --- a/dlls/user32/painting.c +++ b/dlls/user32/painting.c @@ -19,72 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#include "ntstatus.h" -#define WIN32_NO_STATUS #include "user_private.h" -#include "win.h" -#include "controls.h" -#include "wine/server.h" -#include "wine/list.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(win); - - -/************************************************************************* - * fix_caret - * - * Helper for ScrollWindowEx: - * If the return value is 0, no special caret handling is necessary. - * Otherwise the return value is the handle of the window that owns the - * caret. Its caret needs to be hidden during the scroll operation and - * moved to new_caret_pos if move_caret is TRUE. - */ -static HWND fix_caret(HWND hWnd, const RECT *scroll_rect, INT dx, INT dy, - UINT flags, LPBOOL move_caret, LPPOINT new_caret_pos) -{ - GUITHREADINFO info; - RECT rect, mapped_rcCaret; - - info.cbSize = sizeof(info); - if (!NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info )) return 0; - if (!info.hwndCaret) return 0; - - mapped_rcCaret = info.rcCaret; - if (info.hwndCaret == hWnd) - { - /* The caret needs to be moved along with scrolling even if it's - * outside the visible area. Otherwise, when the caret is scrolled - * out from the view, the position won't get updated anymore and - * the caret will never scroll back again. */ - *move_caret = TRUE; - new_caret_pos->x = info.rcCaret.left + dx; - new_caret_pos->y = info.rcCaret.top + dy; - } - else - { - *move_caret = FALSE; - if (!(flags & SW_SCROLLCHILDREN) || !IsChild(hWnd, info.hwndCaret)) - return 0; - MapWindowPoints(info.hwndCaret, hWnd, (LPPOINT)&mapped_rcCaret, 2); - } - - /* If the caret is not in the src/dest rects, all is fine done. */ - if (!IntersectRect(&rect, scroll_rect, &mapped_rcCaret)) - { - rect = *scroll_rect; - OffsetRect(&rect, dx, dy); - if (!IntersectRect(&rect, &rect, &mapped_rcCaret)) - return 0; - } - - /* Indicate that the caret needs to be updated during the scrolling. */ - return info.hwndCaret; -}
/*********************************************************************** @@ -197,177 +132,6 @@ BOOL WINAPI ValidateRect( HWND hwnd, const RECT *rect ) }
-static INT scroll_window( HWND hwnd, INT dx, INT dy, const RECT *rect, const RECT *clipRect, - HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags, BOOL is_ex ) -{ - INT retVal = NULLREGION; - BOOL bOwnRgn = TRUE; - BOOL bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE)); - int rdw_flags; - HRGN hrgnTemp; - HRGN hrgnWinupd = 0; - HDC hDC; - RECT rc, cliprc; - HWND hwndCaret = NULL; - BOOL moveCaret = FALSE; - POINT newCaretPos; - - TRACE( "%p, %d,%d hrgnUpdate=%p rcUpdate = %p %s %04x\n", - hwnd, dx, dy, hrgnUpdate, rcUpdate, wine_dbgstr_rect(rect), flags ); - TRACE( "clipRect = %s\n", wine_dbgstr_rect(clipRect)); - if( flags & ~( SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE)) - FIXME("some flags (%04x) are unhandled\n", flags); - - rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ? - RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE ; - - if (!WIN_IsWindowDrawable( hwnd, TRUE )) return ERROR; - hwnd = WIN_GetFullHandle( hwnd ); - - GetClientRect(hwnd, &rc); - - if (clipRect) IntersectRect(&cliprc,&rc,clipRect); - else cliprc = rc; - - if (rect) IntersectRect(&rc, &rc, rect); - - if( hrgnUpdate ) bOwnRgn = FALSE; - else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 ); - - newCaretPos.x = newCaretPos.y = 0; - - if( !IsRectEmpty(&cliprc) && (dx || dy)) { - DWORD dcxflags = 0; - DWORD style = GetWindowLongW( hwnd, GWL_STYLE ); - - hwndCaret = fix_caret(hwnd, &rc, dx, dy, flags, &moveCaret, &newCaretPos); - if (hwndCaret) - NtUserHideCaret( hwndCaret ); - - if (is_ex) dcxflags |= DCX_CACHE; - if( style & WS_CLIPSIBLINGS) dcxflags |= DCX_CLIPSIBLINGS; - if( GetClassLongW( hwnd, GCL_STYLE ) & CS_PARENTDC) - dcxflags |= DCX_PARENTCLIP; - if( !(flags & SW_SCROLLCHILDREN) && (style & WS_CLIPCHILDREN)) - dcxflags |= DCX_CLIPCHILDREN; - hDC = NtUserGetDCEx( hwnd, 0, dcxflags); - if (hDC) - { - NtUserScrollDC( hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate ); - - NtUserReleaseDC( hwnd, hDC ); - - if (!bUpdate) - NtUserRedrawWindow( hwnd, NULL, hrgnUpdate, rdw_flags); - } - - /* If the windows has an update region, this must be - * scrolled as well. Keep a copy in hrgnWinupd - * to be added to hrngUpdate at the end. */ - hrgnTemp = CreateRectRgn( 0, 0, 0, 0 ); - retVal = NtUserGetUpdateRgn( hwnd, hrgnTemp, FALSE ); - if (retVal != NULLREGION) - { - HRGN hrgnClip = CreateRectRgnIndirect(&cliprc); - if( !bOwnRgn) { - hrgnWinupd = CreateRectRgn( 0, 0, 0, 0); - CombineRgn( hrgnWinupd, hrgnTemp, 0, RGN_COPY); - } - OffsetRgn( hrgnTemp, dx, dy ); - CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND ); - if( !bOwnRgn) - CombineRgn( hrgnWinupd, hrgnWinupd, hrgnTemp, RGN_OR ); - NtUserRedrawWindow( hwnd, NULL, hrgnTemp, rdw_flags); - - /* Catch the case where the scrolling amount exceeds the size of the - * original window. This generated a second update area that is the - * location where the original scrolled content would end up. - * This second region is not returned by the ScrollDC and sets - * ScrollWindowEx apart from just a ScrollDC. - * - * This has been verified with testing on windows. - */ - if (abs(dx) > abs(rc.right - rc.left) || - abs(dy) > abs(rc.bottom - rc.top)) - { - SetRectRgn( hrgnTemp, rc.left + dx, rc.top + dy, rc.right+dx, rc.bottom + dy); - CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND ); - CombineRgn( hrgnUpdate, hrgnUpdate, hrgnTemp, RGN_OR ); - - if (rcUpdate) - { - RECT rcTemp; - GetRgnBox( hrgnTemp, &rcTemp ); - UnionRect( rcUpdate, rcUpdate, &rcTemp ); - } - - if( !bOwnRgn) - CombineRgn( hrgnWinupd, hrgnWinupd, hrgnTemp, RGN_OR ); - } - DeleteObject( hrgnClip ); - } - DeleteObject( hrgnTemp ); - } else { - /* nothing was scrolled */ - if( !bOwnRgn) - SetRectRgn( hrgnUpdate, 0, 0, 0, 0 ); - SetRectEmpty( rcUpdate); - } - - if( flags & SW_SCROLLCHILDREN ) - { - HWND *list = WIN_ListChildren( hwnd ); - if (list) - { - int i; - RECT r, dummy; - for (i = 0; list[i]; i++) - { - WIN_GetRectangles( list[i], COORDS_PARENT, &r, NULL ); - if (!rect || IntersectRect(&dummy, &r, rect)) - NtUserSetWindowPos( list[i], 0, r.left + dx, r.top + dy, 0, 0, - SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | - SWP_NOREDRAW | SWP_DEFERERASE ); - } - HeapFree( GetProcessHeap(), 0, list ); - } - } - - if( flags & (SW_INVALIDATE | SW_ERASE) ) - NtUserRedrawWindow( hwnd, NULL, hrgnUpdate, rdw_flags | - ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ) ); - - if( hrgnWinupd) { - CombineRgn( hrgnUpdate, hrgnUpdate, hrgnWinupd, RGN_OR); - DeleteObject( hrgnWinupd); - } - - if( moveCaret ) - SetCaretPos( newCaretPos.x, newCaretPos.y ); - if( hwndCaret ) - NtUserShowCaret( hwndCaret ); - - if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate ); - - return retVal; -} - - -/************************************************************************* - * ScrollWindowEx (USER32.@) - * - * Note: contrary to what the doc says, pixels that are scrolled from the - * outside of clipRect to the inside are NOT painted. - * - */ -INT WINAPI ScrollWindowEx( HWND hwnd, INT dx, INT dy, - const RECT *rect, const RECT *clipRect, - HRGN hrgnUpdate, LPRECT rcUpdate, - UINT flags ) -{ - return scroll_window( hwnd, dx, dy, rect, clipRect, hrgnUpdate, rcUpdate, flags, TRUE ); -} - /************************************************************************* * ScrollWindow (USER32.@) * @@ -375,8 +139,8 @@ INT WINAPI ScrollWindowEx( HWND hwnd, INT dx, INT dy, BOOL WINAPI ScrollWindow( HWND hwnd, INT dx, INT dy, const RECT *rect, const RECT *clipRect ) { - return scroll_window( hwnd, dx, dy, rect, clipRect, 0, NULL, - SW_INVALIDATE | SW_ERASE | (rect ? 0 : SW_SCROLLCHILDREN), FALSE ) != ERROR; + UINT flags = SW_INVALIDATE | SW_ERASE | (rect ? 0 : SW_SCROLLCHILDREN) | SW_NODCCACHE; + return NtUserScrollWindowEx( hwnd, dx, dy, rect, clipRect, 0, NULL, flags ); }
/************************************************************************ diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index ee533305a6e..8a7387040dc 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -630,7 +630,7 @@ @ stdcall ScrollChildren(long long long long) @ stdcall ScrollDC(long long long ptr ptr long ptr) NtUserScrollDC @ stdcall ScrollWindow(long long long ptr ptr) -@ stdcall ScrollWindowEx(long long long ptr ptr long ptr long) +@ stdcall ScrollWindowEx(long long long ptr ptr long ptr long) NtUserScrollWindowEx @ stdcall SendDlgItemMessageA(long long long long long) @ stdcall SendDlgItemMessageW(long long long long long) @ stdcall SendIMEMessageExA(long long) diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index acbb213d7b7..872112e4a24 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1591,3 +1591,207 @@ BOOL WINAPI NtUserLockWindowUpdate( HWND hwnd ) } return !InterlockedCompareExchangePointer( (void **)&locked_hwnd, hwnd, 0 ); } + +/************************************************************************* + * fix_caret + * + * Helper for NtUserScrollWindowEx: + * If the return value is 0, no special caret handling is necessary. + * Otherwise the return value is the handle of the window that owns the + * caret. Its caret needs to be hidden during the scroll operation and + * moved to new_caret_pos if move_caret is TRUE. + */ +static HWND fix_caret( HWND hwnd, const RECT *scroll_rect, INT dx, INT dy, + UINT flags, BOOL *move_caret, POINT *new_caret_pos ) +{ + RECT rect, mapped_caret; + GUITHREADINFO info; + + info.cbSize = sizeof(info); + if (!NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info )) return 0; + if (!info.hwndCaret) return 0; + + mapped_caret = info.rcCaret; + if (info.hwndCaret == hwnd) + { + /* The caret needs to be moved along with scrolling even if it's + * outside the visible area. Otherwise, when the caret is scrolled + * out from the view, the position won't get updated anymore and + * the caret will never scroll back again. */ + *move_caret = TRUE; + new_caret_pos->x = info.rcCaret.left + dx; + new_caret_pos->y = info.rcCaret.top + dy; + } + else + { + *move_caret = FALSE; + if (!(flags & SW_SCROLLCHILDREN) || !is_child( hwnd, info.hwndCaret )) + return 0; + map_window_points( info.hwndCaret, hwnd, (POINT *)&mapped_caret, 2, get_thread_dpi() ); + } + + /* If the caret is not in the src/dest rects, all is fine done. */ + if (!intersect_rect( &rect, scroll_rect, &mapped_caret )) + { + rect = *scroll_rect; + OffsetRect( &rect, dx, dy ); + if (!intersect_rect( &rect, &rect, &mapped_caret )) + return 0; + } + + /* Indicate that the caret needs to be updated during the scrolling. */ + return info.hwndCaret; +} + +/************************************************************************* + * NtUserScrollWindowEx (win32u.@) + * + * Note: contrary to what the doc says, pixels that are scrolled from the + * outside of clipRect to the inside are NOT painted. + */ +INT WINAPI NtUserScrollWindowEx( HWND hwnd, INT dx, INT dy, const RECT *rect, + const RECT *clip_rect, HRGN update_rgn, + RECT *update_rect, UINT flags ) +{ + BOOL update = update_rect || update_rgn || flags & (SW_INVALIDATE | SW_ERASE); + BOOL own_rgn = TRUE, move_caret = FALSE; + HRGN temp_rgn, winupd_rgn = 0; + INT retval = NULLREGION; + HWND caret_hwnd = NULL; + POINT new_caret_pos; + RECT rc, cliprc; + int rdw_flags; + HDC hdc; + + TRACE( "%p, %d,%d update_rgn=%p update_rect = %p %s %04x\n", + hwnd, dx, dy, update_rgn, update_rect, wine_dbgstr_rect(rect), flags ); + TRACE( "clip_rect = %s\n", wine_dbgstr_rect(clip_rect) ); + if (flags & ~(SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE)) + FIXME( "some flags (%04x) are unhandled\n", flags ); + + rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ? + RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE; + + if (!is_window_drawable( hwnd, TRUE )) return ERROR; + hwnd = get_full_window_handle( hwnd ); + + get_client_rect( hwnd, &rc ); + if (clip_rect) intersect_rect( &cliprc, &rc, clip_rect ); + else cliprc = rc; + + if (rect) intersect_rect( &rc, &rc, rect ); + if (update_rgn) own_rgn = FALSE; + else if (update) update_rgn = NtGdiCreateRectRgn( 0, 0, 0, 0 ); + + new_caret_pos.x = new_caret_pos.y = 0; + + if (!IsRectEmpty( &cliprc ) && (dx || dy)) + { + DWORD style = get_window_long( hwnd, GWL_STYLE ); + DWORD dcxflags = 0; + + caret_hwnd = fix_caret( hwnd, &rc, dx, dy, flags, &move_caret, &new_caret_pos ); + if (caret_hwnd) NtUserHideCaret( caret_hwnd ); + + if (!(flags & SW_NODCCACHE)) dcxflags |= DCX_CACHE; + if (style & WS_CLIPSIBLINGS) dcxflags |= DCX_CLIPSIBLINGS; + if (get_class_long( hwnd, GCL_STYLE, FALSE ) & CS_PARENTDC) dcxflags |= DCX_PARENTCLIP; + if (!(flags & SW_SCROLLCHILDREN) && (style & WS_CLIPCHILDREN)) + dcxflags |= DCX_CLIPCHILDREN; + hdc = NtUserGetDCEx( hwnd, 0, dcxflags); + if (hdc) + { + NtUserScrollDC( hdc, dx, dy, &rc, &cliprc, update_rgn, update_rect ); + NtUserReleaseDC( hwnd, hdc ); + if (!update) NtUserRedrawWindow( hwnd, NULL, update_rgn, rdw_flags ); + } + + /* If the windows has an update region, this must be scrolled as well. + * Keep a copy in winupd_rgn to be added to hrngUpdate at the end. */ + temp_rgn = NtGdiCreateRectRgn( 0, 0, 0, 0 ); + retval = NtUserGetUpdateRgn( hwnd, temp_rgn, FALSE ); + if (retval != NULLREGION) + { + HRGN clip_rgn = NtGdiCreateRectRgn( cliprc.left, cliprc.top, + cliprc.right, cliprc.bottom ); + if (!own_rgn) + { + winupd_rgn = NtGdiCreateRectRgn( 0, 0, 0, 0); + NtGdiCombineRgn( winupd_rgn, temp_rgn, 0, RGN_COPY); + } + NtGdiOffsetRgn( temp_rgn, dx, dy ); + NtGdiCombineRgn( temp_rgn, temp_rgn, clip_rgn, RGN_AND ); + if (!own_rgn) NtGdiCombineRgn( winupd_rgn, winupd_rgn, temp_rgn, RGN_OR ); + NtUserRedrawWindow( hwnd, NULL, temp_rgn, rdw_flags ); + + /* + * Catch the case where the scrolling amount exceeds the size of the + * original window. This generated a second update area that is the + * location where the original scrolled content would end up. + * This second region is not returned by the ScrollDC and sets + * ScrollWindowEx apart from just a ScrollDC. + * + * This has been verified with testing on windows. + */ + if (abs( dx ) > abs( rc.right - rc.left ) || abs( dy ) > abs( rc.bottom - rc.top )) + { + NtGdiSetRectRgn( temp_rgn, rc.left + dx, rc.top + dy, rc.right+dx, rc.bottom + dy ); + NtGdiCombineRgn( temp_rgn, temp_rgn, clip_rgn, RGN_AND ); + NtGdiCombineRgn( update_rgn, update_rgn, temp_rgn, RGN_OR ); + + if (update_rect) + { + RECT temp_rect; + NtGdiGetRgnBox( temp_rgn, &temp_rect ); + union_rect( update_rect, update_rect, &temp_rect ); + } + + if (!own_rgn) NtGdiCombineRgn( winupd_rgn, winupd_rgn, temp_rgn, RGN_OR ); + } + NtGdiDeleteObjectApp( clip_rgn ); + } + NtGdiDeleteObjectApp( temp_rgn ); + } + else + { + /* nothing was scrolled */ + if (!own_rgn) NtGdiSetRectRgn( update_rgn, 0, 0, 0, 0 ); + SetRectEmpty( update_rect ); + } + + if (flags & SW_SCROLLCHILDREN) + { + HWND *list = list_window_children( 0, hwnd, NULL, 0 ); + if (list) + { + RECT r, dummy; + int i; + + for (i = 0; list[i]; i++) + { + get_window_rects( list[i], COORDS_PARENT, &r, NULL, get_thread_dpi() ); + if (!rect || intersect_rect( &dummy, &r, rect )) + NtUserSetWindowPos( list[i], 0, r.left + dx, r.top + dy, 0, 0, + SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | + SWP_NOREDRAW | SWP_DEFERERASE ); + } + free( list ); + } + } + + if (flags & (SW_INVALIDATE | SW_ERASE)) + NtUserRedrawWindow( hwnd, NULL, update_rgn, rdw_flags | + ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ) ); + + if (winupd_rgn) + { + NtGdiCombineRgn( update_rgn, update_rgn, winupd_rgn, RGN_OR ); + NtGdiDeleteObjectApp( winupd_rgn ); + } + + if (move_caret) set_caret_pos( new_caret_pos.x, new_caret_pos.y ); + if (caret_hwnd) NtUserShowCaret( caret_hwnd ); + if (own_rgn && update_rgn) NtGdiDeleteObjectApp( update_rgn ); + + return retval; +} diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index c29e7773e6c..222b74b45d6 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1200,6 +1200,7 @@ static struct unix_funcs unix_funcs = NtUserRegisterHotKey, NtUserReleaseDC, NtUserScrollDC, + NtUserScrollWindowEx, NtUserSelectPalette, NtUserSendInput, NtUserSetActiveWindow, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 8584fc4e5c3..86d359b8386 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1156,7 +1156,7 @@ @ stub NtUserRestoreWindowDpiChanges @ stub NtUserSBGetParms @ stdcall NtUserScrollDC(long long long ptr ptr long ptr) -@ stub NtUserScrollWindowEx +@ stdcall NtUserScrollWindowEx(long long long ptr ptr long ptr long) @ stdcall NtUserSelectPalette(long long long) @ stub NtUserSendEventMessage @ stdcall NtUserSendInput(long ptr long) diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index c5303010ef3..2394a8850a5 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -268,6 +268,9 @@ struct unix_funcs INT (WINAPI *pNtUserReleaseDC)( HWND hwnd, HDC hdc ); BOOL (WINAPI *pNtUserScrollDC)( HDC hdc, INT dx, INT dy, const RECT *scroll, const RECT *clip, HRGN ret_update_rgn, RECT *update_rect ); + INT (WINAPI *pNtUserScrollWindowEx)( HWND hwnd, INT dx, INT dy, const RECT *rect, + const RECT *clip_rect, HRGN update_rgn, + RECT *update_rect, UINT flags ); HPALETTE (WINAPI *pNtUserSelectPalette)( HDC hdc, HPALETTE hpal, WORD bkg ); UINT (WINAPI *pNtUserSendInput)( UINT count, INPUT *inputs, int size ); HWND (WINAPI *pNtUserSetActiveWindow)( HWND hwnd ); @@ -449,6 +452,7 @@ extern HWND is_current_process_window( HWND hwnd ) DECLSPEC_HIDDEN; extern HWND is_current_thread_window( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL is_desktop_window( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL is_iconic( HWND hwnd ) DECLSPEC_HIDDEN; +extern BOOL is_window_drawable( HWND hwnd, BOOL icon ) DECLSPEC_HIDDEN; extern BOOL is_window_enabled( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL is_window_unicode( HWND hwnd ) DECLSPEC_HIDDEN; extern DWORD get_window_long( HWND hwnd, INT offset ) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 319f47712e6..34bf87bc9ba 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -762,7 +762,7 @@ static BOOL is_window_visible( HWND hwnd ) * minimized, and it is itself not minimized unless we are * trying to draw its default class icon. */ -static BOOL is_window_drawable( HWND hwnd, BOOL icon ) +BOOL is_window_drawable( HWND hwnd, BOOL icon ) { HWND *list; BOOL retval = TRUE; diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index b336059fe96..679cce95b9a 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -1112,6 +1112,15 @@ BOOL WINAPI NtUserScrollDC( HDC hdc, INT dx, INT dy, const RECT *scroll, const R return unix_funcs->pNtUserScrollDC( hdc, dx, dy, scroll, clip, ret_update_rgn, update_rect ); }
+INT WINAPI NtUserScrollWindowEx( HWND hwnd, INT dx, INT dy, const RECT *rect, + const RECT *clip_rect, HRGN update_rgn, + RECT *update_rect, UINT flags ) +{ + if (!unix_funcs) return 0; + return unix_funcs->pNtUserScrollWindowEx( hwnd, dx, dy, rect, clip_rect, + update_rgn, update_rect, flags ); +} + HPALETTE WINAPI NtUserSelectPalette( HDC hdc, HPALETTE hpal, WORD bkg ) { if (!unix_funcs) return 0; diff --git a/include/ntuser.h b/include/ntuser.h index e0c65a9f532..b6b69879dd7 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -227,6 +227,9 @@ struct send_message_callback_params #define NTUSER_OBJ_ACCEL 0x08 #define NTUSER_OBJ_HOOK 0x0f
+/* NtUserScrollWindowEx flag */ +#define SW_NODCCACHE 0x8000 + /* NtUserInitializeClientPfnArrays parameter, not compatible with Windows */ struct user_client_procs { @@ -615,6 +618,9 @@ BOOL WINAPI NtUserRemoveMenu( HMENU menu, UINT id, UINT flags ); HANDLE WINAPI NtUserRemoveProp( HWND hwnd, const WCHAR *str ); BOOL WINAPI NtUserScrollDC( HDC hdc, INT dx, INT dy, const RECT *scroll, const RECT *clip, HRGN ret_update_rgn, RECT *update_rect ); +INT WINAPI NtUserScrollWindowEx( HWND hwnd, INT dx, INT dy, const RECT *rect, + const RECT *clip_rect, HRGN update_rgn, + RECT *update_rect, UINT flags ) DECLSPEC_HIDDEN; HPALETTE WINAPI NtUserSelectPalette( HDC hdc, HPALETTE palette, WORD force_background ); UINT WINAPI NtUserSendInput( UINT count, INPUT *inputs, int size ); HWND WINAPI NtUserSetActiveWindow( HWND hwnd );