Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58210 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=38975
From: Paul Gofman pgofman@codeweavers.com
--- dlls/user32/tests/win.c | 136 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 166653f0d2c..08a1d0609cc 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -126,6 +126,17 @@ static void flush_events( BOOL remove_messages ) } }
+static void pump_messages(void) +{ + MSG msg; + + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } +} + /* check the values returned by the various parent/owner functions on a given window */ static void check_parents( HWND hwnd, HWND ga_parent, HWND gwl_parent, HWND get_parent, HWND gw_owner, HWND ga_root, HWND ga_root_owner ) @@ -10880,6 +10891,8 @@ static void test_update_region(void) const RECT rc = {15, 15, 40, 40}; const POINT wnd_orig = {30, 20}; const POINT child_orig = {10, 5}; + RECT r, expect_rect; + BOOL bret;
parent = CreateWindowExA(0, "MainWindowClass", NULL, WS_VISIBLE | WS_CLIPCHILDREN, @@ -10937,7 +10950,130 @@ static void test_update_region(void)
DeleteObject(rgn1); DeleteObject(rgn2); + + pump_messages(); + /* Test that NULL invalidated region means current full client rect and not the one at the moment of + * invalidation. */ + ValidateRect(parent, NULL); + GetUpdateRect(parent, &r, FALSE); + SetRect(&expect_rect, 0, 0, 0, 0); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + InvalidateRect(parent, NULL, FALSE); + SetRect(&r, 0, 0, 10, 10); + /* Adding a rectangle to NULL one still keeps that as full window. */ + InvalidateRect(parent, &r, FALSE); + GetUpdateRect(parent, &r, FALSE); + GetClientRect(parent, &expect_rect); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + SetWindowPos(parent, NULL, 0, 0, 350, 200, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + GetUpdateRect(parent, &r, FALSE); + GetClientRect(parent, &expect_rect); + todo_wine ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + ValidateRect(parent, NULL); + + SetWindowPos(parent, NULL, 0, 0, 300, 150, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + GetUpdateRect(parent, &r, FALSE); + SetRect(&expect_rect, 0, 0, 0, 0); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + RedrawWindow(parent, NULL, 0, RDW_INVALIDATE | RDW_FRAME); + RedrawWindow(parent, NULL, 0, RDW_INVALIDATE); + GetUpdateRect(parent, &r, FALSE); + GetClientRect(parent, &expect_rect); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + SetWindowPos(parent, NULL, 0, 0, 350, 200, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + GetUpdateRect(parent, &r, FALSE); + GetClientRect(parent, &expect_rect); + todo_wine ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + pump_messages(); + RedrawWindow(parent, NULL, 0, RDW_VALIDATE | RDW_FRAME | RDW_ALLCHILDREN); + + ValidateRect(hwnd, NULL); + SetRect(&expect_rect, 0, 0, 0, 0); + GetUpdateRect(hwnd, &r, FALSE); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + GetClientRect(hwnd, &expect_rect); + RedrawWindow(parent, NULL, 0, RDW_INVALIDATE | RDW_ALLCHILDREN); + GetUpdateRect(hwnd, &r, FALSE); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + SetWindowPos(hwnd, NULL, 0, 0, 210, 110, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + GetUpdateRect(hwnd, &r, FALSE); + GetClientRect(hwnd, &expect_rect); + todo_wine ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + ValidateRect(hwnd, NULL); + ValidateRect(parent, NULL); + SetWindowPos(hwnd, NULL, 0, 0, 200, 100, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + + SetRect(&expect_rect, 0, 0, 0, 0); + GetUpdateRect(hwnd, &r, FALSE); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + GetClientRect(hwnd, &expect_rect); + InvalidateRect(hwnd, NULL, FALSE); + GetUpdateRect(hwnd, &r, FALSE); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + SetWindowPos(hwnd, NULL, 0, 0, 210, 110, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + GetUpdateRect(hwnd, &r, FALSE); + GetClientRect(hwnd, &expect_rect); + todo_wine ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + ValidateRect(hwnd, NULL); + ValidateRect(parent, NULL); + SetWindowPos(hwnd, NULL, 0, 0, 200, 100, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + + SetRect(&expect_rect, 0, 0, 0, 0); + GetUpdateRect(hwnd, &r, FALSE); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + GetClientRect(hwnd, &expect_rect); + InvalidateRect(hwnd, NULL, FALSE); + GetUpdateRect(hwnd, &r, FALSE); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + /* Child window bottom is outside parent window. Invalidated area is still new child window extents + * coordinates cropped to visible part. */ + SetWindowPos(hwnd, NULL, 0, 150, 210, 100, SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + GetClientRect(hwnd, &expect_rect); + GetClientRect(parent, &r); + expect_rect.bottom = r.bottom - 150; + GetUpdateRect(hwnd, &r, FALSE); + todo_wine ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + ValidateRect(hwnd, NULL); + ValidateRect(parent, NULL); + SetWindowPos(hwnd, NULL, 0, 0, 200, 100, SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + + SetWindowPos(parent, NULL, 0, 0, 300, 150, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + GetUpdateRect(parent, &r, FALSE); + SetRect(&expect_rect, 0, 0, 0, 0); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + + GetClientRect(parent, &r); + InvalidateRect(parent, &r, FALSE); + expect_rect = r; + GetUpdateRect(parent, &r, FALSE); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + SetWindowPos(parent, NULL, 0, 0, 350, 200, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + GetUpdateRect(parent, &r, FALSE); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + GetClientRect(parent, &r); + ok(!EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + + ValidateRect(parent, NULL); + SetWindowPos(parent, NULL, 0, 0, 300, 150, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + GetUpdateRect(parent, &r, FALSE); + SetRect(&expect_rect, 0, 0, 0, 0); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + InvalidateRect(parent, NULL, FALSE); + SetRect(&r, 0, 0, 0, 0); + /* Subtracting empty rectangle from update region turns 'full client rect' into the specific coordinates + * region (unlike adding rectangle). */ + bret = ValidateRect(parent, &r); + ok(bret, "got error %lu.\n", GetLastError()); + GetClientRect(parent, &expect_rect); + GetUpdateRect(parent, &r, FALSE); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + SetWindowPos(parent, NULL, 0, 0, 350, 200, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); + GetUpdateRect(parent, &r, FALSE); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + + ValidateRect(parent, NULL); DestroyWindow(parent); + pump_messages(); }
static void test_window_without_child_style(void)
From: Paul Gofman pgofman@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58210 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=38975 --- dlls/user32/tests/win.c | 10 ++++---- server/window.c | 54 +++++++++++++++++++++++++++-------------- 2 files changed, 41 insertions(+), 23 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 08a1d0609cc..47ad916c05b 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -10968,7 +10968,7 @@ static void test_update_region(void) SetWindowPos(parent, NULL, 0, 0, 350, 200, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); GetUpdateRect(parent, &r, FALSE); GetClientRect(parent, &expect_rect); - todo_wine ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); ValidateRect(parent, NULL);
SetWindowPos(parent, NULL, 0, 0, 300, 150, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); @@ -10983,7 +10983,7 @@ static void test_update_region(void) SetWindowPos(parent, NULL, 0, 0, 350, 200, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); GetUpdateRect(parent, &r, FALSE); GetClientRect(parent, &expect_rect); - todo_wine ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); pump_messages(); RedrawWindow(parent, NULL, 0, RDW_VALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
@@ -10998,7 +10998,7 @@ static void test_update_region(void) SetWindowPos(hwnd, NULL, 0, 0, 210, 110, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); GetUpdateRect(hwnd, &r, FALSE); GetClientRect(hwnd, &expect_rect); - todo_wine ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); ValidateRect(hwnd, NULL); ValidateRect(parent, NULL); SetWindowPos(hwnd, NULL, 0, 0, 200, 100, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); @@ -11013,7 +11013,7 @@ static void test_update_region(void) SetWindowPos(hwnd, NULL, 0, 0, 210, 110, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); GetUpdateRect(hwnd, &r, FALSE); GetClientRect(hwnd, &expect_rect); - todo_wine ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); ValidateRect(hwnd, NULL); ValidateRect(parent, NULL); SetWindowPos(hwnd, NULL, 0, 0, 200, 100, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); @@ -11032,7 +11032,7 @@ static void test_update_region(void) GetClientRect(parent, &r); expect_rect.bottom = r.bottom - 150; GetUpdateRect(hwnd, &r, FALSE); - todo_wine ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); + ok(EqualRect(&r, &expect_rect), "got %s, expected %s.\n", wine_dbgstr_rect(&r), wine_dbgstr_rect(&expect_rect)); ValidateRect(hwnd, NULL); ValidateRect(parent, NULL); SetWindowPos(hwnd, NULL, 0, 0, 200, 100, SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); diff --git a/server/window.c b/server/window.c index 1eb815dfe3e..e7375440ca3 100644 --- a/server/window.c +++ b/server/window.c @@ -80,6 +80,8 @@ struct window unsigned int is_linked : 1; /* is it linked into the parent z-order list? */ unsigned int is_layered : 1; /* has layered info been set? */ unsigned int is_orphan : 1; /* is window orphaned */ + int is_update_region_full_frame : 1; /* the whole window rect is invalidated */ + int is_update_region_full_client : 1; /* the whole client rect is invalidated */ unsigned int color_key; /* color key for a layered window */ unsigned int alpha; /* alpha value for a layered window */ unsigned int layered_flags; /* flags for a layered window */ @@ -1451,8 +1453,9 @@ done:
/* set a region as new update region for the window */ -static void set_update_region( struct window *win, struct region *region ) +static void set_update_region( struct window *win, struct region *region, int clear_full_window ) { + if (clear_full_window) win->is_update_region_full_client = win->is_update_region_full_frame = 0; if (region && !is_region_empty( region )) { if (!win->update_region) inc_window_paint_count( win, 1 ); @@ -1481,7 +1484,7 @@ static int add_update_region( struct window *win, struct region *region ) free_region( region ); return 0; } - set_update_region( win, region ); + set_update_region( win, region, 0 ); return 1; }
@@ -1499,7 +1502,7 @@ static void crop_children_update_region( struct window *win, struct rectangle *r if (!rect) /* crop everything out */ { crop_children_update_region( child, NULL ); - set_update_region( child, NULL ); + set_update_region( child, NULL, 1 ); continue; }
@@ -1519,7 +1522,7 @@ static void crop_children_update_region( struct window *win, struct rectangle *r if (!(tmp = create_empty_region())) continue; set_region_rect( tmp, rect ); offset_region( tmp, -child->window_rect.left, -child->window_rect.top ); - if (intersect_region( tmp, child->update_region, tmp )) set_update_region( child, tmp ); + if (intersect_region( tmp, child->update_region, tmp )) set_update_region( child, tmp, 0 ); else free_region( tmp ); } } @@ -1543,7 +1546,7 @@ static void validate_non_client( struct window *win ) { set_region_rect( tmp, &rect ); if (intersect_region( tmp, win->update_region, tmp )) - set_update_region( win, tmp ); + set_update_region( win, tmp, 1 ); else free_region( tmp ); } @@ -1554,7 +1557,7 @@ static void validate_non_client( struct window *win ) /* validate a window completely so that we don't get any further paint messages for it */ static void validate_whole_window( struct window *win ) { - set_update_region( win, NULL ); + set_update_region( win, NULL, 1 );
if (win->paint_flags & PAINT_INTERNAL) { @@ -1605,7 +1608,7 @@ static void validate_parents( struct window *child ) offset_region( child->update_region, offset_x, offset_y ); if (subtract_region( tmp, win->update_region, child->update_region )) { - set_update_region( win, tmp ); + set_update_region( win, tmp, 1 ); tmp = NULL; } /* restore child coords */ @@ -1617,7 +1620,8 @@ static void validate_parents( struct window *child )
/* add/subtract a region (in client coordinates) to the update region of the window */ -static void redraw_window( struct window *win, struct region *region, int frame, unsigned int flags ) +static void redraw_window( struct window *win, struct region *region, int frame, unsigned int flags, + int invalidate_full_window ) { struct region *child_rgn, *tmp; struct window *child; @@ -1627,6 +1631,11 @@ static void redraw_window( struct window *win, struct region *region, int frame, if (!(tmp = crop_region_to_win_rect( win, region, frame ))) return;
if (!add_update_region( win, tmp )) return; + if (invalidate_full_window) + { + if (frame) win->is_update_region_full_frame = 1; + else win->is_update_region_full_client = 1; + }
if (flags & RDW_FRAME) win->paint_flags |= PAINT_NONCLIENT; if (flags & RDW_ERASE) win->paint_flags |= PAINT_ERASE; @@ -1635,7 +1644,7 @@ static void redraw_window( struct window *win, struct region *region, int frame, { if (!region && (flags & RDW_NOFRAME)) /* shortcut: validate everything */ { - set_update_region( win, NULL ); + set_update_region( win, NULL, 1 ); } else if (win->update_region) { @@ -1646,7 +1655,11 @@ static void redraw_window( struct window *win, struct region *region, int frame, free_region( tmp ); return; } - set_update_region( win, tmp ); + set_update_region( win, tmp, 1 ); + } + else + { + win->is_update_region_full_client = win->is_update_region_full_frame = 0; } if (flags & RDW_NOFRAME) validate_non_client( win ); if (flags & RDW_NOERASE) win->paint_flags &= ~(PAINT_ERASE | PAINT_DELAYED_ERASE); @@ -1688,7 +1701,7 @@ static void redraw_window( struct window *win, struct region *region, int frame, if (rect_in_region( child_rgn, &child->window_rect )) { offset_region( child_rgn, -child->client_rect.left, -child->client_rect.top ); - redraw_window( child, child_rgn, 1, flags ); + redraw_window( child, child_rgn, 1, flags, invalidate_full_window ); } } free_region( child_rgn ); @@ -1885,7 +1898,7 @@ static struct region *expose_window( struct window *win, const struct rectangle { /* make it relative to parent */ offset_region( new_vis_rgn, old_window_rect->left, old_window_rect->top ); - redraw_window( win->parent, new_vis_rgn, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN ); + redraw_window( win->parent, new_vis_rgn, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN, 0 ); } } } @@ -1962,6 +1975,11 @@ static void set_window_pos( struct window *win, struct window *previous,
if (win->update_region) { + if (win->is_update_region_full_client || win->is_update_region_full_frame) + { + if (get_window_visible_rect( win, &rect, win->is_update_region_full_frame )) + set_region_rect( win->update_region, &rect ); + } if (get_window_visible_rect( win, &rect, 1 )) { struct region *tmp = create_empty_region(); @@ -1969,12 +1987,12 @@ static void set_window_pos( struct window *win, struct window *previous, { set_region_rect( tmp, &rect ); if (intersect_region( tmp, win->update_region, tmp )) - set_update_region( win, tmp ); + set_update_region( win, tmp, 0 ); else free_region( tmp ); } } - else set_update_region( win, NULL ); /* visible rect is empty */ + else set_update_region( win, NULL, 1 ); /* visible rect is empty */ }
/* crop children regions to the new window rect */ @@ -2056,7 +2074,7 @@ static void set_window_pos( struct window *win, struct window *previous, }
if (exposed_rgn) - redraw_window( win, exposed_rgn, 1, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN ); + redraw_window( win, exposed_rgn, 1, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN, 0 );
done: if (old_vis_rgn) free_region( old_vis_rgn ); @@ -2081,7 +2099,7 @@ static void set_window_region( struct window *win, struct region *region, int re /* expose anything revealed by the change */ 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 ); + redraw_window( win, exposed_rgn, 1, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN, 0 ); free_region( exposed_rgn ); }
@@ -2992,7 +3010,7 @@ DECL_HANDLER(redraw_window) } }
- redraw_window( win, region, (flags & RDW_INVALIDATE) && (flags & RDW_FRAME), flags ); + redraw_window( win, region, (flags & RDW_INVALIDATE) && (flags & RDW_FRAME), flags, !region ); if (region) free_region( region ); }
@@ -3168,7 +3186,7 @@ DECL_HANDLER(set_window_layered_info) win->layered_flags = req->flags; win->is_layered = 1; /* repaint since we know now it's not going to use UpdateLayeredWindow */ - if (!was_layered) redraw_window( win, 0, 1, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_ERASE | RDW_FRAME ); + if (!was_layered) redraw_window( win, 0, 1, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_ERASE | RDW_FRAME, 0 ); } else set_win32_error( ERROR_INVALID_WINDOW_HANDLE ); }
It turns out current semantics of NULL invalidated rect or region differs between Windows and Wine: on Wine it gets the current size based on window size while on Windows that means "full window" rectangle which changes with changing window position (including changed with SWP_NOREDRAW which doesn't invalidate enlarged window).
An alternative implementation would be to manage that in region.c, but after some consideration it seems to me that would be less straightforward because the rules when a rectangle continues to be full window or not are not mathematically straightforward: e. g., subtracting empty region with ValidateRect breaks region's fullscreen status while adding some region with additional InvalidateRect doesn't. While the operations in region.c seem to follow strict rules and are based on X consortium code. Besides, pulling the logic there would require relaying window sizes.
Rémi Bernon (@rbernon) commented about server/window.c:
unsigned int is_linked : 1; /* is it linked into the parent z-order list? */ unsigned int is_layered : 1; /* has layered info been set? */ unsigned int is_orphan : 1; /* is window orphaned */
- int is_update_region_full_frame : 1; /* the whole window rect is invalidated */
- int is_update_region_full_client : 1; /* the whole client rect is invalidated */
I would need some time to look at and understand the window update logic, but adding two flags just for this feels a bit overkill? Isn't there a simpler way maybe? (also the flags should be unsigned but that's irrelevant if we can do without)