server: When moving/resizing a window crop the update region against the new rectangle of the parents.
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 @@
}
+/* 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 @@
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 @@
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 @@
/* 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 */