These patches fix painting in an application that draws outside of a CS_PARENTDC child client area in its WM_PAINT handler.
Comments and suggestions are welcome.
-- v4: win32u: Use parent rectangle for visible region calculations of a CS_PARENTDC child. win32u: Don't clip update region to the window client rectangle. win32u: GetUpdateRect() should clip update rectangle to the window client area. win32u: GetUpdateRgn() should clip update region to the window client area. win32u: Clip PAINTSTRUCT.rcPaint to the window client area. server: For a CS_PARENTDC child use parent for visible region calculations. server: If the being validated region covers whole window then validate everything. user32/tests: Add a message test for listbox redrawing after LB_SETCOUNT. user32/tests: Test BeginPaint() clipbox of cropped window with CS_PARENTDC.
From: Jinoh Kang jinoh.kang.kr@gmail.com
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/user32/tests/dce.c | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)
diff --git a/dlls/user32/tests/dce.c b/dlls/user32/tests/dce.c index 18f31e3708c..09c6dd0da54 100644 --- a/dlls/user32/tests/dce.c +++ b/dlls/user32/tests/dce.c @@ -525,6 +525,55 @@ static void test_begin_paint(void) ReleaseDC( hwnd_parent, hdc ); }
+static void test_cropped_parentdc_paint_clipbox(void) +{ + /* Use WS_BORDER to differentiate window and client rects */ + const UINT common_style = WS_VISIBLE | WS_BORDER; + HWND hwnd_toplevel, hwnd_container, hwnd_child; + RECT parent_rect, expect_rect, toplevel_rect, rect; + POINT dot_pos = { 10, 10 }; + PAINTSTRUCT ps; + COLORREF cr; + HDC hdc; + + hwnd_toplevel = CreateWindowA( "static", NULL, WS_OVERLAPPED | common_style, + 400, 200, 100, 100, NULL, NULL, NULL, NULL ); + + /* Container window extends "outside" the top-level window (hence cropped) */ + hwnd_container = CreateWindowA( "static", NULL, WS_CHILD | common_style, + -40, -40, 180, 180, hwnd_toplevel, NULL, NULL, NULL ); + + hwnd_child = CreateWindowA( "parentdc_class", NULL, WS_CHILD | common_style, + 50, 50, 3, 3, hwnd_container, NULL, NULL, NULL ); + + RedrawWindow( hwnd_toplevel, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE ); + RedrawWindow( hwnd_child, NULL, 0, RDW_INVALIDATE ); + + hdc = BeginPaint( hwnd_child, &ps ); + GetClipBox( hdc, &rect ); + cr = SetPixel( hdc, dot_pos.x, dot_pos.y, RGB(255, 0, 0) ); + ok( cr != -1, "error drawing outside of window client area\n" ); + EndPaint( hwnd_child, &ps ); + + GetClientRect( hwnd_toplevel, &toplevel_rect ); + MapWindowPoints( hwnd_toplevel, hwnd_container, (POINT *)&toplevel_rect, 2); + GetClientRect( hwnd_container, &parent_rect ); + IntersectRect( &expect_rect, &toplevel_rect, &parent_rect ); + + MapWindowPoints( hwnd_child, hwnd_container, (POINT *)&rect, 2 ); + todo_wine + ok( EqualRect( &rect, &expect_rect ), "rect = %s, expected %s\n", + wine_dbgstr_rect( &rect ), wine_dbgstr_rect( &expect_rect ) ); + + hdc = GetDC( hwnd_container ); + MapWindowPoints( hwnd_child, hwnd_container, &dot_pos, 1 ); + todo_wine + ok( GetPixel( hdc, dot_pos.x, dot_pos.y ) == cr, "error drawing outside of window client area\n" ); + ReleaseDC( hwnd_container, hdc ); + + DestroyWindow( hwnd_toplevel ); +} + /* test ScrollWindow with window DCs */ static void test_scroll_window(void) { @@ -780,6 +829,7 @@ START_TEST(dce) test_parameters(); test_dc_visrgn(); test_begin_paint(); + test_cropped_parentdc_paint_clipbox(); test_scroll_window(); test_invisible_create(); test_dc_layout();
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/user32/tests/msg.c | 71 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 71da1494291..e462c9bf5cb 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -2330,6 +2330,7 @@ static BOOL after_end_dialog, test_def_id, paint_loop_done; static int sequence_cnt, sequence_size; static struct recvd_message* sequence; static int log_all_parent_messages; +static int log_painting_messages; static CRITICAL_SECTION sequence_cs;
/* user32 functions */ @@ -16923,6 +16924,25 @@ static const struct message wm_lb_dblclick_0[] = { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 }, { 0 } }; +static const struct message wm_lb_setcount[] = +{ + { LB_SETCOUNT, sent|wparam|lparam, 100, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_ERASEBKGND, sent|parent }, + { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTMOVE }, + { WM_SIZE, sent|defwinproc }, + { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_VSCROLL, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 }, + { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_VSCROLL, 0 }, + { WM_USER, sent|wparam|lparam, 0, 0 }, + { WM_NCPAINT, sent|wparam|lparam, 1, 0 }, + { WM_ERASEBKGND, sent }, + { WM_CTLCOLORLISTBOX, sent|parent }, + { WM_USER+1, sent|wparam|lparam, 0, 0 }, + { 0 } +};
#define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
@@ -16935,10 +16955,11 @@ static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPAR struct recvd_message msg;
/* do not log painting messages */ - if (message != WM_PAINT && + if ((log_painting_messages || + (message != WM_PAINT && message != WM_NCPAINT && message != WM_SYNCPAINT && - message != WM_ERASEBKGND && + message != WM_ERASEBKGND)) && message != WM_NCHITTEST && message != WM_GETTEXT && !ignore_message( message )) @@ -16983,11 +17004,57 @@ static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
static void test_listbox_messages(void) { + PAINTSTRUCT ps; + RECT rc, rc1; HWND parent, listbox; LRESULT ret;
parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, 0, 0, 0, NULL); + + /* test listbox redrawing after LB_SETCOUNT */ + listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL, + LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VSCROLL | WS_VISIBLE, + 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL); + listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc); + + UpdateWindow(listbox); + + check_lb_state(listbox, 0, LB_ERR, 0, 0); + + flush_sequence(); + + log_all_parent_messages++; + log_painting_messages++; + + ret = GetWindowLongA(listbox, GWL_STYLE); + ok((ret & (WS_VSCROLL | WS_HSCROLL)) == 0, "Listbox should not have scroll bars\n"); + + ret = SendMessageA(listbox, LB_SETCOUNT, 100, 0); + ok(ret == 0, "got %Id\n", ret); + ret = GetWindowLongA(listbox, GWL_STYLE); + ok((ret & (WS_VSCROLL | WS_HSCROLL)) == WS_VSCROLL, "Listbox should have vertical scroll bar\n"); + + SendMessageA(listbox, WM_USER, 0, 0); /* Mark */ + BeginPaint(listbox, &ps); + GetClientRect(parent, &rc1); + MapWindowPoints(parent, listbox, (POINT *)&rc1, 2); + GetClipBox(ps.hdc, &rc); + todo_wine + ok(EqualRect(&rc, &rc1), "hdc clipbox %s != parent client rect %s\n", wine_dbgstr_rect(&rc), wine_dbgstr_rect(&rc1)); + GetClientRect(listbox, &rc); + ok(EqualRect(&ps.rcPaint, &rc), "rcPaint %s != listbox client rect %s\n", wine_dbgstr_rect(&ps.rcPaint), wine_dbgstr_rect(&rc)); + EndPaint(listbox, &ps); + SendMessageA(listbox, WM_USER+1, 0, 0); /* Mark */ + + ok_sequence(wm_lb_setcount, "LB_SETCOUNT", FALSE); + flush_sequence(); + + log_painting_messages--; + log_all_parent_messages--; + + DestroyWindow(listbox); + /* with LBS_HASSTRINGS */ listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL, WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- server/window.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/server/window.c b/server/window.c index 4ebfec3da12..51f573751c7 100644 --- a/server/window.c +++ b/server/window.c @@ -1532,7 +1532,24 @@ static void redraw_window( struct window *win, struct region *region, int frame, { if ((tmp = crop_region_to_win_rect( win, region, frame ))) { - if (!subtract_region( tmp, win->update_region, tmp )) + if ((child_rgn = create_empty_region())) + { + rectangle_t rect = win->window_rect; + + offset_rect( &rect, -rect.left, -rect.top ); + set_region_rect( child_rgn, &rect ); + + if (subtract_region( child_rgn, child_rgn, tmp ) && is_region_empty( child_rgn ) ) + { + /* region covers whole window: validate everything */ + free_region( tmp ); + tmp = NULL; + } + + free_region( child_rgn ); + } + + if (tmp && !subtract_region( tmp, win->update_region, tmp )) { free_region( tmp ); return;
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- server/window.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/server/window.c b/server/window.c index 51f573751c7..0dcaae0fca5 100644 --- a/server/window.c +++ b/server/window.c @@ -1316,6 +1316,18 @@ static struct region *crop_region_to_win_rect( struct window *win, struct region struct region *tmp;
if (!get_window_visible_rect( win, &rect, frame )) return NULL; + + if (win->parent && is_window_using_parent_dc( win )) + { + int offset_x, offset_y; + + if (!get_window_visible_rect( win->parent, &rect, 0 )) return NULL; + + offset_x = win->parent->client_rect.left - win->parent->window_rect.left + win->window_rect.left; + offset_y = win->parent->client_rect.top - win->parent->window_rect.top + win->window_rect.top; + offset_rect( &rect, -offset_x, -offset_y ); + } + if (!(tmp = create_empty_region())) return NULL; set_region_rect( tmp, &rect );
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/win32u/dce.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index cfa3510c60b..727b5c31417 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1157,6 +1157,8 @@ static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn, HDC hdc = 0; RECT dummy;
+ TRACE( "hwnd %p, flags %08x, client_rgn %p\n", hwnd, flags, client_rgn ); + if (!clip_rect) clip_rect = &dummy; if (hdc_ret || (flags & UPDATE_ERASE)) { @@ -1167,6 +1169,13 @@ static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn, { INT type = NtGdiGetAppClipBox( hdc, clip_rect );
+ if (get_class_long( hwnd, GCL_STYLE, FALSE ) & CS_PARENTDC) + { + RECT client_rect; + get_client_rect( hwnd, &client_rect, get_thread_dpi() ); + intersect_rect( clip_rect, clip_rect, &client_rect ); + } + if (flags & UPDATE_ERASE) { /* don't erase if the clip box is empty */
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/win32u/dce.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 727b5c31417..76570b2747b 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1444,7 +1444,15 @@ INT WINAPI NtUserGetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
if ((update_rgn = send_ncpaint( hwnd, NULL, &flags ))) { - retval = NtGdiCombineRgn( hrgn, update_rgn, 0, RGN_COPY ); + RECT client_rect; + HRGN client_rgn; + + get_window_rects( hwnd, COORDS_SCREEN, NULL, &client_rect, get_thread_dpi() ); + + client_rgn = NtGdiCreateRectRgn( client_rect.left, client_rect.top, client_rect.right, client_rect.bottom ); + retval = NtGdiCombineRgn( hrgn, update_rgn, client_rgn, RGN_AND ); + NtGdiDeleteObjectApp( client_rgn ); + if (send_erase( hwnd, flags, update_rgn, NULL, NULL )) { flags = UPDATE_DELAYED_ERASE;
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/win32u/dce.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 76570b2747b..fa8f61301be 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1471,13 +1471,20 @@ INT WINAPI NtUserGetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase ) BOOL WINAPI NtUserGetUpdateRect( HWND hwnd, RECT *rect, BOOL erase ) { UINT flags = UPDATE_NOCHILDREN; - HRGN update_rgn; + HRGN update_rgn, client_rgn; + RECT client_rect; BOOL need_erase;
if (erase) flags |= UPDATE_NONCLIENT | UPDATE_ERASE;
if (!(update_rgn = send_ncpaint( hwnd, NULL, &flags ))) return FALSE;
+ get_window_rects( hwnd, COORDS_SCREEN, NULL, &client_rect, get_thread_dpi() ); + + client_rgn = NtGdiCreateRectRgn( client_rect.left, client_rect.top, client_rect.right, client_rect.bottom ); + NtGdiCombineRgn( update_rgn, update_rgn, client_rgn, RGN_AND ); + NtGdiDeleteObjectApp( client_rgn ); + if (rect && NtGdiGetRgnBox( update_rgn, rect ) != NULLREGION) { HDC hdc = NtUserGetDCEx( hwnd, 0, DCX_USESTYLE );
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/user32/tests/dce.c | 9 ++++----- dlls/user32/tests/win.c | 24 ++++++++++++------------ dlls/win32u/dce.c | 35 ++++++++++++++++++----------------- 3 files changed, 34 insertions(+), 34 deletions(-)
diff --git a/dlls/user32/tests/dce.c b/dlls/user32/tests/dce.c index 09c6dd0da54..e9cc9817432 100644 --- a/dlls/user32/tests/dce.c +++ b/dlls/user32/tests/dce.c @@ -515,10 +515,10 @@ static void test_begin_paint(void) EndPaint( hwnd_parentdc, &ps ); GetClientRect( hwnd_parent, &parent_rect );
- todo_wine ok( rect.left == parent_rect.left, "rect.left = %ld, expected %ld\n", rect.left, parent_rect.left ); - todo_wine ok( rect.top == parent_rect.top, "rect.top = %ld, expected %ld\n", rect.top, parent_rect.top ); - todo_wine ok( rect.right == parent_rect.right, "rect.right = %ld, expected %ld\n", rect.right, parent_rect.right ); - todo_wine ok( rect.bottom == parent_rect.bottom, "rect.bottom = %ld, expected %ld\n", rect.bottom, parent_rect.bottom ); + ok( rect.left == parent_rect.left, "rect.left = %ld, expected %ld\n", rect.left, parent_rect.left ); + ok( rect.top == parent_rect.top, "rect.top = %ld, expected %ld\n", rect.top, parent_rect.top ); + ok( rect.right == parent_rect.right, "rect.right = %ld, expected %ld\n", rect.right, parent_rect.right ); + ok( rect.bottom == parent_rect.bottom, "rect.bottom = %ld, expected %ld\n", rect.bottom, parent_rect.bottom );
hdc = GetDC( hwnd_parent ); todo_wine ok( GetPixel( hdc, 60, 60 ) == cr, "error drawing outside of window client area\n" ); @@ -561,7 +561,6 @@ static void test_cropped_parentdc_paint_clipbox(void) IntersectRect( &expect_rect, &toplevel_rect, &parent_rect );
MapWindowPoints( hwnd_child, hwnd_container, (POINT *)&rect, 2 ); - todo_wine ok( EqualRect( &rect, &expect_rect ), "rect = %s, expected %s\n", wine_dbgstr_rect( &rect ), wine_dbgstr_rect( &expect_rect ) );
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 775164e3e9f..b92c386251b 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -6274,49 +6274,49 @@ static void test_csparentdc(void) struct parentdc_test test_answer;
#define nothing_todo {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}} - const struct parentdc_test test1 = + const struct parentdc_test test1 = { {{0, 0, 150, 150}, {0, 0, 150, 150}, {0, 0, 150, 150}}, nothing_todo, - {{0, 0, 40, 40}, {-20, -20, 130, 130}, {0, 0, 40, 40}}, {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}}, - {{0, 0, 40, 40}, {-40, -40, 110, 110}, {0, 0, 40, 40}}, {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}}, + {{0, 0, 40, 40}, {-20, -20, 130, 130}, {0, 0, 40, 40}}, nothing_todo, + {{0, 0, 40, 40}, {-40, -40, 110, 110}, {0, 0, 40, 40}}, nothing_todo, };
- const struct parentdc_test test2 = + const struct parentdc_test test2 = { {{0, 0, 150, 150}, {0, 0, 50, 50}, {0, 0, 50, 50}}, nothing_todo, - {{0, 0, 40, 40}, {-20, -20, 30, 30}, {0, 0, 30, 30}}, {{0, 0, 0, 0}, {1, 1, 0, 0}, {0, 0, 0, 0}}, - {{0, 0, 40, 40}, {-40, -40, 10, 10}, {0, 0, 10, 10}}, {{0, 0, 0, 0}, {1, 1, 0, 0}, {0, 0, 0, 0}}, + {{0, 0, 40, 40}, {-20, -20, 30, 30}, {0, 0, 30, 30}}, nothing_todo, + {{0, 0, 40, 40}, {-40, -40, 10, 10}, {0, 0, 10, 10}}, nothing_todo, };
- const struct parentdc_test test3 = + const struct parentdc_test test3 = { {{0, 0, 150, 150}, {0, 0, 10, 10}, {0, 0, 10, 10}}, nothing_todo, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, nothing_todo, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, nothing_todo, };
- const struct parentdc_test test4 = + const struct parentdc_test test4 = { {{0, 0, 150, 150}, {40, 40, 50, 50}, {40, 40, 50, 50}}, nothing_todo, {{0, 0, 40, 40}, {20, 20, 30, 30}, {20, 20, 30, 30}}, nothing_todo, {{0, 0, 40, 40}, {0, 0, 10, 10}, {0, 0, 10, 10}}, nothing_todo, };
- const struct parentdc_test test5 = + const struct parentdc_test test5 = { {{0, 0, 150, 150}, {20, 20, 60, 60}, {20, 20, 60, 60}}, nothing_todo, {{0, 0, 40, 40}, {-20, -20, 130, 130}, {0, 0, 40, 40}}, {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}}, - {{0, 0, 40, 40}, {-20, -20, 20, 20}, {0, 0, 20, 20}}, {{0, 0, 0, 0}, {1, 1, 0, 0}, {0, 0, 0, 0}}, + {{0, 0, 40, 40}, {-20, -20, 20, 20}, {0, 0, 20, 20}}, nothing_todo, };
- const struct parentdc_test test6 = + const struct parentdc_test test6 = { {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, nothing_todo, {{0, 0, 40, 40}, {0, 0, 10, 10}, {0, 0, 10, 10}}, nothing_todo, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, nothing_todo, };
- const struct parentdc_test test7 = + const struct parentdc_test test7 = { {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, nothing_todo, {{0, 0, 40, 40}, {-20, -20, 130, 130}, {0, 0, 40, 40}}, {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}}, diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index fa8f61301be..93107f93930 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1083,10 +1083,13 @@ static BOOL get_update_flags( HWND hwnd, HWND *child, UINT *flags ) */ static HRGN send_ncpaint( HWND hwnd, HWND *child, UINT *flags ) { - HRGN whole_rgn = get_update_region( hwnd, flags, child ); - HRGN client_rgn = 0; + HRGN whole_rgn; DWORD style;
+ TRACE( "hwnd %p, flags %08x\n", hwnd, *flags ); + + whole_rgn = get_update_region( hwnd, flags, child ); + if (child) hwnd = *child;
if (hwnd == get_desktop_window()) return whole_rgn; @@ -1096,6 +1099,7 @@ static HRGN send_ncpaint( HWND hwnd, HWND *child, UINT *flags ) UINT context; RECT client, window, update; INT type; + HRGN nc_rgn = 0;
context = set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd ));
@@ -1107,23 +1111,17 @@ static HRGN send_ncpaint( HWND hwnd, HWND *child, UINT *flags ) 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 )) + if (type == SIMPLEREGION && update.left <= window.left && update.top <= window.top && + update.right >= window.right && update.bottom >= window.bottom) { - NtGdiDeleteObjectApp( whole_rgn ); - whole_rgn = (HRGN)1; + nc_rgn = (HRGN)1; } - } - else - { - client_rgn = whole_rgn; - whole_rgn = 0; + else + nc_rgn = whole_rgn; }
- if (whole_rgn) /* NOTE: WM_NCPAINT allows wParam to be 1 */ + if (nc_rgn) /* NOTE: WM_NCPAINT allows wParam to be 1 */ { if (*flags & UPDATE_NONCLIENT) { @@ -1134,13 +1132,12 @@ static HRGN send_ncpaint( HWND hwnd, HWND *child, UINT *flags ) if (style & WS_VSCROLL) set_standard_scroll_painted( hwnd, SB_VERT, FALSE );
- send_message( hwnd, WM_NCPAINT, (WPARAM)whole_rgn, 0 ); + send_message( hwnd, WM_NCPAINT, (WPARAM)nc_rgn, 0 ); } - if (whole_rgn > (HRGN)1) NtGdiDeleteObjectApp( whole_rgn ); } set_thread_dpi_awareness_context( context ); } - return client_rgn; + return whole_rgn; }
/*********************************************************************** @@ -1264,6 +1261,8 @@ HDC WINAPI NtUserBeginPaint( HWND hwnd, PAINTSTRUCT *ps ) RECT rect; UINT flags = UPDATE_NONCLIENT | UPDATE_ERASE | UPDATE_PAINT | UPDATE_INTERNALPAINT | UPDATE_NOCHILDREN;
+ TRACE( "hwnd %p, %p\n", hwnd, ps ); + NtUserHideCaret( hwnd );
if (!(hrgn = send_ncpaint( hwnd, NULL, &flags ))) return 0; @@ -1288,6 +1287,8 @@ HDC WINAPI NtUserBeginPaint( HWND hwnd, PAINTSTRUCT *ps ) */ BOOL WINAPI NtUserEndPaint( HWND hwnd, const PAINTSTRUCT *ps ) { + TRACE( "hwnd %p, %p\n", hwnd, ps ); + NtUserShowCaret( hwnd ); flush_window_surfaces( FALSE ); if (!ps) return FALSE;
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/user32/tests/dce.c | 3 +-- dlls/win32u/dce.c | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/tests/dce.c b/dlls/user32/tests/dce.c index e9cc9817432..ccc7b03e273 100644 --- a/dlls/user32/tests/dce.c +++ b/dlls/user32/tests/dce.c @@ -521,7 +521,7 @@ static void test_begin_paint(void) ok( rect.bottom == parent_rect.bottom, "rect.bottom = %ld, expected %ld\n", rect.bottom, parent_rect.bottom );
hdc = GetDC( hwnd_parent ); - todo_wine ok( GetPixel( hdc, 60, 60 ) == cr, "error drawing outside of window client area\n" ); + ok( GetPixel( hdc, 60, 60 ) == cr, "error drawing outside of window client area\n" ); ReleaseDC( hwnd_parent, hdc ); }
@@ -566,7 +566,6 @@ static void test_cropped_parentdc_paint_clipbox(void)
hdc = GetDC( hwnd_container ); MapWindowPoints( hwnd_child, hwnd_container, &dot_pos, 1 ); - todo_wine ok( GetPixel( hdc, dot_pos.x, dot_pos.y ) == cr, "error drawing outside of window client area\n" ); ReleaseDC( hwnd_container, hdc );
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 93107f93930..58d7c30ee4e 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -420,6 +420,11 @@ static void update_visible_region( struct dce *dce ) top_win = wine_server_ptr_handle( reply->top_win ); win_rect = wine_server_get_rect( reply->win_rect ); top_rect = wine_server_get_rect( reply->top_rect ); + if (flags & DCX_PARENTCLIP) + { + win_rect.right = top_rect.right; + win_rect.bottom = top_rect.bottom; + } paint_flags = reply->paint_flags; } else size = reply->total_size;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=146302
Your paranoid android.
=== w10pro64 (32 bit report) ===
user32: win.c:3818: Test failed: GetForegroundWindow returned 000202C8 win.c:3749: Test failed: SetForegroundWindow failed, error 0 win.c:3752: Test failed: GetForegroundWindow returned 000202C8 win.c:3789: Test failed: GetForegroundWindow returned 000202C8 win.c:3877: Test failed: GetActiveWindow() = 000201A8 win.c:3881: Test failed: GetFocus() = 00000000 win.c:3884: Test failed: GetFocus() = 00000000
=== w10pro64 (64 bit report) ===
user32: win.c:3818: Test failed: GetForegroundWindow returned 000000000003017E win.c:3749: Test failed: SetForegroundWindow failed, error 0 win.c:3752: Test failed: GetForegroundWindow returned 000000000003017E win.c:3789: Test failed: GetForegroundWindow returned 000000000003017E win.c:3877: Test failed: GetActiveWindow() = 00000000000102B2 win.c:3881: Test failed: GetFocus() = 0000000000000000 win.c:3884: Test failed: GetFocus() = 0000000000000000
=== debian11 (32 bit report) ===
user32: msg.c:6934: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got hook 0x0005 instead msg.c:6934: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got winevent_hook 0x0003 instead msg.c:6934: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got msg 0x030f instead msg.c:6934: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got msg 0x001c instead msg.c:6934: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got msg 0x0086 instead msg.c:6934: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got msg 0x0006 instead msg.c:6934: Test failed: SetFocus(hwnd) on a button: 3: the winevent_hook 0x8005 was expected, but got hook 0x0009 instead
On Fri Jun 14 12:48:31 2024 +0000, Dmitry Timoshkov wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/5665/diffs?diff_id=117923&start_sha=86149680b63b2265d53992560ff025e4b284a67f#3dde8c1935f0e74922f8b34a2af10931253453d9_1327_1326)
I've included your test to this MR (with unconditional todo_wine) to better see which patch fixes parts of the test.
This merge request was approved by Dmitry Timoshkov.
On Sat Jun 15 11:01:02 2024 +0000, Jinoh Kang wrote:
I think that your test answers this question, because "static" and
"parentdc_class" both have CS_PARENTDC style. Not really, since `CS_PARENTDC` is ineffective for an overlapped window. Sorry for confusion.
Ok, just tested this, turns out `CS_PARENTDC` is indeed not transitive. Resolving as not an issue.
On Sat Jun 15 09:55:49 2024 +0000, Dmitry Timoshkov wrote:
I've included your test to this MR (with unconditional todo_wine) to better see which patch fixes parts of the test.
Just confirmed. Thanks.
On Sat Jun 15 11:20:37 2024 +0000, Jinoh Kang wrote:
Just confirmed. Thanks.
What do you think about approving this MR and closing 5836?
Rémi Bernon (@rbernon) commented about dlls/win32u/dce.c:
top_win = wine_server_ptr_handle( reply->top_win ); win_rect = wine_server_get_rect( reply->win_rect ); top_rect = wine_server_get_rect( reply->top_rect );
if (flags & DCX_PARENTCLIP)
{
win_rect.right = top_rect.right;
win_rect.bottom = top_rect.bottom;
}
This doesn't look right, why only the right / bottom coordinates?
On Mon Jun 17 08:37:32 2024 +0000, Rémi Bernon wrote:
This doesn't look right, why only the right / bottom coordinates?
Because otherwise the DC has wrong origin.
What do you think about approving this MR
Sorry, that would take real review work and I'm not ready to do it right now.
and closing 5836?
ACK. Done.