From e02969ddf091e5e7cb1db02efc291a6bc308e1a9 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 12 May 2008 12:26:26 +0200 Subject: [PATCH] server: When moving/resizing a window crop the update region against the new rectangle of the parents. --- dlls/user32/tests/msg.c | 32 ++++++++++++++++++++ server/window.c | 67 +++++++++++++++++++++++++++++++++-------- 2 files changed, 87 insertions(+), 12 deletions(-) diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 6d1acb135f4..3499f69843c 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -5783,6 +5783,38 @@ static void test_paint_messages(void) DestroyWindow( hparent ); ok(!IsWindow(hchild), "child must be destroyed with its parent\n"); + /* tests for moving windows off-screen (needs simple WS_POPUP windows) */ + + hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok (hparent != 0, "Failed to create parent window\n"); + + hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE, + 10, 10, 100, 100, hparent, 0, 0, NULL); + ok (hchild != 0, "Failed to create child window\n"); + + ShowWindow( hparent, SW_SHOW ); + UpdateWindow( hparent ); + UpdateWindow( hchild ); + flush_events(); + flush_sequence(); + + /* moving child outside of parent boundaries changes update region */ + SetRect( &rect, 0, 0, 40, 40 ); + RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE ); + SetRectRgn( hrgn, 0, 0, 40, 40 ); + check_update_rgn( hchild, hrgn ); + MoveWindow( hchild, -10, 10, 100, 100, FALSE ); + SetRectRgn( hrgn, 10, 0, 40, 40 ); + check_update_rgn( hchild, hrgn ); + MoveWindow( hchild, -10, -10, 100, 100, FALSE ); + SetRectRgn( hrgn, 10, 10, 40, 40 ); + check_update_rgn( hchild, hrgn ); + + DestroyWindow( hparent ); + ok(!IsWindow(hchild), "child must be destroyed with its parent\n"); + flush_sequence(); + DeleteObject( hrgn ); DeleteObject( hrgn2 ); } diff --git a/server/window.c b/server/window.c index e10f9a7ae5b..4c3b3ba0519 100644 --- a/server/window.c +++ b/server/window.c @@ -876,6 +876,16 @@ static inline int intersect_rect( rectangle_t *dst, const rectangle_t *src1, con } +/* offset the coordinates of a rectangle */ +static inline void offset_rect( rectangle_t *rect, int offset_x, int offset_y ) +{ + rect->left += offset_x; + rect->top += offset_y; + rect->right += offset_x; + rect->bottom += offset_y; +} + + /* set the region to the client rect clipped by the window rect, in parent-relative coordinates */ static void set_region_client_rect( struct region *region, struct window *win ) { @@ -990,6 +1000,38 @@ struct window_class* get_window_class( user_handle_t window ) return win->class; } +/* determine the window visible rectangle, i.e. window or client rect cropped by parent rects */ +/* the returned rectangle is in window coordinates; return 0 if rectangle is empty */ +static int get_window_visible_rect( struct window *win, rectangle_t *rect, int frame ) +{ + int offset_x = 0, offset_y = 0; + + if (!(win->style & WS_VISIBLE)) return 0; + + *rect = frame ? win->window_rect : win->client_rect; + if (!is_desktop_window(win)) + { + offset_x = win->window_rect.left; + offset_y = win->window_rect.top; + } + + while (win->parent) + { + win = win->parent; + if (!(win->style & WS_VISIBLE) || win->style & WS_MINIMIZE) return 0; + if (!is_desktop_window(win)) + { + offset_x += win->client_rect.left; + offset_y += win->client_rect.top; + offset_rect( rect, win->client_rect.left, win->client_rect.top ); + } + if (!intersect_rect( rect, rect, &win->client_rect )) return 0; + if (!intersect_rect( rect, rect, &win->window_rect )) return 0; + } + offset_rect( rect, -offset_x, -offset_y ); + return 1; +} + /* return a copy of the specified region cropped to the window client or frame rectangle, */ /* and converted from client to window coordinates. Helper for (in)validate_window. */ static struct region *crop_region_to_win_rect( struct window *win, struct region *region, int frame ) @@ -1413,6 +1455,7 @@ static void set_window_pos( struct window *win, struct window *previous, struct region *old_vis_rgn = NULL, *exposed_rgn = NULL; const rectangle_t old_window_rect = win->window_rect; const rectangle_t old_client_rect = win->client_rect; + rectangle_t rect; int client_changed, frame_changed; int visible = (win->style & WS_VISIBLE) || (swp_flags & SWP_SHOWWINDOW); @@ -1461,21 +1504,21 @@ static void set_window_pos( struct window *win, struct window *previous, /* crop update region to the new window rect */ - if (win->update_region && - (window_rect->right - window_rect->left < old_window_rect.right - old_window_rect.left || - window_rect->bottom - window_rect->top < old_window_rect.bottom - old_window_rect.top)) + if (win->update_region) { - struct region *tmp = create_empty_region(); - if (tmp) + if (get_window_visible_rect( win, &rect, 1 )) { - set_region_rect( tmp, window_rect ); - if (!is_desktop_window(win)) - offset_region( tmp, -window_rect->left, -window_rect->top ); - if (intersect_region( tmp, win->update_region, tmp )) - set_update_region( win, tmp ); - else - free_region( tmp ); + struct region *tmp = create_empty_region(); + if (tmp) + { + set_region_rect( tmp, &rect ); + if (intersect_region( tmp, win->update_region, tmp )) + set_update_region( win, tmp ); + else + free_region( tmp ); + } } + else set_update_region( win, NULL ); /* visible rect is empty */ } if (swp_flags & SWP_NOREDRAW) goto done; /* do not repaint anything */