diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c index eceeaaf1082..8722cb68f12 100644 --- a/dlls/user32/painting.c +++ b/dlls/user32/painting.c @@ -47,22 +47,6 @@ void free_dce( struct dce *dce, HWND hwnd ) } -/*********************************************************************** - * delete_clip_rgn - */ -static void delete_clip_rgn( struct dce *dce ) -{ - if (!dce->clip_rgn) return; /* nothing to do */ - - dce->flags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN); - DeleteObject( dce->clip_rgn ); - dce->clip_rgn = 0; - - /* make it dirty so that the vis rgn gets recomputed next time */ - SetHookFlags( dce->hdc, DCHF_INVALIDATEVISRGN ); -} - - /*********************************************************************** * invalidate_dce * @@ -79,36 +63,6 @@ void invalidate_dce( WND *win, const RECT *extra_rect ) } -/*********************************************************************** - * release_dc - * - * Implementation of ReleaseDC. - */ -static INT release_dc( HWND hwnd, HDC hdc, BOOL end_paint ) -{ - struct dce *dce; - BOOL ret = FALSE; - - TRACE("%p %p\n", hwnd, hdc ); - - USER_Lock(); - dce = (struct dce *)GetDCHook( hdc, NULL ); - if (dce && dce->count && dce->hwnd) - { - if (!(dce->flags & DCX_NORESETATTRS)) SetHookFlags( dce->hdc, DCHF_RESETDC ); - if (end_paint || (dce->flags & DCX_CACHE)) delete_clip_rgn( dce ); - if (dce->flags & DCX_CACHE) - { - dce->count = 0; - SetHookFlags( dce->hdc, DCHF_DISABLEDC ); - } - ret = TRUE; - } - USER_Unlock(); - return ret; -} - - /*********************************************************************** * get_update_region * @@ -157,140 +111,6 @@ static HRGN get_update_region( HWND hwnd, UINT *flags, HWND *child ) } -/*********************************************************************** - * get_update_flags - * - * Get only the update flags, not the update region. - */ -static BOOL get_update_flags( HWND hwnd, HWND *child, UINT *flags ) -{ - BOOL ret; - - SERVER_START_REQ( get_update_region ) - { - req->window = wine_server_user_handle( hwnd ); - req->from_child = wine_server_user_handle( child ? *child : 0 ); - req->flags = *flags | UPDATE_NOREGION; - if ((ret = !wine_server_call_err( req ))) - { - if (child) *child = wine_server_ptr_handle( reply->child ); - *flags = reply->flags; - } - } - SERVER_END_REQ; - return ret; -} - - -/*********************************************************************** - * send_ncpaint - * - * Send a WM_NCPAINT message if needed, and return the resulting update region (in screen coords). - * Helper for erase_now and BeginPaint. - */ -static HRGN send_ncpaint( HWND hwnd, HWND *child, UINT *flags ) -{ - HRGN whole_rgn = get_update_region( hwnd, flags, child ); - HRGN client_rgn = 0; - DWORD style; - - if (child) hwnd = *child; - - if (hwnd == GetDesktopWindow()) return whole_rgn; - - if (whole_rgn) - { - DPI_AWARENESS_CONTEXT context; - RECT client, window, update; - INT type; - - context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd )); - - /* check if update rgn overlaps with nonclient area */ - type = GetRgnBox( whole_rgn, &update ); - WIN_GetRectangles( hwnd, COORDS_SCREEN, &window, &client ); - - if ((*flags & UPDATE_NONCLIENT) || - update.left < client.left || update.top < client.top || - update.right > client.right || update.bottom > client.bottom) - { - client_rgn = CreateRectRgnIndirect( &client ); - CombineRgn( client_rgn, client_rgn, whole_rgn, RGN_AND ); - - /* check if update rgn contains complete nonclient area */ - if (type == SIMPLEREGION && EqualRect( &window, &update )) - { - DeleteObject( whole_rgn ); - whole_rgn = (HRGN)1; - } - } - else - { - client_rgn = whole_rgn; - whole_rgn = 0; - } - - if (whole_rgn) /* NOTE: WM_NCPAINT allows wParam to be 1 */ - { - if (*flags & UPDATE_NONCLIENT) - { - /* Mark standard scroll bars as not painted before sending WM_NCPAINT */ - style = GetWindowLongW( hwnd, GWL_STYLE ); - if (style & WS_HSCROLL) - SCROLL_SetStandardScrollPainted( hwnd, SB_HORZ, FALSE ); - if (style & WS_VSCROLL) - SCROLL_SetStandardScrollPainted( hwnd, SB_VERT, FALSE ); - - SendMessageW( hwnd, WM_NCPAINT, (WPARAM)whole_rgn, 0 ); - } - if (whole_rgn > (HRGN)1) DeleteObject( whole_rgn ); - } - SetThreadDpiAwarenessContext( context ); - } - return client_rgn; -} - - -/*********************************************************************** - * send_erase - * - * Send a WM_ERASEBKGND message if needed, and optionally return the DC for painting. - * If a DC is requested, the region is selected into it. In all cases the region is deleted. - * Helper for erase_now and BeginPaint. - */ -static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn, - RECT *clip_rect, HDC *hdc_ret ) -{ - BOOL need_erase = (flags & UPDATE_DELAYED_ERASE) != 0; - HDC hdc = 0; - RECT dummy; - - if (!clip_rect) clip_rect = &dummy; - if (hdc_ret || (flags & UPDATE_ERASE)) - { - UINT dcx_flags = DCX_INTERSECTRGN | DCX_USESTYLE; - if (IsIconic(hwnd)) dcx_flags |= DCX_WINDOW; - - if ((hdc = NtUserGetDCEx( hwnd, client_rgn, dcx_flags ))) - { - INT type = GetClipBox( hdc, clip_rect ); - - if (flags & UPDATE_ERASE) - { - /* don't erase if the clip box is empty */ - if (type != NULLREGION) - need_erase = !SendMessageW( hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0 ); - } - if (!hdc_ret) release_dc( hwnd, hdc, TRUE ); - } - - if (hdc_ret) *hdc_ret = hdc; - } - if (!hdc) DeleteObject( client_rgn ); - return need_erase; -} - - /*********************************************************************** * copy_bits_from_surface * @@ -582,44 +402,6 @@ BOOL WINAPI ValidateRect( HWND hwnd, const RECT *rect ) } -/*********************************************************************** - * GetUpdateRect (USER32.@) - */ -BOOL WINAPI GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase ) -{ - DPI_AWARENESS_CONTEXT context; - UINT flags = UPDATE_NOCHILDREN; - HRGN update_rgn; - BOOL need_erase; - - if (erase) flags |= UPDATE_NONCLIENT | UPDATE_ERASE; - - if (!(update_rgn = send_ncpaint( hwnd, NULL, &flags ))) return FALSE; - - if (rect) - { - if (GetRgnBox( update_rgn, rect ) != NULLREGION) - { - HDC hdc = NtUserGetDCEx( hwnd, 0, DCX_USESTYLE ); - DWORD layout = SetLayout( hdc, 0 ); /* MapWindowPoints mirrors already */ - context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd )); - MapWindowPoints( 0, hwnd, (LPPOINT)rect, 2 ); - SetThreadDpiAwarenessContext( context ); - *rect = rect_win_to_thread_dpi( hwnd, *rect ); - DPtoLP( hdc, (LPPOINT)rect, 2 ); - SetLayout( hdc, layout ); - NtUserReleaseDC( hwnd, hdc ); - } - } - need_erase = send_erase( hwnd, flags, update_rgn, NULL, NULL ); - - /* check if we still have an update region */ - flags = UPDATE_PAINT | UPDATE_NOCHILDREN; - if (need_erase) flags |= UPDATE_DELAYED_ERASE; - return (get_update_flags( hwnd, NULL, &flags ) && (flags & UPDATE_PAINT)); -} - - /*********************************************************************** * ExcludeUpdateRgn (USER32.@) */ diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index bb20ce3f332..bde66708a15 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -392,7 +392,7 @@ @ stdcall GetTitleBarInfo(long ptr) @ stdcall GetTopWindow(long) @ stdcall GetTouchInputInfo(long long ptr long) -@ stdcall GetUpdateRect(long ptr long) +@ stdcall GetUpdateRect(long ptr long) NtUserGetUpdateRect @ stdcall GetUpdateRgn(long long long) NtUserGetUpdateRgn @ stdcall GetUpdatedClipboardFormats(ptr long ptr) NtUserGetUpdatedClipboardFormats @ stdcall GetUserObjectInformationA (long long ptr long ptr) diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index da725efa880..97288b26ff9 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1167,3 +1167,35 @@ INT WINAPI NtUserGetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase ) set_thread_dpi_awareness_context( context ); return retval; } + +/*********************************************************************** + * NtUserGetUpdateRect (win32u.@) + */ +BOOL WINAPI NtUserGetUpdateRect( HWND hwnd, RECT *rect, BOOL erase ) +{ + UINT flags = UPDATE_NOCHILDREN; + HRGN update_rgn; + BOOL need_erase; + + if (erase) flags |= UPDATE_NONCLIENT | UPDATE_ERASE; + + if (!(update_rgn = send_ncpaint( hwnd, NULL, &flags ))) return FALSE; + + if (rect && NtGdiGetRgnBox( update_rgn, rect ) != NULLREGION) + { + HDC hdc = NtUserGetDCEx( hwnd, 0, DCX_USESTYLE ); + DWORD layout = NtGdiSetLayout( hdc, -1, 0 ); /* map_window_points mirrors already */ + UINT win_dpi = get_dpi_for_window( hwnd ); + map_window_points( 0, hwnd, (POINT *)rect, 2, win_dpi ); + *rect = map_dpi_rect( *rect, win_dpi, get_thread_dpi() ); + NtGdiTransformPoints( hdc, (POINT *)rect, (POINT *)rect, 2, NtGdiDPtoLP ); + NtGdiSetLayout( hdc, -1, layout ); + NtUserReleaseDC( hwnd, hdc ); + } + need_erase = send_erase( hwnd, flags, update_rgn, NULL, NULL ); + + /* check if we still have an update region */ + flags = UPDATE_PAINT | UPDATE_NOCHILDREN; + if (need_erase) flags |= UPDATE_DELAYED_ERASE; + return get_update_flags( hwnd, NULL, &flags ) && (flags & UPDATE_PAINT); +} diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index b8d12a23dd3..888313ad685 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1179,6 +1179,7 @@ static struct unix_funcs unix_funcs = NtUserGetKeyboardLayoutList, NtUserGetPriorityClipboardFormat, NtUserGetQueueStatus, + NtUserGetUpdateRect, NtUserGetUpdateRgn, NtUserGetUpdatedClipboardFormats, NtUserIsClipboardFormatAvailable, @@ -1214,7 +1215,6 @@ static struct unix_funcs unix_funcs = NtUserVkKeyScanEx, NtUserWindowFromPoint, - GetDCHook, SetDIBits, SetHookFlags, __wine_get_brush_bitmap_info, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 1853e141083..fc659c4ca9f 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1002,7 +1002,7 @@ @ stub NtUserGetTouchInputInfo @ stub NtUserGetTouchValidationStatus @ stub NtUserGetUniformSpaceMapping -@ stub NtUserGetUpdateRect +@ stdcall NtUserGetUpdateRect(long ptr long) @ stdcall NtUserGetUpdateRgn(long long long) @ stdcall NtUserGetUpdatedClipboardFormats(ptr long ptr) @ stub NtUserGetWOWClass @@ -1321,7 +1321,6 @@ # Wine internal extensions # user32 -@ stdcall GetDCHook(long ptr) @ stdcall SetHookFlags(long long) @ cdecl __wine_set_visible_region(long long ptr ptr ptr) diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index f956abe2093..3f9183a2b1d 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -222,6 +222,7 @@ struct unix_funcs UINT (WINAPI *pNtUserGetKeyboardLayoutList)( INT size, HKL *layouts ); INT (WINAPI *pNtUserGetPriorityClipboardFormat)( UINT *list, INT count ); DWORD (WINAPI *pNtUserGetQueueStatus)( UINT flags ); + BOOL (WINAPI *pNtUserGetUpdateRect)( HWND hwnd, RECT *rect, BOOL erase ); INT (WINAPI *pNtUserGetUpdateRgn)( HWND hwnd, HRGN hrgn, BOOL erase ); BOOL (WINAPI *pNtUserGetUpdatedClipboardFormats)( UINT *formats, UINT size, UINT *out_size ); BOOL (WINAPI *pNtUserIsClipboardFormatAvailable)( UINT format ); @@ -269,7 +270,6 @@ struct unix_funcs HWND (WINAPI *pNtUserWindowFromPoint)( LONG x, LONG y ); /* Wine-specific functions */ - DWORD_PTR (WINAPI *pGetDCHook)( HDC hdc, DCHOOKPROC *proc ); INT (WINAPI *pSetDIBits)( HDC hdc, HBITMAP hbitmap, UINT startscan, UINT lines, const void *bits, const BITMAPINFO *info, UINT coloruse ); @@ -358,6 +358,8 @@ extern BOOL get_window_rects( HWND hwnd, enum coords_relative relative, RECT *wi RECT *client_rect, UINT dpi ) DECLSPEC_HIDDEN; extern HWND *list_window_children( HDESK desktop, HWND hwnd, UNICODE_STRING *class, DWORD tid ) DECLSPEC_HIDDEN; +extern int map_window_points( HWND hwnd_from, HWND hwnd_to, POINT *points, UINT count, + UINT dpi ) DECLSPEC_HIDDEN; extern void map_window_region( HWND from, HWND to, HRGN hrgn ) DECLSPEC_HIDDEN; extern BOOL set_window_pos( WINDOWPOS *winpos, int parent_x, int parent_y ) DECLSPEC_HIDDEN; extern void update_window_state( HWND hwnd ) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 42f2d82ddff..c3da53d08e4 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1873,7 +1873,7 @@ INT WINAPI NtUserInternalGetWindowText( HWND hwnd, WCHAR *text, INT count ) * Calculate the offset between the origin of the two windows. Used * to implement MapWindowPoints. */ -static BOOL get_windows_offset( HWND hwnd_from, HWND hwnd_to, BOOL *mirrored, POINT *ret_offset ) +static BOOL get_windows_offset( HWND hwnd_from, HWND hwnd_to, UINT dpi, BOOL *mirrored, POINT *ret_offset ) { WND *win; POINT offset; @@ -1915,7 +1915,7 @@ static BOOL get_windows_offset( HWND hwnd_from, HWND hwnd_to, BOOL *mirrored, PO } } if (win && win != WND_DESKTOP) release_win_ptr( win ); - offset = map_dpi_point( offset, get_dpi_for_window( hwnd_from ), get_thread_dpi() ); + offset = map_dpi_point( offset, get_dpi_for_window( hwnd_from ), dpi ); } } @@ -1952,7 +1952,7 @@ static BOOL get_windows_offset( HWND hwnd_from, HWND hwnd_to, BOOL *mirrored, PO } } if (win && win != WND_DESKTOP) release_win_ptr( win ); - pt = map_dpi_point( pt, get_dpi_for_window( hwnd_to ), get_thread_dpi() ); + pt = map_dpi_point( pt, get_dpi_for_window( hwnd_to ), dpi ); offset.x -= pt.x; offset.y -= pt.y; } @@ -1968,7 +1968,7 @@ other_process: /* one of the parents may belong to another process, do it the h { req->from = wine_server_user_handle( hwnd_from ); req->to = wine_server_user_handle( hwnd_to ); - req->dpi = get_thread_dpi(); + req->dpi = dpi; if ((ret = !wine_server_call_err( req ))) { ret_offset->x = reply->x; @@ -1990,7 +1990,7 @@ void map_window_region( HWND from, HWND to, HRGN hrgn ) HRGN new_rgn; RECT *rect; - if (!get_windows_offset( from, to, &mirrored, &offset )) return; + if (!get_windows_offset( from, to, get_thread_dpi(), &mirrored, &offset )) return; if (!mirrored) { @@ -2017,6 +2017,30 @@ void map_window_region( HWND from, HWND to, HRGN hrgn ) free( data ); } +/* see MapWindowPoints */ +int map_window_points( HWND hwnd_from, HWND hwnd_to, POINT *points, UINT count, UINT dpi ) +{ + BOOL mirrored; + POINT offset; + UINT i; + + if (!get_windows_offset( hwnd_from, hwnd_to, dpi, &mirrored, &offset )) return 0; + + for (i = 0; i < count; i++) + { + points[i].x += offset.x; + points[i].y += offset.y; + if (mirrored) points[i].x = -points[i].x; + } + if (mirrored && count == 2) /* special case for rectangle */ + { + int tmp = points[0].x; + points[0].x = points[1].x; + points[1].x = tmp; + } + return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) ); +} + /*********************************************************************** * dump_winpos_flags */ diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index 2f9ffd3df40..471bfa449b1 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -873,6 +873,12 @@ INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size ) return unix_funcs->pNtUserGetKeyNameText( lparam, buffer, size ); } +BOOL WINAPI NtUserGetUpdateRect( HWND hwnd, RECT *rect, BOOL erase ) +{ + if (!unix_funcs) return FALSE; + return unix_funcs->pNtUserGetUpdateRect( hwnd, rect, erase ); +} + INT WINAPI NtUserGetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase ) { if (!unix_funcs) return 0; @@ -1098,12 +1104,6 @@ HWND WINAPI NtUserWindowFromPoint( LONG x, LONG y ) return unix_funcs->pNtUserWindowFromPoint( x, y ); } -DWORD_PTR WINAPI GetDCHook( HDC hdc, DCHOOKPROC *proc ) -{ - if (!unix_funcs) return 0; - return unix_funcs->pGetDCHook( hdc, proc ); -} - INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan, UINT lines, const void *bits, const BITMAPINFO *info, UINT coloruse ) diff --git a/include/ntuser.h b/include/ntuser.h index dc0517bc767..a4e28764e0d 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -355,6 +355,7 @@ ULONG WINAPI NtUserGetSystemDpiForProcess( HANDLE process ); HDESK WINAPI NtUserGetThreadDesktop( DWORD thread ); INT WINAPI NtUserGetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase ); BOOL WINAPI NtUserGetUpdatedClipboardFormats( UINT *formats, UINT size, UINT *out_size ); +BOOL WINAPI NtUserGetUpdateRect( HWND hwnd, RECT *rect, BOOL erase ); int WINAPI NtUserGetWindowRgnEx( HWND hwnd, HRGN hrgn, UINT unk ); NTSTATUS WINAPI NtUserInitializeClientPfnArrays( const struct user_client_procs *client_procsA, const struct user_client_procs *client_procsW,