Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2022
- 68 participants
- 3274 messages
[PATCH v4 1/4] user32/tests: Test for window exposure behaviours.
by Jinoh Kang
From: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
Signed-off-by: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
---
dlls/user32/tests/msg.c | 378 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 378 insertions(+)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 2705914d5e5..c62b25446a2 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -9035,6 +9035,378 @@ static void test_paint_messages(void)
DeleteObject( hrgn2 );
}
+static void visualize_region_differences( HWND hwnd, HWND hother, HRGN hrgn_expect, HRGN hrgn_actual )
+{
+ HBRUSH b_expectonly, b_actualonly, b_intersect;
+ HRGN hrgn_intersect;
+ HWND hstatic, hshow, hhide;
+ HDC hdc, hdctmp;
+ HBITMAP hbitmap;
+ MSG msg;
+ RECT rect;
+ DWORD start_time, elapsed, timeout = 60 * 1000;
+ BOOL toggle = TRUE, stop = FALSE;
+
+ start_time = GetTickCount();
+
+ b_expectonly = CreateSolidBrush( RGB( 64, 64, 255 ));
+ b_actualonly = CreateSolidBrush( RGB( 255, 64, 64 ));
+ b_intersect = CreateSolidBrush( RGB( 159, 64, 159 ));
+
+ hrgn_intersect = CreateRectRgn( 0, 0, 0, 0 );
+ CombineRgn( hrgn_intersect, hrgn_expect, hrgn_actual, RGN_AND );
+
+ GetClientRect( hwnd, &rect );
+ hdc = GetDC( hwnd );
+ hbitmap = CreateCompatibleBitmap( hdc, rect.right, rect.bottom );
+ hdctmp = CreateCompatibleDC( hdc );
+ ReleaseDC( hwnd, hdc );
+
+ SelectObject( hdctmp, hbitmap );
+ FillRgn( hdctmp, hrgn_expect, b_expectonly );
+ FillRgn( hdctmp, hrgn_actual, b_actualonly );
+ FillRgn( hdctmp, hrgn_intersect, b_intersect );
+
+ DeleteObject( hdctmp );
+ DeleteObject( hrgn_intersect );
+ DeleteObject( b_intersect );
+ DeleteObject( b_actualonly );
+ DeleteObject( b_expectonly );
+
+ hstatic = CreateWindowExA( 0, WC_STATICA, "", WS_CHILD | SS_BITMAP,
+ 0, 0, rect.right, rect.bottom, hwnd, 0, 0, NULL );
+ SendMessageA( hstatic, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbitmap );
+
+ hshow = hstatic;
+ hhide = hother;
+
+ for (;;)
+ {
+ if (stop) toggle = hshow == hother;
+ if (toggle)
+ {
+ HWND htmp;
+ HDWP hdwp;
+
+ hdwp = BeginDeferWindowPos( !!hhide + !!hshow );
+ if (hhide)
+ {
+ DeferWindowPos( hdwp, hhide, NULL, 0, 0, 0, 0,
+ SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER );
+ }
+ if (hshow)
+ {
+ DeferWindowPos( hdwp, hshow, HWND_TOP, 0, 0, 0, 0,
+ SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
+ }
+ EndDeferWindowPos( hdwp );
+
+ htmp = hshow;
+ hshow = hhide;
+ hhide = htmp;
+ toggle = FALSE;
+ }
+ if (stop) break;
+ if ((elapsed = GetTickCount() - start_time) >= timeout)
+ {
+ stop = TRUE;
+ continue;
+ }
+ MsgWaitForMultipleObjects( 0, NULL, FALSE, timeout - elapsed, QS_ALLINPUT );
+ while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
+ {
+ TranslateMessage( &msg );
+ DispatchMessageA( &msg );
+ if (msg.message == WM_MOUSEMOVE)
+ {
+ start_time = GetTickCount();
+ }
+ else if (msg.message == WM_LBUTTONUP || (msg.message == WM_CHAR && msg.wParam == VK_SPACE))
+ {
+ toggle = !toggle;
+ }
+ else if (msg.message == WM_RBUTTONUP || (msg.message == WM_CHAR && msg.wParam == VK_RETURN))
+ {
+ stop = TRUE;
+ }
+ }
+ }
+
+ DestroyWindow( hstatic );
+ DeleteObject( hbitmap );
+}
+
+#define subtest_swp_paint_regions(w,p,c) subtest_swp_paint_regions_(__LINE__,w,p,c)
+
+static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR parent_class, LPCSTR child_class )
+{
+ static const struct exposure_test {
+ int ex_style, style;
+ BOOL shuffle_zorder;
+ HWND insert_after;
+ } exposure_tests[] = {
+ { 0, WS_CLIPCHILDREN, FALSE, NULL },
+ { 0, 0, FALSE, NULL },
+ { WS_EX_COMPOSITED, WS_CLIPCHILDREN, FALSE, NULL },
+ { WS_EX_COMPOSITED, WS_CLIPCHILDREN, TRUE , HWND_TOP },
+ { WS_EX_COMPOSITED, WS_CLIPCHILDREN, TRUE , HWND_BOTTOM },
+ { WS_EX_COMPOSITED, 0, FALSE, NULL },
+ { WS_EX_COMPOSITED, 0, TRUE , HWND_TOP },
+ { WS_EX_COMPOSITED, 0, TRUE , HWND_BOTTOM },
+ };
+ size_t i;
+ HWND htoplevel = NULL, hparent, hchild, hauxchild;
+ const RECT rect_old = { 10, 10, 100, 100 };
+ HRGN hrgn_old_vis = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_new_vis = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_expect = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_old_vis_child = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_new_vis_child = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_expect_child = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_actual_child = CreateRectRgn( 0, 0, 0, 0 );
+ int base_style;
+ BOOL is_composition_possible, has_parentdc_anomaly;
+ WNDCLASSA parent_wc;
+
+ if (wrap_toplevel)
+ {
+ htoplevel = CreateWindowExA( 0, "SimpleWindowClass", "Test toplevel", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ 100, 100, 400, 400, 0, 0, 0, NULL );
+ ok( htoplevel != 0, "Failed to create top-level window: %lu\n", GetLastError() );
+ base_style = WS_CHILD | WS_VISIBLE;
+ }
+ else
+ {
+ base_style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
+ }
+
+ ok( GetClassInfoA( GetModuleHandleA( NULL ), parent_class, &parent_wc ),
+ "GetClassInfoA failed\n" );
+
+ is_composition_possible = (base_style & (WS_POPUP|WS_CHILD)) != WS_CHILD ||
+ (parent_wc.style & CS_PARENTDC) == 0;
+
+ has_parentdc_anomaly = (base_style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
+ (parent_wc.style & CS_PARENTDC) != 0;
+
+ hparent = CreateWindowExA( 0, parent_class, "Test parent", base_style,
+ 80, 80, 200, 200, htoplevel, 0, 0, NULL );
+ ok( hparent != 0, "Creating parent window (%s) returned error %lu\n",
+ debugstr_a( parent_class ), GetLastError() );
+
+ hchild = CreateWindowExA( 0, child_class, "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
+ rect_old.left, rect_old.top,
+ rect_old.right - rect_old.left, rect_old.bottom - rect_old.top,
+ hparent, 0, 0, NULL );
+ ok( hchild != 0, "Creating child window (%s) returned error %lu\n",
+ debugstr_a( child_class ), GetLastError() );
+
+ hauxchild = CreateWindowExA( 0, child_class, "Auxiliary child for z order test", WS_CHILD | WS_VISIBLE,
+ 110, 0, 0, 0, hparent, 0, 0, NULL );
+ ok( hauxchild != 0, "Creating child window (%s) returned error %lu\n",
+ debugstr_a( child_class ), GetLastError() );
+
+ for (i = 0; i < ARRAY_SIZE(exposure_tests); i++)
+ {
+ const struct exposure_test *extest = &exposure_tests[i];
+ BOOL has_ws_ex_composited = (extest->ex_style & WS_EX_COMPOSITED) != 0;
+ BOOL is_composited = is_composition_possible && has_ws_ex_composited;
+ BOOL is_zorder_redraw = is_composited && extest->shuffle_zorder;
+ int delta;
+
+ winetest_push_context( "%d: SetWindowPos redraw #%Id (ex_style = %#x, style = %#x, shuffle_zorder = %d, insert_after = %Id)",
+ line, i, extest->ex_style, extest->style, extest->shuffle_zorder, (LONG_PTR)extest->insert_after );
+
+ SetWindowLongA( hparent, GWL_EXSTYLE, extest->ex_style );
+ SetWindowLongA( hparent, GWL_STYLE, base_style | extest->style );
+ RedrawWindow( hparent, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
+
+ for (delta = -20; delta <= 20; delta += 20)
+ {
+ RECT rect_old_vis, rect_new, rect_new_vis;
+ RECT rect_parent_clip, rect_child_clip;
+ RECT rect_old_vis_child, rect_new_vis_child;
+ BOOL rgn_equal;
+
+ winetest_push_context( "delta = %+d", delta );
+
+ SetWindowPos( hchild, HWND_TOP,
+ rect_old.left,
+ rect_old.top,
+ rect_old.right - rect_old.left,
+ rect_old.bottom - rect_old.top,
+ SWP_NOACTIVATE );
+
+ rect_new = rect_old;
+ OffsetRect( &rect_new, delta, delta );
+
+ rect_old_vis_child = rect_old;
+ MapWindowPoints( hparent, hchild, (POINT *)&rect_old_vis_child, 2 );
+
+ SetRectRgn( hrgn_actual, 0, 0, 0, 0 );
+ SetRectRgn( hrgn_actual_child, 0, 0, 0, 0 );
+
+ UpdateWindow( hparent );
+ flush_events();
+
+ if (extest->shuffle_zorder)
+ {
+ /* bring sibling to top/bottom first so we can trigger z-order change */
+ SetWindowPos( hauxchild, extest->insert_after, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+ }
+
+ SetWindowPos( hchild, extest->insert_after,
+ rect_new.left,
+ rect_new.top,
+ rect_new.right - rect_new.left,
+ rect_new.bottom - rect_new.top,
+ SWP_NOACTIVATE |
+ (extest->shuffle_zorder || extest->insert_after ? 0 : SWP_NOZORDER) );
+
+ ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR,
+ "GetUpdateRgn on parentshall succeed\n" );
+ ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR,
+ "GetUpdateRgn on child shall succeed\n" );
+
+ /* Compute parent window expose region */
+ GetClientRect( hparent, &rect_parent_clip );
+ IntersectRect( &rect_old_vis, &rect_old, &rect_parent_clip );
+ SetRectRgn( hrgn_old_vis, rect_old_vis.left, rect_old_vis.top, rect_old_vis.right, rect_old_vis.bottom );
+ IntersectRect( &rect_new_vis, &rect_new, &rect_parent_clip );
+ SetRectRgn( hrgn_new_vis, rect_new_vis.left, rect_new_vis.top, rect_new_vis.right, rect_new_vis.bottom );
+
+ if (!EqualRect( &rect_old, &rect_new ) || is_zorder_redraw)
+ {
+ CombineRgn( hrgn_expect, hrgn_old_vis, hrgn_new_vis, is_composited ? RGN_OR : RGN_DIFF );
+ }
+ else
+ {
+ SetRectRgn( hrgn_expect, 0, 0, 0, 0 );
+ }
+
+ rgn_equal = EqualRgn( hrgn_expect, hrgn_actual );
+ if (!rgn_equal && broken( has_parentdc_anomaly && is_composited &&
+ LOBYTE(LOWORD(GetVersion())) < 8 ) /* Win7 */)
+ {
+ trace( "Forcing non-composited update region (broken)\n" );
+ CombineRgn( hrgn_expect, hrgn_old_vis, hrgn_new_vis, RGN_DIFF );
+ rgn_equal = EqualRgn( hrgn_expect, hrgn_actual );
+ }
+ todo_wine_if( EqualRect( &rect_old, &rect_new ) ? is_zorder_redraw :
+ ((extest->style & WS_CLIPCHILDREN) == 0 || is_composited) )
+ ok( !!rgn_equal, "Parent update region shall match expected region\n" );
+
+ if (!rgn_equal && winetest_debug > 0)
+ {
+ printf( "Expected parent update region: " );
+ dump_region( hrgn_expect );
+ printf( "Actual parent update region: " );
+ dump_region( hrgn_actual );
+ printf( "Old child window visible area: %s\n", wine_dbgstr_rect( &rect_old_vis ) );
+ printf( "New child window visible area: %s\n", wine_dbgstr_rect( &rect_new_vis ) );
+ }
+
+ if (winetest_interactive)
+ {
+ if (!rgn_equal)
+ {
+ visualize_region_differences( hparent, hchild, hrgn_expect, hrgn_actual );
+ }
+
+ /* Let the position change be visible to the user */
+ flush_events();
+ }
+
+ rect_new_vis_child = rect_new;
+ MapWindowPoints( hparent, hchild, (POINT *)&rect_new_vis_child, 2 );
+
+ /* Compute child window expose region */
+ GetClientRect( hchild, &rect_child_clip );
+ if (is_composited)
+ {
+ RECT rect_outer_clip;
+ GetClientRect( hparent, &rect_outer_clip );
+ MapWindowPoints( hparent, hchild, (POINT *)&rect_outer_clip, 2 );
+ IntersectRect( &rect_child_clip, &rect_child_clip, &rect_outer_clip );
+ }
+ IntersectRect( &rect_old_vis_child, &rect_old_vis_child, &rect_child_clip );
+ SetRectRgn( hrgn_old_vis_child, rect_old_vis_child.left, rect_old_vis_child.top, rect_old_vis_child.right, rect_old_vis_child.bottom );
+ IntersectRect( &rect_new_vis_child, &rect_new_vis_child, &rect_child_clip );
+ SetRectRgn( hrgn_new_vis_child, rect_new_vis_child.left, rect_new_vis_child.top, rect_new_vis_child.right, rect_new_vis_child.bottom );
+
+ if (!EqualRect( &rect_old, &rect_new ) || is_zorder_redraw)
+ {
+ CombineRgn( hrgn_expect_child, hrgn_new_vis_child, hrgn_old_vis_child, is_composited ? RGN_OR : RGN_DIFF );
+ }
+ else
+ {
+ SetRectRgn( hrgn_expect_child, 0, 0, 0, 0 );
+ }
+
+ rgn_equal = EqualRgn( hrgn_expect_child, hrgn_actual_child );
+ if (!rgn_equal && broken( has_parentdc_anomaly && is_composited &&
+ LOBYTE(LOWORD(GetVersion())) < 8 ) /* Win7 */)
+ {
+ trace( "Forcing non-composited update region (broken)\n" );
+ CombineRgn( hrgn_expect_child, hrgn_new_vis_child, hrgn_old_vis_child, RGN_DIFF );
+ rgn_equal = EqualRgn( hrgn_expect, hrgn_actual );
+ }
+ todo_wine_if( EqualRect( &rect_old, &rect_new ) ? is_zorder_redraw :
+ ((extest->style & WS_CLIPCHILDREN) == 0 || is_composited) )
+ ok( !!rgn_equal, "Child update region shall match expected region\n" );
+
+ if (!rgn_equal && winetest_debug > 0)
+ {
+ printf( "Expected child update region: " );
+ dump_region( hrgn_expect_child );
+ printf( "Actual child update region: " );
+ dump_region( hrgn_actual_child );
+ printf( "Old child window client visible area: %s\n", wine_dbgstr_rect( &rect_old_vis_child ) );
+ printf( "New child window client visible area: %s\n", wine_dbgstr_rect( &rect_new_vis_child ) );
+ }
+
+ if (winetest_interactive)
+ {
+ if (!rgn_equal)
+ {
+ visualize_region_differences( hchild, NULL, hrgn_expect_child, hrgn_actual_child );
+ }
+
+ /* Let the position change be visible to the user */
+ flush_events();
+ }
+
+ winetest_pop_context();
+ }
+
+ winetest_pop_context();
+ }
+
+ DestroyWindow( hauxchild );
+ DestroyWindow( hchild );
+ DestroyWindow( hparent );
+ if (htoplevel) DestroyWindow( htoplevel );
+
+ DeleteObject( hrgn_actual );
+ DeleteObject( hrgn_expect );
+ DeleteObject( hrgn_new_vis );
+ DeleteObject( hrgn_old_vis );
+}
+
+static void test_swp_paint_regions(void)
+{
+ subtest_swp_paint_regions( 1, "SimpleWindowClass", "SimpleWindowClass" );
+ subtest_swp_paint_regions( 1, "SimpleWindowClass", "SimpleWindowClassWithParentDC" );
+ subtest_swp_paint_regions( 1, "SimpleWindowClassWithParentDC", "SimpleWindowClass" );
+ subtest_swp_paint_regions( 1, "SimpleWindowClassWithParentDC", "SimpleWindowClassWithParentDC" );
+ subtest_swp_paint_regions( 0, "SimpleWindowClass", "SimpleWindowClass" );
+ subtest_swp_paint_regions( 0, "SimpleWindowClass", "SimpleWindowClassWithParentDC" );
+ subtest_swp_paint_regions( 0, "SimpleWindowClassWithParentDC", "SimpleWindowClass" );
+ subtest_swp_paint_regions( 0, "SimpleWindowClassWithParentDC", "SimpleWindowClassWithParentDC" );
+}
+
struct wnd_event
{
HWND hwnd;
@@ -10387,6 +10759,11 @@ static BOOL RegisterWindowClasses(void)
cls.lpszClassName = "TestDialogClass";
if(!RegisterClassA(&cls)) return FALSE;
+ cls.lpfnWndProc = DefWindowProcA;
+ cls.style = CS_PARENTDC;
+ cls.lpszClassName = "SimpleWindowClassWithParentDC";
+ if(!RegisterClassA(&cls)) return FALSE;
+
clsW.style = 0;
clsW.lpfnWndProc = MsgCheckProcW;
clsW.cbClsExtra = 0;
@@ -18870,6 +19247,7 @@ START_TEST(msg)
test_combobox_messages();
test_wmime_keydown_message();
test_paint_messages();
+ test_swp_paint_regions();
test_interthread_messages();
test_message_conversion();
test_accelerators();
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/231
June 17, 2022
[PATCH v4 0/4] MR231: SetWindowPos() parent window exposure fixes (#53153)
by Jinoh Kang (@iamahuman)
Signed-off-by: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
--
v4: server: Don't invalidate the newly exposed child region on the parent if it doesn't clip children.
server: Redraw composited window child when its z-order changes.
server: Correctly expose composited parent window and its child on position change.
user32/tests: Test for window exposure behaviours.
https://gitlab.winehq.org/wine/wine/-/merge_requests/231
June 17, 2022
[PATCH v3 4/4] server: Don't invalidate the newly exposed child region on the parent with WS_CLIPCHILDREN.
by Jinoh Kang
From: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
This partly reverts e42eaaaf3a873d29b14f8f3a3617df2d0d4210ca.
Signed-off-by: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
---
dlls/user32/tests/msg.c | 4 ----
server/window.c | 6 ++----
2 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 991f1c22076..551d1bea44f 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -9294,8 +9294,6 @@ static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR pare
CombineRgn( hrgn_expect, hrgn_old_vis, hrgn_new_vis, RGN_DIFF );
rgn_equal = EqualRgn( hrgn_expect, hrgn_actual );
}
- todo_wine_if( !EqualRect( &rect_old, &rect_new ) &&
- (extest->style & WS_CLIPCHILDREN) == 0 && !is_composited )
ok( !!rgn_equal, "Parent update region shall match expected region\n" );
if (!rgn_equal && winetest_debug > 0)
@@ -9353,8 +9351,6 @@ static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR pare
CombineRgn( hrgn_expect_child, hrgn_new_vis_child, hrgn_old_vis_child, RGN_DIFF );
rgn_equal = EqualRgn( hrgn_expect, hrgn_actual );
}
- todo_wine_if( !EqualRect( &rect_old, &rect_new ) &&
- (extest->style & WS_CLIPCHILDREN) == 0 && !is_composited )
ok( !!rgn_equal, "Child update region shall match expected region\n" );
if (!rgn_equal && winetest_debug > 0)
diff --git a/server/window.c b/server/window.c
index 7e418b7b3fa..464967084c2 100644
--- a/server/window.c
+++ b/server/window.c
@@ -1754,10 +1754,8 @@ static struct region *expose_window( struct window *win, const rectangle_t *old_
offset_region( new_vis_rgn, win->window_rect.left - old_window_rect->left,
win->window_rect.top - old_window_rect->top );
- if (is_composited ? union_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ) :
- (win->parent->style & WS_CLIPCHILDREN) ?
- subtract_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ) :
- xor_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ))
+ if (is_composited ? union_region( new_vis_rgn, old_vis_rgn, new_vis_rgn )
+ : subtract_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ))
{
if (!is_region_empty( new_vis_rgn ))
{
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/231
June 17, 2022
[PATCH v3 3/4] server: Redraw composited window child on its z-order change on SetWindowPos().
by Jinoh Kang
From: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53153
Signed-off-by: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
---
dlls/user32/tests/msg.c | 8 ++++----
server/window.c | 18 ++++++++++++------
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 317dd9e48dc..991f1c22076 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -9294,8 +9294,8 @@ static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR pare
CombineRgn( hrgn_expect, hrgn_old_vis, hrgn_new_vis, RGN_DIFF );
rgn_equal = EqualRgn( hrgn_expect, hrgn_actual );
}
- todo_wine_if( EqualRect( &rect_old, &rect_new ) ? is_zorder_redraw :
- ((extest->style & WS_CLIPCHILDREN) == 0 && !is_composited) )
+ todo_wine_if( !EqualRect( &rect_old, &rect_new ) &&
+ (extest->style & WS_CLIPCHILDREN) == 0 && !is_composited )
ok( !!rgn_equal, "Parent update region shall match expected region\n" );
if (!rgn_equal && winetest_debug > 0)
@@ -9353,8 +9353,8 @@ static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR pare
CombineRgn( hrgn_expect_child, hrgn_new_vis_child, hrgn_old_vis_child, RGN_DIFF );
rgn_equal = EqualRgn( hrgn_expect, hrgn_actual );
}
- todo_wine_if( EqualRect( &rect_old, &rect_new ) ? is_zorder_redraw :
- ((extest->style & WS_CLIPCHILDREN) == 0 && !is_composited) )
+ todo_wine_if( !EqualRect( &rect_old, &rect_new ) &&
+ (extest->style & WS_CLIPCHILDREN) == 0 && !is_composited )
ok( !!rgn_equal, "Child update region shall match expected region\n" );
if (!rgn_equal && winetest_debug > 0)
diff --git a/server/window.c b/server/window.c
index 6fc9f9f9e40..7e418b7b3fa 100644
--- a/server/window.c
+++ b/server/window.c
@@ -1719,12 +1719,12 @@ static unsigned int get_window_update_flags( struct window *win, struct window *
/* expose the areas revealed by a vis region change on the window parent */
/* returns the region exposed on the window itself (in client coordinates) */
static struct region *expose_window( struct window *win, const rectangle_t *old_window_rect,
- struct region *old_vis_rgn )
+ struct region *old_vis_rgn, int zorder_changed )
{
struct region *new_vis_rgn, *exposed_rgn;
int is_composited = win->parent && is_window_composited( win->parent );
- if (is_rect_equal( &win->window_rect, old_window_rect ))
+ if (is_rect_equal( &win->window_rect, old_window_rect ) && !(is_composited && zorder_changed))
{
return NULL;
}
@@ -1785,6 +1785,7 @@ static void set_window_pos( struct window *win, struct window *previous,
rectangle_t rect;
int client_changed, frame_changed;
int visible = (win->style & WS_VISIBLE) || (swp_flags & SWP_SHOWWINDOW);
+ int zorder_changed = 0;
if (win->parent && !is_visible( win->parent )) visible = 0;
@@ -1796,7 +1797,12 @@ static void set_window_pos( struct window *win, struct window *previous,
win->visible_rect = *visible_rect;
win->surface_rect = *surface_rect;
win->client_rect = *client_rect;
- if (!(swp_flags & SWP_NOZORDER) && win->parent) link_window( win, previous );
+ if (!(swp_flags & SWP_NOZORDER) && win->parent)
+ {
+ struct list *old_prev = win->is_linked ? win->entry.prev : NULL;
+ link_window( win, previous );
+ if (old_prev != win->entry.prev) zorder_changed = 1;
+ }
if (swp_flags & SWP_SHOWWINDOW) win->style |= WS_VISIBLE;
else if (swp_flags & SWP_HIDEWINDOW) win->style &= ~WS_VISIBLE;
@@ -1825,7 +1831,7 @@ static void set_window_pos( struct window *win, struct window *previous,
/* expose anything revealed by the change */
if (!(swp_flags & SWP_NOREDRAW))
- exposed_rgn = expose_window( win, &old_window_rect, old_vis_rgn );
+ exposed_rgn = expose_window( win, &old_window_rect, old_vis_rgn, zorder_changed );
if (!(win->style & WS_VISIBLE))
{
@@ -1956,7 +1962,7 @@ static void set_window_region( struct window *win, struct region *region, int re
win->win_region = region;
/* expose anything revealed by the change */
- if (old_vis_rgn && ((exposed_rgn = expose_window( win, &win->window_rect, old_vis_rgn ))))
+ if (old_vis_rgn && ((exposed_rgn = expose_window( win, &win->window_rect, old_vis_rgn, 0 ))))
{
redraw_window( win, exposed_rgn, 1, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
free_region( exposed_rgn );
@@ -1981,7 +1987,7 @@ void free_window_handle( struct window *win )
win->style &= ~WS_VISIBLE;
if (vis_rgn)
{
- struct region *exposed_rgn = expose_window( win, &win->window_rect, vis_rgn );
+ struct region *exposed_rgn = expose_window( win, &win->window_rect, vis_rgn, 0 );
if (exposed_rgn) free_region( exposed_rgn );
free_region( vis_rgn );
}
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/231
June 17, 2022
[PATCH v3 2/4] server: Correctly expose composited parent window on SetWindowPos().
by Jinoh Kang
From: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53153
Signed-off-by: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
---
dlls/user32/tests/msg.c | 4 ++--
server/class.c | 5 +++++
server/user.h | 8 ++++++++
server/window.c | 23 +++++++++++++++++++++--
4 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index c62b25446a2..317dd9e48dc 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -9295,7 +9295,7 @@ static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR pare
rgn_equal = EqualRgn( hrgn_expect, hrgn_actual );
}
todo_wine_if( EqualRect( &rect_old, &rect_new ) ? is_zorder_redraw :
- ((extest->style & WS_CLIPCHILDREN) == 0 || is_composited) )
+ ((extest->style & WS_CLIPCHILDREN) == 0 && !is_composited) )
ok( !!rgn_equal, "Parent update region shall match expected region\n" );
if (!rgn_equal && winetest_debug > 0)
@@ -9354,7 +9354,7 @@ static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR pare
rgn_equal = EqualRgn( hrgn_expect, hrgn_actual );
}
todo_wine_if( EqualRect( &rect_old, &rect_new ) ? is_zorder_redraw :
- ((extest->style & WS_CLIPCHILDREN) == 0 || is_composited) )
+ ((extest->style & WS_CLIPCHILDREN) == 0 && !is_composited) )
ok( !!rgn_equal, "Child update region shall match expected region\n" );
if (!rgn_equal && winetest_debug > 0)
diff --git a/server/class.c b/server/class.c
index e1e180bd97c..3231f366b26 100644
--- a/server/class.c
+++ b/server/class.c
@@ -141,6 +141,11 @@ int is_hwnd_message_class( struct window_class *class )
return (!class->local && class->atom == find_global_atom( NULL, &name ));
}
+int get_class_style( struct window_class *class )
+{
+ return class->style;
+}
+
atom_t get_class_atom( struct window_class *class )
{
return class->base_atom;
diff --git a/server/user.h b/server/user.h
index 55a0d35feff..9e91d427a3a 100644
--- a/server/user.h
+++ b/server/user.h
@@ -175,6 +175,7 @@ extern struct window_class *grab_class( struct process *process, atom_t atom,
extern void release_class( struct window_class *class );
extern int is_desktop_class( struct window_class *class );
extern int is_hwnd_message_class( struct window_class *class );
+extern int get_class_style( struct window_class *class );
extern atom_t get_class_atom( struct window_class *class );
extern client_ptr_t get_class_client_ptr( struct window_class *class );
@@ -191,6 +192,13 @@ extern void close_process_desktop( struct process *process );
extern void set_thread_default_desktop( struct thread *thread, struct desktop *desktop, obj_handle_t handle );
extern void release_thread_desktop( struct thread *thread, int close );
+/* checks if two rectangles are identical */
+static inline int is_rect_equal( const rectangle_t *rect1, const rectangle_t *rect2 )
+{
+ return (rect1->left == rect2->left && rect1->right == rect2->right &&
+ rect1->top == rect2->top && rect1->bottom == rect2->bottom);
+}
+
static inline int is_rect_empty( const rectangle_t *rect )
{
return (rect->left >= rect->right || rect->top >= rect->bottom);
diff --git a/server/window.c b/server/window.c
index 7675cd1103d..6fc9f9f9e40 100644
--- a/server/window.c
+++ b/server/window.c
@@ -789,6 +789,16 @@ int is_window_transparent( user_handle_t window )
return (win->ex_style & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT);
}
+static int is_window_using_parent_dc( struct window *win )
+{
+ return (win->style & (WS_POPUP|WS_CHILD)) == WS_CHILD && (get_class_style( win->class ) & CS_PARENTDC) != 0;
+}
+
+static int is_window_composited( struct window *win )
+{
+ return (win->ex_style & WS_EX_COMPOSITED) != 0 && !is_window_using_parent_dc(win);
+}
+
/* check if point is inside the window, and map to window dpi */
static int is_point_in_window( struct window *win, int *x, int *y, unsigned int dpi )
{
@@ -1712,12 +1722,20 @@ static struct region *expose_window( struct window *win, const rectangle_t *old_
struct region *old_vis_rgn )
{
struct region *new_vis_rgn, *exposed_rgn;
+ int is_composited = win->parent && is_window_composited( win->parent );
+
+ if (is_rect_equal( &win->window_rect, old_window_rect ))
+ {
+ return NULL;
+ }
if (!(new_vis_rgn = get_visible_region( win, DCX_WINDOW ))) return NULL;
if ((exposed_rgn = create_empty_region()))
{
- if (subtract_region( exposed_rgn, new_vis_rgn, old_vis_rgn ) && !is_region_empty( exposed_rgn ))
+ if ((is_composited ? union_region( exposed_rgn, new_vis_rgn, old_vis_rgn )
+ : subtract_region( exposed_rgn, new_vis_rgn, old_vis_rgn )) &&
+ !is_region_empty( exposed_rgn ))
{
/* make it relative to the new client area */
offset_region( exposed_rgn, win->window_rect.left - win->client_rect.left,
@@ -1736,7 +1754,8 @@ static struct region *expose_window( struct window *win, const rectangle_t *old_
offset_region( new_vis_rgn, win->window_rect.left - old_window_rect->left,
win->window_rect.top - old_window_rect->top );
- if ((win->parent->style & WS_CLIPCHILDREN) ?
+ if (is_composited ? union_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ) :
+ (win->parent->style & WS_CLIPCHILDREN) ?
subtract_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ) :
xor_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ))
{
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/231
June 17, 2022
[PATCH v3 1/4] user32/tests: Test for parent window exposure by SetWindowPos().
by Jinoh Kang
From: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
Signed-off-by: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
---
dlls/user32/tests/msg.c | 378 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 378 insertions(+)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 2705914d5e5..c62b25446a2 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -9035,6 +9035,378 @@ static void test_paint_messages(void)
DeleteObject( hrgn2 );
}
+static void visualize_region_differences( HWND hwnd, HWND hother, HRGN hrgn_expect, HRGN hrgn_actual )
+{
+ HBRUSH b_expectonly, b_actualonly, b_intersect;
+ HRGN hrgn_intersect;
+ HWND hstatic, hshow, hhide;
+ HDC hdc, hdctmp;
+ HBITMAP hbitmap;
+ MSG msg;
+ RECT rect;
+ DWORD start_time, elapsed, timeout = 60 * 1000;
+ BOOL toggle = TRUE, stop = FALSE;
+
+ start_time = GetTickCount();
+
+ b_expectonly = CreateSolidBrush( RGB( 64, 64, 255 ));
+ b_actualonly = CreateSolidBrush( RGB( 255, 64, 64 ));
+ b_intersect = CreateSolidBrush( RGB( 159, 64, 159 ));
+
+ hrgn_intersect = CreateRectRgn( 0, 0, 0, 0 );
+ CombineRgn( hrgn_intersect, hrgn_expect, hrgn_actual, RGN_AND );
+
+ GetClientRect( hwnd, &rect );
+ hdc = GetDC( hwnd );
+ hbitmap = CreateCompatibleBitmap( hdc, rect.right, rect.bottom );
+ hdctmp = CreateCompatibleDC( hdc );
+ ReleaseDC( hwnd, hdc );
+
+ SelectObject( hdctmp, hbitmap );
+ FillRgn( hdctmp, hrgn_expect, b_expectonly );
+ FillRgn( hdctmp, hrgn_actual, b_actualonly );
+ FillRgn( hdctmp, hrgn_intersect, b_intersect );
+
+ DeleteObject( hdctmp );
+ DeleteObject( hrgn_intersect );
+ DeleteObject( b_intersect );
+ DeleteObject( b_actualonly );
+ DeleteObject( b_expectonly );
+
+ hstatic = CreateWindowExA( 0, WC_STATICA, "", WS_CHILD | SS_BITMAP,
+ 0, 0, rect.right, rect.bottom, hwnd, 0, 0, NULL );
+ SendMessageA( hstatic, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbitmap );
+
+ hshow = hstatic;
+ hhide = hother;
+
+ for (;;)
+ {
+ if (stop) toggle = hshow == hother;
+ if (toggle)
+ {
+ HWND htmp;
+ HDWP hdwp;
+
+ hdwp = BeginDeferWindowPos( !!hhide + !!hshow );
+ if (hhide)
+ {
+ DeferWindowPos( hdwp, hhide, NULL, 0, 0, 0, 0,
+ SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER );
+ }
+ if (hshow)
+ {
+ DeferWindowPos( hdwp, hshow, HWND_TOP, 0, 0, 0, 0,
+ SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
+ }
+ EndDeferWindowPos( hdwp );
+
+ htmp = hshow;
+ hshow = hhide;
+ hhide = htmp;
+ toggle = FALSE;
+ }
+ if (stop) break;
+ if ((elapsed = GetTickCount() - start_time) >= timeout)
+ {
+ stop = TRUE;
+ continue;
+ }
+ MsgWaitForMultipleObjects( 0, NULL, FALSE, timeout - elapsed, QS_ALLINPUT );
+ while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
+ {
+ TranslateMessage( &msg );
+ DispatchMessageA( &msg );
+ if (msg.message == WM_MOUSEMOVE)
+ {
+ start_time = GetTickCount();
+ }
+ else if (msg.message == WM_LBUTTONUP || (msg.message == WM_CHAR && msg.wParam == VK_SPACE))
+ {
+ toggle = !toggle;
+ }
+ else if (msg.message == WM_RBUTTONUP || (msg.message == WM_CHAR && msg.wParam == VK_RETURN))
+ {
+ stop = TRUE;
+ }
+ }
+ }
+
+ DestroyWindow( hstatic );
+ DeleteObject( hbitmap );
+}
+
+#define subtest_swp_paint_regions(w,p,c) subtest_swp_paint_regions_(__LINE__,w,p,c)
+
+static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR parent_class, LPCSTR child_class )
+{
+ static const struct exposure_test {
+ int ex_style, style;
+ BOOL shuffle_zorder;
+ HWND insert_after;
+ } exposure_tests[] = {
+ { 0, WS_CLIPCHILDREN, FALSE, NULL },
+ { 0, 0, FALSE, NULL },
+ { WS_EX_COMPOSITED, WS_CLIPCHILDREN, FALSE, NULL },
+ { WS_EX_COMPOSITED, WS_CLIPCHILDREN, TRUE , HWND_TOP },
+ { WS_EX_COMPOSITED, WS_CLIPCHILDREN, TRUE , HWND_BOTTOM },
+ { WS_EX_COMPOSITED, 0, FALSE, NULL },
+ { WS_EX_COMPOSITED, 0, TRUE , HWND_TOP },
+ { WS_EX_COMPOSITED, 0, TRUE , HWND_BOTTOM },
+ };
+ size_t i;
+ HWND htoplevel = NULL, hparent, hchild, hauxchild;
+ const RECT rect_old = { 10, 10, 100, 100 };
+ HRGN hrgn_old_vis = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_new_vis = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_expect = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_old_vis_child = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_new_vis_child = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_expect_child = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn_actual_child = CreateRectRgn( 0, 0, 0, 0 );
+ int base_style;
+ BOOL is_composition_possible, has_parentdc_anomaly;
+ WNDCLASSA parent_wc;
+
+ if (wrap_toplevel)
+ {
+ htoplevel = CreateWindowExA( 0, "SimpleWindowClass", "Test toplevel", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ 100, 100, 400, 400, 0, 0, 0, NULL );
+ ok( htoplevel != 0, "Failed to create top-level window: %lu\n", GetLastError() );
+ base_style = WS_CHILD | WS_VISIBLE;
+ }
+ else
+ {
+ base_style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
+ }
+
+ ok( GetClassInfoA( GetModuleHandleA( NULL ), parent_class, &parent_wc ),
+ "GetClassInfoA failed\n" );
+
+ is_composition_possible = (base_style & (WS_POPUP|WS_CHILD)) != WS_CHILD ||
+ (parent_wc.style & CS_PARENTDC) == 0;
+
+ has_parentdc_anomaly = (base_style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
+ (parent_wc.style & CS_PARENTDC) != 0;
+
+ hparent = CreateWindowExA( 0, parent_class, "Test parent", base_style,
+ 80, 80, 200, 200, htoplevel, 0, 0, NULL );
+ ok( hparent != 0, "Creating parent window (%s) returned error %lu\n",
+ debugstr_a( parent_class ), GetLastError() );
+
+ hchild = CreateWindowExA( 0, child_class, "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
+ rect_old.left, rect_old.top,
+ rect_old.right - rect_old.left, rect_old.bottom - rect_old.top,
+ hparent, 0, 0, NULL );
+ ok( hchild != 0, "Creating child window (%s) returned error %lu\n",
+ debugstr_a( child_class ), GetLastError() );
+
+ hauxchild = CreateWindowExA( 0, child_class, "Auxiliary child for z order test", WS_CHILD | WS_VISIBLE,
+ 110, 0, 0, 0, hparent, 0, 0, NULL );
+ ok( hauxchild != 0, "Creating child window (%s) returned error %lu\n",
+ debugstr_a( child_class ), GetLastError() );
+
+ for (i = 0; i < ARRAY_SIZE(exposure_tests); i++)
+ {
+ const struct exposure_test *extest = &exposure_tests[i];
+ BOOL has_ws_ex_composited = (extest->ex_style & WS_EX_COMPOSITED) != 0;
+ BOOL is_composited = is_composition_possible && has_ws_ex_composited;
+ BOOL is_zorder_redraw = is_composited && extest->shuffle_zorder;
+ int delta;
+
+ winetest_push_context( "%d: SetWindowPos redraw #%Id (ex_style = %#x, style = %#x, shuffle_zorder = %d, insert_after = %Id)",
+ line, i, extest->ex_style, extest->style, extest->shuffle_zorder, (LONG_PTR)extest->insert_after );
+
+ SetWindowLongA( hparent, GWL_EXSTYLE, extest->ex_style );
+ SetWindowLongA( hparent, GWL_STYLE, base_style | extest->style );
+ RedrawWindow( hparent, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
+
+ for (delta = -20; delta <= 20; delta += 20)
+ {
+ RECT rect_old_vis, rect_new, rect_new_vis;
+ RECT rect_parent_clip, rect_child_clip;
+ RECT rect_old_vis_child, rect_new_vis_child;
+ BOOL rgn_equal;
+
+ winetest_push_context( "delta = %+d", delta );
+
+ SetWindowPos( hchild, HWND_TOP,
+ rect_old.left,
+ rect_old.top,
+ rect_old.right - rect_old.left,
+ rect_old.bottom - rect_old.top,
+ SWP_NOACTIVATE );
+
+ rect_new = rect_old;
+ OffsetRect( &rect_new, delta, delta );
+
+ rect_old_vis_child = rect_old;
+ MapWindowPoints( hparent, hchild, (POINT *)&rect_old_vis_child, 2 );
+
+ SetRectRgn( hrgn_actual, 0, 0, 0, 0 );
+ SetRectRgn( hrgn_actual_child, 0, 0, 0, 0 );
+
+ UpdateWindow( hparent );
+ flush_events();
+
+ if (extest->shuffle_zorder)
+ {
+ /* bring sibling to top/bottom first so we can trigger z-order change */
+ SetWindowPos( hauxchild, extest->insert_after, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+ }
+
+ SetWindowPos( hchild, extest->insert_after,
+ rect_new.left,
+ rect_new.top,
+ rect_new.right - rect_new.left,
+ rect_new.bottom - rect_new.top,
+ SWP_NOACTIVATE |
+ (extest->shuffle_zorder || extest->insert_after ? 0 : SWP_NOZORDER) );
+
+ ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR,
+ "GetUpdateRgn on parentshall succeed\n" );
+ ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR,
+ "GetUpdateRgn on child shall succeed\n" );
+
+ /* Compute parent window expose region */
+ GetClientRect( hparent, &rect_parent_clip );
+ IntersectRect( &rect_old_vis, &rect_old, &rect_parent_clip );
+ SetRectRgn( hrgn_old_vis, rect_old_vis.left, rect_old_vis.top, rect_old_vis.right, rect_old_vis.bottom );
+ IntersectRect( &rect_new_vis, &rect_new, &rect_parent_clip );
+ SetRectRgn( hrgn_new_vis, rect_new_vis.left, rect_new_vis.top, rect_new_vis.right, rect_new_vis.bottom );
+
+ if (!EqualRect( &rect_old, &rect_new ) || is_zorder_redraw)
+ {
+ CombineRgn( hrgn_expect, hrgn_old_vis, hrgn_new_vis, is_composited ? RGN_OR : RGN_DIFF );
+ }
+ else
+ {
+ SetRectRgn( hrgn_expect, 0, 0, 0, 0 );
+ }
+
+ rgn_equal = EqualRgn( hrgn_expect, hrgn_actual );
+ if (!rgn_equal && broken( has_parentdc_anomaly && is_composited &&
+ LOBYTE(LOWORD(GetVersion())) < 8 ) /* Win7 */)
+ {
+ trace( "Forcing non-composited update region (broken)\n" );
+ CombineRgn( hrgn_expect, hrgn_old_vis, hrgn_new_vis, RGN_DIFF );
+ rgn_equal = EqualRgn( hrgn_expect, hrgn_actual );
+ }
+ todo_wine_if( EqualRect( &rect_old, &rect_new ) ? is_zorder_redraw :
+ ((extest->style & WS_CLIPCHILDREN) == 0 || is_composited) )
+ ok( !!rgn_equal, "Parent update region shall match expected region\n" );
+
+ if (!rgn_equal && winetest_debug > 0)
+ {
+ printf( "Expected parent update region: " );
+ dump_region( hrgn_expect );
+ printf( "Actual parent update region: " );
+ dump_region( hrgn_actual );
+ printf( "Old child window visible area: %s\n", wine_dbgstr_rect( &rect_old_vis ) );
+ printf( "New child window visible area: %s\n", wine_dbgstr_rect( &rect_new_vis ) );
+ }
+
+ if (winetest_interactive)
+ {
+ if (!rgn_equal)
+ {
+ visualize_region_differences( hparent, hchild, hrgn_expect, hrgn_actual );
+ }
+
+ /* Let the position change be visible to the user */
+ flush_events();
+ }
+
+ rect_new_vis_child = rect_new;
+ MapWindowPoints( hparent, hchild, (POINT *)&rect_new_vis_child, 2 );
+
+ /* Compute child window expose region */
+ GetClientRect( hchild, &rect_child_clip );
+ if (is_composited)
+ {
+ RECT rect_outer_clip;
+ GetClientRect( hparent, &rect_outer_clip );
+ MapWindowPoints( hparent, hchild, (POINT *)&rect_outer_clip, 2 );
+ IntersectRect( &rect_child_clip, &rect_child_clip, &rect_outer_clip );
+ }
+ IntersectRect( &rect_old_vis_child, &rect_old_vis_child, &rect_child_clip );
+ SetRectRgn( hrgn_old_vis_child, rect_old_vis_child.left, rect_old_vis_child.top, rect_old_vis_child.right, rect_old_vis_child.bottom );
+ IntersectRect( &rect_new_vis_child, &rect_new_vis_child, &rect_child_clip );
+ SetRectRgn( hrgn_new_vis_child, rect_new_vis_child.left, rect_new_vis_child.top, rect_new_vis_child.right, rect_new_vis_child.bottom );
+
+ if (!EqualRect( &rect_old, &rect_new ) || is_zorder_redraw)
+ {
+ CombineRgn( hrgn_expect_child, hrgn_new_vis_child, hrgn_old_vis_child, is_composited ? RGN_OR : RGN_DIFF );
+ }
+ else
+ {
+ SetRectRgn( hrgn_expect_child, 0, 0, 0, 0 );
+ }
+
+ rgn_equal = EqualRgn( hrgn_expect_child, hrgn_actual_child );
+ if (!rgn_equal && broken( has_parentdc_anomaly && is_composited &&
+ LOBYTE(LOWORD(GetVersion())) < 8 ) /* Win7 */)
+ {
+ trace( "Forcing non-composited update region (broken)\n" );
+ CombineRgn( hrgn_expect_child, hrgn_new_vis_child, hrgn_old_vis_child, RGN_DIFF );
+ rgn_equal = EqualRgn( hrgn_expect, hrgn_actual );
+ }
+ todo_wine_if( EqualRect( &rect_old, &rect_new ) ? is_zorder_redraw :
+ ((extest->style & WS_CLIPCHILDREN) == 0 || is_composited) )
+ ok( !!rgn_equal, "Child update region shall match expected region\n" );
+
+ if (!rgn_equal && winetest_debug > 0)
+ {
+ printf( "Expected child update region: " );
+ dump_region( hrgn_expect_child );
+ printf( "Actual child update region: " );
+ dump_region( hrgn_actual_child );
+ printf( "Old child window client visible area: %s\n", wine_dbgstr_rect( &rect_old_vis_child ) );
+ printf( "New child window client visible area: %s\n", wine_dbgstr_rect( &rect_new_vis_child ) );
+ }
+
+ if (winetest_interactive)
+ {
+ if (!rgn_equal)
+ {
+ visualize_region_differences( hchild, NULL, hrgn_expect_child, hrgn_actual_child );
+ }
+
+ /* Let the position change be visible to the user */
+ flush_events();
+ }
+
+ winetest_pop_context();
+ }
+
+ winetest_pop_context();
+ }
+
+ DestroyWindow( hauxchild );
+ DestroyWindow( hchild );
+ DestroyWindow( hparent );
+ if (htoplevel) DestroyWindow( htoplevel );
+
+ DeleteObject( hrgn_actual );
+ DeleteObject( hrgn_expect );
+ DeleteObject( hrgn_new_vis );
+ DeleteObject( hrgn_old_vis );
+}
+
+static void test_swp_paint_regions(void)
+{
+ subtest_swp_paint_regions( 1, "SimpleWindowClass", "SimpleWindowClass" );
+ subtest_swp_paint_regions( 1, "SimpleWindowClass", "SimpleWindowClassWithParentDC" );
+ subtest_swp_paint_regions( 1, "SimpleWindowClassWithParentDC", "SimpleWindowClass" );
+ subtest_swp_paint_regions( 1, "SimpleWindowClassWithParentDC", "SimpleWindowClassWithParentDC" );
+ subtest_swp_paint_regions( 0, "SimpleWindowClass", "SimpleWindowClass" );
+ subtest_swp_paint_regions( 0, "SimpleWindowClass", "SimpleWindowClassWithParentDC" );
+ subtest_swp_paint_regions( 0, "SimpleWindowClassWithParentDC", "SimpleWindowClass" );
+ subtest_swp_paint_regions( 0, "SimpleWindowClassWithParentDC", "SimpleWindowClassWithParentDC" );
+}
+
struct wnd_event
{
HWND hwnd;
@@ -10387,6 +10759,11 @@ static BOOL RegisterWindowClasses(void)
cls.lpszClassName = "TestDialogClass";
if(!RegisterClassA(&cls)) return FALSE;
+ cls.lpfnWndProc = DefWindowProcA;
+ cls.style = CS_PARENTDC;
+ cls.lpszClassName = "SimpleWindowClassWithParentDC";
+ if(!RegisterClassA(&cls)) return FALSE;
+
clsW.style = 0;
clsW.lpfnWndProc = MsgCheckProcW;
clsW.cbClsExtra = 0;
@@ -18870,6 +19247,7 @@ START_TEST(msg)
test_combobox_messages();
test_wmime_keydown_message();
test_paint_messages();
+ test_swp_paint_regions();
test_interthread_messages();
test_message_conversion();
test_accelerators();
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/231
June 17, 2022
[PATCH v3 0/4] MR231: SetWindowPos() parent window exposure fixes (#53153)
by Jinoh Kang (@iamahuman)
Signed-off-by: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
--
v3: server: Don't invalidate the newly exposed child region on the parent with WS_CLIPCHILDREN.
server: Redraw composited window child on its z-order change on SetWindowPos().
server: Correctly expose composited parent window on SetWindowPos().
user32/tests: Test for parent window exposure by SetWindowPos().
https://gitlab.winehq.org/wine/wine/-/merge_requests/231
June 17, 2022
Re: [PATCH 3/6] win32u: Move WM_NCLBUTTONDBLCLK and WM_LBUTTONDBLCLK implementation from user32.
by Marvin
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=117144
Your paranoid android.
=== debian11 (32 bit WoW report) ===
user32:
menu.c:2324: Test failed: test 25
June 17, 2022
Re: [PATCH 2/6] win32u: Move WM_SETCURSOR implementation from user32.
by Marvin
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=117143
Your paranoid android.
=== debian11 (32 bit report) ===
user32:
msg.c:6881: Test failed: SetFocus(hwnd) on a button: 5: the msg 0x0135 was expected, but got msg 0x030f instead
msg.c:6881: Test failed: SetFocus(hwnd) on a button: 7: the msg 0x8000 was expected, but got msg 0x0086 instead
msg.c:6881: Test failed: SetFocus(hwnd) on a button: 8: the msg sequence is not complete: expected 0000 - actual 0006
win.c:11770: Test succeeded inside todo block: child should be topmost
win.c:11773: Test failed: grandchild should be topmost
win.c:11781: Test failed: child should NOT be topmost
win.c:11784: Test succeeded inside todo block: grandchild should NOT be topmost
win.c:11787: Test failed: 007200BA: expected NOT topmost
win.c:11606: Test succeeded inside todo block: 5: hwnd 014F0052 is still topmost
June 17, 2022
[PATCH 6/6] win32u: Move NtUserGetTitleBarInfo implementation from user32.
by Jacek Caban
From: Jacek Caban <jacek(a)codeweavers.com>
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/user32/nonclient.c | 125 ----------------------------------------
dlls/user32/user32.spec | 2 +-
dlls/win32u/defwnd.c | 73 +++++++++++++++++++++++
dlls/win32u/syscall.c | 1 +
dlls/win32u/win32u.spec | 2 +-
dlls/wow64win/syscall.h | 1 +
dlls/wow64win/user.c | 8 +++
include/ntuser.h | 1 +
8 files changed, 86 insertions(+), 127 deletions(-)
diff --git a/dlls/user32/nonclient.c b/dlls/user32/nonclient.c
index d972930b10b..ece63dea4a8 100644
--- a/dlls/user32/nonclient.c
+++ b/dlls/user32/nonclient.c
@@ -31,28 +31,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
- /* Some useful macros */
-#define HAS_DLGFRAME(style,exStyle) \
- (((exStyle) & WS_EX_DLGMODALFRAME) || \
- (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
-
-#define HAS_THICKFRAME(style,exStyle) \
- (((style) & WS_THICKFRAME) && \
- !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
-
-#define HAS_THINFRAME(style) \
- (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
-
-#define HAS_BIGFRAME(style,exStyle) \
- (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
- ((exStyle) & WS_EX_DLGMODALFRAME))
-
-#define HAS_STATICOUTERFRAME(style,exStyle) \
- (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
- WS_EX_STATICEDGE)
-
-#define HAS_MENU(hwnd,style) ((((style) & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
-
static void adjust_window_rect( RECT *rect, DWORD style, BOOL menu, DWORD exStyle, NONCLIENTMETRICSW *ncm )
{
@@ -162,42 +140,6 @@ BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectExForDpi( LPRECT rect, DWORD style
}
-/***********************************************************************
- * NC_GetInsideRect
- *
- * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
- * but without the borders (if any).
- */
-static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
- DWORD style, DWORD ex_style )
-{
- WIN_GetRectangles( hwnd, relative, rect, NULL );
-
- /* Remove frame from rectangle */
- if (HAS_THICKFRAME( style, ex_style ))
- {
- InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
- }
- else if (HAS_DLGFRAME( style, ex_style ))
- {
- InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
- }
- else if (HAS_THINFRAME( style ))
- {
- InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
- }
-
- /* We have additional border information if the window
- * is a child (but not an MDI child) */
- if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
- {
- if (ex_style & WS_EX_CLIENTEDGE)
- InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
- if (ex_style & WS_EX_STATICEDGE)
- InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
- }
-}
-
LRESULT NC_HandleNCMouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
RECT rect;
@@ -286,70 +228,3 @@ LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
}
return 0;
}
-
-/***********************************************************************
- * GetTitleBarInfo (USER32.@)
- * TODO: Handle STATE_SYSTEM_PRESSED
- */
-BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
- DWORD dwStyle;
- DWORD dwExStyle;
-
- TRACE("(%p %p)\n", hwnd, tbi);
-
- if(!tbi) {
- SetLastError(ERROR_NOACCESS);
- return FALSE;
- }
-
- if(tbi->cbSize != sizeof(TITLEBARINFO)) {
- TRACE("Invalid TITLEBARINFO size: %ld\n", tbi->cbSize);
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
- dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
- NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
-
- tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
- if(dwExStyle & WS_EX_TOOLWINDOW)
- tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
- else {
- tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
- tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
- }
-
- ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
- /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
- * Under XP it seems to
- */
- tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
- if(dwStyle & WS_CAPTION) {
- tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
- if(dwStyle & WS_SYSMENU) {
- if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
- tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
- tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
- }
- else {
- if(!(dwStyle & WS_MINIMIZEBOX))
- tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
- if(!(dwStyle & WS_MAXIMIZEBOX))
- tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
- }
- if(!(dwExStyle & WS_EX_CONTEXTHELP))
- tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
- if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
- tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
- }
- else {
- tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
- tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
- tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
- tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
- }
- }
- else
- tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
- return TRUE;
-}
diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec
index bed557ba67e..90ddad761f0 100644
--- a/dlls/user32/user32.spec
+++ b/dlls/user32/user32.spec
@@ -389,7 +389,7 @@
@ stdcall GetTaskmanWindow ()
@ stdcall GetThreadDesktop(long) NtUserGetThreadDesktop
@ stdcall GetThreadDpiAwarenessContext()
-@ stdcall GetTitleBarInfo(long ptr)
+@ stdcall GetTitleBarInfo(long ptr) NtUserGetTitleBarInfo
@ stdcall GetTopWindow(long)
@ stdcall GetTouchInputInfo(long long ptr long)
@ stdcall GetUpdateRect(long ptr long) NtUserGetUpdateRect
diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c
index 9cb46c1c78b..c4eb9b76287 100644
--- a/dlls/win32u/defwnd.c
+++ b/dlls/win32u/defwnd.c
@@ -2512,3 +2512,76 @@ LRESULT desktop_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
return default_window_proc( hwnd, msg, wparam, lparam, FALSE );
}
+
+/***********************************************************************
+ * NtUserGetTitleBarInfo (win32u.@)
+ */
+BOOL WINAPI NtUserGetTitleBarInfo( HWND hwnd, TITLEBARINFO *info )
+{
+ DWORD style, ex_style;
+
+ TRACE( "(%p %p)\n", hwnd, info );
+
+ if (!info)
+ {
+ SetLastError( ERROR_NOACCESS );
+ return FALSE;
+ }
+
+ if (info->cbSize != sizeof(TITLEBARINFO))
+ {
+ TRACE( "Invalid TITLEBARINFO size: %d\n", info->cbSize );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+
+ style = get_window_long( hwnd, GWL_STYLE );
+ ex_style = get_window_long( hwnd, GWL_EXSTYLE );
+ get_inside_rect( hwnd, COORDS_SCREEN, &info->rcTitleBar, style, ex_style );
+
+ info->rcTitleBar.bottom = info->rcTitleBar.top;
+ if (ex_style & WS_EX_TOOLWINDOW)
+ info->rcTitleBar.bottom += get_system_metrics( SM_CYSMCAPTION );
+ else
+ {
+ info->rcTitleBar.bottom += get_system_metrics( SM_CYCAPTION );
+ info->rcTitleBar.left += get_system_metrics( SM_CXSIZE );
+ }
+
+ memset( info->rgstate, 0, sizeof(info->rgstate) );
+ info->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
+
+ if (style & WS_CAPTION)
+ {
+ info->rgstate[1] = STATE_SYSTEM_INVISIBLE;
+ if (style & WS_SYSMENU)
+ {
+ if (!(style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX)))
+ {
+ info->rgstate[2] = STATE_SYSTEM_INVISIBLE;
+ info->rgstate[3] = STATE_SYSTEM_INVISIBLE;
+ }
+ else
+ {
+ if (!(style & WS_MINIMIZEBOX))
+ info->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
+ if (!(style & WS_MAXIMIZEBOX))
+ info->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
+ }
+ if (!(ex_style & WS_EX_CONTEXTHELP))
+ info->rgstate[4] = STATE_SYSTEM_INVISIBLE;
+ if (get_class_long( hwnd, GCL_STYLE, FALSE ) & CS_NOCLOSE )
+ info->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
+ }
+ else
+ {
+ info->rgstate[2] = STATE_SYSTEM_INVISIBLE;
+ info->rgstate[3] = STATE_SYSTEM_INVISIBLE;
+ info->rgstate[4] = STATE_SYSTEM_INVISIBLE;
+ info->rgstate[5] = STATE_SYSTEM_INVISIBLE;
+ }
+ }
+ else
+ info->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
+ return TRUE;
+}
diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c
index 6bbdfc66f50..ffb1529e03f 100644
--- a/dlls/win32u/syscall.c
+++ b/dlls/win32u/syscall.c
@@ -147,6 +147,7 @@ static void * const syscalls[] =
NtUserGetProp,
NtUserGetSystemDpiForProcess,
NtUserGetThreadDesktop,
+ NtUserGetTitleBarInfo,
NtUserGetWindowRgnEx,
NtUserInitializeClientPfnArrays,
NtUserInternalGetWindowText,
diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec
index 7087e04653f..8d8f46705b8 100644
--- a/dlls/win32u/win32u.spec
+++ b/dlls/win32u/win32u.spec
@@ -997,7 +997,7 @@
@ stdcall NtUserGetSystemMenu(long long)
@ stdcall -syscall NtUserGetThreadDesktop(long)
@ stub NtUserGetThreadState
-@ stub NtUserGetTitleBarInfo
+@ stdcall -syscall NtUserGetTitleBarInfo(long ptr)
@ stub NtUserGetTopLevelWindow
@ stub NtUserGetTouchInputInfo
@ stub NtUserGetTouchValidationStatus
diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h
index 27e1ba76c56..e1364c2811e 100644
--- a/dlls/wow64win/syscall.h
+++ b/dlls/wow64win/syscall.h
@@ -134,6 +134,7 @@
SYSCALL_ENTRY( NtUserGetProp ) \
SYSCALL_ENTRY( NtUserGetSystemDpiForProcess ) \
SYSCALL_ENTRY( NtUserGetThreadDesktop ) \
+ SYSCALL_ENTRY( NtUserGetTitleBarInfo ) \
SYSCALL_ENTRY( NtUserGetWindowRgnEx ) \
SYSCALL_ENTRY( NtUserInitializeClientPfnArrays ) \
SYSCALL_ENTRY( NtUserInternalGetWindowText ) \
diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c
index 6208c939310..08b8fb6f2a0 100644
--- a/dlls/wow64win/user.c
+++ b/dlls/wow64win/user.c
@@ -850,3 +850,11 @@ NTSTATUS WINAPI wow64_NtUserLockWindowUpdate( UINT *args )
return NtUserLockWindowUpdate( hwnd );
}
+
+NTSTATUS WINAPI wow64_NtUserGetTitleBarInfo( UINT *args )
+{
+ HWND hwnd = get_handle( &args );
+ TITLEBARINFO *info = get_ptr( &args );
+
+ return NtUserGetTitleBarInfo( hwnd, info );
+}
diff --git a/include/ntuser.h b/include/ntuser.h
index 5abe9b9a3cb..76d0387eed7 100644
--- a/include/ntuser.h
+++ b/include/ntuser.h
@@ -609,6 +609,7 @@ DWORD WINAPI NtUserGetQueueStatus( UINT flags );
ULONG WINAPI NtUserGetSystemDpiForProcess( HANDLE process );
HMENU WINAPI NtUserGetSystemMenu( HWND hwnd, BOOL revert );
HDESK WINAPI NtUserGetThreadDesktop( DWORD thread );
+BOOL WINAPI NtUserGetTitleBarInfo( HWND hwnd, TITLEBARINFO *info );
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 );
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/261
June 16, 2022