]> Pileus Git - ~andy/gtk/blobdiff - gdk/gdkwindow.c
Abstract some GdkWindow API into an interface that the backends must
[~andy/gtk] / gdk / gdkwindow.c
index 41e5e2ab97cc796918868134b83c2402102b1c4e..7cba2daa20cab88f19581e7d180335761170158e 100644 (file)
@@ -1,5 +1,6 @@
 /* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
+ * Josh MacDonald, Ryan Lortie
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include <config.h>
-#include "gdkalias.h"
+#include "config.h"
 #include "gdkwindow.h"
+#include "gdkwindowimpl.h"
 #include "gdkinternals.h"
 #include "gdk.h"               /* For gdk_rectangle_union() */
 #include "gdkpixmap.h"
 #include "gdkdrawable.h"
-#include "gdkpixmap.h"
 #include "gdkscreen.h"
+#include "gdkalias.h"
 
 #define USE_BACKING_STORE      /* Appears to work on Win32, too, now. */
 
@@ -44,6 +45,27 @@ struct _GdkWindowPaint
   GdkPixmap *pixmap;
   gint x_offset;
   gint y_offset;
+  cairo_surface_t *surface;
+};
+
+typedef struct {
+  GdkRegion *old_region;
+  gint old_clip_x_origin;
+  gint old_clip_y_origin;
+  gint x_offset;
+  gint y_offset;
+} GdkWindowClipData;
+
+struct _GdkWindowRedirect
+{
+  GdkWindowObject *redirected;
+  GdkDrawable *pixmap;
+  gint src_x;
+  gint src_y;
+  gint dest_x;
+  gint dest_y;
+  gint width;
+  gint height;
 };
 
 static GdkGC *gdk_window_create_gc      (GdkDrawable     *drawable,
@@ -157,6 +179,8 @@ static GdkImage* gdk_window_copy_to_image (GdkDrawable *drawable,
                                           gint         width,
                                           gint         height);
 
+static cairo_surface_t *gdk_window_ref_cairo_surface (GdkDrawable *drawable);
+
 static void   gdk_window_real_get_size  (GdkDrawable     *drawable,
                                          gint            *width,
                                          gint            *height);
@@ -188,6 +212,23 @@ static void gdk_window_clear_backing_rect (GdkWindow *window,
                                           gint       y,
                                           gint       width,
                                           gint       height);
+static void setup_redirect_clip           (GdkWindow         *window,
+                                          GdkGC             *gc,
+                                          GdkWindowClipData *data);
+static void reset_redirect_clip           (GdkWindow         *offscreen,
+                                          GdkGC             *gc,
+                                          GdkWindowClipData *data);
+static void gdk_window_redirect_free      (GdkWindowRedirect *redirect);
+static void apply_redirect_to_children    (GdkWindowObject   *private,
+                                          GdkWindowRedirect *redirect);
+static void remove_redirect_from_children (GdkWindowObject   *private,
+                                          GdkWindowRedirect *redirect);
+static GdkRegion *_gdk_window_calculate_full_clip_region (GdkWindow *window,
+                                                         GdkWindow *base_window,
+                                                         GdkGC *gc,
+                                                         gboolean do_children,
+                                                         gint *base_x_offset,
+                                                         gint *base_y_offset);
 
 static gpointer parent_class = NULL;
 
@@ -197,26 +238,39 @@ gdk_window_object_get_type (void)
   static GType object_type = 0;
 
   if (!object_type)
+    object_type = g_type_register_static_simple (GDK_TYPE_DRAWABLE,
+                                                "GdkWindow",
+                                                sizeof (GdkWindowObjectClass),
+                                                (GClassInitFunc) gdk_window_class_init,
+                                                sizeof (GdkWindowObject),
+                                                (GInstanceInitFunc) gdk_window_init,
+                                                0);
+  
+  return object_type;
+}
+
+GType
+_gdk_paintable_get_type (void)
+{
+  static GType paintable_type = 0;
+
+  if (!paintable_type)
     {
-      static const GTypeInfo object_info =
+      const GTypeInfo paintable_info =
       {
-        sizeof (GdkWindowObjectClass),
-        (GBaseInitFunc) NULL,
-        (GBaseFinalizeFunc) NULL,
-        (GClassInitFunc) gdk_window_class_init,
-        NULL,           /* class_finalize */
-        NULL,           /* class_data */
-        sizeof (GdkWindowObject),
-        0,              /* n_preallocs */
-        (GInstanceInitFunc) gdk_window_init,
+       sizeof (GdkPaintableIface),  /* class_size */
+       NULL,                        /* base_init */
+       NULL,                        /* base_finalize */
       };
-      
-      object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
-                                            "GdkWindow",
-                                            &object_info, 0);
+
+      paintable_type = g_type_register_static (G_TYPE_INTERFACE,
+                                              g_intern_static_string ("GdkPaintable"),
+                                              &paintable_info, 0);
+
+      g_type_interface_add_prerequisite (paintable_type, G_TYPE_OBJECT);
     }
-  
-  return object_type;
+
+  return paintable_type;
 }
 
 static void
@@ -227,8 +281,6 @@ gdk_window_init (GdkWindowObject *window)
   window->window_type = GDK_WINDOW_CHILD;
 
   window->state = GDK_WINDOW_STATE_WITHDRAWN;
-  
-  window->impl = g_object_new (_gdk_window_impl_get_type (), NULL);
 }
 
 static void
@@ -263,6 +315,7 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
   drawable_class->get_colormap = gdk_window_real_get_colormap;
   drawable_class->get_visual = gdk_window_real_get_visual;
   drawable_class->_copy_to_image = gdk_window_copy_to_image;
+  drawable_class->ref_cairo_surface = gdk_window_ref_cairo_surface;
   drawable_class->get_clip_region = gdk_window_get_clip_region;
   drawable_class->get_visible_region = gdk_window_get_visible_region;
   drawable_class->get_composite_drawable = gdk_window_get_composite_drawable;
@@ -294,6 +347,95 @@ gdk_window_finalize (GObject *object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+/**
+ * gdk_window_new:
+ * @parent: a #GdkWindow, or %NULL to create the window as a child of
+ *   the default root window for the default display.
+ * @attributes: attributes of the new window
+ * @attributes_mask: mask indicating which fields in @attributes are valid
+ * 
+ * Creates a new #GdkWindow using the attributes from
+ * @attributes. See #GdkWindowAttr and #GdkWindowAttributesType for
+ * more details.  Note: to use this on displays other than the default
+ * display, @parent must be specified.
+ * 
+ * Return value: the new #GdkWindow
+ **/
+GdkWindow*
+gdk_window_new (GdkWindow     *parent,
+               GdkWindowAttr *attributes,
+               gint           attributes_mask)
+{
+  GdkWindow *window;
+  GdkWindowObject *private, *parent_private;
+  
+  g_return_val_if_fail (attributes != NULL, NULL);
+
+  window = _gdk_window_new (parent, attributes, attributes_mask);
+
+  /* Inherit redirection from parent */
+  if (parent != NULL)
+    {
+      parent_private = GDK_WINDOW_OBJECT (parent);
+      private = GDK_WINDOW_OBJECT (window);
+      private->redirect = parent_private->redirect;
+    }
+  
+  return window;
+}
+
+/**
+ * gdk_window_reparent:
+ * @window: a #GdkWindow
+ * @new_parent: new parent to move @window into
+ * @x: X location inside the new parent
+ * @y: Y location inside the new parent
+ *
+ * Reparents @window into the given @new_parent. The window being
+ * reparented will be unmapped as a side effect.
+ * 
+ **/
+void
+gdk_window_reparent (GdkWindow *window,
+                    GdkWindow *new_parent,
+                    gint       x,
+                    gint       y)
+{
+  GdkWindowObject *private;
+  gboolean show;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent));
+  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      (new_parent && GDK_WINDOW_DESTROYED (new_parent)))
+    {
+      return;
+    }
+
+  private = (GdkWindowObject *) window;
+
+  /* Break up redirection if inherited */
+  if (private->redirect && private->redirect->redirected != private)
+    {
+      remove_redirect_from_children (private, private->redirect);
+      private->redirect = NULL;
+    }
+  
+  show = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->reparent (window, new_parent, x, y);
+
+  /* Inherit parent redirect if we don't have our own */
+  if (private->parent && private->redirect == NULL)
+    {
+      private->redirect = private->parent->redirect;
+      apply_redirect_to_children (private, private->redirect);
+    }
+
+  if (show)
+    gdk_window_show (window);
+}
+
 static void
 window_remove_filters (GdkWindow *window)
 {
@@ -335,6 +477,7 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
   GdkWindowObject *private;
   GdkWindowObject *temp_private;
   GdkWindow *temp_window;
+  GdkScreen *screen;
   GList *children;
   GList *tmp;
   
@@ -347,6 +490,14 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
     
   switch (GDK_WINDOW_TYPE (window))
     {
+    case GDK_WINDOW_ROOT:
+      screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
+      if (!screen->closed)
+       {
+         g_error ("attempted to destroy root window");
+         break;
+       }
+      /* else fall thru */
     case GDK_WINDOW_TOPLEVEL:
     case GDK_WINDOW_CHILD:
     case GDK_WINDOW_DIALOG:
@@ -420,12 +571,14 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
          window_remove_filters (window);
 
           gdk_drawable_set_colormap (GDK_DRAWABLE (window), NULL);
+
+         /* If we own the redirect, free it */
+         if (private->redirect && private->redirect->redirected == private)
+           gdk_window_redirect_free (private->redirect);
+
+         private->redirect = NULL;
        }
       break;
-      
-    case GDK_WINDOW_ROOT:
-      g_error ("attempted to destroy root window");
-      break;
     }
 }
 
@@ -654,7 +807,9 @@ gdk_window_peek_children (GdkWindow *window)
  * easy to break GDK and/or GTK+, so you have to know what you're
  * doing. Pass %NULL for @window to get all events for all windows,
  * instead of events for a specific window.
- * 
+ *
+ * See gdk_display_add_client_message_filter() if you are interested
+ * in X ClientMessage events.
  **/
 void          
 gdk_window_add_filter (GdkWindow     *window,
@@ -782,7 +937,7 @@ gdk_screen_get_toplevel_windows (GdkScreen *screen)
  * gdk_window_get_toplevels:
  * 
  * Obtains a list of all toplevel windows known to GDK on the default
- * screen (see gdk_window_get_toplevels_for_screen()).
+ * screen (see gdk_screen_get_toplevel_windows()).
  * A toplevel window is a child of the root window (see
  * gdk_get_default_root_window()).
  *
@@ -881,8 +1036,8 @@ gdk_window_get_state (GdkWindow *window)
  * 
  **/
 void
-gdk_window_begin_paint_rect (GdkWindow    *window,
-                            GdkRectangle *rectangle)
+gdk_window_begin_paint_rect (GdkWindow          *window,
+                             const GdkRectangle *rectangle)
 {
   GdkRegion *region;
 
@@ -944,8 +1099,8 @@ gdk_window_begin_paint_rect (GdkWindow    *window,
  * 
  **/
 void         
-gdk_window_begin_paint_region (GdkWindow *window,
-                              GdkRegion *region)
+gdk_window_begin_paint_region (GdkWindow       *window,
+                               const GdkRegion *region)
 {
 #ifdef USE_BACKING_STORE
   GdkWindowObject *private = (GdkWindowObject *)window;
@@ -959,6 +1114,16 @@ gdk_window_begin_paint_region (GdkWindow *window,
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
+  if (GDK_IS_PAINTABLE (private->impl)) 
+    {
+      GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl);
+
+      if (iface->begin_paint_region)
+        iface->begin_paint_region ((GdkPaintable*)private->impl, region);
+
+      return;
+    }
+
   gdk_region_get_clipbox (region, &clip_box);
 
   paint = g_new (GdkWindowPaint, 1);
@@ -969,6 +1134,10 @@ gdk_window_begin_paint_region (GdkWindow *window,
     gdk_pixmap_new (window,
                    MAX (clip_box.width, 1), MAX (clip_box.height, 1), -1);
 
+  paint->surface = _gdk_drawable_ref_cairo_surface (paint->pixmap);
+  cairo_surface_set_device_offset (paint->surface,
+                                  - paint->x_offset, - paint->y_offset);
+  
   for (list = private->paint_stack; list != NULL; list = list->next)
     {
       GdkWindowPaint *tmp_paint = list->data;
@@ -1005,6 +1174,7 @@ gdk_window_end_paint (GdkWindow *window)
 {
 #ifdef USE_BACKING_STORE
   GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkWindowObject *composited;
   GdkWindowPaint *paint;
   GdkGC *tmp_gc;
   GdkRectangle clip_box;
@@ -1016,6 +1186,15 @@ gdk_window_end_paint (GdkWindow *window)
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
+  if (GDK_IS_PAINTABLE (private->impl))
+    {
+      GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl);
+
+      if (iface->end_paint)
+        iface->end_paint ((GdkPaintable*)private->impl);
+      return;
+    }
+
   if (private->paint_stack == NULL)
     {
       g_warning (G_STRLOC": no preceding call to gdk_window_begin_paint_region(), see documentation");
@@ -1030,7 +1209,7 @@ gdk_window_end_paint (GdkWindow *window)
 
   tmp_gc = _gdk_drawable_get_scratch_gc (window, FALSE);
 
-  _gdk_windowing_window_get_offsets (window, &x_offset, &y_offset);
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (window, &x_offset, &y_offset);
 
   gdk_gc_set_clip_region (tmp_gc, paint->region);
   gdk_gc_set_clip_origin (tmp_gc, - x_offset, - y_offset);
@@ -1041,12 +1220,55 @@ gdk_window_end_paint (GdkWindow *window)
                      clip_box.x - x_offset, clip_box.y - y_offset,
                      clip_box.width, clip_box.height);
 
+  if (private->redirect)
+    {
+      GdkWindowClipData data;
+      
+      setup_redirect_clip (window, tmp_gc, &data);
+      gdk_draw_drawable (private->redirect->pixmap, tmp_gc, paint->pixmap,
+                        clip_box.x - paint->x_offset,
+                        clip_box.y - paint->y_offset,
+                        clip_box.x + data.x_offset,
+                        clip_box.y + data.y_offset,
+                        clip_box.width, clip_box.height);
+      reset_redirect_clip (window, tmp_gc, &data);
+    }
+  
   /* Reset clip region of the cached GdkGC */
   gdk_gc_set_clip_region (tmp_gc, NULL);
-  
+
+  cairo_surface_destroy (paint->surface);
   g_object_unref (paint->pixmap);
   gdk_region_destroy (paint->region);
   g_free (paint);
+
+  /* find a composited window in our hierarchy to signal its
+   * parent to redraw, calculating the clip box as we go...
+   *
+   * stop if parent becomes NULL since then we'd have nowhere
+   * to draw (ie: 'composited' will always be non-NULL here).
+   */
+  for (composited = private;
+       composited->parent;
+       composited = composited->parent)
+    {
+      int width, height;
+
+      gdk_drawable_get_size (GDK_DRAWABLE (composited->parent),
+                            &width, &height);
+
+      clip_box.x += composited->x;
+      clip_box.y += composited->y;
+      clip_box.width = MIN (clip_box.width, width - clip_box.x);
+      clip_box.height = MIN (clip_box.height, height - clip_box.y);
+
+      if (composited->composited)
+       {
+         gdk_window_invalidate_rect (GDK_WINDOW (composited->parent),
+                                     &clip_box, FALSE);
+         break;
+       }
+    }
 #endif /* USE_BACKING_STORE */
 }
 
@@ -1091,7 +1313,7 @@ gdk_window_get_offsets (GdkWindow *window,
       *y_offset = paint->y_offset;
     }
   else
-    _gdk_windowing_window_get_offsets (window, x_offset, y_offset);
+    GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (window, x_offset, y_offset);
 }
 
 /**
@@ -1205,7 +1427,7 @@ gdk_window_draw_rectangle (GdkDrawable *drawable,
     {
       GdkWindowPaint *paint = private->paint_stack->data;
       gdk_draw_rectangle (paint->pixmap, gc, filled,
-                         x - x_offset, y - y_offset, width, height);
+                          x - x_offset, y - y_offset, width, height);
     }
   else
     gdk_draw_rectangle (private->impl, gc, filled,
@@ -1362,9 +1584,9 @@ gdk_window_get_composite_drawable (GdkDrawable *drawable,
   GdkGC *tmp_gc;
   gboolean overlap_buffer;
 
-  _gdk_windowing_window_get_offsets (drawable,
-                                    composite_x_offset,
-                                    composite_y_offset);
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (GDK_WINDOW (drawable),
+                                                          composite_x_offset,
+                                                          composite_y_offset);
   
   if ((GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable))
       || private->paint_stack == NULL)
@@ -1697,6 +1919,15 @@ gdk_window_draw_glyphs_transformed (GdkDrawable      *drawable,
          tmp_matrix.y0 -= y_offset;
          matrix = &tmp_matrix;
        }
+      else if (GDK_PANGO_UNITS_OVERFLOWS (x_offset, y_offset))
+       {
+         PangoMatrix identity = PANGO_MATRIX_INIT;
+         
+         tmp_matrix = identity;
+         tmp_matrix.x0 -= x_offset;
+         tmp_matrix.y0 -= y_offset;
+         matrix = &tmp_matrix;
+       }
       else
        {
          x -= x_offset * PANGO_SCALE;
@@ -1716,41 +1947,86 @@ gdk_window_draw_glyphs_transformed (GdkDrawable      *drawable,
   RESTORE_GC (gc);
 }
 
-static GdkGC *
-gdk_window_get_bg_gc (GdkWindow      *window,
-                     GdkWindowPaint *paint)
+typedef struct {
+  cairo_t *cr; /* if non-null, it means use this cairo context */
+  GdkGC *gc;   /* if non-null, it means use this GC instead */
+} BackingRectMethod;
+
+static void
+setup_backing_rect_method (BackingRectMethod *method, GdkWindow *window, GdkWindowPaint *paint, int x_offset_cairo, int y_offset_cairo)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
 
-  guint gc_mask = 0;
-  GdkGCValues gc_values;
-
   if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG && private->parent)
     {
-      GdkWindowPaint tmp_paint = *paint;
+      GdkWindowPaint tmp_paint;
+
+      tmp_paint = *paint;
       tmp_paint.x_offset += private->x;
       tmp_paint.y_offset += private->y;
-      
-      return gdk_window_get_bg_gc (GDK_WINDOW (private->parent), &tmp_paint);
+
+      x_offset_cairo += private->x;
+      y_offset_cairo += private->y;
+
+      setup_backing_rect_method (method, GDK_WINDOW (private->parent), &tmp_paint, x_offset_cairo, y_offset_cairo);
     }
-  else if (private->bg_pixmap && 
-           private->bg_pixmap != GDK_PARENT_RELATIVE_BG && 
-           private->bg_pixmap != GDK_NO_BG)
+  else if (private->bg_pixmap &&
+          private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
+          private->bg_pixmap != GDK_NO_BG)
     {
+/* This is a workaround for https://bugs.freedesktop.org/show_bug.cgi?id=4320.
+ * In it, using a pixmap as a repeating pattern in Cairo, and painting it to a
+ * pixmap destination surface, can be very slow (on the order of seconds for a
+ * whole-screen copy).  The workaround is to use pretty much the same code that
+ * we used in GTK+ 2.6 (pre-Cairo), which clears the double-buffer pixmap with
+ * a tiled GC XFillRectangle().
+ */
+
+/* Actually computing this flag is left as an exercise for the reader */
+#if defined (G_OS_UNIX)
+#  define GDK_CAIRO_REPEAT_IS_FAST 0
+#else
+#  define GDK_CAIRO_REPEAT_IS_FAST 1
+#endif
+
+#if GDK_CAIRO_REPEAT_IS_FAST
+      cairo_surface_t *surface = _gdk_drawable_ref_cairo_surface (private->bg_pixmap);
+      cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
+      cairo_surface_destroy (surface);
+
+      if (x_offset_cairo != 0 || y_offset_cairo != 0)
+       {
+         cairo_matrix_t matrix;
+         cairo_matrix_init_translate (&matrix, x_offset_cairo, y_offset_cairo);
+         cairo_pattern_set_matrix (pattern, &matrix);
+       }
+
+      cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+
+      method->cr = cairo_create (paint->surface);
+      method->gc = NULL;
+
+      cairo_set_source (method->cr, pattern);
+      cairo_pattern_destroy (pattern);
+#else
+      guint gc_mask;
+      GdkGCValues gc_values;
+
       gc_values.fill = GDK_TILED;
       gc_values.tile = private->bg_pixmap;
-      
-      gc_mask = GDK_GC_FILL | GDK_GC_TILE;
+      gc_values.ts_x_origin = -x_offset_cairo;
+      gc_values.ts_y_origin = -y_offset_cairo;
 
-      return gdk_gc_new_with_values (paint->pixmap, &gc_values, gc_mask);
+      gc_mask = GDK_GC_FILL | GDK_GC_TILE | GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN;
+
+      method->gc = gdk_gc_new_with_values (paint->pixmap, &gc_values, gc_mask);
+#endif
     }
   else
     {
-      GdkGC *gc = _gdk_drawable_get_scratch_gc (paint->pixmap, FALSE);
+      method->cr = cairo_create (paint->surface);
 
-      gdk_gc_set_foreground (gc, &(private->bg_color));
-
-      return g_object_ref (gc);
+      gdk_cairo_set_source_color (method->cr, &private->bg_color);
     }
 }
 
@@ -1763,22 +2039,117 @@ gdk_window_clear_backing_rect (GdkWindow *window,
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   GdkWindowPaint *paint = private->paint_stack->data;
-  GdkGC *tmp_gc;
+  BackingRectMethod method;
+#if 0
+  GTimer *timer;
+  double elapsed;
+#endif
 
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
-  tmp_gc = gdk_window_get_bg_gc (window, paint);
-  gdk_gc_set_clip_region (tmp_gc, paint->region);
+#if 0
+  timer = g_timer_new ();
+#endif
+
+  method.cr = NULL;
+  method.gc = NULL;
+  setup_backing_rect_method (&method, window, paint, 0, 0);
+
+  if (method.cr)
+    {
+      g_assert (method.gc == NULL);
+
+      cairo_rectangle (method.cr, x, y, width, height);
+      cairo_clip (method.cr);
+
+      gdk_cairo_region (method.cr, paint->region);
+      cairo_fill (method.cr);
+
+      cairo_destroy (method.cr);
+#if 0
+      elapsed = g_timer_elapsed (timer, NULL);
+      g_print ("Draw the background with Cairo: %fs\n", elapsed);
+#endif
+    }
+  else
+    {
+      g_assert (method.gc != NULL);
+
+      gdk_gc_set_clip_region (method.gc, paint->region);
+      gdk_draw_rectangle (window, method.gc, TRUE, x, y, width, height);
+      g_object_unref (method.gc);
+
+#if 0
+      elapsed = g_timer_elapsed (timer, NULL);
+      g_print ("Draw the background with GDK: %fs\n", elapsed);
+#endif
+    }
+
+#if 0
+  g_timer_destroy (timer);
+#endif
+}
+
+static void
+gdk_window_clear_backing_rect_redirect (GdkWindow *window,
+                                       gint       x,
+                                       gint       y,
+                                       gint       width,
+                                       gint       height)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkWindowRedirect *redirect = private->redirect;
+  GdkRegion *clip_region;
+  gint x_offset, y_offset;
+  BackingRectMethod method;
+  GdkWindowPaint paint;
   
-  gdk_draw_rectangle (window, tmp_gc, TRUE,
-                     x, y, width, height);
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
 
-  gdk_gc_set_clip_region (tmp_gc, NULL);
+  paint.x_offset = x_offset;
+  paint.y_offset = y_offset;
+  paint.pixmap = redirect->pixmap;
+  paint.surface = _gdk_drawable_ref_cairo_surface (redirect->pixmap);
   
-  g_object_unref (tmp_gc);
+  clip_region = _gdk_window_calculate_full_clip_region (window,
+                                                       GDK_WINDOW (redirect->redirected),
+                                                       NULL, TRUE,
+                                                       &x_offset, &y_offset);
+  
+
+  method.cr = NULL;
+  method.gc = NULL;
+  setup_backing_rect_method (&method, window, &paint, 0, 0);
+
+  if (method.cr)
+    {
+      g_assert (method.gc == NULL);
+
+      cairo_rectangle (method.cr, x, y, width, height);
+      cairo_clip (method.cr);
+
+      gdk_cairo_region (method.cr, clip_region);
+      cairo_fill (method.cr);
+
+      cairo_destroy (method.cr);
+    }
+  else
+    {
+      g_assert (method.gc != NULL);
+
+      gdk_gc_set_clip_region (method.gc, clip_region);
+      gdk_draw_rectangle (window, method.gc, TRUE, x, y, width, height);
+      g_object_unref (method.gc);
+
+    }
+
+  gdk_region_destroy (clip_region);
+  cairo_surface_destroy (paint.surface);
 }
 
+
 /**
  * gdk_window_clear:
  * @window: a #GdkWindow
@@ -1821,11 +2192,19 @@ gdk_window_clear_area (GdkWindow *window,
 
   g_return_if_fail (window != NULL);
   g_return_if_fail (GDK_IS_WINDOW (window));
-  
+
   if (private->paint_stack)
     gdk_window_clear_backing_rect (window, x, y, width, height);
   else
-    _gdk_windowing_window_clear_area (window, x, y, width, height);
+    {
+      if (private->redirect)
+       gdk_window_clear_backing_rect_redirect (window, x, y, width, height);
+
+      GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_area (window,
+                                                             x, y,
+                                                             width, height,
+                                                             FALSE);
+    }
 }
 
 /**
@@ -1858,7 +2237,13 @@ gdk_window_clear_area_e (GdkWindow *window,
   if (private->paint_stack)
     gdk_window_clear_backing_rect (window, x, y, width, height);
 
-  _gdk_windowing_window_clear_area_e (window, x, y, width, height);
+  if (private->redirect)
+    gdk_window_clear_backing_rect_redirect (window, x, y, width, height);
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_area (window,
+                                                         x, y,
+                                                         width, height,
+                                                         TRUE);
 }
 
 static void
@@ -1995,8 +2380,7 @@ gdk_window_draw_trapezoids (GdkDrawable   *drawable,
   else
     gdk_draw_trapezoids (private->impl, gc, trapezoids, n_trapezoids);
   
-  if (new_trapezoids)
-    g_free (new_trapezoids);
+  g_free (new_trapezoids);
 
   RESTORE_GC (gc);
 }
@@ -2070,6 +2454,7 @@ gdk_window_copy_to_image (GdkDrawable     *drawable,
                          gint             width,
                          gint             height)
 {
+  GdkWindowObject *private = (GdkWindowObject *) drawable;
   gint x_offset, y_offset;
   
   g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
@@ -2081,9 +2466,10 @@ gdk_window_copy_to_image (GdkDrawable     *drawable,
    * we can ignore the paint stack.
    */
   
-  _gdk_windowing_window_get_offsets (drawable, &x_offset, &y_offset);
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (drawable,
+                                                          &x_offset, &y_offset);
   
-  return gdk_drawable_copy_to_image (((GdkWindowObject*)drawable)->impl,
+  return gdk_drawable_copy_to_image (private->impl,
                                     image,
                                     src_x - x_offset,
                                     src_y - y_offset,
@@ -2091,6 +2477,25 @@ gdk_window_copy_to_image (GdkDrawable     *drawable,
                                     width, height);
 }
 
+static cairo_surface_t *
+gdk_window_ref_cairo_surface (GdkDrawable *drawable)
+{
+  GdkWindowObject *private = (GdkWindowObject*) drawable;
+  cairo_surface_t *surface;
+
+  if (private->paint_stack)
+    {
+      GdkWindowPaint *paint = private->paint_stack->data;
+
+      surface = paint->surface;
+      cairo_surface_reference (surface);
+    }
+  else
+    surface = _gdk_drawable_ref_cairo_surface (private->impl);
+
+  return surface;
+}
+
 /* Code for dirty-region queueing
  */
 static GSList *update_windows = NULL;
@@ -2100,22 +2505,32 @@ static gboolean debug_updates = FALSE;
 static gboolean
 gdk_window_update_idle (gpointer data)
 {
-  GDK_THREADS_ENTER ();
   gdk_window_process_all_updates ();
-  GDK_THREADS_LEAVE ();
   
   return FALSE;
 }
 
+static gboolean
+gdk_window_is_toplevel_frozen (GdkWindow *window)
+{
+  GdkWindowObject *toplevel;
+
+  toplevel = (GdkWindowObject *)gdk_window_get_toplevel (window);
+
+  return toplevel->update_and_descendants_freeze_count > 0;
+}
+
 static void
 gdk_window_schedule_update (GdkWindow *window)
 {
-  if (window && GDK_WINDOW_OBJECT (window)->update_freeze_count)
+  if (window &&
+      (GDK_WINDOW_OBJECT (window)->update_freeze_count ||
+       gdk_window_is_toplevel_frozen (window)))
     return;
 
   if (!update_idle)
     {
-      update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW,
+      update_idle = gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
                                     gdk_window_update_idle, NULL, NULL);
     }
 }
@@ -2175,6 +2590,7 @@ gdk_window_process_updates_internal (GdkWindow *window)
              
              event.expose.type = GDK_EXPOSE;
              event.expose.window = g_object_ref (window);
+             event.expose.send_event = FALSE;
              event.expose.count = 0;
              event.expose.region = expose_region;
              gdk_region_get_clipbox (expose_region, &event.expose.area);
@@ -2204,6 +2620,16 @@ flush_all_displays (void)
   g_slist_free (displays);
 }
 
+/* Currently it is not possible to override
+ * gdk_window_process_all_updates in the same manner as
+ * gdk_window_process_updates and gdk_window_invalidate_maybe_recurse
+ * by implementing the GdkPaintable interface.  If in the future a
+ * backend would need this, the right solution would be to add a
+ * method to GdkDisplay that can be optionally
+ * NULL. gdk_window_process_all_updates can then walk the list of open
+ * displays and call the mehod.
+ */
+
 /**
  * gdk_window_process_all_updates:
  *
@@ -2229,11 +2655,15 @@ gdk_window_process_all_updates (void)
     {
       GdkWindowObject *private = (GdkWindowObject *)tmp_list->data;
       
-      if (private->update_freeze_count)
-       update_windows = g_slist_prepend (update_windows, private);
-      else
-       gdk_window_process_updates_internal (tmp_list->data);
-      
+      if (!GDK_WINDOW_DESTROYED (tmp_list->data))
+        {
+         if (private->update_freeze_count ||
+             gdk_window_is_toplevel_frozen (tmp_list->data))
+           update_windows = g_slist_prepend (update_windows, private);
+         else
+           gdk_window_process_updates_internal (tmp_list->data);
+       }
+
       g_object_unref (tmp_list->data);
       tmp_list = tmp_list->next;
     }
@@ -2267,7 +2697,19 @@ gdk_window_process_updates (GdkWindow *window,
   g_return_if_fail (window != NULL);
   g_return_if_fail (GDK_IS_WINDOW (window));
   
-  if (private->update_area && !private->update_freeze_count)
+  if (GDK_IS_PAINTABLE (private->impl))
+    {
+      GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl);
+
+      if (iface->process_updates)
+        iface->process_updates ((GdkPaintable*)private->impl, update_children);
+
+      return;
+    }
+  
+  if (private->update_area &&
+      !private->update_freeze_count &&
+      !gdk_window_is_toplevel_frozen (window))
     {      
       gdk_window_process_updates_internal (window);
       update_windows = g_slist_remove (update_windows, window);
@@ -2287,18 +2729,18 @@ gdk_window_process_updates (GdkWindow *window,
 /**
  * gdk_window_invalidate_rect:
  * @window: a #GdkWindow
- * @rect: rectangle to invalidate
+ * @rect: rectangle to invalidate or %NULL to invalidate the whole
+ *      window
  * @invalidate_children: whether to also invalidate child windows
  *
  * A convenience wrapper around gdk_window_invalidate_region() which
  * invalidates a rectangular region. See
  * gdk_window_invalidate_region() for details.
- * 
  **/
 void
-gdk_window_invalidate_rect   (GdkWindow    *window,
-                             GdkRectangle *rect,
-                             gboolean      invalidate_children)
+gdk_window_invalidate_rect (GdkWindow          *window,
+                            const GdkRectangle *rect,
+                            gboolean            invalidate_children)
 {
   GdkRectangle window_rect;
   GdkRegion *region;
@@ -2329,8 +2771,8 @@ gdk_window_invalidate_rect   (GdkWindow    *window,
 }
 
 static void
-draw_ugly_color (GdkWindow *window,
-                GdkRegion *region)
+draw_ugly_color (GdkWindow       *window,
+                 const GdkRegion *region)
 {
   /* Draw ugly color all over the newly-invalid region */
   GdkColor ugly_color = { 0, 50000, 10000, 10000 };
@@ -2378,13 +2820,15 @@ draw_ugly_color (GdkWindow *window,
  * invalidated.
  **/
 void
-gdk_window_invalidate_maybe_recurse (GdkWindow *window,
-                                    GdkRegion *region,
-                                    gboolean (*child_func) (GdkWindow *, gpointer),
+gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
+                                     const GdkRegion *region,
+                                     gboolean       (*child_func) (GdkWindow *,
+                                                                   gpointer),
                                     gpointer   user_data)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   GdkRegion *visible_region;
+  GList *tmp_list;
 
   g_return_if_fail (window != NULL);
   g_return_if_fail (GDK_IS_WINDOW (window));
@@ -2395,14 +2839,77 @@ gdk_window_invalidate_maybe_recurse (GdkWindow *window,
   if (private->input_only || !GDK_WINDOW_IS_MAPPED (window))
     return;
 
-  visible_region = gdk_drawable_get_visible_region (window);
+  if (GDK_IS_PAINTABLE (private->impl))
+    {
+      GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl);
+
+      if (iface->invalidate_maybe_recurse)
+        iface->invalidate_maybe_recurse ((GdkPaintable*)private->impl, 
+                                         region, child_func, user_data);
+      return;
+    }
+
+  /* windows that a redirection has ben setup for need to be considered
+   * fully visible, in order to avoid missing redirected paint ops
+   * anywhere in the window area.
+   */
+  if (private->redirect && private->redirect->redirected == private)
+    {
+      GdkRectangle visible_rect = { 0, 0, 0, 0 };
+      gdk_drawable_get_size (GDK_DRAWABLE (window), &visible_rect.width, &visible_rect.height);
+      visible_region = gdk_region_rectangle (&visible_rect);
+    }
+  else
+    visible_region = gdk_drawable_get_visible_region (window);
   gdk_region_intersect (visible_region, region);
 
+  tmp_list = private->children;
+  while (tmp_list)
+    {
+      GdkWindowObject *child = tmp_list->data;
+      
+      if (!child->input_only)
+       {
+         GdkRegion *child_region;
+         GdkRectangle child_rect;
+         
+         gdk_window_get_position ((GdkWindow *)child,
+                                  &child_rect.x, &child_rect.y);
+         gdk_drawable_get_size ((GdkDrawable *)child,
+                                &child_rect.width, &child_rect.height);
+
+         child_region = gdk_region_rectangle (&child_rect);
+         
+         /* remove child area from the invalid area of the parent */
+         if (GDK_WINDOW_IS_MAPPED (child) && !child->shaped &&
+             !child->composited)
+           gdk_region_subtract (visible_region, child_region);
+         
+         if (child_func && (*child_func) ((GdkWindow *)child, user_data))
+           {
+              GdkRegion *tmp = gdk_region_copy (region);
+
+             gdk_region_offset (tmp, - child_rect.x, - child_rect.y);
+             gdk_region_offset (child_region, - child_rect.x, - child_rect.y);
+             gdk_region_intersect (child_region, tmp);
+             
+             gdk_window_invalidate_maybe_recurse ((GdkWindow *)child,
+                                                  child_region, child_func, user_data);
+             
+             gdk_region_destroy (tmp);
+           }
+
+         gdk_region_destroy (child_region);
+       }
+
+      tmp_list = tmp_list->next;
+    }
+  
   if (!gdk_region_empty (visible_region))
     {
       if (debug_updates)
         draw_ugly_color (window, region);
-      
+
       if (private->update_area)
        {
          gdk_region_union (private->update_area, visible_region);
@@ -2414,38 +2921,10 @@ gdk_window_invalidate_maybe_recurse (GdkWindow *window,
          
          gdk_window_schedule_update (window);
        }
-      
-      if (child_func)
-       {
-         GList *tmp_list;
-         
-         tmp_list = private->children;
-         while (tmp_list)
-           {
-             GdkWindowObject *child = tmp_list->data;
-             tmp_list = tmp_list->next;
-
-             if (!child->input_only && (*child_func) ((GdkWindow *)child, user_data))
-               {
-                 GdkRegion *child_region;
-                 gint x, y;
-
-                 gdk_window_get_position ((GdkWindow *)child, &x, &y);
-
-                 /* This copy could be saved with a little more complexity */
-                 child_region = gdk_region_copy (visible_region);
-                 gdk_region_offset (child_region, - x, - y);
-                 
-                 gdk_window_invalidate_maybe_recurse ((GdkWindow *)child, child_region, child_func, user_data);
-                 
-                 gdk_region_destroy (child_region);
-               }
-           }
-       }
-    }
-  
-  gdk_region_destroy (visible_region);
-}
+    }
+  
+  gdk_region_destroy (visible_region);
+}
 
 static gboolean
 true_predicate (GdkWindow *window,
@@ -2479,9 +2958,9 @@ true_predicate (GdkWindow *window,
  * fine grained control over which children are invalidated.
  **/
 void
-gdk_window_invalidate_region (GdkWindow *window,
-                             GdkRegion *region,
-                             gboolean   invalidate_children)
+gdk_window_invalidate_region (GdkWindow       *window,
+                             const GdkRegion *region,
+                             gboolean         invalidate_children)
 {
   gdk_window_invalidate_maybe_recurse (window, region,
                                       invalidate_children ?
@@ -2588,6 +3067,58 @@ gdk_window_thaw_updates (GdkWindow *window)
     gdk_window_schedule_update (window);
 }
 
+/**
+ * gdk_window_freeze_toplevel_updates_libgtk_only:
+ * @window: a #GdkWindow
+ *
+ * Temporarily freezes a window and all its descendants such that it won't
+ * receive expose events.  The window will begin receiving expose events
+ * again when gdk_window_thaw_toplevel_updates_libgtk_only() is called. If
+ * gdk_window_freeze_toplevel_updates_libgtk_only()
+ * has been called more than once,
+ * gdk_window_thaw_toplevel_updates_libgtk_only() must be called
+ * an equal number of times to begin processing exposes.
+ *
+ * This function is not part of the GDK public API and is only
+ * for use by GTK+.
+ **/
+void
+gdk_window_freeze_toplevel_updates_libgtk_only (GdkWindow *window)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (private->window_type != GDK_WINDOW_CHILD);
+
+  private->update_and_descendants_freeze_count++;
+}
+
+/**
+ * gdk_window_thaw_toplevel_updates_libgtk_only:
+ * @window: a #GdkWindow
+ * 
+ * Thaws a window frozen with
+ * gdk_window_freeze_toplevel_updates_libgtk_only().
+ *
+ * This function is not part of the GDK public API and is only
+ * for use by GTK+.
+ **/
+void
+gdk_window_thaw_toplevel_updates_libgtk_only (GdkWindow *window)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (private->window_type != GDK_WINDOW_CHILD);
+  g_return_if_fail (private->update_and_descendants_freeze_count > 0);
+
+  private->update_and_descendants_freeze_count--;
+
+  gdk_window_schedule_update (window);
+}
+
 /**
  * gdk_window_set_debug_updates:
  * @setting: %TRUE to turn on update debugging
@@ -2751,12 +3282,16 @@ gdk_window_constrain_size (GdkGeometry *geometry,
 /**
  * gdk_window_get_pointer:
  * @window: a #GdkWindow
- * @x: return location for X coordinate of pointer
- * @y: return location for Y coordinate of pointer
- * @mask: return location for modifier mask
+ * @x: return location for X coordinate of pointer or %NULL to not
+ *      return the X coordinate
+ * @y: return location for Y coordinate of pointer or %NULL to not
+ *      return the Y coordinate
+ * @mask: return location for modifier mask or %NULL to not return the
+ *      modifier mask
  *
  * Obtains the current pointer position and modifier state.
- * The position is given in coordinates relative to @window.
+ * The position is given in coordinates relative to the upper left 
+ * corner of @window.
  * 
  * Return value: the window containing the pointer (as with
  * gdk_window_at_pointer()), or %NULL if the window containing the
@@ -2859,3 +3394,1142 @@ gdk_window_foreign_new (GdkNativeWindow anid)
   return gdk_window_foreign_new_for_display (gdk_display_get_default (), anid);
 }
 
+/**
+ * gdk_window_show_unraised:
+ * @window: a #GdkWindow
+ *
+ * Shows a #GdkWindow onscreen, but does not modify its stacking
+ * order. In contrast, gdk_window_show() will raise the window
+ * to the top of the window stack.
+ *
+ * On the X11 platform, in Xlib terms, this function calls
+ * XMapWindow() (it also updates some internal GDK state, which means
+ * that you can't really use XMapWindow() directly on a GDK window).
+ */
+void
+gdk_window_show_unraised (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window, FALSE);
+}
+
+static inline void
+gdk_window_raise_internal (GdkWindow *window)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkWindowObject *parent = private->parent;
+
+  if (parent)
+    {
+      parent->children = g_list_remove (parent->children, window);
+      parent->children = g_list_prepend (parent->children, window);
+    }
+}
+
+/**
+ * gdk_window_raise:
+ * @window: a #GdkWindow
+ *
+ * Raises @window to the top of the Z-order (stacking order), so that
+ * other windows with the same parent window appear below @window.
+ * This is true whether or not the windows are visible.
+ *
+ * If @window is a toplevel, the window manager may choose to deny the
+ * request to move the window in the Z-order, gdk_window_raise() only
+ * requests the restack, does not guarantee it.
+ */
+void
+gdk_window_raise (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  /* Keep children in (reverse) stacking order */
+  gdk_window_raise_internal (window);
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (window);
+}
+
+static void
+gdk_window_lower_internal (GdkWindow *window)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkWindowObject *parent = private->parent;
+
+  if (parent)
+    {
+      parent->children = g_list_remove (parent->children, window);
+      parent->children = g_list_append (parent->children, window);
+    }
+}
+
+/**
+ * gdk_window_lower:
+ * @window: a #GdkWindow
+ *
+ * Lowers @window to the bottom of the Z-order (stacking order), so that
+ * other windows with the same parent window appear above @window.
+ * This is true whether or not the other windows are visible.
+ *
+ * If @window is a toplevel, the window manager may choose to deny the
+ * request to move the window in the Z-order, gdk_window_lower() only
+ * requests the restack, does not guarantee it.
+ *
+ * Note that gdk_window_show() raises the window again, so don't call this
+ * function before gdk_window_show(). (Try gdk_window_show_unraised().)
+ */
+void
+gdk_window_lower (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  /* Keep children in (reverse) stacking order */
+  gdk_window_lower_internal (window);
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->lower (window);
+}
+
+/**
+ * gdk_window_show:
+ * @window: a #GdkWindow
+ *
+ * Like gdk_window_show_unraised(), but also raises the window to the
+ * top of the window stack (moves the window to the front of the
+ * Z-order).
+ *
+ * This function maps a window so it's visible onscreen. Its opposite
+ * is gdk_window_hide().
+ *
+ * When implementing a #GtkWidget, you should call this function on the widget's
+ * #GdkWindow as part of the "map" method.
+ */
+void
+gdk_window_show (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  /* Keep children in (reverse) stacking order */
+  gdk_window_raise_internal (window);
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window, TRUE);
+}
+
+/**
+ * gdk_window_hide:
+ * @window: a #GdkWindow
+ *
+ * For toplevel windows, withdraws them, so they will no longer be
+ * known to the window manager; for all windows, unmaps them, so
+ * they won't be displayed. Normally done automatically as
+ * part of gtk_widget_hide().
+ */
+void
+gdk_window_hide (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->hide (window);
+}
+
+/**
+ * gdk_window_withdraw:
+ * @window: a toplevel #GdkWindow
+ *
+ * Withdraws a window (unmaps it and asks the window manager to forget about it).
+ * This function is not really useful as gdk_window_hide() automatically
+ * withdraws toplevel windows before hiding them.
+ **/
+void
+gdk_window_withdraw (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->withdraw (window);
+}
+
+/**
+ * gdk_window_set_events:
+ * @window: a #GdkWindow
+ * @event_mask: event mask for @window
+ *
+ * The event mask for a window determines which events will be reported
+ * for that window. For example, an event mask including #GDK_BUTTON_PRESS_MASK
+ * means the window should report button press events. The event mask
+ * is the bitwise OR of values from the #GdkEventMask enumeration.
+ **/
+void
+gdk_window_set_events (GdkWindow       *window,
+                      GdkEventMask     event_mask)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window, event_mask);
+}
+
+/**
+ * gdk_window_get_events:
+ * @window: a #GdkWindow
+ *
+ * Gets the event mask for @window. See gdk_window_set_events().
+ *
+ * Return value: event mask for @window
+ **/
+GdkEventMask
+gdk_window_get_events (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return 0;
+
+  return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_events (window);
+}
+
+/**
+ * gdk_window_move:
+ * @window: a #GdkWindow
+ * @x: X coordinate relative to window's parent
+ * @y: Y coordinate relative to window's parent
+ *
+ * Repositions a window relative to its parent window.
+ * For toplevel windows, window managers may ignore or modify the move;
+ * you should probably use gtk_window_move() on a #GtkWindow widget
+ * anyway, instead of using GDK functions. For child windows,
+ * the move will reliably succeed.
+ *
+ * If you're also planning to resize the window, use gdk_window_move_resize()
+ * to both move and resize simultaneously, for a nicer visual effect.
+ **/
+void
+gdk_window_move (GdkWindow *window,
+                gint       x,
+                gint       y)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, TRUE, x, y, -1, -1);
+}
+
+/**
+ * gdk_window_resize:
+ * @window: a #GdkWindow
+ * @width: new width of the window
+ * @height: new height of the window
+ *
+ * Resizes @window; for toplevel windows, asks the window manager to resize
+ * the window. The window manager may not allow the resize. When using GTK+,
+ * use gtk_window_resize() instead of this low-level GDK function.
+ *
+ * Windows may not be resized below 1x1.
+ *
+ * If you're also planning to move the window, use gdk_window_move_resize()
+ * to both move and resize simultaneously, for a nicer visual effect.
+ **/
+void
+gdk_window_resize (GdkWindow *window,
+                  gint       width,
+                  gint       height)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, FALSE, 0, 0, width, height);
+}
+
+
+/**
+ * gdk_window_move_resize:
+ * @window: a #GdkWindow
+ * @x: new X position relative to window's parent
+ * @y: new Y position relative to window's parent
+ * @width: new width
+ * @height: new height
+ *
+ * Equivalent to calling gdk_window_move() and gdk_window_resize(),
+ * except that both operations are performed at once, avoiding strange
+ * visual effects. (i.e. the user may be able to see the window first
+ * move, then resize, if you don't use gdk_window_move_resize().)
+ **/
+void
+gdk_window_move_resize (GdkWindow *window,
+                       gint       x,
+                       gint       y,
+                       gint       width,
+                       gint       height)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, TRUE, x, y, width, height);
+}
+
+
+/**
+ * gdk_window_scroll:
+ * @window: a #GdkWindow
+ * @dx: Amount to scroll in the X direction
+ * @dy: Amount to scroll in the Y direction
+ *
+ * Scroll the contents of @window, both pixels and children, by the
+ * given amount. @window itself does not move. Portions of the window
+ * that the scroll operation brings in from offscreen areas are
+ * invalidated. The invalidated region may be bigger than what would
+ * strictly be necessary.
+ *
+ * For X11, a minimum area will be invalidated if the window has no
+ * subwindows, or if the edges of the window's parent do not extend
+ * beyond the edges of the window. In other cases, a multi-step process
+ * is used to scroll the window which may produce temporary visual
+ * artifacts and unnecessary invalidations.
+ **/
+void
+gdk_window_scroll (GdkWindow *window,
+                  gint       dx,
+                  gint       dy)
+{
+  GdkWindowObject *private = (GdkWindowObject *) window;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if (dx == 0 && dy == 0)
+    return;
+
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->scroll (window, dx, dy);
+}
+
+/**
+ * gdk_window_move_region:
+ * @window: a #GdkWindow
+ * @region: The #GdkRegion to move
+ * @dx: Amount to move in the X direction
+ * @dy: Amount to move in the Y direction
+ *
+ * Move the part of @window indicated by @region by @dy pixels in the Y
+ * direction and @dx pixels in the X direction. The portions of @region
+ * that not covered by the new position of @region are invalidated.
+ *
+ * Child windows are not moved.
+ *
+ * Since: 2.8
+ */
+void
+gdk_window_move_region (GdkWindow       *window,
+                       const GdkRegion *region,
+                       gint             dx,
+                       gint             dy)
+{
+  GdkWindowObject *private = (GdkWindowObject *) window;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (region != NULL);
+
+  if (dx == 0 && dy == 0)
+    return;
+
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_region (window, region, dx, dy);
+}
+
+/**
+ * gdk_window_set_background:
+ * @window: a #GdkWindow
+ * @color: an allocated #GdkColor
+ *
+ * Sets the background color of @window. (However, when using GTK+,
+ * set the background of a widget with gtk_widget_modify_bg() - if
+ * you're an application - or gtk_style_set_background() - if you're
+ * implementing a custom widget.)
+ *
+ * The @color must be allocated; gdk_rgb_find_color() is the best way
+ * to allocate a color.
+ *
+ * See also gdk_window_set_back_pixmap().
+ */
+void
+gdk_window_set_background (GdkWindow      *window,
+                          const GdkColor *color)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, color);
+}
+
+/**
+ * gdk_window_set_back_pixmap:
+ * @window: a #GdkWindow
+ * @pixmap: a #GdkPixmap, or %NULL
+ * @parent_relative: whether the tiling origin is at the origin of
+ *   @window's parent
+ *
+ * Sets the background pixmap of @window. May also be used to set a
+ * background of "None" on @window, by setting a background pixmap
+ * of %NULL.
+ *
+ * A background pixmap will be tiled, positioning the first tile at
+ * the origin of @window, or if @parent_relative is %TRUE, the tiling
+ * will be done based on the origin of the parent window (useful to
+ * align tiles in a parent with tiles in a child).
+ *
+ * A background pixmap of %NULL means that the window will have no
+ * background.  A window with no background will never have its
+ * background filled by the windowing system, instead the window will
+ * contain whatever pixels were already in the corresponding area of
+ * the display.
+ *
+ * The windowing system will normally fill a window with its background
+ * when the window is obscured then exposed, and when you call
+ * gdk_window_clear().
+ */
+void
+gdk_window_set_back_pixmap (GdkWindow *window,
+                           GdkPixmap *pixmap,
+                           gboolean   parent_relative)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (pixmap == NULL || !parent_relative);
+  g_return_if_fail (pixmap == NULL || gdk_drawable_get_depth (window) == gdk_drawable_get_depth (pixmap));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, pixmap, parent_relative);
+}
+
+/**
+ * gdk_window_set_cursor:
+ * @window: a #GdkWindow
+ * @cursor: a cursor
+ *
+ * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new() or
+ * gdk_cursor_new_from_pixmap() to create the cursor.
+ * To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create
+ * a cursor with no pixels in it. Passing %NULL for the @cursor argument
+ * to gdk_window_set_cursor() means that @window will use the cursor of
+ * its parent window. Most windows should use this default.
+ */
+void
+gdk_window_set_cursor (GdkWindow *window,
+                      GdkCursor *cursor)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_cursor (window, cursor);
+}
+
+/**
+ * gdk_window_get_geometry:
+ * @window: a #GdkWindow
+ * @x: return location for X coordinate of window (relative to its parent)
+ * @y: return location for Y coordinate of window (relative to its parent)
+ * @width: return location for width of window
+ * @height: return location for height of window
+ * @depth: return location for bit depth of window
+ *
+ * Any of the return location arguments to this function may be %NULL,
+ * if you aren't interested in getting the value of that field.
+ *
+ * The X and Y coordinates returned are relative to the parent window
+ * of @window, which for toplevels usually means relative to the
+ * window decorations (titlebar, etc.) rather than relative to the
+ * root window (screen-size background window).
+ *
+ * On the X11 platform, the geometry is obtained from the X server,
+ * so reflects the latest position of @window; this may be out-of-sync
+ * with the position of @window delivered in the most-recently-processed
+ * #GdkEventConfigure. gdk_window_get_position() in contrast gets the
+ * position from the most recent configure event.
+ *
+ * <note>
+ * If @window is not a toplevel, it is <emphasis>much</emphasis> better
+ * to call gdk_window_get_position() and gdk_drawable_get_size() instead,
+ * because it avoids the roundtrip to the X server and because
+ * gdk_drawable_get_size() supports the full 32-bit coordinate space,
+ * whereas gdk_window_get_geometry() is restricted to the 16-bit
+ * coordinates of X11.
+ *</note>
+ **/
+void
+gdk_window_get_geometry (GdkWindow *window,
+                        gint      *x,
+                        gint      *y,
+                        gint      *width,
+                        gint      *height,
+                        gint      *depth)
+{
+  GdkWindowObject *private;
+
+  if (!window)
+    {
+      GDK_NOTE (MULTIHEAD,
+               g_message ("gdk_window_get_geometry(): Window needs "
+                           "to be non-NULL to be multi head safe"));
+      window = gdk_screen_get_root_window ((gdk_screen_get_default ()));
+    }
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_geometry (window, x, y,
+                                                              width, height,
+                                                               depth);
+    }
+}
+
+/**
+ * gdk_window_get_origin:
+ * @window: a #GdkWindow
+ * @x: return location for X coordinate
+ * @y: return location for Y coordinate
+ *
+ * Obtains the position of a window in root window coordinates.
+ * (Compare with gdk_window_get_position() and
+ * gdk_window_get_geometry() which return the position of a window
+ * relative to its parent window.)
+ *
+ * Return value: not meaningful, ignore
+ */
+gint
+gdk_window_get_origin (GdkWindow *window,
+                      gint      *x,
+                      gint      *y)
+{
+  GdkWindowObject *private;
+
+  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+
+  private = (GdkWindowObject *) window;
+
+  return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_origin (window, x, y);
+}
+
+/**
+ * gdk_window_shape_combine_mask:
+ * @window: a #GdkWindow
+ * @mask: shape mask
+ * @x: X position of shape mask with respect to @window
+ * @y: Y position of shape mask with respect to @window
+ *
+ * Applies a shape mask to @window. Pixels in @window corresponding to
+ * set bits in the @mask will be visible; pixels in @window
+ * corresponding to unset bits in the @mask will be transparent. This
+ * gives a non-rectangular window.
+ *
+ * If @mask is %NULL, the shape mask will be unset, and the @x/@y
+ * parameters are not used.
+ *
+ * On the X11 platform, this uses an X server extension which is
+ * widely available on most common platforms, but not available on
+ * very old X servers, and occasionally the implementation will be
+ * buggy. On servers without the shape extension, this function
+ * will do nothing.
+ *
+ * This function works on both toplevel and child windows.
+ */
+void
+gdk_window_shape_combine_mask (GdkWindow *window,
+                              GdkBitmap *mask,
+                              gint       x,
+                               gint       y)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_mask (window, mask, x, y);
+}
+
+/**
+ * gdk_window_shape_combine_region:
+ * @window: a #GdkWindow
+ * @shape_region: region of window to be non-transparent
+ * @offset_x: X position of @shape_region in @window coordinates
+ * @offset_y: Y position of @shape_region in @window coordinates
+ *
+ * Makes pixels in @window outside @shape_region be transparent,
+ * so that the window may be nonrectangular. See also
+ * gdk_window_shape_combine_mask() to use a bitmap as the mask.
+ *
+ * If @shape_region is %NULL, the shape will be unset, so the whole
+ * window will be opaque again. @offset_x and @offset_y are ignored
+ * if @shape_region is %NULL.
+ *
+ * On the X11 platform, this uses an X server extension which is
+ * widely available on most common platforms, but not available on
+ * very old X servers, and occasionally the implementation will be
+ * buggy. On servers without the shape extension, this function
+ * will do nothing.
+ *
+ * This function works on both toplevel and child windows.
+ */
+void
+gdk_window_shape_combine_region (GdkWindow       *window,
+                                 const GdkRegion *shape_region,
+                                 gint             offset_x,
+                                 gint             offset_y)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region (window, shape_region, offset_x, offset_y);
+}
+
+/**
+ * gdk_window_set_child_shapes:
+ * @window: a #GdkWindow
+ *
+ * Sets the shape mask of @window to the union of shape masks
+ * for all children of @window, ignoring the shape mask of @window
+ * itself. Contrast with gdk_window_merge_child_shapes() which includes
+ * the shape mask of @window in the masks to be merged.
+ **/
+void
+gdk_window_set_child_shapes (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_child_shapes (window);
+}
+
+/**
+ * gdk_window_merge_child_shapes:
+ * @window: a #GdkWindow
+ *
+ * Merges the shape masks for any child windows into the
+ * shape mask for @window. i.e. the union of all masks
+ * for @window and its children will become the new mask
+ * for @window. See gdk_window_shape_combine_mask().
+ *
+ * This function is distinct from gdk_window_set_child_shapes()
+ * because it includes @window's shape mask in the set of shapes to
+ * be merged.
+ */
+void
+gdk_window_merge_child_shapes (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->merge_child_shapes (window);
+}
+
+
+/**
+ * gdk_window_set_static_gravities:
+ * @window: a #GdkWindow
+ * @use_static: %TRUE to turn on static gravity
+ *
+ * Set the bit gravity of the given window to static, and flag it so
+ * all children get static subwindow gravity. This is used if you are
+ * implementing scary features that involve deep knowledge of the
+ * windowing system. Don't worry about it unless you have to.
+ *
+ * Return value: %TRUE if the server supports static gravity
+ */
+gboolean
+gdk_window_set_static_gravities (GdkWindow *window,
+                                gboolean   use_static)
+{
+  GdkWindowObject *private;
+
+  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+
+  private = (GdkWindowObject *) window;
+
+  return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_static_gravities (window, use_static);
+}
+
+/**
+ * gdk_window_set_composited:
+ * @window: a #GdkWindow
+ * @composited: %TRUE to set the window as composited
+ *
+ * Sets a #GdkWindow as composited, or unsets it. Composited 
+ * windows do not automatically have their contents drawn to 
+ * the screen. Drawing is redirected to an offscreen buffer 
+ * and an expose event is emitted on the parent of the composited 
+ * window. It is the responsibility of the parent's expose handler
+ * to manually merge the off-screen content onto the screen in
+ * whatever way it sees fit. See <xref linkend="composited-window-example"/>
+ * for an example.
+ *
+ * It only makes sense for child windows to be composited; see
+ * gdk_window_set_opacity() if you need translucent toplevel
+ * windows.
+ *
+ * An additional effect of this call is that the area of this
+ * window is no longer clipped from regions marked for
+ * invalidation on its parent. Draws done on the parent
+ * window are also no longer clipped by the child.
+ *
+ * This call is only supported on some systems (currently,
+ * only X11 with new enough Xcomposite and Xdamage extensions). 
+ * You must call gdk_display_supports_composite() to check if
+ * setting a window as composited is supported before
+ * attempting to do so.
+ *
+ * Since: 2.12
+ */
+void
+gdk_window_set_composited (GdkWindow *window,
+                           gboolean   composited)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkDisplay *display;
+
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  composited = composited != FALSE;
+
+  if (private->composited == composited)
+    return;
+
+  display = gdk_drawable_get_display (GDK_DRAWABLE (window));
+
+  if (!gdk_display_supports_composite (display) && composited)
+    {
+      g_warning ("gdk_window_set_composited called but "
+                "compositing is not supported");
+      return;
+    }
+
+  _gdk_windowing_window_set_composited (window, composited);
+
+  private->composited = composited;
+}
+
+
+static void
+remove_redirect_from_children (GdkWindowObject *private, GdkWindowRedirect *redirect)
+{
+  GList *l;
+  GdkWindowObject *child;
+
+  for (l = private->children; l != NULL; l = l->next)
+    {
+      child = l->data;
+
+      /* Don't redirect this child if it already has another redirect */
+      if (child->redirect == redirect)
+       {
+         child->redirect = NULL;
+         remove_redirect_from_children (child, redirect);
+       }
+    }
+}
+
+/**
+ * gdk_window_remove_redirection:
+ * @window: a #GdkWindow
+ *
+ * Removes and active redirection started by
+ * gdk_window_redirect_to_drawable().
+ **/
+void
+gdk_window_remove_redirection (GdkWindow *window)
+{
+  GdkWindowObject *private;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  if (private->redirect &&
+      private->redirect->redirected == private)
+    {
+      remove_redirect_from_children (private, private->redirect);
+      gdk_window_redirect_free (private->redirect);
+      private->redirect = NULL;
+    }
+}
+
+static void
+apply_redirect_to_children (GdkWindowObject *private, GdkWindowRedirect *redirect)
+{
+  GList *l;
+  GdkWindowObject *child;
+
+  for (l = private->children; l != NULL; l = l->next)
+    {
+      child = l->data;
+
+      /* Don't redirect this child if it already has another redirect */
+      if (!child->redirect)
+       {
+         child->redirect = redirect;
+         apply_redirect_to_children (child, redirect);
+       }
+    }
+}
+
+/**
+ * gdk_window_redirect_to_drawable:
+ * @window: a #GdkWindow
+ * @drawable: a #GdkDrawable
+ * @src_x: x position in @window
+ * @src_y: y position in @window
+ * @dest_x: x position in @drawable
+ * @dest_y: y position in @drawable
+ * @width: width of redirection
+ * @height: height of redirection
+ *
+ * Redirects drawing into @windows so that drawing to the
+ * window in the rectangle specified by @src_x, @src_y,
+ * @width and @height is also drawn into @drawable at
+ * @dest_x, @dest_y.
+ *
+ * Only drawing between gdk_window_begin_paint_region() and
+ * gdk_window_end_paint() is redirected.
+ *
+ * Redirection is active until gdk_window_remove_redirection()
+ * is called.
+ *
+ * This function should not be used on windows created by
+ * gdk_window_new_offscreen(), as that is implemented using
+ * redirection.
+ **/
+void
+gdk_window_redirect_to_drawable (GdkWindow *window,
+                                GdkDrawable *drawable,
+                                gint src_x, gint src_y,
+                                gint dest_x, gint dest_y,
+                                gint width, gint height)
+{
+  GdkWindowObject *private;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_DRAWABLE (drawable));
+  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
+
+  private = (GdkWindowObject *) window;
+
+  if (private->redirect)
+    gdk_window_remove_redirection (window);
+
+  if (width == -1 || height == -1)
+    {
+      gint w, h;
+      gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
+      if (width == -1)
+       width = w;
+      if (height == -1)
+       height = h;
+    }
+  
+  private->redirect = g_new0 (GdkWindowRedirect, 1);
+  private->redirect->redirected = private;
+  private->redirect->pixmap = g_object_ref (drawable);
+  private->redirect->src_x = src_x;
+  private->redirect->src_y = src_y;
+  private->redirect->dest_x = dest_x;
+  private->redirect->dest_y = dest_y;
+  private->redirect->width = width;
+  private->redirect->height = height;
+
+  apply_redirect_to_children (private, private->redirect);
+}
+
+static void
+window_get_size_rectangle (GdkWindow    *window,
+                           GdkRectangle *rect)
+{
+  rect->x = rect->y = 0;
+  gdk_drawable_get_size (GDK_DRAWABLE (window), &rect->width, &rect->height);
+}
+
+/* Calculates the real clipping region for a window, in window coordinates,
+ * taking into account other windows, gc clip region and gc clip mask.
+ */
+static GdkRegion *
+_gdk_window_calculate_full_clip_region (GdkWindow *window,
+                                       GdkWindow *base_window,
+                                       GdkGC *gc,
+                                       gboolean do_children,
+                                       gint *base_x_offset,
+                                       gint *base_y_offset)
+{
+  GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
+  GdkRectangle visible_rect;
+  GdkRegion *real_clip_region, *tmpreg;
+  gint x_offset, y_offset;
+  GdkWindowObject *parentwin, *lastwin;
+
+  if (base_x_offset)
+    *base_x_offset = 0;
+  if (base_y_offset)
+    *base_y_offset = 0;
+  
+  if (!GDK_WINDOW_IS_MAPPED (window) || private->input_only)
+    return gdk_region_new ();
+
+  window_get_size_rectangle (window, &visible_rect);
+
+  /* windows that a redirection has ben setup for need to be considered
+   * fully visible, in order to avoid missing redirected paint ops
+   * anywhere in the window area.
+   */
+  if (private->redirect && private->redirect->redirected == private)
+    return gdk_region_rectangle (&visible_rect);
+
+  /* real_clip_region is in window coordinates */
+  real_clip_region = gdk_region_rectangle (&visible_rect);
+
+  x_offset = y_offset = 0;
+
+  lastwin = private;
+  if (do_children)
+    parentwin = lastwin;
+  else
+    parentwin = lastwin->parent;
+  
+  /* Remove the areas of all overlapping windows above parentwin in the hiearachy */
+  for (; parentwin != NULL && (parentwin == private || lastwin != (GdkWindowObject *)base_window);
+       lastwin = parentwin, parentwin = lastwin->parent)
+    {
+      GList *cur;
+      GdkRectangle real_clip_rect;
+      
+      if (parentwin != private)
+       {
+         x_offset += GDK_WINDOW_OBJECT (lastwin)->x;
+         y_offset += GDK_WINDOW_OBJECT (lastwin)->y;
+       }
+      
+      /* children is ordered in reverse stack order */
+      for (cur = GDK_WINDOW_OBJECT (parentwin)->children; cur && cur->data != lastwin; cur = cur->next)
+       {
+         GdkWindow *child = cur->data;
+         GdkWindowObject *child_private = (GdkWindowObject *)child;
+         
+         if (!GDK_WINDOW_IS_MAPPED (child) || child_private->input_only)
+           continue;
+
+          window_get_size_rectangle (child, &visible_rect);
+
+         /* Convert rect to "window" coords */
+         visible_rect.x += child_private->x - x_offset;
+         visible_rect.y += child_private->y - y_offset;
+         
+         /* This shortcut is really necessary for performance when there are a lot of windows */
+         gdk_region_get_clipbox (real_clip_region, &real_clip_rect);
+         if (visible_rect.x >= real_clip_rect.x + real_clip_rect.width ||
+             visible_rect.x + visible_rect.width <= real_clip_rect.x ||
+             visible_rect.y >= real_clip_rect.y + real_clip_rect.height ||
+             visible_rect.y + visible_rect.height <= real_clip_rect.y)
+           continue;
+         
+         tmpreg = gdk_region_rectangle (&visible_rect);
+         gdk_region_subtract (real_clip_region, tmpreg);
+         gdk_region_destroy (tmpreg);
+       }
+      
+    }
+
+  if (gc)
+    {
+      GdkRegion *clip_region = _gdk_gc_get_clip_region (gc);
+      
+      if (clip_region)
+       {
+         /* clip_region is relative to gc clip origin which is relative to the window */
+         /* offset it to window relative: */
+         tmpreg = gdk_region_copy (clip_region);
+         gdk_region_offset (real_clip_region,
+                            gc->clip_x_origin,
+                            gc->clip_y_origin);
+         /* Intersect it with window hierarchy cliprect: */
+         gdk_region_intersect (real_clip_region, tmpreg);
+         gdk_region_destroy (tmpreg);
+       }
+    }
+
+  if (base_x_offset)
+    *base_x_offset = x_offset;
+  if (base_y_offset)
+    *base_y_offset = y_offset;
+
+  return real_clip_region;
+}
+
+static void
+gdk_window_add_damage (GdkWindow *toplevel,
+                      GdkRegion *damaged_region)
+{
+  GdkDisplay *display;
+  GdkEvent event = { 0, };
+  event.expose.type = GDK_DAMAGE;
+  event.expose.window = toplevel;
+  event.expose.send_event = FALSE;
+  event.expose.region = damaged_region;
+  gdk_region_get_clipbox (event.expose.region, &event.expose.area);
+  display = gdk_drawable_get_display (event.expose.window);
+  _gdk_event_queue_append (display, gdk_event_copy (&event));
+}
+
+static void
+setup_redirect_clip (GdkWindow         *window,
+                    GdkGC             *gc,
+                    GdkWindowClipData *data)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkRegion *visible_region;
+  GdkRectangle dest_rect;
+  GdkRegion *tmpreg;
+  GdkWindow *toplevel;
+
+  data->old_region = _gdk_gc_get_clip_region (gc);
+  if (data->old_region) 
+    data->old_region = gdk_region_copy (data->old_region);
+
+  data->old_clip_x_origin = gc->clip_x_origin;
+  data->old_clip_y_origin = gc->clip_y_origin;
+
+  toplevel = GDK_WINDOW (private->redirect->redirected);
+  
+  /* Get the clip region for gc clip rect + window hierarchy in
+     window relative coords */
+  visible_region =
+    _gdk_window_calculate_full_clip_region (window, toplevel,
+                                           gc, TRUE,
+                                           &data->x_offset, 
+                                           &data->y_offset);
+
+  /* Compensate for the source pos/size */
+  data->x_offset -= private->redirect->src_x;
+  data->y_offset -= private->redirect->src_y;
+  dest_rect.x = -data->x_offset;
+  dest_rect.y = -data->y_offset;
+  dest_rect.width = private->redirect->width;
+  dest_rect.height = private->redirect->height;
+  tmpreg = gdk_region_rectangle (&dest_rect);
+  gdk_region_intersect (visible_region, tmpreg);
+  gdk_region_destroy (tmpreg);
+
+  /* Compensate for the dest pos */
+  data->x_offset += private->redirect->dest_x;
+  data->y_offset += private->redirect->dest_y;
+
+  gdk_gc_set_clip_region (gc, visible_region); /* This resets clip origin! */
+
+  /* offset clip and tiles from window coords to pixmaps coords */
+  gdk_gc_offset (gc, -data->x_offset, -data->y_offset);
+
+  /* Offset region to abs coords and add to damage */
+  gdk_region_offset (visible_region, data->x_offset, data->y_offset);
+  gdk_window_add_damage (toplevel, visible_region);
+  
+  gdk_region_destroy (visible_region);
+}
+
+static void
+reset_redirect_clip (GdkWindow *offscreen, GdkGC *gc, GdkWindowClipData *data)
+{
+  /* offset back */
+  gdk_gc_offset (gc, data->x_offset, data->y_offset);
+
+  /* reset old clip */
+  gdk_gc_set_clip_region (gc, data->old_region);
+  if (data->old_region)
+    gdk_region_destroy (data->old_region);
+  gdk_gc_set_clip_origin (gc, data->old_clip_x_origin, data->old_clip_y_origin);
+}
+
+static void
+gdk_window_redirect_free (GdkWindowRedirect *redirect)
+{
+  g_object_unref (redirect->pixmap);
+  g_free (redirect);
+}
+
+#define __GDK_WINDOW_C__
+#include "gdkaliasdef.c"