diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c index b3907a0fe91..06b02adeab5 100644 --- a/dlls/user32/driver.c +++ b/dlls/user32/driver.c @@ -154,15 +154,6 @@ static void CDECL nulldrv_ReleaseDC( HWND hwnd, HDC hdc ) { } -static BOOL CDECL nulldrv_ScrollDC( HDC hdc, INT dx, INT dy, HRGN update ) -{ - RECT rect; - - GetClipBox( hdc, &rect ); - return BitBlt( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, - hdc, rect.left - dx, rect.top - dy, SRCCOPY ); -} - static void CDECL nulldrv_SetCapture( HWND hwnd, UINT flags ) { } @@ -365,7 +356,7 @@ static struct user_driver_funcs lazy_load_driver = loaderdrv_GetDC, nulldrv_MsgWaitForMultipleObjectsEx, nulldrv_ReleaseDC, - nulldrv_ScrollDC, + NULL, nulldrv_SetCapture, nulldrv_SetFocus, loaderdrv_SetLayeredWindowAttributes, diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c index 43566182c59..41c0bb3c6e1 100644 --- a/dlls/user32/painting.c +++ b/dlls/user32/painting.c @@ -1506,7 +1506,7 @@ static INT scroll_window( HWND hwnd, INT dx, INT dy, const RECT *rect, const REC hDC = GetDCEx( hwnd, 0, dcxflags); if (hDC) { - ScrollDC( hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate ); + NtUserScrollDC( hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate ); ReleaseDC( hwnd, hDC ); @@ -1632,119 +1632,6 @@ BOOL WINAPI ScrollWindow( HWND hwnd, INT dx, INT dy, SW_INVALIDATE | SW_ERASE | (rect ? 0 : SW_SCROLLCHILDREN), FALSE ) != ERROR; } - -/************************************************************************* - * ScrollDC (USER32.@) - * - * dx, dy, lprcScroll and lprcClip are all in logical coordinates (msdn is - * wrong) hrgnUpdate is returned in device coordinates with rcUpdate in - * logical coordinates. - */ -BOOL WINAPI ScrollDC( HDC hdc, INT dx, INT dy, const RECT *scroll, const RECT *clip, - HRGN ret_update_rgn, LPRECT update_rect ) - -{ - HRGN update_rgn = ret_update_rgn; - RECT src_rect, clip_rect, offset; - INT dxdev, dydev; - HRGN dstrgn, cliprgn, visrgn; - BOOL ret; - - TRACE( "dx,dy %d,%d scroll %s clip %s update %p rect %p\n", - dx, dy, wine_dbgstr_rect(scroll), wine_dbgstr_rect(clip), ret_update_rgn, update_rect ); - - /* get the visible region */ - visrgn = CreateRectRgn( 0, 0, 0, 0 ); - GetRandomRgn( hdc, visrgn, SYSRGN ); - if (!(GetVersion() & 0x80000000)) - { - POINT org; - GetDCOrgEx( hdc, &org ); - OffsetRgn( visrgn, -org.x, -org.y ); - } - - /* intersect with the clipping region if the DC has one */ - cliprgn = CreateRectRgn( 0, 0, 0, 0); - if (GetClipRgn( hdc, cliprgn ) != 1) - { - DeleteObject( cliprgn ); - cliprgn = 0; - } - else CombineRgn( visrgn, visrgn, cliprgn, RGN_AND ); - - /* only those pixels in the scroll rectangle that remain in the clipping - * rect are scrolled. */ - if (clip) - clip_rect = *clip; - else - GetClipBox( hdc, &clip_rect ); - src_rect = clip_rect; - OffsetRect( &clip_rect, -dx, -dy ); - IntersectRect( &src_rect, &src_rect, &clip_rect ); - - /* if an scroll rectangle is specified, only the pixels within that - * rectangle are scrolled */ - if (scroll) IntersectRect( &src_rect, &src_rect, scroll ); - - /* now convert to device coordinates */ - LPtoDP( hdc, (LPPOINT)&src_rect, 2 ); - TRACE( "source rect: %s\n", wine_dbgstr_rect(&src_rect) ); - /* also dx and dy */ - SetRect( &offset, 0, 0, dx, dy ); - LPtoDP( hdc, (LPPOINT)&offset, 2 ); - dxdev = offset.right - offset.left; - dydev = offset.bottom - offset.top; - - /* now intersect with the visible region to get the pixels that will actually scroll */ - dstrgn = CreateRectRgnIndirect( &src_rect ); - CombineRgn( dstrgn, dstrgn, visrgn, RGN_AND ); - OffsetRgn( dstrgn, dxdev, dydev ); - ExtSelectClipRgn( hdc, dstrgn, RGN_AND ); - - /* compute the update areas. This is the combined clip rectangle - * minus the scrolled region, and intersected with the visible region. */ - if (ret_update_rgn || update_rect) - { - /* intersect clip and scroll rectangles, allowing NULL values */ - if (scroll) - { - if (clip) - IntersectRect( &clip_rect, clip, scroll ); - else - clip_rect = *scroll; - } - else if (clip) - clip_rect = *clip; - else - GetClipBox( hdc, &clip_rect ); - - /* Convert the combined clip rectangle to device coordinates */ - LPtoDP( hdc, (LPPOINT)&clip_rect, 2 ); - if (update_rgn) - SetRectRgn( update_rgn, clip_rect.left, clip_rect.top, clip_rect.right, clip_rect.bottom ); - else - update_rgn = CreateRectRgnIndirect( &clip_rect ); - - CombineRgn( update_rgn, update_rgn, visrgn, RGN_AND ); - CombineRgn( update_rgn, update_rgn, dstrgn, RGN_DIFF ); - } - - ret = USER_Driver->pScrollDC( hdc, dx, dy, update_rgn ); - - if (ret && update_rect) - { - GetRgnBox( update_rgn, update_rect ); - DPtoLP( hdc, (LPPOINT)update_rect, 2 ); - TRACE( "returning update_rect %s\n", wine_dbgstr_rect(update_rect) ); - } - if (!ret_update_rgn) DeleteObject( update_rgn ); - SelectClipRgn( hdc, cliprgn ); - if (cliprgn) DeleteObject( cliprgn ); - DeleteObject( visrgn ); - DeleteObject( dstrgn ); - return ret; -} - /************************************************************************ * PrintWindow (USER32.@) * diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 0e9d98164b5..78946be86b3 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -627,7 +627,7 @@ @ stdcall ReuseDDElParam(long long long long long) @ stdcall ScreenToClient(long ptr) @ stdcall ScrollChildren(long long long long) -@ stdcall ScrollDC(long long long ptr ptr long ptr) +@ 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 SendDlgItemMessageA(long long long long long) diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index f8cce32b5f3..9f682fa8eea 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -1054,6 +1054,7 @@ static const struct user_driver_funcs lazy_load_driver = .pUnregisterHotKey = loaderdrv_UnregisterHotKey, .pVkKeyScanEx = loaderdrv_VkKeyScanEx, .pUpdateClipboard = loaderdrv_UpdateClipboard, + .pScrollDC = nulldrv_ScrollDC, }; const struct user_driver_funcs *user_driver = &lazy_load_driver; diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c index 1ac48e67d65..d2f61526540 100644 --- a/dlls/win32u/font.c +++ b/dlls/win32u/font.c @@ -277,11 +277,6 @@ static inline INT INTERNAL_YWSTODS(DC *dc, INT height) return pt[1].y - pt[0].y; } -static inline BOOL is_win9x(void) -{ - return NtCurrentTeb()->Peb->OSPlatformId == VER_PLATFORM_WIN32s; -} - static inline WCHAR *strdupW( const WCHAR *p ) { WCHAR *ret; diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index 39186cc94a7..c330dcfbe75 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1175,6 +1175,7 @@ static struct unix_funcs unix_funcs = NtUserGetUpdatedClipboardFormats, NtUserIsClipboardFormatAvailable, NtUserMapVirtualKeyEx, + NtUserScrollDC, NtUserToUnicodeEx, NtUserUnregisterHotKey, NtUserVkKeyScanEx, diff --git a/dlls/win32u/painting.c b/dlls/win32u/painting.c index b0e1ad117c0..7939ea878da 100644 --- a/dlls/win32u/painting.c +++ b/dlls/win32u/painting.c @@ -905,3 +905,115 @@ BOOL WINAPI NtGdiDrawStream( HDC hdc, ULONG in, void *pvin ) FIXME("stub: %p, %d, %p\n", hdc, in, pvin); return FALSE; } + +/************************************************************************* + * NtUserScrollDC (win32u.@) + */ +BOOL WINAPI NtUserScrollDC( HDC hdc, INT dx, INT dy, const RECT *scroll, const RECT *clip, + HRGN ret_update_rgn, RECT *update_rect ) + +{ + HRGN update_rgn = ret_update_rgn; + RECT src_rect, clip_rect, offset; + INT dxdev, dydev; + HRGN dstrgn, cliprgn, visrgn; + POINT org; + DC *dc; + BOOL ret; + + TRACE( "dx,dy %d,%d scroll %s clip %s update %p rect %p\n", + dx, dy, wine_dbgstr_rect(scroll), wine_dbgstr_rect(clip), ret_update_rgn, update_rect ); + + if (!(dc = get_dc_ptr( hdc ))) return FALSE; + org.x = dc->attr->vis_rect.left; + org.y = dc->attr->vis_rect.top; + release_dc_ptr( dc ); + + /* get the visible region */ + visrgn = NtGdiCreateRectRgn( 0, 0, 0, 0 ); + NtGdiGetRandomRgn( hdc, visrgn, SYSRGN ); + if (!is_win9x()) NtGdiOffsetRgn( visrgn, -org.x, -org.y ); + + /* intersect with the clipping region if the DC has one */ + cliprgn = NtGdiCreateRectRgn( 0, 0, 0, 0); + if (NtGdiGetRandomRgn( hdc, cliprgn, NTGDI_RGN_MIRROR_RTL | 1 ) != 1) + { + NtGdiDeleteObjectApp( cliprgn ); + cliprgn = 0; + } + else NtGdiCombineRgn( visrgn, visrgn, cliprgn, RGN_AND ); + + /* only those pixels in the scroll rectangle that remain in the clipping + * rect are scrolled. */ + if (clip) + clip_rect = *clip; + else + NtGdiGetAppClipBox( hdc, &clip_rect ); + src_rect = clip_rect; + offset_rect( &clip_rect, -dx, -dy ); + intersect_rect( &src_rect, &src_rect, &clip_rect ); + + /* if an scroll rectangle is specified, only the pixels within that + * rectangle are scrolled */ + if (scroll) intersect_rect( &src_rect, &src_rect, scroll ); + + /* now convert to device coordinates */ + NtGdiTransformPoints( hdc, (POINT *)&src_rect, (POINT *)&src_rect, 2, NtGdiLPtoDP ); + TRACE( "source rect: %s\n", wine_dbgstr_rect(&src_rect) ); + /* also dx and dy */ + SetRect( &offset, 0, 0, dx, dy ); + NtGdiTransformPoints( hdc, (POINT *)&offset, (POINT *)&offset, 2, NtGdiLPtoDP ); + dxdev = offset.right - offset.left; + dydev = offset.bottom - offset.top; + + /* now intersect with the visible region to get the pixels that will actually scroll */ + dstrgn = NtGdiCreateRectRgn( src_rect.left, src_rect.top, src_rect.right, src_rect.bottom ); + NtGdiCombineRgn( dstrgn, dstrgn, visrgn, RGN_AND ); + NtGdiOffsetRgn( dstrgn, dxdev, dydev ); + NtGdiExtSelectClipRgn( hdc, dstrgn, RGN_AND ); + + /* compute the update areas. This is the combined clip rectangle + * minus the scrolled region, and intersected with the visible region. */ + if (ret_update_rgn || update_rect) + { + /* intersect clip and scroll rectangles, allowing NULL values */ + if (scroll) + { + if (clip) + intersect_rect( &clip_rect, clip, scroll ); + else + clip_rect = *scroll; + } + else if (clip) + clip_rect = *clip; + else + NtGdiGetAppClipBox( hdc, &clip_rect ); + + /* Convert the combined clip rectangle to device coordinates */ + NtGdiTransformPoints( hdc, (POINT *)&clip_rect, (POINT *)&clip_rect, 2, NtGdiLPtoDP ); + if (update_rgn) + NtGdiSetRectRgn( update_rgn, clip_rect.left, clip_rect.top, + clip_rect.right, clip_rect.bottom ); + else + update_rgn = NtGdiCreateRectRgn( clip_rect.left, clip_rect.top, + clip_rect.right, clip_rect.bottom ); + + NtGdiCombineRgn( update_rgn, update_rgn, visrgn, RGN_AND ); + NtGdiCombineRgn( update_rgn, update_rgn, dstrgn, RGN_DIFF ); + } + + ret = user_driver->pScrollDC( hdc, dx, dy, update_rgn ); + + if (ret && update_rect) + { + NtGdiGetRgnBox( update_rgn, update_rect ); + NtGdiTransformPoints( hdc, (POINT *)&update_rect, (POINT *)&update_rect, 2, NtGdiDPtoLP ); + TRACE( "returning update_rect %s\n", wine_dbgstr_rect(update_rect) ); + } + if (!ret_update_rgn) NtGdiDeleteObjectApp( update_rgn ); + NtGdiExtSelectClipRgn( hdc, cliprgn, RGN_COPY ); + if (cliprgn) NtGdiDeleteObjectApp( cliprgn ); + NtGdiDeleteObjectApp( visrgn ); + NtGdiDeleteObjectApp( dstrgn ); + return ret; +} diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 7ae65b09279..f2d0efed43e 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1155,7 +1155,7 @@ @ stub NtUserResolveDesktopForWOW @ stub NtUserRestoreWindowDpiChanges @ stub NtUserSBGetParms -@ stub NtUserScrollDC +@ stdcall NtUserScrollDC(long long long ptr ptr long ptr) @ stub NtUserScrollWindowEx @ stub NtUserSelectPalette @ stub NtUserSendEventMessage diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index ecc9833a037..0dc6648480a 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -202,6 +202,8 @@ struct unix_funcs BOOL (WINAPI *pNtUserGetUpdatedClipboardFormats)( UINT *formats, UINT size, UINT *out_size ); BOOL (WINAPI *pNtUserIsClipboardFormatAvailable)( UINT format ); UINT (WINAPI *pNtUserMapVirtualKeyEx)( UINT code, UINT type, HKL layout ); + BOOL (WINAPI *pNtUserScrollDC)( HDC hdc, INT dx, INT dy, const RECT *scroll, const RECT *clip, + HRGN ret_update_rgn, RECT *update_rect ); INT (WINAPI *pNtUserToUnicodeEx)( UINT virt, UINT scan, const BYTE *state, WCHAR *str, int size, UINT flags, HKL layout ); BOOL (WINAPI *pNtUserUnregisterHotKey)( HWND hwnd, INT id ); @@ -407,4 +409,9 @@ DWORD win32u_mbtowc( CPTABLEINFO *info, WCHAR *dst, DWORD dstlen, const char *sr DWORD win32u_wctomb( CPTABLEINFO *info, char *dst, DWORD dstlen, const WCHAR *src, DWORD srclen ) DECLSPEC_HIDDEN; +static inline BOOL is_win9x(void) +{ + return NtCurrentTeb()->Peb->OSPlatformId == VER_PLATFORM_WIN32s; +} + #endif /* __WINE_WIN32U_PRIVATE */ diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index 63866ac451c..9d770fe414c 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -636,6 +636,12 @@ UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ) return unix_funcs->pNtUserMapVirtualKeyEx( code, type, layout ); } +BOOL WINAPI NtUserScrollDC( HDC hdc, INT dx, INT dy, const RECT *scroll, const RECT *clip, + HRGN ret_update_rgn, RECT *update_rect ) +{ + return unix_funcs->pNtUserScrollDC( hdc, dx, dy, scroll, clip, ret_update_rgn, update_rect ); +} + INT WINAPI NtUserToUnicodeEx( UINT virt, UINT scan, const BYTE *state, WCHAR *str, int size, UINT flags, HKL layout ) { diff --git a/include/ntuser.h b/include/ntuser.h index 60a7d47554a..0791605c9c3 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -92,6 +92,8 @@ HDESK WINAPI NtUserOpenDesktop( OBJECT_ATTRIBUTES *attr, DWORD flags, ACCESS_M HDESK WINAPI NtUserOpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK access ); BOOL WINAPI NtUserRemoveClipboardFormatListener( HWND hwnd ); 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 ); BOOL WINAPI NtUserSetKeyboardState( BYTE *state ); BOOL WINAPI NtUserSetProcessWindowStation( HWINSTA handle ); BOOL WINAPI NtUserSetProp( HWND hwnd, const WCHAR *str, HANDLE handle );