Alexandre Julliard : server: When moving/ resizing a window crop the update region against the new rectangle of the parents .

Alexandre Julliard julliard at winehq.org
Mon May 12 07:12:22 CDT 2008


Module: wine
Branch: master
Commit: e02969ddf091e5e7cb1db02efc291a6bc308e1a9
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=e02969ddf091e5e7cb1db02efc291a6bc308e1a9

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Mon May 12 12:26:26 2008 +0200

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 6d1acb1..3499f69 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 e10f9a7..4c3b3ba 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 */




More information about the wine-cvs mailing list