Moved visible region calculation to the server.

diff --git a/server/window.c b/server/window.c
index 8550de1..dbfde58 100644
--- a/server/window.c
+++ b/server/window.c
@@ -463,6 +463,114 @@
 }
 
 
+/* clip all children of a given window out of the visible region */
+static struct region *clip_children( struct window *parent, struct window *last,
+                                     struct region *region, int offset_x, int offset_y )
+{
+    struct window *ptr;
+    struct region *tmp = create_empty_region();
+
+    if (!tmp) return NULL;
+    for (ptr = parent->first_child; ptr && ptr != last; ptr = ptr->next)
+    {
+        if (!(ptr->style & WS_VISIBLE)) continue;
+        if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
+        set_region_rect( tmp, &ptr->window_rect );
+        offset_region( tmp, offset_x, offset_y );
+        if (!(region = subtract_region( region, region, tmp ))) break;
+        if (is_region_empty( region )) break;
+    }
+    free_region( tmp );
+    return region;
+}
+
+
+/* compute the visible region of a window */
+static struct region *get_visible_region( struct window *win, struct window *top,
+                                          unsigned int flags )
+{
+    struct region *tmp, *region;
+    struct window *ptr;
+    rectangle_t rect;
+    int offset_x, offset_y;
+
+    if (!(region = create_empty_region())) return NULL;
+
+    /* first check if all ancestors are visible */
+
+    for (ptr = win; ptr != top_window; ptr = ptr->parent)
+        if (!(ptr->style & WS_VISIBLE)) return region;  /* empty region */
+
+    /* retrieve window rectangle in parent coordinates */
+
+    if ((flags & DCX_PARENTCLIP) && win->parent)
+    {
+        rect.left = rect.top = 0;
+        rect.right = win->parent->client_rect.right - win->parent->client_rect.left;
+        rect.bottom = win->parent->client_rect.bottom - win->parent->client_rect.top;
+        offset_x = win->client_rect.left;
+        offset_y = win->client_rect.top;
+    }
+    else if (flags & DCX_WINDOW)
+    {
+        rect = win->window_rect;
+        offset_x = win->window_rect.left;
+        offset_y = win->window_rect.top;
+    }
+    else
+    {
+        rect = win->client_rect;
+        offset_x = win->client_rect.left;
+        offset_y = win->client_rect.top;
+    }
+
+    /* create a region relative to the window itself */
+
+    set_region_rect( region, &rect );
+    offset_region( region, -offset_x, -offset_y );
+
+    /* clip children */
+
+    if (flags & DCX_CLIPCHILDREN)
+    {
+        if (!clip_children( win, NULL, region,
+                            offset_x - win->client_rect.left,
+                            offset_y - win->client_rect.top )) goto error;
+    }
+
+    /* clip siblings of ancestors */
+
+    if (top && top != win && (tmp = create_empty_region()) != NULL)
+    {
+        offset_region( region, offset_x, offset_y );  /* make it relative to parent */
+        while (win->parent)
+        {
+            if (win->style & WS_CLIPSIBLINGS)
+            {
+                if (!clip_children( win->parent, win, region, 0, 0 )) goto error;
+                if (is_region_empty( region )) break;
+            }
+            if (win == top) break;
+            /* clip to parent client area */
+            win = win->parent;
+            offset_x += win->client_rect.left;
+            offset_y += win->client_rect.top;
+            offset_region( region, win->client_rect.left, win->client_rect.top );
+            set_region_rect( tmp, &win->client_rect );
+            if (!intersect_region( region, region, tmp )) goto error;
+            if (is_region_empty( region )) break;
+        }
+        offset_region( region, -offset_x, -offset_y );  /* make it relative to target window again */
+        free_region( tmp );
+    }
+    return region;
+
+error:
+    free_region( region );
+    return NULL;
+}
+
+
 /* get the window class of a window */
 struct window_class* get_window_class( user_handle_t window )
 {
@@ -825,6 +933,24 @@
 }
 
 
+/* get the visible region of a window */
+DECL_HANDLER(get_visible_region)
+{
+    struct region *region;
+    struct window *win = get_window( req->window );
+    struct window *top = NULL;
+
+    if (!win) return;
+    if (req->top_win && !(top = get_window( req->top_win ))) return;
+
+    if ((region = get_visible_region( win, top, req->flags )))
+    {
+        rectangle_t *data = get_region_data_and_free( region, &reply->total_size );
+        set_reply_data_ptr( data, min(reply->total_size,get_reply_max_size()) );
+    }
+}
+
+
 /* set a window property */
 DECL_HANDLER(set_window_property)
 {