From: Rémi Bernon rbernon@codeweavers.com
Since 4e06b87633ec7e04822ad4f4854df7ae43f0d7e0, we are moving the window rects, which is in screen coordinates for the old rects, because invalidate_dce expects it, but in parent coordinates for the new rects.
This makes the old and new rectangles to be consistently using parent-relative coordinates, fixing some broken window bits copy with child windows.
Fixes 4e06b87633ec7e04822ad4f4854df7ae43f0d7e0 --- dlls/win32u/dce.c | 32 ++++++++++++++++++++++---------- dlls/win32u/ntuser_private.h | 2 +- dlls/win32u/window.c | 5 +---- 3 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 3fa18fc8ace..dbb4da0202b 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1146,19 +1146,16 @@ static void make_dc_dirty( struct dce *dce ) * rectangle. In addition, pWnd->parent DCEs may need to be updated if * DCX_CLIPCHILDREN flag is set. */ -void invalidate_dce( WND *win, const RECT *extra_rect ) +void invalidate_dce( WND *win, const RECT *old_rect ) { UINT context; - RECT window_rect; struct dce *dce;
if (!win->parent) return;
context = set_thread_dpi_awareness_context( get_window_dpi_awareness_context( win->obj.handle )); - get_window_rect( win->obj.handle, &window_rect, get_thread_dpi() );
- TRACE("%p parent %p %s (%s)\n", - win->obj.handle, win->parent, wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(extra_rect) ); + TRACE("%p parent %p, old_rect %s\n", win->obj.handle, win->parent, wine_dbgstr_rect(old_rect) );
/* walk all DCEs and fixup non-empty entries */
@@ -1182,11 +1179,26 @@ void invalidate_dce( WND *win, const RECT *extra_rect ) /* otherwise check if the window rectangle intersects this DCE window */ if (win->parent == dce->hwnd || is_child( win->parent, dce->hwnd )) { - RECT dce_rect, tmp; - get_window_rect( dce->hwnd, &dce_rect, get_thread_dpi() ); - if (intersect_rect( &tmp, &dce_rect, &window_rect ) || - (extra_rect && intersect_rect( &tmp, &dce_rect, extra_rect ))) - make_dc_dirty( dce ); + RECT tmp, new_window_rect, old_window_rect; + struct window_rects rects; + + /* get the parent client-relative old/new window rects */ + get_window_rects( win->obj.handle, COORDS_PARENT, &rects, get_thread_dpi() ); + old_window_rect = old_rect ? *old_rect : rects.window; + new_window_rect = rects.window; + + /* get the DCE window rect in client-relative coordinates */ + get_window_rects( dce->hwnd, COORDS_CLIENT, &rects, get_thread_dpi() ); + if (win->parent != dce->hwnd) + { + /* map the window rects from parent client-relative to DCE window client-relative coordinates */ + map_window_points( win->parent, dce->hwnd, (POINT *)&new_window_rect, 2, get_thread_dpi() ); + map_window_points( win->parent, dce->hwnd, (POINT *)&old_window_rect, 2, get_thread_dpi() ); + } + + /* check if any of the window rects intersects with the DCE window rect */ + if (intersect_rect( &tmp, &rects.window, &old_window_rect )) make_dc_dirty( dce ); + else if (intersect_rect( &tmp, &rects.window, &new_window_rect )) make_dc_dirty( dce ); } } set_thread_dpi_awareness_context( context ); diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index fd594488c08..f7d84e12cd1 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -221,7 +221,7 @@ HICON alloc_cursoricon_handle( BOOL is_icon );
/* dce.c */ extern void free_dce( struct dce *dce, HWND hwnd ); -extern void invalidate_dce( WND *win, const RECT *extra_rect ); +extern void invalidate_dce( WND *win, const RECT *old_rect );
/* message.c */ struct peek_message_filter diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index f67ddc2903c..5bda3a5913a 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2013,13 +2013,10 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru if (is_child) monitor_dpi = get_win_monitor_dpi( parent, &raw_dpi ); else monitor_dpi = monitor_dpi_from_rect( new_rects->window, get_thread_dpi(), &raw_dpi );
- get_window_rects( hwnd, COORDS_SCREEN, &old_rects, get_thread_dpi() ); + get_window_rects( hwnd, COORDS_PARENT, &old_rects, get_thread_dpi() ); if (IsRectEmpty( &valid_rects[0] ) || is_layered) valid_rects = NULL;
if (!(win = get_win_ptr( hwnd )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS) return FALSE; - - old_rects.visible = win->rects.visible; - old_rects.client = win->rects.client; old_surface = win->surface; if (old_surface != new_surface) swp_flags |= SWP_FRAMECHANGED; /* force refreshing non-client area */ if (new_surface == &dummy_surface) swp_flags |= SWP_NOREDRAW;