diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 3499f69843c..da353f99fc6 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -5811,6 +5811,19 @@ static void test_paint_messages(void) SetRectRgn( hrgn, 10, 10, 40, 40 ); check_update_rgn( hchild, hrgn ); + /* moving parent off-screen does too */ + SetRect( &rect, 0, 0, 100, 100 ); + RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN ); + SetRectRgn( hrgn, 0, 0, 100, 100 ); + check_update_rgn( hparent, hrgn ); + SetRectRgn( hrgn, 10, 10, 40, 40 ); + check_update_rgn( hchild, hrgn ); + MoveWindow( hparent, -20, -20, 200, 200, FALSE ); + SetRectRgn( hrgn, 20, 20, 100, 100 ); + check_update_rgn( hparent, hrgn ); + SetRectRgn( hrgn, 30, 30, 40, 40 ); + check_update_rgn( hchild, hrgn ); + DestroyWindow( hparent ); ok(!IsWindow(hchild), "child must be destroyed with its parent\n"); flush_sequence(); diff --git a/server/window.c b/server/window.c index 4c3b3ba0519..3a67b8d742d 100644 --- a/server/window.c +++ b/server/window.c @@ -1097,6 +1097,45 @@ static int add_update_region( struct window *win, struct region *region ) } +/* crop the update region of children to the specified rectangle, in client coords */ +static void crop_children_update_region( struct window *win, rectangle_t *rect ) +{ + struct window *child; + struct region *tmp = create_empty_region(); + rectangle_t child_rect; + + LIST_FOR_EACH_ENTRY( child, &win->children, struct window, entry ) + { + if (!(child->style & WS_VISIBLE)) continue; + if (!rect) /* crop everything out */ + { + crop_children_update_region( child, NULL ); + set_update_region( child, NULL ); + continue; + } + + /* nothing to do if child is completely inside rect */ + if (child->window_rect.left >= rect->left && + child->window_rect.top >= rect->top && + child->window_rect.right <= rect->right && + child->window_rect.bottom <= rect->bottom) continue; + + /* map to child client coords and crop grand-children */ + child_rect = *rect; + offset_rect( &child_rect, -child->client_rect.left, -child->client_rect.top ); + crop_children_update_region( child, &child_rect ); + + /* now crop the child itself */ + if (!child->update_region) continue; + 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 ); + else free_region( tmp ); + } +} + + /* validate the non client area of a window */ static void validate_non_client( struct window *win ) { @@ -1521,6 +1560,17 @@ static void set_window_pos( struct window *win, struct window *previous, else set_update_region( win, NULL ); /* visible rect is empty */ } + /* crop children regions to the new window rect */ + + if (get_window_visible_rect( win, &rect, 0 )) + { + /* map to client coords */ + offset_rect( &rect, win->window_rect.left - win->client_rect.left, + win->window_rect.top - win->client_rect.top ); + crop_children_update_region( win, &rect ); + } + else crop_children_update_region( win, NULL ); + if (swp_flags & SWP_NOREDRAW) goto done; /* do not repaint anything */ /* expose the whole non-client area if it changed in any way */