From 0b0403baa889c729cf40cd302b00adcd7b8d4aea Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Mon, 14 Mar 2022 11:44:10 +0100 Subject: [PATCH] win32u: Move NtUserBeginPaint implementation from user32. Signed-off-by: Jacek Caban Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- dlls/user32/button.c | 2 +- dlls/user32/combo.c | 6 +- dlls/user32/defwnd.c | 2 +- dlls/user32/edit.c | 2 +- dlls/user32/listbox.c | 2 +- dlls/user32/menu.c | 2 +- dlls/user32/painting.c | 31 ------ dlls/user32/scroll.c | 4 +- dlls/user32/static.c | 2 +- dlls/user32/user32.spec | 2 +- dlls/user32/user_main.c | 2 + dlls/user32/user_private.h | 2 +- dlls/win32u/dce.c | 184 +++++++++++++++++++++++++++++++++++ dlls/win32u/gdiobj.c | 1 + dlls/win32u/ntuser_private.h | 2 + dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 1 + dlls/win32u/wrappers.c | 6 ++ include/ntuser.h | 1 + 19 files changed, 210 insertions(+), 46 deletions(-) diff --git a/dlls/user32/button.c b/dlls/user32/button.c index e0e9ba235a1..37b5fe317e1 100644 --- a/dlls/user32/button.c +++ b/dlls/user32/button.c @@ -246,7 +246,7 @@ LRESULT ButtonWndProc_common(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, case WM_PAINT: { PAINTSTRUCT ps; - HDC hdc = wParam ? (HDC)wParam : BeginPaint( hWnd, &ps ); + HDC hdc = wParam ? (HDC)wParam : NtUserBeginPaint( hWnd, &ps ); if (btnPaintFunc[btn_type]) { int nOldMode = SetBkMode( hdc, OPAQUE ); diff --git a/dlls/user32/combo.c b/dlls/user32/combo.c index 0529eecddff..21de55ad479 100644 --- a/dlls/user32/combo.c +++ b/dlls/user32/combo.c @@ -28,8 +28,7 @@ #include "windef.h" #include "winbase.h" -#include "wingdi.h" -#include "winuser.h" +#include "ntuser.h" #include "user_private.h" #include "win.h" #include "controls.h" @@ -792,8 +791,7 @@ static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC hParamDC) PAINTSTRUCT ps; HDC hDC; - hDC = (hParamDC) ? hParamDC - : BeginPaint( lphc->self, &ps); + hDC = hParamDC ? hParamDC : NtUserBeginPaint( lphc->self, &ps ); TRACE("hdc=%p\n", hDC); diff --git a/dlls/user32/defwnd.c b/dlls/user32/defwnd.c index 012ca5c7d42..9804c3b5418 100644 --- a/dlls/user32/defwnd.c +++ b/dlls/user32/defwnd.c @@ -365,7 +365,7 @@ static LRESULT DEFWND_DefWinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPa case WM_PAINT: { PAINTSTRUCT ps; - HDC hdc = BeginPaint( hwnd, &ps ); + HDC hdc = NtUserBeginPaint( hwnd, &ps ); if( hdc ) { HICON hIcon; diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c index c17d680e492..e56fd85926d 100644 --- a/dlls/user32/edit.c +++ b/dlls/user32/edit.c @@ -3706,7 +3706,7 @@ static void EDIT_WM_Paint(EDITSTATE *es, HDC hdc) BOOL rev = es->bEnableState && ((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL)); - dc = hdc ? hdc : BeginPaint(es->hwndSelf, &ps); + dc = hdc ? hdc : NtUserBeginPaint( es->hwndSelf, &ps ); /* The dc we use for calculating may not be the one we paint into. This is the safest action. */ diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c index fa713dbe607..29ed35be331 100644 --- a/dlls/user32/listbox.c +++ b/dlls/user32/listbox.c @@ -3090,7 +3090,7 @@ LRESULT ListBoxWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam case WM_PAINT: { PAINTSTRUCT ps; - HDC hdc = ( wParam ) ? ((HDC)wParam) : BeginPaint( descr->self, &ps ); + HDC hdc = ( wParam ) ? ((HDC)wParam) : NtUserBeginPaint( descr->self, &ps ); ret = LISTBOX_Paint( descr, hdc ); if( !wParam ) EndPaint( descr->self, &ps ); } diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index f895b8dac80..430d7ca8402 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -3581,7 +3581,7 @@ LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM case WM_PAINT: { PAINTSTRUCT ps; - BeginPaint( hwnd, &ps ); + NtUserBeginPaint( hwnd, &ps ); MENU_DrawPopupMenu( hwnd, ps.hdc, (HMENU)GetWindowLongPtrW( hwnd, 0 ) ); EndPaint( hwnd, &ps ); diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c index 84677c7e75b..3cc1f802abd 100644 --- a/dlls/user32/painting.c +++ b/dlls/user32/painting.c @@ -550,37 +550,6 @@ static HWND fix_caret(HWND hWnd, const RECT *scroll_rect, INT dx, INT dy, } -/*********************************************************************** - * BeginPaint (USER32.@) - */ -HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps ) -{ - HRGN hrgn; - HDC hdc; - BOOL erase; - RECT rect; - UINT flags = UPDATE_NONCLIENT | UPDATE_ERASE | UPDATE_PAINT | UPDATE_INTERNALPAINT | UPDATE_NOCHILDREN; - - HideCaret( hwnd ); - - if (!(hrgn = send_ncpaint( hwnd, NULL, &flags ))) return 0; - - erase = send_erase( hwnd, flags, hrgn, &rect, &hdc ); - - TRACE("hdc = %p box = (%s), fErase = %d\n", hdc, wine_dbgstr_rect(&rect), erase); - - if (!lps) - { - release_dc( hwnd, hdc, TRUE ); - return 0; - } - lps->fErase = erase; - lps->rcPaint = rect; - lps->hdc = hdc; - return hdc; -} - - /*********************************************************************** * EndPaint (USER32.@) */ diff --git a/dlls/user32/scroll.c b/dlls/user32/scroll.c index 2942001e9a3..090d0bc1c7e 100644 --- a/dlls/user32/scroll.c +++ b/dlls/user32/scroll.c @@ -644,7 +644,7 @@ void WINAPI USER_ScrollBarDraw( HWND hwnd, HDC hdc, INT nBar, enum SCROLL_HITTES } } -void SCROLL_SetStandardScrollPainted( HWND hwnd, INT bar, BOOL painted ) +void WINAPI SCROLL_SetStandardScrollPainted( HWND hwnd, INT bar, BOOL painted ) { LPSCROLLBAR_INFO info; @@ -1521,7 +1521,7 @@ LRESULT WINAPI USER_ScrollBarProc( HWND hwnd, UINT message, WPARAM wParam, LPARA case WM_PAINT: { PAINTSTRUCT ps; - HDC hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps); + HDC hdc = wParam ? (HDC)wParam : NtUserBeginPaint( hwnd, &ps ); SCROLL_DrawScrollBar( hwnd, hdc, SB_CTL, g_tracking_info.hit_test, &g_tracking_info, TRUE, TRUE ); if (!wParam) EndPaint(hwnd, &ps); } diff --git a/dlls/user32/static.c b/dlls/user32/static.c index 5b21e55e24a..88ccb83c687 100644 --- a/dlls/user32/static.c +++ b/dlls/user32/static.c @@ -374,7 +374,7 @@ LRESULT StaticWndProc_common( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam { PAINTSTRUCT ps; RECT rect; - HDC hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps); + HDC hdc = wParam ? (HDC)wParam : NtUserBeginPaint( hwnd, &ps ); HRGN hrgn; HBRUSH hbrush; diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 7dc7a2abece..00decbbfade 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -14,7 +14,7 @@ @ stdcall ArrangeIconicWindows(long) @ stdcall AttachThreadInput(long long long) NtUserAttachThreadInput @ stdcall BeginDeferWindowPos(long) -@ stdcall BeginPaint(long ptr) +@ stdcall BeginPaint(long ptr) NtUserBeginPaint @ stdcall BlockInput(long) @ stdcall BringWindowToTop(long) @ stdcall BroadcastSystemMessage(long ptr long long long) BroadcastSystemMessageA diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 3c2c96692c1..d1d7a7ef1b2 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -143,6 +143,7 @@ static void CDECL notify_ime( HWND hwnd, UINT param ) static const struct user_callbacks user_funcs = { CopyImage, + HideCaret, PostMessageW, RedrawWindow, SendInput, @@ -154,6 +155,7 @@ static const struct user_callbacks user_funcs = notify_ime, register_builtin_classes, MSG_SendInternalMessageTimeout, + SCROLL_SetStandardScrollPainted, (void *)__wine_set_user_driver, set_window_pos, }; diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index ca8ba93d5c9..b6cc87d3027 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -243,6 +243,6 @@ LRESULT WINAPI USER_ScrollBarProc(HWND, UINT, WPARAM, LPARAM, BOOL) DECLSPEC_HID void WINAPI USER_ScrollBarDraw(HWND, HDC, INT, enum SCROLL_HITTEST, const struct SCROLL_TRACKING_INFO *, BOOL, BOOL, RECT *, INT, INT, INT, BOOL) DECLSPEC_HIDDEN; -void SCROLL_SetStandardScrollPainted(HWND hwnd, INT bar, BOOL visible); +void WINAPI SCROLL_SetStandardScrollPainted(HWND hwnd, INT bar, BOOL visible); #endif /* __WINE_USER_PRIVATE_H */ diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index d7c1c8d5635..5055e909351 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -742,3 +742,187 @@ HWND WINAPI NtUserWindowFromDC( HDC hdc ) user_unlock(); return hwnd; } + +/*********************************************************************** + * get_update_region + * + * Return update region (in screen coordinates) for a window. + */ +static HRGN get_update_region( HWND hwnd, UINT *flags, HWND *child ) +{ + HRGN hrgn = 0; + NTSTATUS status; + RGNDATA *data; + size_t size = 256; + + do + { + if (!(data = malloc( sizeof(*data) + size - 1 ))) + { + SetLastError( ERROR_OUTOFMEMORY ); + return 0; + } + + 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; + wine_server_set_reply( req, data->Buffer, size ); + if (!(status = wine_server_call( req ))) + { + size_t reply_size = wine_server_reply_size( reply ); + data->rdh.dwSize = sizeof(data->rdh); + data->rdh.iType = RDH_RECTANGLES; + data->rdh.nCount = reply_size / sizeof(RECT); + data->rdh.nRgnSize = reply_size; + hrgn = NtGdiExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data ); + if (child) *child = wine_server_ptr_handle( reply->child ); + *flags = reply->flags; + } + else size = reply->total_size; + } + SERVER_END_REQ; + free( data ); + } while (status == STATUS_BUFFER_OVERFLOW); + + if (status) SetLastError( RtlNtStatusToDosError(status) ); + return hrgn; +} + +/*********************************************************************** + * 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 == get_desktop_window()) return whole_rgn; + + if (whole_rgn) + { + DPI_AWARENESS_CONTEXT context; + RECT client, window, update; + INT type; + + context = set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd )); + + /* check if update rgn overlaps with nonclient area */ + type = NtGdiGetRgnBox( whole_rgn, &update ); + get_window_rects( hwnd, COORDS_SCREEN, &window, &client, get_thread_dpi() ); + + if ((*flags & UPDATE_NONCLIENT) || + update.left < client.left || update.top < client.top || + update.right > client.right || update.bottom > client.bottom) + { + client_rgn = NtGdiCreateRectRgn( client.left, client.top, client.right, client.bottom ); + NtGdiCombineRgn( client_rgn, client_rgn, whole_rgn, RGN_AND ); + + /* check if update rgn contains complete nonclient area */ + if (type == SIMPLEREGION && EqualRect( &window, &update )) + { + NtGdiDeleteObjectApp( 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) && user_callbacks) + { + /* Mark standard scroll bars as not painted before sending WM_NCPAINT */ + style = get_window_long( hwnd, GWL_STYLE ); + if (style & WS_HSCROLL) + user_callbacks->set_standard_scroll_painted( hwnd, SB_HORZ, FALSE ); + if (style & WS_VSCROLL) + user_callbacks->set_standard_scroll_painted( hwnd, SB_VERT, FALSE ); + + send_message( hwnd, WM_NCPAINT, (WPARAM)whole_rgn, 0 ); + } + if (whole_rgn > (HRGN)1) NtGdiDeleteObjectApp( whole_rgn ); + } + set_thread_dpi_awareness_context( 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 (is_iconic(hwnd)) dcx_flags |= DCX_WINDOW; + + if ((hdc = NtUserGetDCEx( hwnd, client_rgn, dcx_flags ))) + { + INT type = NtGdiGetAppClipBox( hdc, clip_rect ); + + if (flags & UPDATE_ERASE) + { + /* don't erase if the clip box is empty */ + if (type != NULLREGION) + need_erase = !send_message( hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0 ); + } + if (!hdc_ret) release_dc( hwnd, hdc, TRUE ); + } + + if (hdc_ret) *hdc_ret = hdc; + } + if (!hdc) NtGdiDeleteObjectApp( client_rgn ); + return need_erase; +} + +/*********************************************************************** + * NtUserBeginPaint (win32u.@) + */ +HDC WINAPI NtUserBeginPaint( HWND hwnd, PAINTSTRUCT *ps ) +{ + HRGN hrgn; + HDC hdc; + BOOL erase; + RECT rect; + UINT flags = UPDATE_NONCLIENT | UPDATE_ERASE | UPDATE_PAINT | UPDATE_INTERNALPAINT | UPDATE_NOCHILDREN; + + if (user_callbacks) user_callbacks->pHideCaret( hwnd ); + + if (!(hrgn = send_ncpaint( hwnd, NULL, &flags ))) return 0; + + erase = send_erase( hwnd, flags, hrgn, &rect, &hdc ); + + TRACE( "hdc = %p box = (%s), fErase = %d\n", hdc, wine_dbgstr_rect(&rect), erase ); + + if (!ps) + { + release_dc( hwnd, hdc, TRUE ); + return 0; + } + ps->fErase = erase; + ps->rcPaint = rect; + ps->hdc = hdc; + return hdc; +} diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index 768feb79c0f..a186c05a7cf 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1150,6 +1150,7 @@ static struct unix_funcs unix_funcs = NtGdiUpdateColors, NtGdiWidenPath, NtUserActivateKeyboardLayout, + NtUserBeginPaint, NtUserCallHwnd, NtUserCallHwndParam, NtUserCallNextHookEx, diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 0eb3b1d72b3..b870d0d0bcd 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -30,6 +30,7 @@ struct dce; struct user_callbacks { HANDLE (WINAPI *pCopyImage)( HANDLE, UINT, INT, INT, UINT ); + BOOL (WINAPI *pHideCaret)( HWND hwnd ); BOOL (WINAPI *pPostMessageW)( HWND, UINT, WPARAM, LPARAM ); BOOL (WINAPI *pRedrawWindow)( HWND, const RECT*, HRGN, UINT ); UINT (WINAPI *pSendInput)( UINT count, INPUT *inputs, int size ); @@ -41,6 +42,7 @@ struct user_callbacks void (CDECL *notify_ime)( HWND hwnd, UINT param ); void (CDECL *register_builtin_classes)(void); LRESULT (WINAPI *send_ll_message)( DWORD, DWORD, UINT, WPARAM, LPARAM, UINT, UINT, PDWORD_PTR ); + void (WINAPI *set_standard_scroll_painted)( HWND hwnd, INT bar, BOOL visible ); void (CDECL *set_user_driver)( void *, UINT ); BOOL (CDECL *set_window_pos)( HWND hwnd, HWND insert_after, UINT swp_flags, const RECT *window_rect, const RECT *client_rect, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index ef4be5a41ec..1c1cb19ae94 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -758,7 +758,7 @@ @ stub NtUserAutoPromoteMouseInPointer @ stub NtUserAutoRotateScreen @ stub NtUserBeginLayoutUpdate -@ stub NtUserBeginPaint +@ stdcall NtUserBeginPaint(long ptr) @ stub NtUserBitBltSysBmp @ stub NtUserBlockInput @ stub NtUserBroadcastThemeChangeEvent diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index d656b333016..6350813037c 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -184,6 +184,7 @@ struct unix_funcs BOOL (WINAPI *pNtGdiUpdateColors)( HDC hdc ); BOOL (WINAPI *pNtGdiWidenPath)( HDC hdc ); HKL (WINAPI *pNtUserActivateKeyboardLayout)( HKL layout, UINT flags ); + HDC (WINAPI *pNtUserBeginPaint)( HWND hwnd, PAINTSTRUCT *ps ); ULONG_PTR (WINAPI *pNtUserCallHwnd)( HWND hwnd, DWORD code ); ULONG_PTR (WINAPI *pNtUserCallHwndParam)( HWND hwnd, DWORD_PTR param, DWORD code ); LRESULT (WINAPI *pNtUserCallNextHookEx)( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam ); diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index d499a863caf..a69e81e8e10 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -701,6 +701,12 @@ HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ) return unix_funcs->pNtUserActivateKeyboardLayout( layout, flags ); } +HDC WINAPI NtUserBeginPaint( HWND hwnd, PAINTSTRUCT *ps ) +{ + if (!unix_funcs) return 0; + return unix_funcs->pNtUserBeginPaint( hwnd, ps ); +} + LRESULT WINAPI NtUserCallNextHookEx( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam ) { if (!unix_funcs) return 0; diff --git a/include/ntuser.h b/include/ntuser.h index 1927880dd43..455d81a10fb 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -271,6 +271,7 @@ enum wine_internal_message HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ); BOOL WINAPI NtUserAddClipboardFormatListener( HWND hwnd ); BOOL WINAPI NtUserAttachThreadInput( DWORD from, DWORD to, BOOL attach ); +HDC WINAPI NtUserBeginPaint( HWND hwnd, PAINTSTRUCT *ps ); NTSTATUS WINAPI NtUserBuildHwndList( HDESK desktop, ULONG unk2, ULONG unk3, ULONG unk4, ULONG thread_id, ULONG count, HWND *buffer, ULONG *size ); ULONG_PTR WINAPI NtUserCallHwnd( HWND hwnd, DWORD code );