]> Pileus Git - ~andy/gtk/blobdiff - gdk/gdkwindow.c
Warn when a parent is destroyed
[~andy/gtk] / gdk / gdkwindow.c
index b4428651efa7e39ae662d449e0371df01912a9fe..3acf0ff4af84366be2513ef7c8bc9a841e136dfb 100644 (file)
@@ -22,7 +22,7 @@
  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GTK+ Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
  */
 
 #include "config.h"
@@ -32,7 +32,9 @@
 #include "gdk.h"               /* For gdk_rectangle_union() */
 #include "gdkpixmap.h"
 #include "gdkdrawable.h"
+#include "gdkintl.h"
 #include "gdkscreen.h"
+#include "gdkmarshalers.h"
 #include "gdkalias.h"
 
 #undef DEBUG_WINDOW_PRINTING
 
 #include "math.h"
 
-/* Not all GdkWindows have a corresponding native window.
- * Instead some draw into the nearest parent that has whatss
- * called an "impl", i.e. the implementation window.
- * For toplevel window system windows the impl is always native
- * window, but child windows can also have native windows as
- * this is sometimes necessary. Furthermore, offscreen windows
- * (type GDK_WINDOW_OFFSCREEN) have an impl of type
- * GdkOffscreenWindow rather than a backend implementation native
- * window. Such windows draw into an offscreen pixmap instead
- * of a window and collect damage that lets you paint it where
- * you want.
- *
- * All GdkWindow track their position, size, clip region and
- * absolute position in the impl window. For child window with
- * native windows the clip region is set on the native window
- * as a window shape to make it clip against other non-native windows.
- */  
+/* Historically a GdkWindow always matches a platform native window,
+ * be it a toplevel window or a child window. In this setup the
+ * GdkWindow (and other GdkDrawables) were platform independent classes,
+ * and the actual platform specific implementation was in a delegate
+ * object availible as "impl" in the window object.
+ *
+ * With the addition of client side windows and offscreen windows this
+ * changes a bit. The application-visible GdkWindow object behaves as
+ * it did before, but not all such windows now have a corresponding native
+ * window. Instead windows that are "client side" are emulated by the gdk
+ * code such that clipping, drawing, moving, events etc work as expected.
+ *
+ * For GdkWindows that have a native window the "impl" object is the
+ * same as before. However, for all client side windows the impl object
+ * is shared with its parent (i.e. all client windows descendants of one
+ * native window has the same impl.
+ *
+ * Additionally there is a new type of platform independent impl object,
+ * GdkOffscreenWindow. All windows of type GDK_WINDOW_OFFSCREEN get an impl
+ * of this type (while their children are generally GDK_WINDOW_CHILD virtual
+ * windows). Such windows work by allocating a GdkPixmap as the backing store
+ * for drawing operations, which is resized with the window.
+ *
+ * GdkWindows have a pointer to the "impl window" they are in, i.e.
+ * the topmost GdkWindow which have the same "impl" value. This is stored
+ * in impl_window, which is different from the window itself only for client
+ * side windows.
+ * All GdkWindows (native or not) track the position of the window in the parent
+ * (x, y), the size of the window (width, height), the position of the window
+ * with respect to the impl window (abs_x, abs_y). We also track the clip
+ * region of the window wrt parent windows and siblings, in window-relative
+ * coordinates with and without child windows included (clip_region,
+ * clip_region_with_children).
+ *
+ * All toplevel windows are native windows, but also child windows can be
+ * native (although not children of offscreens). We always listen to
+ * a basic set of events (see get_native_event_mask) for these windows
+ * so that we can emulate events for any client side children.
+ *
+ * For native windows we apply the calculated clip region as a window shape
+ * so that eg. client side siblings that overlap the native child properly
+ * draws over the native child window.
+ *
+ * In order to minimize flicker and for performance we use a couple of cacheing
+ * tricks. First of all, every time we do a window to window copy area, for instance
+ * when moving a client side window or when scrolling/moving a region in a window
+ * we store this in outstanding_moves instead of applying immediately. We then
+ * delay this move until we really need it (because something depends on being
+ * able to read it), or until we're handing a redraw from an expose/invalidation
+ * (actually we delay it past redraw, but before blitting the double buffer pixmap
+ * to the window). This gives us two advantages. First of all it minimizes the time
+ * from the window is moved to the exposes related to that move, secondly it allows
+ * us to be smart about how to do the copy. We combine multiple moves into one (when
+ * possible) and we don't actually do copies to anything that is or will be
+ * invalidated and exposed anyway.
+ *
+ * Secondly, we use something called a "implicit paint" during repaint handling.
+ * An implicit paint is similar to a regular paint for the paint stack, but it is
+ * not put on the stack. Instead, it is set on the impl window, and later when
+ * regular gdk_window_begin_paint_region()  happen on a window of this impl window
+ * we reuse the pixmap from the implicit paint. During repaint we create and at the
+ * end flush an implicit paint, which means we can collect all the paints on
+ * multiple client side windows in the same backing store pixmap.
+ *
+ * All drawing to windows are wrapped with macros that set up the GC such that
+ * the offsets and clip region is right for drawing to the paint object or
+ * directly to the emulated window. It also automatically handles any flushing
+ * needed when drawing directly to a window. Adding window/paint clipping is
+ * done using _gdk_gc_add_drawable_clip which lets us efficiently add and then
+ * remove a custom clip region.
+ */
 
 #define USE_BACKING_STORE      /* Appears to work on Win32, too, now. */
 
+/* This adds a local value to the GdkVisibilityState enum */
+#define GDK_VISIBILITY_NOT_VIEWABLE 3
+
+enum {
+  PICK_EMBEDDED_CHILD, /* only called if children are embedded */
+  TO_EMBEDDER,
+  FROM_EMBEDDER,
+  LAST_SIGNAL
+};
+
+enum {
+  PROP_0,
+  PROP_CURSOR
+};
+
 struct _GdkWindowPaint
 {
   GdkRegion *region;
@@ -75,68 +146,69 @@ struct _GdkWindowPaint
 };
 
 typedef struct {
-  GdkRegion *region; /* The destination region */
-  int dx, dy;
+  GdkRegion *dest_region; /* The destination region */
+  int dx, dy; /* The amount that the source was moved to reach dest_region */
 } GdkWindowRegionMove;
 
 
 /* Global info */
 
 static GdkGC *gdk_window_create_gc      (GdkDrawable     *drawable,
-                                         GdkGCValues     *values,
-                                         GdkGCValuesMask  mask);
+                                        GdkGCValues     *values,
+                                        GdkGCValuesMask  mask);
 static void   gdk_window_draw_rectangle (GdkDrawable     *drawable,
-                                         GdkGC           *gc,
-                                         gboolean         filled,
-                                         gint             x,
-                                         gint             y,
-                                         gint             width,
-                                         gint             height);
+                                        GdkGC           *gc,
+                                        gboolean         filled,
+                                        gint             x,
+                                        gint             y,
+                                        gint             width,
+                                        gint             height);
 static void   gdk_window_draw_arc       (GdkDrawable     *drawable,
-                                         GdkGC           *gc,
-                                         gboolean         filled,
-                                         gint             x,
-                                         gint             y,
-                                         gint             width,
-                                         gint             height,
-                                         gint             angle1,
-                                         gint             angle2);
+                                        GdkGC           *gc,
+                                        gboolean         filled,
+                                        gint             x,
+                                        gint             y,
+                                        gint             width,
+                                        gint             height,
+                                        gint             angle1,
+                                        gint             angle2);
 static void   gdk_window_draw_polygon   (GdkDrawable     *drawable,
-                                         GdkGC           *gc,
-                                         gboolean         filled,
-                                         GdkPoint        *points,
-                                         gint             npoints);
+                                        GdkGC           *gc,
+                                        gboolean         filled,
+                                        GdkPoint        *points,
+                                        gint             npoints);
 static void   gdk_window_draw_text      (GdkDrawable     *drawable,
-                                         GdkFont         *font,
-                                         GdkGC           *gc,
-                                         gint             x,
-                                         gint             y,
-                                         const gchar     *text,
-                                         gint             text_length);
+                                        GdkFont         *font,
+                                        GdkGC           *gc,
+                                        gint             x,
+                                        gint             y,
+                                        const gchar     *text,
+                                        gint             text_length);
 static void   gdk_window_draw_text_wc   (GdkDrawable     *drawable,
-                                         GdkFont         *font,
-                                         GdkGC           *gc,
-                                         gint             x,
-                                         gint             y,
-                                         const GdkWChar  *text,
-                                         gint             text_length);
+                                        GdkFont         *font,
+                                        GdkGC           *gc,
+                                        gint             x,
+                                        gint             y,
+                                        const GdkWChar  *text,
+                                        gint             text_length);
 static void   gdk_window_draw_drawable  (GdkDrawable     *drawable,
-                                         GdkGC           *gc,
-                                         GdkPixmap       *src,
-                                         gint             xsrc,
-                                         gint             ysrc,
-                                         gint             xdest,
-                                         gint             ydest,
-                                         gint             width,
-                                         gint             height);
+                                        GdkGC           *gc,
+                                        GdkPixmap       *src,
+                                        gint             xsrc,
+                                        gint             ysrc,
+                                        gint             xdest,
+                                        gint             ydest,
+                                        gint             width,
+                                        gint             height,
+                                        GdkDrawable     *original_src);
 static void   gdk_window_draw_points    (GdkDrawable     *drawable,
-                                         GdkGC           *gc,
-                                         GdkPoint        *points,
-                                         gint             npoints);
+                                        GdkGC           *gc,
+                                        GdkPoint        *points,
+                                        gint             npoints);
 static void   gdk_window_draw_segments  (GdkDrawable     *drawable,
-                                         GdkGC           *gc,
-                                         GdkSegment      *segs,
-                                         gint             nsegs);
+                                        GdkGC           *gc,
+                                        GdkSegment      *segs,
+                                        gint             nsegs);
 static void   gdk_window_draw_lines     (GdkDrawable     *drawable,
                                         GdkGC           *gc,
                                         GdkPoint        *points,
@@ -157,14 +229,14 @@ static void gdk_window_draw_glyphs_transformed (GdkDrawable      *drawable,
                                                PangoGlyphString *glyphs);
 
 static void   gdk_window_draw_image     (GdkDrawable     *drawable,
-                                         GdkGC           *gc,
-                                         GdkImage        *image,
-                                         gint             xsrc,
-                                         gint             ysrc,
-                                         gint             xdest,
-                                         gint             ydest,
-                                         gint             width,
-                                         gint             height);
+                                        GdkGC           *gc,
+                                        GdkImage        *image,
+                                        gint             xsrc,
+                                        gint             ysrc,
+                                        gint             xdest,
+                                        gint             ydest,
+                                        gint             width,
+                                        gint             height);
 
 static void gdk_window_draw_pixbuf (GdkDrawable     *drawable,
                                    GdkGC           *gc,
@@ -201,8 +273,8 @@ static void             gdk_window_set_cairo_clip    (GdkDrawable *drawable,
                                                      cairo_t *cr);
 
 static void   gdk_window_real_get_size  (GdkDrawable     *drawable,
-                                         gint            *width,
-                                         gint            *height);
+                                        gint            *width,
+                                        gint            *height);
 
 static GdkVisual*   gdk_window_real_get_visual   (GdkDrawable *drawable);
 static gint         gdk_window_real_get_depth    (GdkDrawable *drawable);
@@ -227,11 +299,18 @@ static void gdk_window_free_paint_stack (GdkWindow *window);
 static void gdk_window_init       (GdkWindowObject      *window);
 static void gdk_window_class_init (GdkWindowObjectClass *klass);
 static void gdk_window_finalize   (GObject              *object);
-static void gdk_window_clear_backing_rect (GdkWindow *window,
-                                          gint       x,
-                                          gint       y,
-                                          gint       width,
-                                          gint       height);
+
+static void gdk_window_set_property (GObject      *object,
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec);
+static void gdk_window_get_property (GObject      *object,
+                                     guint         prop_id,
+                                     GValue       *value,
+                                     GParamSpec   *pspec);
+
+static void gdk_window_clear_backing_region (GdkWindow *window,
+                                            GdkRegion *region);
 static void gdk_window_redirect_free      (GdkWindowRedirect *redirect);
 static void apply_redirect_to_children    (GdkWindowObject   *private,
                                           GdkWindowRedirect *redirect);
@@ -249,7 +328,11 @@ static void do_move_region_bits_on_impl (GdkWindowObject *private,
                                         int dx, int dy);
 static void gdk_window_invalidate_in_parent (GdkWindowObject *private);
 static void move_native_children (GdkWindowObject *private);
-  
+static void update_cursor (GdkDisplay *display);
+static void gdk_window_region_move_free (GdkWindowRegionMove *move);
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 static gpointer parent_class = NULL;
 
 static const cairo_user_data_key_t gdk_window_cairo_key;
@@ -275,7 +358,7 @@ gdk_window_object_get_type (void)
                                                 sizeof (GdkWindowObject),
                                                 (GInstanceInitFunc) gdk_window_init,
                                                 0);
-  
+
   return object_type;
 }
 
@@ -314,6 +397,23 @@ gdk_window_init (GdkWindowObject *window)
   window->width = 1;
   window->height = 1;
   window->toplevel_window_type = -1;
+  /* starts hidden */
+  window->effective_visibility = GDK_VISIBILITY_NOT_VIEWABLE;
+  window->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
+  /* Default to unobscured since some backends don't send visibility events */
+  window->native_visibility = GDK_VISIBILITY_UNOBSCURED;
+}
+
+/* Stop and return on the first non-NULL parent */
+static gboolean
+accumulate_get_window (GSignalInvocationHint *ihint,
+                      GValue                  *return_accu,
+                      const GValue            *handler_return,
+                      gpointer               data)
+{
+  g_value_copy (handler_return, return_accu);
+  /* Continue while returning NULL */
+  return g_value_get_object (handler_return) == NULL;
 }
 
 static GQuark quark_pointer_window = 0;
@@ -323,10 +423,12 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
-  
+
   parent_class = g_type_class_peek_parent (klass);
 
   object_class->finalize = gdk_window_finalize;
+  object_class->set_property = gdk_window_set_property;
+  object_class->get_property = gdk_window_get_property;
 
   drawable_class->create_gc = gdk_window_create_gc;
   drawable_class->draw_rectangle = gdk_window_draw_rectangle;
@@ -334,7 +436,7 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
   drawable_class->draw_polygon = gdk_window_draw_polygon;
   drawable_class->draw_text = gdk_window_draw_text;
   drawable_class->draw_text_wc = gdk_window_draw_text_wc;
-  drawable_class->draw_drawable = gdk_window_draw_drawable;
+  drawable_class->draw_drawable_with_src = gdk_window_draw_drawable;
   drawable_class->draw_points = gdk_window_draw_points;
   drawable_class->draw_segments = gdk_window_draw_segments;
   drawable_class->draw_lines = gdk_window_draw_lines;
@@ -359,6 +461,94 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
   drawable_class->get_source_drawable = gdk_window_get_source_drawable;
 
   quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
+
+
+  /* Properties */
+  g_object_class_install_property (object_class,
+                                   PROP_CURSOR,
+                                   g_param_spec_pointer ("cursor",
+                                                         P_("Cursor"),
+                                                         P_("Cursor"),
+                                                         G_PARAM_READWRITE));
+
+  /**
+   * GdkWindow::pick-embedded-child:
+   * @window: the window on which the signal is emitted
+   * @x: x coordinate in the window
+   * @y: y coordinate in the window
+   *
+   * The ::pick-embedded-child signal is emitted to find an embedded
+   * child at the given position.
+   *
+   * Returns: the GdkWindow of the embedded child at @x, @y, or %NULL
+   *
+   * Since: 2.18
+   */
+  signals[PICK_EMBEDDED_CHILD] =
+    g_signal_new (g_intern_static_string ("pick-embedded-child"),
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_LAST,
+                 0,
+                 accumulate_get_window, NULL,
+                 _gdk_marshal_OBJECT__DOUBLE_DOUBLE,
+                 GDK_TYPE_WINDOW,
+                 2,
+                 G_TYPE_DOUBLE,
+                 G_TYPE_DOUBLE);
+
+  /**
+   * GdkWindow::to-embedder:
+   * @window: the offscreen window on which the signal is emitted
+   * @offscreen-x: x coordinate in the offscreen window
+   * @offscreen-y: y coordinate in the offscreen window
+   * @embedder-x: return location for the x coordinate in the embedder window
+   * @embedder-y: return location for the y coordinate in the embedder window
+   *
+   * The ::to-embedder signal is emitted to translate coordinates
+   * in an offscreen window to its embedder.
+   *
+   * Since: 2.18
+   */
+  signals[TO_EMBEDDER] =
+    g_signal_new (g_intern_static_string ("to-embedder"),
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_LAST,
+                 0,
+                 NULL, NULL,
+                 _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTER,
+                 G_TYPE_NONE,
+                 4,
+                 G_TYPE_DOUBLE,
+                 G_TYPE_DOUBLE,
+                 G_TYPE_POINTER,
+                 G_TYPE_POINTER);
+
+  /**
+   * GdkWindow::from-embedder:
+   * @window: the offscreen window on which the signal is emitted
+   * @embedder-x: x coordinate in the embedder window
+   * @embedder-y: y coordinate in the embedder window
+   * @offscreen-x: return location for the x coordinate in the offscreen window
+   * @offscreen-y: return location for the y coordinate in the offscreen window
+   *
+   * The ::from-embedder signal is emitted to translate coordinates
+   * in the embedder of an offscreen window to the offscreen window.
+   *
+   * Since: 2.18
+   */
+  signals[FROM_EMBEDDER] =
+    g_signal_new (g_intern_static_string ("from-embedder"),
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_LAST,
+                 0,
+                 NULL, NULL,
+                 _gdk_marshal_VOID__DOUBLE_DOUBLE_POINTER_POINTER,
+                 G_TYPE_NONE,
+                 4,
+                 G_TYPE_DOUBLE,
+                 G_TYPE_DOUBLE,
+                 G_TYPE_POINTER,
+                 G_TYPE_POINTER);
 }
 
 static void
@@ -366,7 +556,7 @@ gdk_window_finalize (GObject *object)
 {
   GdkWindow *window = GDK_WINDOW (object);
   GdkWindowObject *obj = (GdkWindowObject *) object;
-  
+
   if (!GDK_WINDOW_DESTROYED (window))
     {
       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
@@ -392,7 +582,7 @@ gdk_window_finalize (GObject *object)
       g_object_unref (obj->impl_window);
       obj->impl_window = NULL;
     }
-  
+
   if (obj->shape)
     gdk_region_destroy (obj->shape);
 
@@ -405,10 +595,50 @@ gdk_window_finalize (GObject *object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+static void
+gdk_window_set_property (GObject      *object,
+                         guint         prop_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+  GdkWindow *window = (GdkWindow *)object;
+
+  switch (prop_id)
+    {
+    case PROP_CURSOR:
+      gdk_window_set_cursor (window, g_value_get_pointer (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gdk_window_get_property (GObject    *object,
+                         guint       prop_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
+{
+  GdkWindow *window = (GdkWindow *) object;
+
+  switch (prop_id)
+    {
+    case PROP_CURSOR:
+      g_value_set_pointer (value, gdk_window_get_cursor (window));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
 static gboolean
 gdk_window_is_offscreen (GdkWindowObject *window)
 {
-  return GDK_WINDOW_TYPE (window) == GDK_WINDOW_OFFSCREEN;
+  return window->window_type == GDK_WINDOW_OFFSCREEN;
 }
 
 static GdkWindowObject *
@@ -452,14 +682,19 @@ remove_child_area (GdkWindowObject *private,
   GdkRectangle r;
   GList *l;
   GdkRegion *shape;
-  
+
   for (l = private->children; l; l = l->next)
     {
       child = l->data;
 
       if (child == until)
        break;
-      
+
+      /* If region is empty already, no need to do
+        anything potentially costly */
+      if (gdk_region_empty (region))
+       break;
+
       if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
        continue;
 
@@ -473,10 +708,19 @@ remove_child_area (GdkWindowObject *private,
       r.width = child->width;
       r.height = child->height;
 
+      /* Bail early if child totally outside region */
+      if (gdk_region_rect_in (region, &r) == GDK_OVERLAP_RECTANGLE_OUT)
+       continue;
+
       child_region = gdk_region_rectangle (&r);
-      
+
       if (child->shape)
-       gdk_region_intersect (child_region, child->shape);
+       {
+         /* Adjust shape region to parent window coords */
+         gdk_region_offset (child->shape, child->x, child->y);
+         gdk_region_intersect (child_region, child->shape);
+         gdk_region_offset (child->shape, -child->x, -child->y);
+       }
       else if (private->window_type == GDK_WINDOW_FOREIGN)
        {
          shape = _gdk_windowing_window_get_shape ((GdkWindow *)child);
@@ -501,13 +745,71 @@ remove_child_area (GdkWindowObject *private,
                }
            }
        }
-      
+
       gdk_region_subtract (region, child_region);
       gdk_region_destroy (child_region);
 
     }
 }
 
+static GdkVisibilityState
+effective_visibility (GdkWindowObject *private)
+{
+  GdkVisibilityState native;
+
+  if (!gdk_window_is_viewable ((GdkWindow *)private))
+    return GDK_VISIBILITY_NOT_VIEWABLE;
+
+  native = private->impl_window->native_visibility;
+
+  if (native == GDK_VISIBILITY_FULLY_OBSCURED ||
+      private->visibility == GDK_VISIBILITY_FULLY_OBSCURED)
+    return GDK_VISIBILITY_FULLY_OBSCURED;
+  else if (native == GDK_VISIBILITY_UNOBSCURED)
+    return private->visibility;
+  else /* native PARTIAL, private partial or unobscured  */
+    return GDK_VISIBILITY_PARTIAL;
+}
+
+static void
+gdk_window_update_visibility (GdkWindowObject *private)
+{
+  GdkVisibilityState new_visibility;
+  GdkEvent *event;
+
+  new_visibility = effective_visibility (private);
+
+  if (new_visibility != private->effective_visibility)
+    {
+      private->effective_visibility = new_visibility;
+
+      if (new_visibility != GDK_VISIBILITY_NOT_VIEWABLE &&
+         private->event_mask & GDK_VISIBILITY_NOTIFY)
+       {
+         event = _gdk_make_event ((GdkWindow *)private, GDK_VISIBILITY_NOTIFY,
+                                  NULL, FALSE);
+         event->visibility.state = new_visibility;
+       }
+    }
+}
+
+static void
+gdk_window_update_visibility_recursively (GdkWindowObject *private,
+                                         GdkWindowObject *only_for_impl)
+{
+  GdkWindowObject *child;
+  GList *l;
+
+  gdk_window_update_visibility (private);
+  for (l = private->children; l != NULL; l = l->next)
+    {
+      child = l->data;
+      if ((only_for_impl == NULL) ||
+         (only_for_impl == child->impl_window))
+       gdk_window_update_visibility_recursively (child, only_for_impl);
+    }
+}
+
 static void
 recompute_visible_regions_internal (GdkWindowObject *private,
                                    gboolean recalculate_clip,
@@ -524,7 +826,7 @@ recompute_visible_regions_internal (GdkWindowObject *private,
 
   old_abs_x = private->abs_x;
   old_abs_y = private->abs_y;
-  
+
   /* Update absolute position */
   if (gdk_window_has_impl (private))
     {
@@ -550,38 +852,51 @@ recompute_visible_regions_internal (GdkWindowObject *private,
   clip_region_changed = FALSE;
   if (recalculate_clip)
     {
-      /* Calculate visible region (sans children) in parent window coords */
-      r.x = private->x;
-      r.y = private->y;
-      r.width = private->width;
-      r.height = private->height;
-      new_clip = gdk_region_rectangle (&r);
-
-      if (private->parent != NULL && GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
+      if (private->viewable)
        {
-         gdk_region_intersect (new_clip, private->parent->clip_region);
-         
-         /* Remove all overlapping children from parent */
-         remove_child_area (private->parent, private, FALSE, new_clip);
-       }
-      
-      /* Convert from parent coords to window coords */
-      gdk_region_offset (new_clip, -private->x, -private->y);
+         /* Calculate visible region (sans children) in parent window coords */
+         r.x = private->x;
+         r.y = private->y;
+         r.width = private->width;
+         r.height = private->height;
+         new_clip = gdk_region_rectangle (&r);
+
+         if (private->parent != NULL &&
+             private->parent->window_type != GDK_WINDOW_ROOT)
+           {
+             gdk_region_intersect (new_clip, private->parent->clip_region);
+
+             /* Remove all overlapping children from parent.
+              * Unless we're all native, because then we don't need to take
+              * siblings into account since X does that clipping for us.
+              * This makes things like SWT that modify the raw X stacking
+              * order without GDKs knowledge work.
+              */
+             if (!_gdk_native_windows)
+               remove_child_area (private->parent, private, FALSE, new_clip);
+           }
+
+         /* Convert from parent coords to window coords */
+         gdk_region_offset (new_clip, -private->x, -private->y);
 
-      if (private->shape)
-       gdk_region_intersect (new_clip, private->shape);
+         if (private->shape)
+           gdk_region_intersect (new_clip, private->shape);
+       }
+      else
+       new_clip = gdk_region_new ();
 
       if (private->clip_region == NULL ||
          !gdk_region_equal (private->clip_region, new_clip))
        clip_region_changed = TRUE;
-       
+
       if (private->clip_region)
        gdk_region_destroy (private->clip_region);
       private->clip_region = new_clip;
 
       old_clip_region_with_children = private->clip_region_with_children;
       private->clip_region_with_children = gdk_region_copy (private->clip_region);
-      remove_child_area (private, NULL, FALSE, private->clip_region_with_children);
+      if (private->window_type != GDK_WINDOW_ROOT)
+       remove_child_area (private, NULL, FALSE, private->clip_region_with_children);
 
       if (clip_region_changed ||
          !gdk_region_equal (private->clip_region_with_children, old_clip_region_with_children))
@@ -591,8 +906,45 @@ recompute_visible_regions_internal (GdkWindowObject *private,
        gdk_region_destroy (old_clip_region_with_children);
     }
 
-  /* Update all children, recursively. */
-  if (abs_pos_changed || clip_region_changed || recalculate_children)
+  if (clip_region_changed)
+    {
+      GdkVisibilityState visibility;
+      gboolean fully_visible;
+
+      if (gdk_region_empty (private->clip_region))
+       visibility = GDK_VISIBILITY_FULLY_OBSCURED;
+      else
+        {
+          if (private->shape)
+            {
+             fully_visible = gdk_region_equal (private->clip_region,
+                                               private->shape);
+            }
+          else
+            {
+             r.x = 0;
+             r.y = 0;
+             r.width = private->width;
+             r.height = private->height;
+             fully_visible = gdk_region_rect_equal (private->clip_region, &r);
+           }
+
+         if (fully_visible)
+           visibility = GDK_VISIBILITY_UNOBSCURED;
+         else
+           visibility = GDK_VISIBILITY_PARTIAL;
+       }
+
+      if (private->visibility != visibility)
+       {
+         private->visibility = visibility;
+         gdk_window_update_visibility (private);
+       }
+    }
+
+  /* Update all children, recursively (except for root, where children are not exact). */
+  if ((abs_pos_changed || clip_region_changed || recalculate_children) &&
+      private->window_type != GDK_WINDOW_ROOT)
     {
       for (l = private->children; l; l = l->next)
        {
@@ -601,7 +953,9 @@ recompute_visible_regions_internal (GdkWindowObject *private,
           * there is no way the child clip region could change (its has not e.g. moved)
           * Except if recalculate_children is set to force child updates
           */
-         recompute_visible_regions_internal (child, recalculate_clip && (clip_region_changed || recalculate_children), FALSE, FALSE);
+         recompute_visible_regions_internal (child,
+                                             recalculate_clip && (clip_region_changed || recalculate_children),
+                                             FALSE, FALSE);
        }
     }
 
@@ -612,9 +966,11 @@ recompute_visible_regions_internal (GdkWindowObject *private,
       /* or for non-shaped toplevels */
       (private->shaped ||
        (private->parent != NULL &&
-       GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)) &&
+       private->parent->window_type != GDK_WINDOW_ROOT)) &&
       /* or for foreign windows */
-      GDK_WINDOW_TYPE (private) != GDK_WINDOW_FOREIGN
+      private->window_type != GDK_WINDOW_FOREIGN &&
+      /* or for the root window */
+      private->window_type != GDK_WINDOW_ROOT
       )
     {
       GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0);
@@ -622,7 +978,7 @@ recompute_visible_regions_internal (GdkWindowObject *private,
 
   if (recalculate_siblings &&
       private->parent != NULL &&
-      GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
+      private->parent->window_type != GDK_WINDOW_ROOT)
     {
       /* If we moved a child window in parent or changed the stacking order, then we
        * need to recompute the visible area of all the other children in the parent
@@ -650,7 +1006,7 @@ recompute_visible_regions_internal (GdkWindowObject *private,
 
       _gdk_windowing_set_cairo_surface_size (private->cairo_surface,
                                             width, height);
-      cairo_surface_set_device_offset (private->cairo_surface, 
+      cairo_surface_set_device_offset (private->cairo_surface,
                                       private->abs_x,
                                       private->abs_y);
     }
@@ -667,7 +1023,7 @@ recompute_visible_regions_internal (GdkWindowObject *private,
  *
  * Unless the window didn't change stacking order or size/pos, pass in TRUE
  * for recalculate_siblings. (Mostly used internally for the recursion)
- * 
+ *
  * If a child window was removed (and you can't use that child for
  * recompute_visible_regions), pass in TRUE for recalculate_children on the parent
  */
@@ -713,7 +1069,7 @@ find_native_sibling_above_helper (GdkWindowObject *parent,
   for (; l != NULL; l = l->prev)
     {
       w = l->data;
-       
+
       if (gdk_window_has_impl (w))
        return w;
 
@@ -746,17 +1102,55 @@ find_native_sibling_above (GdkWindowObject *parent,
 static GdkEventMask
 get_native_event_mask (GdkWindowObject *private)
 {
-  if (GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
-    return
-      GDK_EXPOSURE_MASK |
-      GDK_POINTER_MOTION_MASK |
-      GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
-      GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
-      GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
-      GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK |
-      GDK_PROXIMITY_IN_MASK | GDK_PROXIMITY_OUT_MASK | GDK_SCROLL_MASK;
+  if (_gdk_native_windows ||
+      private->window_type == GDK_WINDOW_ROOT ||
+      private->window_type == GDK_WINDOW_FOREIGN)
+    return private->event_mask;
   else
-    return GDK_EXPOSURE_MASK;
+    {
+      return
+       /* We need thse for all native window so we can emulate
+          events on children: */
+       GDK_EXPOSURE_MASK |
+       GDK_VISIBILITY_NOTIFY_MASK |
+       GDK_POINTER_MOTION_MASK |
+       GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+       GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
+       GDK_SCROLL_MASK |
+       /* Then do whatever the app asks to, since the app
+        * may be asking for weird things for native windows,
+        * but filter out things that override the above
+        * requests somehow. */
+       (private->event_mask &
+        ~(GDK_POINTER_MOTION_HINT_MASK |
+          GDK_BUTTON_MOTION_MASK |
+          GDK_BUTTON1_MOTION_MASK |
+          GDK_BUTTON2_MOTION_MASK |
+          GDK_BUTTON3_MOTION_MASK));
+    }
+}
+
+/* Puts the native window in the right order wrt the other native windows
+ * in the hierarchy, given the position it has in the client side data.
+ * This is useful if some operation changed the stacking order.
+ * This calls assumes the native window is now topmost in its native parent.
+ */
+static void
+sync_native_window_stack_position (GdkWindow *window)
+{
+  GdkWindowObject *above;
+  GdkWindowObject *private;
+  GList listhead = {0};
+
+  private = (GdkWindowObject *) window;
+
+  above = find_native_sibling_above (private->parent, private);
+  if (above)
+    {
+      listhead.data = window;
+      GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above,
+                                                               &listhead);
+    }
 }
 
 /**
@@ -765,12 +1159,12 @@ get_native_event_mask (GdkWindowObject *private)
  *   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*
@@ -786,14 +1180,14 @@ gdk_window_new (GdkWindow     *parent,
   gboolean native;
   GdkEventMask event_mask;
   GdkWindow *real_parent;
-  
+
   g_return_val_if_fail (attributes != NULL, NULL);
-  
+
   if (!parent)
     {
       GDK_NOTE (MULTIHEAD,
                g_warning ("gdk_window_new(): no parent specified reverting to parent = default root window"));
-      
+
       screen = gdk_screen_get_default ();
       parent = gdk_screen_get_root_window (screen);
     }
@@ -801,9 +1195,19 @@ gdk_window_new (GdkWindow     *parent,
     screen = gdk_drawable_get_screen (parent);
 
   g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL);
-  
+
   if (GDK_WINDOW_DESTROYED (parent))
-    return NULL;
+    {
+      g_warning ("gdk_window_new(): parent is destroyed\n");
+      return NULL;
+    }
+
+  if (attributes->window_type == GDK_WINDOW_OFFSCREEN &&
+      _gdk_native_windows)
+    {
+      g_warning ("Offscreen windows not supported with native-windows gdk");
+      return NULL;
+    }
 
   window = g_object_new (GDK_TYPE_WINDOW, NULL);
   private = (GdkWindowObject *) window;
@@ -824,30 +1228,30 @@ gdk_window_new (GdkWindow     *parent,
     x = attributes->x;
   else
     x = 0;
-  
+
   if (attributes_mask & GDK_WA_Y)
     y = attributes->y;
   else
     y = 0;
-  
+
   private->x = x;
   private->y = y;
   private->width = (attributes->width > 1) ? (attributes->width) : (1);
   private->height = (attributes->height > 1) ? (attributes->height) : (1);
 
 #ifdef GDK_WINDOWING_X11
-  /* Work around a bug where Xorg refuses to map toplevel InputOnly windows 
+  /* Work around a bug where Xorg refuses to map toplevel InputOnly windows
    * from an untrusted client: http://bugs.freedesktop.org/show_bug.cgi?id=6988
    */
   if (attributes->wclass == GDK_INPUT_ONLY &&
-      GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT &&
+      private->parent->window_type == GDK_WINDOW_ROOT &&
       !G_LIKELY (GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (parent))->trusted_client))
     {
       g_warning ("Coercing GDK_INPUT_ONLY toplevel window to GDK_INPUT_OUTPUT to work around bug in Xorg server");
       attributes->wclass = GDK_INPUT_OUTPUT;
     }
 #endif
-  
+
   if (attributes->wclass == GDK_INPUT_ONLY)
     {
       /* Backwards compatiblity - we've always ignored
@@ -868,17 +1272,18 @@ gdk_window_new (GdkWindow     *parent,
     case GDK_WINDOW_TOPLEVEL:
     case GDK_WINDOW_DIALOG:
     case GDK_WINDOW_TEMP:
+    case GDK_WINDOW_OFFSCREEN:
       if (GDK_WINDOW_TYPE (parent) != GDK_WINDOW_ROOT)
        g_warning (G_STRLOC "Toplevel windows must be created as children of\n"
                   "of a window of type GDK_WINDOW_ROOT or GDK_WINDOW_FOREIGN");
     case GDK_WINDOW_CHILD:
-    case GDK_WINDOW_OFFSCREEN:
+      break;
       break;
     default:
       g_warning (G_STRLOC "cannot make windows of type %d", private->window_type);
       return NULL;
     }
-  
+
   if (attributes_mask & GDK_WA_VISUAL)
     visual = attributes->visual;
   else
@@ -890,8 +1295,8 @@ gdk_window_new (GdkWindow     *parent,
     {
       private->input_only = FALSE;
       private->depth = visual->depth;
-  
-      private->bg_color.pixel = 0; // TODO: BlackPixel (xdisplay, screen_x11->screen_num);
+
+      private->bg_color.pixel = 0; /* TODO: BlackPixel (xdisplay, screen_x11->screen_num); */
       private->bg_color.red = private->bg_color.green = private->bg_color.blue = 0;
 
       private->bg_pixmap = NULL;
@@ -905,8 +1310,8 @@ gdk_window_new (GdkWindow     *parent,
   if (private->parent)
     private->parent->children = g_list_prepend (private->parent->children, window);
 
-  native = FALSE; /* Default */
-  if (GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+  native = _gdk_native_windows; /* Default */
+  if (private->parent->window_type == GDK_WINDOW_ROOT)
     native = TRUE; /* Always use native windows for toplevels */
   else if (!private->input_only &&
           ((attributes_mask & GDK_WA_COLORMAP &&
@@ -922,25 +1327,16 @@ gdk_window_new (GdkWindow     *parent,
     }
   else if (native)
     {
-      GdkWindowObject *above;
-      GList listhead = {0};
-      
       event_mask = get_native_event_mask (private);
-      
+
       /* Create the impl */
       _gdk_window_impl_new (window, real_parent, screen, visual, event_mask, attributes, attributes_mask);
       private->impl_window = private;
 
       /* This will put the native window topmost in the native parent, which may
        * be wrong wrt other native windows in the non-native hierarchy, so restack */
-      above = find_native_sibling_above (private->parent, private);
-      if (above)
-       {
-         listhead.data = window;
-         GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above,
-                                                                   &listhead);
-       }
-      
+      if (!_gdk_window_has_impl (real_parent))
+       sync_native_window_stack_position (window);
     }
   else
     {
@@ -949,13 +1345,13 @@ gdk_window_new (GdkWindow     *parent,
     }
 
   recompute_visible_regions (private, TRUE, FALSE);
-  
-  if (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
+
+  if (private->parent->window_type != GDK_WINDOW_ROOT)
     {
       /* Inherit redirection from parent */
       private->redirect = private->parent->redirect;
     }
-    
+
   gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
                                  (attributes->cursor) :
                                  NULL));
@@ -965,7 +1361,7 @@ gdk_window_new (GdkWindow     *parent,
 
 static gboolean
 is_parent_of (GdkWindow *parent,
-              GdkWindow *child)
+             GdkWindow *child)
 {
   GdkWindow *w;
 
@@ -1001,7 +1397,7 @@ change_impl (GdkWindowObject *private,
   if (old_impl_window != private)
     g_object_unref (old_impl_window);
   g_object_unref (old_impl);
-  
+
   for (l = private->children; l != NULL; l = l->next)
     {
       child = l->data;
@@ -1047,7 +1443,7 @@ reparent_to_impl (GdkWindowObject *private)
  *
  * Reparents @window into the given @new_parent. The window being
  * reparented will be unmapped as a side effect.
- * 
+ *
  **/
 void
 gdk_window_reparent (GdkWindow *window,
@@ -1058,9 +1454,11 @@ gdk_window_reparent (GdkWindow *window,
   GdkWindowObject *private;
   GdkWindowObject *new_parent_private;
   GdkWindowObject *old_parent;
-  gboolean show, was_toplevel, was_mapped;
+  GdkScreen *screen;
+  gboolean show, was_mapped;
   gboolean do_reparent_to_impl;
-  
+  GdkEventMask old_native_event_mask;
+
   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);
@@ -1069,9 +1467,10 @@ gdk_window_reparent (GdkWindow *window,
       (new_parent && GDK_WINDOW_DESTROYED (new_parent)))
     return;
 
+  screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
   if (!new_parent)
-    new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window));
-  
+    new_parent = gdk_screen_get_root_window (screen);
+
   private = (GdkWindowObject *) window;
   new_parent_private = (GdkWindowObject *)new_parent;
 
@@ -1082,7 +1481,7 @@ gdk_window_reparent (GdkWindow *window,
   /* Don't create loops in hierarchy */
   if (is_parent_of (window, new_parent))
     return;
-  
+
   if (private->cairo_surface)
     {
       /* This might be wrong in the new parent, e.g. for non-native surfaces.
@@ -1091,7 +1490,7 @@ gdk_window_reparent (GdkWindow *window,
       cairo_surface_set_user_data (private->cairo_surface, &gdk_window_cairo_key,
                                   NULL, NULL);
     }
-  
+
   old_parent = private->parent;
 
   /* Break up redirection if inherited */
@@ -1101,18 +1500,19 @@ gdk_window_reparent (GdkWindow *window,
       private->redirect = NULL;
     }
 
-  was_toplevel = private->parent == NULL;
   was_mapped = GDK_WINDOW_IS_MAPPED (window);
   show = FALSE;
 
   /* Reparenting to toplevel. Ensure we have a native window so this can work */
   if (new_parent_private->window_type == GDK_WINDOW_ROOT ||
       new_parent_private->window_type == GDK_WINDOW_FOREIGN)
-    gdk_window_set_has_native (window, TRUE);
+    gdk_window_ensure_native (window);
 
+  old_native_event_mask = 0;
   do_reparent_to_impl = FALSE;
   if (gdk_window_has_impl (private))
     {
+      old_native_event_mask = get_native_event_mask (private);
       /* Native window */
       show = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->reparent (window, new_parent, x, y);
     }
@@ -1136,19 +1536,19 @@ gdk_window_reparent (GdkWindow *window,
    */
   if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
     {
-      new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window));
+      new_parent = gdk_screen_get_root_window (screen);
       new_parent_private = (GdkWindowObject *)new_parent;
     }
 
-  if (private->parent)
-    private->parent->children = g_list_remove (private->parent->children, window);
-  
+  if (old_parent)
+    old_parent->children = g_list_remove (old_parent->children, window);
+
   private->parent = new_parent_private;
   private->x = x;
   private->y = y;
 
   new_parent_private->children = g_list_prepend (new_parent_private->children, window);
-  
+
   /* Switch the window type as appropriate */
 
   switch (GDK_WINDOW_TYPE (new_parent))
@@ -1179,8 +1579,14 @@ gdk_window_reparent (GdkWindow *window,
   /* We might have changed window type for a native windows, so we
      need to change the event mask too. */
   if (gdk_window_has_impl (private))
-    GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window, get_native_event_mask (private));
-  
+    {
+      GdkEventMask native_event_mask = get_native_event_mask (private);
+
+      if (native_event_mask != old_native_event_mask)
+       GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window,
+                                                              native_event_mask);
+    }
+
   /* Inherit parent redirect if we don't have our own */
   if (private->parent && private->redirect == NULL)
     {
@@ -1188,6 +1594,8 @@ gdk_window_reparent (GdkWindow *window,
       apply_redirect_to_children (private, private->redirect);
     }
 
+  _gdk_window_update_viewable (window);
+
   recompute_visible_regions (private, TRUE, FALSE);
   if (old_parent && GDK_WINDOW_TYPE (old_parent) != GDK_WINDOW_ROOT)
     recompute_visible_regions (old_parent, FALSE, TRUE);
@@ -1196,42 +1604,36 @@ gdk_window_reparent (GdkWindow *window,
     reparent_to_impl (private);
   else
     {
-      GdkWindowObject *above;
-      GList listhead = {0};
-      
       /* The reparent will have put the native window topmost in the native parent,
        * which may be wrong wrt other native windows in the non-native hierarchy,
        * so restack */
-      above = find_native_sibling_above (private->parent, private);
-      if (above)
-       {
-         listhead.data = window;
-         GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above,
-                                                                   &listhead);
-       }
+      if (!gdk_window_has_impl (new_parent_private))
+       sync_native_window_stack_position (window);
     }
 
   if (show)
     gdk_window_show_unraised (window);
   else
-    _gdk_syntesize_crossing_events_for_geometry_change (window);
+    _gdk_synthesize_crossing_events_for_geometry_change (window);
 }
 
 /**
- * gdk_window_set_has_native:
+ * gdk_window_ensure_native:
  * @window: a #GdkWindow
- * @has_native: whethe the window should have a native window
  *
- * Tries to create or remove a window-system native window for this
- * GdkWindow. This may fail in some situations. For instance:
+ * Tries to ensure that there is a window-system native window for this
+ * GdkWindow. This may fail in some situations, returning %FALSE.
  *
- * Toplevel and foreign windows must have a native window.
  * Offscreen window and children of them can never have native windows.
+ *
  * Some backends may not support native child windows.
- * 
- **/
-void
-gdk_window_set_has_native (GdkWindow *window, gboolean has_native)
+ *
+ * Returns: %TRUE if the window has a native window, %FALSE otherwise
+ *
+ * Since: 2.18
+ */
+gboolean
+gdk_window_ensure_native (GdkWindow *window)
 {
   GdkWindowObject *private;
   GdkWindowObject *impl_window;
@@ -1242,94 +1644,73 @@ gdk_window_set_has_native (GdkWindow *window, gboolean has_native)
   GdkWindowObject *above;
   GList listhead;
 
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 
   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT ||
       GDK_WINDOW_DESTROYED (window))
-    return;
+    return FALSE;
 
   private = (GdkWindowObject *) window;
-  
-  if (has_native)
-    {
-      /* Create native window */
-
-      if (gdk_window_has_impl (private))
-       /* Already has an impl, either native (ok) or
-          offscreen (not supported). Bail. */
-       return; 
-
-      impl_window = gdk_window_get_impl_window (private);
-      if (impl_window->window_type == GDK_WINDOW_OFFSCREEN)
-       return; /* native in offscreens not supported */
-
-      screen = gdk_drawable_get_screen (window);
-      visual = gdk_drawable_get_visual (window);
-
-      attributes.colormap = gdk_drawable_get_colormap (window);
-      
-      old_impl = private->impl;
-      _gdk_window_impl_new (window, (GdkWindow *)private->parent, screen, visual,
-                           get_native_event_mask (private), &attributes, GDK_WA_COLORMAP);
-      new_impl = private->impl;
-
-      private->impl = old_impl;
-      change_impl (private, private, new_impl);
-      
-      /* Native window creation will put the native window topmost in the
-       * native parent, which may be wrong wrt other native windows in the
-       * non-native hierarchy, so restack */
-      above = find_native_sibling_above (private->parent, private);
-      if (above)
-       {
-         listhead.data = window;
-         listhead.prev = NULL;
-         listhead.next = NULL;
-         GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above,
-                                                                   &listhead);
-       }
-
-      recompute_visible_regions (private, FALSE, FALSE);
 
-      /* The shape may not have been set, as the clip region doesn't actually
-        change, so do it here manually */
-      GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0);
+  impl_window = gdk_window_get_impl_window (private);
 
-      reparent_to_impl (private);
+  if (impl_window->window_type == GDK_WINDOW_OFFSCREEN)
+    return FALSE; /* native in offscreens not supported */
 
-      GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, &private->bg_color);
-      if (private->bg_pixmap != NULL)
-       GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, private->bg_pixmap);
-      
-      GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_shape_combine_region ((GdkWindow *)private, private->input_shape, 0, 0);
+  if (impl_window == private)
+    /* Already has an impl, and its not offscreen . */
+    return TRUE;
 
-      if (gdk_window_is_viewable (window))
-       GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window);
+  /* Need to create a native window */
 
-      /* We sync here to ensure the window is created in the Xserver when
-       * this function returns. This is required because the returned XID
-       * for this window must be valid immediately, even with another
-       * connection to the Xserver */
-      gdk_display_sync (gdk_drawable_get_display (window));
-    }
-  else
-    {
-      /* Remove native window */
+  screen = gdk_drawable_get_screen (window);
+  visual = gdk_drawable_get_visual (window);
 
-      if (!gdk_window_has_impl (private))
-       return;  /* Not native, can't remove */
+  attributes.colormap = gdk_drawable_get_colormap (window);
 
-      if (private->window_type == GDK_WINDOW_OFFSCREEN)
-       return; /* Not native, can't remove */
-      
-      if (private->parent == NULL ||
-         GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
-       return; /* toplevel, must be native */
+  old_impl = private->impl;
+  _gdk_window_impl_new (window, (GdkWindow *)private->parent, screen, visual,
+                       get_native_event_mask (private), &attributes, GDK_WA_COLORMAP);
+  new_impl = private->impl;
 
-      g_warning ("Tried to turn native window to client side window, this is not supported yet.");
+  private->impl = old_impl;
+  change_impl (private, private, new_impl);
 
-      /* TODO: remove native */
+  /* Native window creation will put the native window topmost in the
+   * native parent, which may be wrong wrt the position of the previous
+   * non-native window wrt to the other non-native children, so correct this.
+   */
+  above = find_native_sibling_above (private->parent, private);
+  if (above)
+    {
+      listhead.data = window;
+      listhead.prev = NULL;
+      listhead.next = NULL;
+      GDK_WINDOW_IMPL_GET_IFACE (private->impl)->restack_under ((GdkWindow *)above,
+                                                               &listhead);
+    }
+
+  recompute_visible_regions (private, FALSE, FALSE);
+
+  /* The shape may not have been set, as the clip region doesn't actually
+     change, so do it here manually */
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0);
+
+  reparent_to_impl (private);
+
+  if (!private->input_only)
+    {
+      GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, &private->bg_color);
+      if (private->bg_pixmap != NULL)
+       GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, private->bg_pixmap);
     }
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_shape_combine_region ((GdkWindow *)private, private->input_shape, 0, 0);
+
+  if (gdk_window_is_viewable (window))
+    GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window, FALSE);
+
+  return TRUE;
 }
 
 static void
@@ -1340,10 +1721,10 @@ window_remove_filters (GdkWindow *window)
   if (obj->filters)
     {
       GList *tmp_list;
-      
+
       for (tmp_list = obj->filters; tmp_list; tmp_list = tmp_list->next)
        g_free (tmp_list->data);
-    
+
       g_list_free (obj->filters);
       obj->filters = NULL;
     }
@@ -1353,12 +1734,14 @@ window_remove_filters (GdkWindow *window)
  * _gdk_window_destroy_hierarchy:
  * @window: a #GdkWindow
  * @recursing: If TRUE, then this is being called because a parent
- *            was destroyed. This generally means that the call to the 
+ *            was destroyed.
+ * @recursing_native: If TRUE, then this is being called because a native parent
+ *            was destroyed. This generally means that the call to the
  *            windowing system to destroy the window can be omitted, since
  *            it will be destroyed as a result of the parent being destroyed.
- *            Unless @foreign_destroy.           
- * @foreign_destroy: If TRUE, the window or a parent was destroyed by some 
- *            external agency. The window has already been destroyed and no 
+ *            Unless @foreign_destroy.
+ * @foreign_destroy: If TRUE, the window or a parent was destroyed by some
+ *            external agency. The window has already been destroyed and no
  *            windowing system calls should be made. (This may never happen
  *            for some windowing systems.)
  *
@@ -1368,6 +1751,7 @@ window_remove_filters (GdkWindow *window)
 static void
 _gdk_window_destroy_hierarchy (GdkWindow *window,
                               gboolean   recursing,
+                              gboolean   recursing_native,
                               gboolean   foreign_destroy)
 {
   GdkWindowObject *private;
@@ -1381,10 +1765,10 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
   g_return_if_fail (GDK_IS_WINDOW (window));
 
   private = (GdkWindowObject*) window;
-  
+
   if (GDK_WINDOW_DESTROYED (window))
     return;
-    
+
   display = gdk_drawable_get_display (GDK_DRAWABLE (window));
   screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
   temp_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
@@ -1392,7 +1776,7 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
     g_object_set_qdata (G_OBJECT (screen), quark_pointer_window, NULL);
 
 
-  switch (GDK_WINDOW_TYPE (window))
+  switch (private->window_type)
     {
     case GDK_WINDOW_ROOT:
       if (!screen->closed)
@@ -1407,7 +1791,7 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
     case GDK_WINDOW_TEMP:
     case GDK_WINDOW_FOREIGN:
     case GDK_WINDOW_OFFSCREEN:
-      if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_FOREIGN && !foreign_destroy)
+      if (private->window_type == GDK_WINDOW_FOREIGN && !foreign_destroy)
        {
          /* Logically, it probably makes more sense to send
           * a "destroy yourself" message to the foreign window
@@ -1443,38 +1827,40 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
            }
 
          gdk_window_free_paint_stack (window);
-         
+
          if (private->bg_pixmap &&
-              private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
-              private->bg_pixmap != GDK_NO_BG)
+             private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
+             private->bg_pixmap != GDK_NO_BG)
            {
              g_object_unref (private->bg_pixmap);
              private->bg_pixmap = NULL;
            }
-         
-         if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_FOREIGN)
+
+         if (private->window_type == GDK_WINDOW_FOREIGN)
            g_assert (private->children == NULL);
          else
            {
              children = tmp = private->children;
              private->children = NULL;
-             
+
              while (tmp)
                {
                  temp_window = tmp->data;
                  tmp = tmp->next;
-                 
+
                  temp_private = (GdkWindowObject*) temp_window;
                  if (temp_private)
                    _gdk_window_destroy_hierarchy (temp_window,
-                                                   TRUE, foreign_destroy);
+                                                  TRUE,
+                                                  recursing_native || gdk_window_has_impl (private),
+                                                  foreign_destroy);
                }
-             
+
              g_list_free (children);
            }
 
-         _gdk_window_clear_update_area (window); 
-         
+         _gdk_window_clear_update_area (window);
+
          if (private->cairo_surface)
            {
              cairo_surface_finish (private->cairo_surface);
@@ -1482,9 +1868,13 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
                                           NULL, NULL);
            }
 
+
+         if (private->extension_events)
+           GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_window_destroy (window);
+
          if (gdk_window_has_impl (private))
            {
-             GDK_WINDOW_IMPL_GET_IFACE (private->impl)->destroy (window, recursing, foreign_destroy);
+             GDK_WINDOW_IMPL_GET_IFACE (private->impl)->destroy (window, recursing_native, foreign_destroy);
            }
          else
            {
@@ -1498,7 +1888,7 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
 
          window_remove_filters (window);
 
-          gdk_drawable_set_colormap (GDK_DRAWABLE (window), NULL);
+         gdk_drawable_set_colormap (GDK_DRAWABLE (window), NULL);
 
          /* If we own the redirect, free it */
          if (private->redirect && private->redirect->redirected == private)
@@ -1511,6 +1901,25 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
              g_object_unref (display->pointer_info.toplevel_under_pointer);
              display->pointer_info.toplevel_under_pointer = NULL;
            }
+
+         if (private->clip_region)
+           {
+             gdk_region_destroy (private->clip_region);
+             private->clip_region = NULL;
+           }
+
+         if (private->clip_region_with_children)
+           {
+             gdk_region_destroy (private->clip_region_with_children);
+             private->clip_region_with_children = NULL;
+           }
+
+         if (private->outstanding_moves)
+           {
+             g_list_foreach (private->outstanding_moves, (GFunc)gdk_window_region_move_free, NULL);
+             g_list_free (private->outstanding_moves);
+             private->outstanding_moves = NULL;
+           }
        }
       break;
     }
@@ -1531,7 +1940,7 @@ void
 _gdk_window_destroy (GdkWindow *window,
                     gboolean   foreign_destroy)
 {
-  _gdk_window_destroy_hierarchy (window, FALSE, foreign_destroy);
+  _gdk_window_destroy_hierarchy (window, FALSE, FALSE, foreign_destroy);
 }
 
 /**
@@ -1549,7 +1958,7 @@ _gdk_window_destroy (GdkWindow *window,
 void
 gdk_window_destroy (GdkWindow *window)
 {
-  _gdk_window_destroy_hierarchy (window, FALSE, FALSE);
+  _gdk_window_destroy_hierarchy (window, FALSE, FALSE, FALSE);
   g_object_unref (window);
 }
 
@@ -1565,7 +1974,7 @@ gdk_window_destroy (GdkWindow *window)
  * this function for that. If GTK+ receives an event for a #GdkWindow,
  * and the user data for the window is non-%NULL, GTK+ will assume the
  * user data is a #GtkWidget, and forward the event to that widget.
- * 
+ *
  **/
 void
 gdk_window_set_user_data (GdkWindow *window,
@@ -1583,7 +1992,7 @@ gdk_window_set_user_data (GdkWindow *window,
  *
  * Retrieves the user data for @window, which is normally the widget
  * that @window belongs to. See gdk_window_set_user_data().
- * 
+ *
  **/
 void
 gdk_window_get_user_data (GdkWindow *window,
@@ -1597,16 +2006,16 @@ gdk_window_get_user_data (GdkWindow *window,
 /**
  * gdk_window_get_window_type:
  * @window: a #GdkWindow
- * 
+ *
  * Gets the type of the window. See #GdkWindowType.
- * 
+ *
  * Return value: type of window
  **/
 GdkWindowType
 gdk_window_get_window_type (GdkWindow *window)
 {
   g_return_val_if_fail (GDK_IS_WINDOW (window), (GdkWindowType) -1);
-  
+
   return GDK_WINDOW_TYPE (window);
 }
 
@@ -1623,7 +2032,7 @@ gdk_window_get_window_type (GdkWindow *window)
  * received or processed.
  *
  * The position coordinates are relative to the window's parent window.
- * 
+ *
  **/
 void
 gdk_window_get_position (GdkWindow *window,
@@ -1631,11 +2040,11 @@ gdk_window_get_position (GdkWindow *window,
                         gint      *y)
 {
   GdkWindowObject *obj;
-  
+
   g_return_if_fail (GDK_IS_WINDOW (window));
-  
+
   obj = (GdkWindowObject*) window;
-  
+
   if (x)
     *x = obj->x;
   if (y)
@@ -1645,60 +2054,60 @@ gdk_window_get_position (GdkWindow *window,
 /**
  * gdk_window_get_parent:
  * @window: a #GdkWindow
- * 
+ *
  * Obtains the parent of @window, as known to GDK. Does not query the
  * X server; thus this returns the parent as passed to gdk_window_new(),
  * not the actual parent. This should never matter unless you're using
  * Xlib calls mixed with GDK calls on the X11 platform. It may also
  * matter for toplevel windows, because the window manager may choose
  * to reparent them.
- * 
+ *
  * Return value: parent of @window
  **/
 GdkWindow*
 gdk_window_get_parent (GdkWindow *window)
 {
   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
-  
+
   return (GdkWindow*) ((GdkWindowObject*) window)->parent;
 }
 
 /**
  * gdk_window_get_toplevel:
  * @window: a #GdkWindow
- * 
+ *
  * Gets the toplevel window that's an ancestor of @window.
  *
  * Any window type but %GDK_WINDOW_CHILD is considered a
  * toplevel window, as is a %GDK_WINDOW_CHILD window that
- * has a root window as parent. 
- * 
+ * has a root window as parent.
+ *
  * Return value: the toplevel window containing @window
  **/
 GdkWindow*
 gdk_window_get_toplevel (GdkWindow *window)
 {
   GdkWindowObject *obj;
-  
+
   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 
   obj = (GdkWindowObject *)window;
-  
-  while (GDK_WINDOW_TYPE (obj) == GDK_WINDOW_CHILD)
+
+  while (obj->window_type == GDK_WINDOW_CHILD)
     {
       if (obj->parent == NULL ||
-         GDK_WINDOW_TYPE (obj->parent) == GDK_WINDOW_ROOT)
+         obj->parent->window_type == GDK_WINDOW_ROOT)
        break;
       obj = obj->parent;
     }
-  
+
   return GDK_WINDOW (obj);
 }
 
 /**
  * gdk_window_get_children:
  * @window: a #GdkWindow
- * 
+ *
  * Gets the list of children of @window known to GDK.
  * This function only returns children created via GDK,
  * so for example it's useless when used with the root window;
@@ -1706,7 +2115,7 @@ gdk_window_get_toplevel (GdkWindow *window)
  *
  * The returned list must be freed, but the elements in the
  * list need not be.
- * 
+ *
  * Return value: list of child windows inside @window
  **/
 GList*
@@ -1723,10 +2132,10 @@ gdk_window_get_children (GdkWindow *window)
 /**
  * gdk_window_peek_children:
  * @window: a #GdkWindow
- * 
+ *
  * Like gdk_window_get_children(), but does not copy the list of
  * children, so the list does not need to be freed.
- * 
+ *
  * Return value: a reference to the list of child windows in @window
  **/
 GList *
@@ -1755,7 +2164,7 @@ gdk_window_peek_children (GdkWindow *window)
  * See gdk_display_add_client_message_filter() if you are interested
  * in X ClientMessage events.
  **/
-void          
+void
 gdk_window_add_filter (GdkWindow     *window,
                       GdkFilterFunc  function,
                       gpointer       data)
@@ -1763,7 +2172,7 @@ gdk_window_add_filter (GdkWindow     *window,
   GdkWindowObject *private;
   GList *tmp_list;
   GdkEventFilter *filter;
-  
+
   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
 
   private = (GdkWindowObject*) window;
@@ -1773,13 +2182,13 @@ gdk_window_add_filter (GdkWindow     *window,
   /* Filters are for the native events on the native window, so
      ensure there is a native window. */
   if (window)
-    gdk_window_set_has_native (window, TRUE);
-  
+    gdk_window_ensure_native (window);
+
   if (private)
     tmp_list = private->filters;
   else
     tmp_list = _gdk_default_filters;
-  
+
   while (tmp_list)
     {
       filter = (GdkEventFilter *)tmp_list->data;
@@ -1787,11 +2196,11 @@ gdk_window_add_filter (GdkWindow     *window,
        return;
       tmp_list = tmp_list->next;
     }
-  
+
   filter = g_new (GdkEventFilter, 1);
   filter->function = function;
   filter->data = data;
-  
+
   if (private)
     private->filters = g_list_append (private->filters, filter);
   else
@@ -1805,7 +2214,7 @@ gdk_window_add_filter (GdkWindow     *window,
  * @data: user data for previously-added filter function
  *
  * Remove a filter previously added with gdk_window_add_filter().
- * 
+ *
  **/
 void
 gdk_window_remove_filter (GdkWindow     *window,
@@ -1815,22 +2224,22 @@ gdk_window_remove_filter (GdkWindow     *window,
   GdkWindowObject *private;
   GList *tmp_list, *node;
   GdkEventFilter *filter;
-  
+
   g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
 
   private = (GdkWindowObject*) window;
-  
+
   if (private)
     tmp_list = private->filters;
   else
     tmp_list = _gdk_default_filters;
-  
+
   while (tmp_list)
     {
       filter = (GdkEventFilter *)tmp_list->data;
       node = tmp_list;
       tmp_list = tmp_list->next;
-      
+
       if ((filter->function == function) && (filter->data == data))
        {
          if (private)
@@ -1839,7 +2248,7 @@ gdk_window_remove_filter (GdkWindow     *window,
            _gdk_default_filters = g_list_remove_link (_gdk_default_filters, node);
          g_list_free_1 (node);
          g_free (filter);
-         
+
          return;
        }
     }
@@ -1848,14 +2257,14 @@ gdk_window_remove_filter (GdkWindow     *window,
 /**
  * gdk_screen_get_toplevel_windows:
  * @screen: The #GdkScreen where the toplevels are located.
- * 
+ *
  * Obtains a list of all toplevel windows known to GDK on the screen @screen.
  * A toplevel window is a child of the root window (see
  * gdk_get_default_root_window()).
  *
  * The returned list should be freed with g_list_free(), but
  * its elements need not be freed.
- * 
+ *
  * Return value: list of toplevel windows, free with g_list_free()
  *
  * Since: 2.2
@@ -1866,25 +2275,27 @@ gdk_screen_get_toplevel_windows (GdkScreen *screen)
   GdkWindow * root_window;
   GList *new_list = NULL;
   GList *tmp_list;
-  
+
   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
-  
+
   root_window = gdk_screen_get_root_window (screen);
 
   tmp_list = ((GdkWindowObject *)root_window)->children;
   while (tmp_list)
     {
-      if (GDK_WINDOW_TYPE (tmp_list->data) != GDK_WINDOW_FOREIGN)
-       new_list = g_list_prepend (new_list, tmp_list->data);
+      GdkWindowObject *w = tmp_list->data;
+
+      if (w->window_type != GDK_WINDOW_FOREIGN)
+       new_list = g_list_prepend (new_list, w);
       tmp_list = tmp_list->next;
     }
-  
+
   return new_list;
 }
 
 /**
  * gdk_window_get_toplevels:
- * 
+ *
  * Obtains a list of all toplevel windows known to GDK on the default
  * screen (see gdk_screen_get_toplevel_windows()).
  * A toplevel window is a child of the root window (see
@@ -1892,7 +2303,7 @@ gdk_screen_get_toplevel_windows (GdkScreen *screen)
  *
  * The returned list should be freed with g_list_free(), but
  * its elements need not be freed.
- * 
+ *
  * Return value: list of toplevel windows, free with g_list_free()
  *
  * Deprecated: 2.16: Use gdk_screen_get_toplevel_windows() instead.
@@ -1906,24 +2317,24 @@ gdk_window_get_toplevels (void)
 /**
  * gdk_window_is_visible:
  * @window: a #GdkWindow
- * 
+ *
  * Checks whether the window has been mapped (with gdk_window_show() or
  * gdk_window_show_unraised()).
- * 
+ *
  * Return value: %TRUE if the window is mapped
  **/
-gboolean 
+gboolean
 gdk_window_is_visible (GdkWindow *window)
 {
   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
-  
+
   return GDK_WINDOW_IS_MAPPED (window);
 }
 
 /**
  * gdk_window_is_viewable:
  * @window: a #GdkWindow
- * 
+ *
  * Check if the window and all ancestors of the window are
  * mapped. (This is not necessarily "viewable" in the X sense, since
  * we only check as far as we have GDK window parents, not to the root
@@ -1931,47 +2342,35 @@ gdk_window_is_visible (GdkWindow *window)
  *
  * Return value: %TRUE if the window is viewable
  **/
-gboolean 
+gboolean
 gdk_window_is_viewable (GdkWindow *window)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
-  GdkScreen *screen;
-  GdkWindow *root_window;
 
   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 
-  screen = gdk_drawable_get_screen (window);
-  root_window = gdk_screen_get_root_window (screen);
-  
-  while (private && 
-        (private != (GdkWindowObject *)root_window) &&
-        (GDK_WINDOW_TYPE (private) != GDK_WINDOW_FOREIGN))
-    {
-      if (GDK_WINDOW_DESTROYED (private) || !GDK_WINDOW_IS_MAPPED (private))
-       return FALSE;
-      
-      private = (GdkWindowObject *)private->parent;
-    }
-  
-  return TRUE;
+  if (private->destroyed)
+    return FALSE;
+
+  return private->viewable;
 }
 
 /**
  * gdk_window_get_state:
  * @window: a #GdkWindow
- * 
+ *
  * Gets the bitwise OR of the currently active window state flags,
  * from the #GdkWindowState enumeration.
- * 
+ *
  * Return value: window state bitfield
  **/
 GdkWindowState
 gdk_window_get_state (GdkWindow *window)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
-  
+
   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
-  
+
   return private->state;
 }
 
@@ -1995,9 +2394,12 @@ gdk_window_begin_implicit_paint (GdkWindow *window, GdkRectangle *rect)
 
   g_assert (gdk_window_has_impl (private));
 
+  if (_gdk_native_windows)
+    return FALSE; /* No need for implicit paints since we can't merge draws anyway */
+
   if (GDK_IS_PAINTABLE (private->impl))
     return FALSE; /* Implementation does double buffering */
-  
+
   if (private->paint_stack != NULL ||
       private->implicit_paint != NULL)
     return FALSE; /* Don't stack implicit paints */
@@ -2013,12 +2415,13 @@ gdk_window_begin_implicit_paint (GdkWindow *window, GdkRectangle *rect)
                    MAX (rect->width, 1), MAX (rect->height, 1), -1);
 
   private->implicit_paint = paint;
-  
+
   return TRUE;
 }
 
 /* Ensure that all content related to this (sub)window is pushed to the
-   native region */
+   native region. If there is an active paint then that area is not
+   pushed, in order to not show partially finished double buffers. */
 static void
 gdk_window_flush_implicit_paint (GdkWindow *window)
 {
@@ -2027,19 +2430,27 @@ gdk_window_flush_implicit_paint (GdkWindow *window)
   GdkWindowPaint *paint;
   GdkRegion *region;
   GdkGC *tmp_gc;
+  GSList *list;
 
-  /* Ensure that there is no explicit paint region. */
-  g_assert (private->paint_stack == NULL);
-  
   impl_window = gdk_window_get_impl_window (private);
   if (impl_window->implicit_paint == NULL)
     return;
 
   paint = impl_window->implicit_paint;
   region = gdk_region_copy (private->clip_region_with_children);
+
+  /* Don't flush active double buffers, as that may show partially done
+   * rendering */
+  for (list = private->paint_stack; list != NULL; list = list->next)
+    {
+      GdkWindowPaint *tmp_paint = list->data;
+
+      gdk_region_subtract (region, tmp_paint->region);
+    }
+
   gdk_region_offset (region, private->abs_x, private->abs_y);
   gdk_region_intersect (region, paint->region);
-  
+
   if (!gdk_region_empty (region))
     {
       /* Some regions are valid, push these to window now */
@@ -2073,8 +2484,6 @@ gdk_window_end_implicit_paint (GdkWindow *window)
 
   private->implicit_paint = NULL;
 
-  gdk_window_flush_outstanding_moves (window);
-
   if (!gdk_region_empty (paint->region))
     {
       /* Some regions are valid, push these to window now */
@@ -2085,7 +2494,7 @@ gdk_window_end_implicit_paint (GdkWindow *window)
       /* Reset clip region of the cached GdkGC */
       gdk_gc_set_clip_region (tmp_gc, NULL);
     }
-  
+
   g_object_unref (paint->pixmap);
   g_free (paint);
 }
@@ -2098,11 +2507,11 @@ gdk_window_end_implicit_paint (GdkWindow *window)
  * A convenience wrapper around gdk_window_begin_paint_region() which
  * creates a rectangular region for you. See
  * gdk_window_begin_paint_region() for details.
- * 
+ *
  **/
 void
 gdk_window_begin_paint_rect (GdkWindow          *window,
-                             const GdkRectangle *rectangle)
+                            const GdkRectangle *rectangle)
 {
   GdkRegion *region;
 
@@ -2113,10 +2522,6 @@ gdk_window_begin_paint_rect (GdkWindow          *window,
   gdk_region_destroy (region);
 }
 
-#ifdef GDK_WINDOWING_X11
-#include "x11/gdkx.h"
-#endif
-
 /**
  * gdk_window_begin_paint_region:
  * @window: a #GdkWindow
@@ -2160,11 +2565,11 @@ gdk_window_begin_paint_rect (GdkWindow          *window,
  * the topmost backing store in the stack. One matching call to
  * gdk_window_end_paint() is required for each call to
  * gdk_window_begin_paint_region().
- * 
+ *
  **/
-void         
+void
 gdk_window_begin_paint_region (GdkWindow       *window,
-                               const GdkRegion *region)
+                              const GdkRegion *region)
 {
 #ifdef USE_BACKING_STORE
   GdkWindowObject *private = (GdkWindowObject *)window;
@@ -2172,21 +2577,19 @@ gdk_window_begin_paint_region (GdkWindow       *window,
   GdkWindowPaint *paint, *implicit_paint;
   GdkWindowObject *impl_window;
   GSList *list;
-  GList *l;
-  GdkWindowRegionMove *move;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
 
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
-  if (GDK_IS_PAINTABLE (private->impl)) 
+  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, window, region);
-      
+       iface->begin_paint_region ((GdkPaintable*)private->impl, window, region);
+
       return;
     }
 
@@ -2204,36 +2607,24 @@ gdk_window_begin_paint_region (GdkWindow       *window,
   gdk_region_offset (paint->region, private->abs_x, private->abs_y);
 
   /* Mark the region as valid on the implicit paint */
-  
+
   if (implicit_paint)
     gdk_region_union (implicit_paint->region, paint->region);
 
-  /* No need to do any moves that will end up over the exposed area */
-  for (l = impl_window->outstanding_moves; l != NULL; l = l->next)
-    {
-      move = l->data;
-      gdk_region_subtract (move->region, paint->region);
-    }
-  
   /* Convert back to normal coords */
   gdk_region_offset (paint->region, -private->abs_x, -private->abs_y);
-  
+
   if (implicit_paint)
     {
       int width, height;
-      
+
       paint->uses_implicit = TRUE;
       paint->pixmap = g_object_ref (implicit_paint->pixmap);
       paint->x_offset = -private->abs_x + implicit_paint->x_offset;
       paint->y_offset = -private->abs_y + implicit_paint->y_offset;
-      
-      /* It would be nice if we had some cairo support here so we
-        could set the clip rect on the cairo surface */
-      width = private->abs_x + private->width;
-      height = private->abs_y + private->height;
-      
-      paint->surface = _gdk_drawable_create_cairo_surface (paint->pixmap, width, height);
 
+      gdk_drawable_get_size (paint->pixmap, &width, &height);
+      paint->surface = _gdk_drawable_create_cairo_surface (paint->pixmap, width, height);
     }
   else
     {
@@ -2245,25 +2636,24 @@ gdk_window_begin_paint_region (GdkWindow       *window,
                        MAX (clip_box.width, 1), MAX (clip_box.height, 1), -1);
       paint->surface = _gdk_drawable_ref_cairo_surface (paint->pixmap);
     }
+
   if (paint->surface)
     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;
 
       gdk_region_subtract (tmp_paint->region, paint->region);
     }
-  
+
   private->paint_stack = g_slist_prepend (private->paint_stack, paint);
 
   if (!gdk_region_empty (paint->region))
     {
-      gdk_window_clear_backing_rect (window,
-                                    clip_box.x, clip_box.y,
-                                    clip_box.width, clip_box.height);
+      gdk_window_clear_backing_region (window,
+                                      paint->region);
     }
 
 #endif /* USE_BACKING_STORE */
@@ -2283,13 +2673,13 @@ setup_redirect_clip (GdkWindow      *window,
   int x_offset, y_offset;
 
   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,
                                            TRUE,
-                                           &x_offset, 
+                                           &x_offset,
                                            &y_offset);
 
   /* Compensate for the source pos/size */
@@ -2329,7 +2719,7 @@ setup_redirect_clip (GdkWindow      *window,
  * gdk_window_begin_paint_region() for full details. It is an error to
  * call this function without a matching
  * gdk_window_begin_paint_region() first.
- * 
+ *
  **/
 void
 gdk_window_end_paint (GdkWindow *window)
@@ -2353,7 +2743,7 @@ gdk_window_end_paint (GdkWindow *window)
       GdkPaintableIface *iface = GDK_PAINTABLE_GET_IFACE (private->impl);
 
       if (iface->end_paint)
-        iface->end_paint ((GdkPaintable*)private->impl);
+       iface->end_paint ((GdkPaintable*)private->impl);
       return;
     }
 
@@ -2365,7 +2755,7 @@ gdk_window_end_paint (GdkWindow *window)
 
   paint = private->paint_stack->data;
 
-  private->paint_stack = g_slist_delete_link (private->paint_stack, 
+  private->paint_stack = g_slist_delete_link (private->paint_stack,
                                              private->paint_stack);
 
   gdk_region_get_clipbox (paint->region, &clip_box);
@@ -2378,7 +2768,7 @@ gdk_window_end_paint (GdkWindow *window)
   if (!paint->uses_implicit)
     {
       gdk_window_flush_outstanding_moves (window);
-      
+
       full_clip = gdk_region_copy (private->clip_region_with_children);
       gdk_region_intersect (full_clip, paint->region);
       _gdk_gc_set_clip_region_internal (tmp_gc, full_clip, TRUE); /* Takes ownership of full_clip */
@@ -2389,7 +2779,7 @@ 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)
     {
       int x_offset, y_offset;
@@ -2403,7 +2793,7 @@ gdk_window_end_paint (GdkWindow *window)
                         clip_box.y + y_offset,
                         clip_box.width, clip_box.height);
     }
-  
+
   /* Reset clip region of the cached GdkGC */
   gdk_gc_set_clip_region (tmp_gc, NULL);
 
@@ -2446,7 +2836,7 @@ static void
 gdk_window_free_paint_stack (GdkWindow *window)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
-  
+
   if (private->paint_stack)
     {
       GSList *tmp_list = private->paint_stack;
@@ -2457,7 +2847,7 @@ gdk_window_free_paint_stack (GdkWindow *window)
 
          if (tmp_list == private->paint_stack)
            g_object_unref (paint->pixmap);
-                 
+
          gdk_region_destroy (paint->region);
          g_free (paint);
 
@@ -2470,17 +2860,13 @@ gdk_window_free_paint_stack (GdkWindow *window)
 }
 
 static void
-do_move_region_bits_on_impl (GdkWindowObject *private,
-                            GdkRegion *region, /* In impl window coords */
+do_move_region_bits_on_impl (GdkWindowObject *impl_window,
+                            GdkRegion *dest_region, /* In impl window coords */
                             int dx, int dy)
 {
   GdkGC *tmp_gc;
   GdkRectangle copy_rect;
-  GdkDrawable *dest;
-
-  dest = private->impl;
-  
-  gdk_region_get_clipbox (region, &copy_rect);
+  GdkWindowObject *private;
 
   /* We need to get data from subwindows here, because we might have
    * shaped a native window over the moving region (with bg none,
@@ -2488,17 +2874,27 @@ do_move_region_bits_on_impl (GdkWindowObject *private,
    * from overlapping native window that are not children of this window,
    * so we copy from the toplevel with INCLUDE_INFERIORS.
    */
-  private = gdk_window_get_impl_window (private);
+  private = impl_window;
   while (private->parent != NULL &&
-        GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
+        private->parent->window_type != GDK_WINDOW_ROOT)
     {
       dx -= private->parent->abs_x + private->x;
       dy -= private->parent->abs_y + private->y;
       private = gdk_window_get_impl_window (private->parent);
     }
   tmp_gc = _gdk_drawable_get_subwindow_scratch_gc ((GdkWindow *)private);
-  gdk_gc_set_clip_region (tmp_gc, region);
-  gdk_draw_drawable (dest,
+
+  gdk_region_get_clipbox (dest_region, &copy_rect);
+  gdk_gc_set_clip_region (tmp_gc, dest_region);
+
+  /* The region area is moved and we queue translations for all expose events
+     to the source area that were sent prior to the copy */
+  gdk_region_offset (dest_region, -dx, -dy); /* Move to source region */
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->queue_translation ((GdkWindow *)impl_window,
+                                                               tmp_gc,
+                                                               dest_region, dx, dy);
+
+  gdk_draw_drawable (impl_window->impl,
                     tmp_gc,
                     private->impl,
                     copy_rect.x-dx, copy_rect.y-dy,
@@ -2507,67 +2903,148 @@ do_move_region_bits_on_impl (GdkWindowObject *private,
   gdk_gc_set_clip_region (tmp_gc, NULL);
 }
 
-static void
-append_move_region (GdkWindowObject *impl_window,
-                   GdkRegion *region,
-                   int dx, int dy)
+static GdkWindowRegionMove *
+gdk_window_region_move_new (GdkRegion *region,
+                           int dx, int dy)
 {
-  GList *moves_to_add, *l, *s;
-  GdkRegion *intersection;
-  GdkWindowRegionMove *move, *new_move, *existing_move;
-  
+  GdkWindowRegionMove *move;
+
   move = g_slice_new (GdkWindowRegionMove);
-  move->region  = region;
+  move->dest_region  = gdk_region_copy (region);
   move->dx = dx;
   move->dy = dy;
 
-  moves_to_add = g_list_prepend (NULL, move);
+  return move;
+}
 
-  for (l = impl_window->outstanding_moves; l != NULL; l = l->next)
-    {
-      existing_move = l->data;
-      
-      for (s = moves_to_add; s != NULL; s = s->next)
-       {
-         move = s->data;
+static void
+gdk_window_region_move_free (GdkWindowRegionMove *move)
+{
+  gdk_region_destroy (move->dest_region);
+  g_slice_free (GdkWindowRegionMove, move);
+}
+
+static void
+append_move_region (GdkWindowObject *impl_window,
+                   GdkRegion *new_dest_region,
+                   int dx, int dy)
+{
+  GdkWindowRegionMove *move, *old_move;
+  GdkRegion *new_total_region, *old_total_region;
+  GdkRegion *source_overlaps_destination;
+  GdkRegion *non_overwritten;
+  gboolean added_move;
+  GList *l, *prev;
 
-         intersection = gdk_region_copy (move->region);
-         gdk_region_offset (intersection, -move->dx, -move->dy);
-         gdk_region_intersect (intersection, existing_move->region);
-         gdk_region_offset (intersection, move->dx, move->dy);
+  if (gdk_region_empty (new_dest_region))
+    return;
 
-         if (!gdk_region_empty (intersection))
+  /* In principle this could just append the move to the list of outstanding
+     moves that will be replayed before drawing anything when we're handling
+     exposes. However, we'd like to do a bit better since its commonly the case
+     that we get multiple copies where A is copied to B and then B is copied
+     to C, and we'd like to express this as a simple copy A to C operation. */
+
+  /* We approach this by taking the new move and pushing it ahead of moves
+     starting at the end of the list and stopping when its not safe to do so.
+     It's not safe to push past a move if either the source of the new move
+     is in the destination of the old move, or if the destination of the new
+     move is in the source of the new move, or if the destination of the new
+     move overlaps the destination of the old move. We simplify this by
+     just comparing the total regions (src + dest) */
+  new_total_region = gdk_region_copy (new_dest_region);
+  gdk_region_offset (new_total_region, -dx, -dy);
+  gdk_region_union (new_total_region, new_dest_region);
+
+  added_move = FALSE;
+  for (l = g_list_last (impl_window->outstanding_moves); l != NULL; l = prev)
+    {
+      prev = l->prev;
+      old_move = l->data;
+
+      old_total_region = gdk_region_copy (old_move->dest_region);
+      gdk_region_offset (old_total_region, -old_move->dx, -old_move->dy);
+      gdk_region_union (old_total_region, old_move->dest_region);
+
+      gdk_region_intersect (old_total_region, new_total_region);
+      /* If these regions intersect then its not safe to push the
+        new region before the old one */
+      if (!gdk_region_empty (old_total_region))
+       {
+         /* The area where the new moves source overlaps the old ones
+            destination */
+         source_overlaps_destination = gdk_region_copy (new_dest_region);
+         gdk_region_offset (source_overlaps_destination, -dx, -dy);
+         gdk_region_intersect (source_overlaps_destination, old_move->dest_region);
+         gdk_region_offset (source_overlaps_destination, dx, dy);
+
+         /* We can do all sort of optimizations here, but to do things safely it becomes
+            quite complicated. However, a very common case is that you copy something first,
+            then copy all that or a subset of it to a new location (i.e. if you scroll twice
+            in the same direction). We'd like to detect this case and optimize it to one
+            copy. */
+         if (gdk_region_equal (source_overlaps_destination, new_dest_region))
            {
-             
-             new_move = g_slice_new (GdkWindowRegionMove);
-             new_move->region  = intersection;
-             new_move->dx = move->dx + existing_move->dx;
-             new_move->dy = move->dy + existing_move->dy;
-             moves_to_add = g_list_prepend (moves_to_add, new_move);
-
-             gdk_region_subtract (move->region, intersection);
-             gdk_region_subtract (existing_move->region, intersection);
+             /* This means we might be able to replace the old move and the new one
+                with the new one read from the old ones source, and a second copy of
+                the non-overwritten parts of the old move. However, such a split
+                is only valid if the source in the old move isn't overwritten
+                by the destination of the new one */
+
+             /* the new destination of old move if split is ok: */
+             non_overwritten = gdk_region_copy (old_move->dest_region);
+             gdk_region_subtract (non_overwritten, new_dest_region);
+             /* move to source region */
+             gdk_region_offset (non_overwritten, -old_move->dx, -old_move->dy);
+
+             gdk_region_intersect (non_overwritten, new_dest_region);
+             if (gdk_region_empty (non_overwritten))
+               {
+                 added_move = TRUE;
+                 move = gdk_window_region_move_new (new_dest_region,
+                                                    dx + old_move->dx,
+                                                    dy + old_move->dy);
+
+                 impl_window->outstanding_moves =
+                   g_list_insert_before (impl_window->outstanding_moves,
+                                         l, move);
+                 gdk_region_subtract (old_move->dest_region, new_dest_region);
+               }
+             gdk_region_destroy (non_overwritten);
            }
-         else
-           gdk_region_destroy (intersection);
+
+         gdk_region_destroy (source_overlaps_destination);
+         gdk_region_destroy (old_total_region);
+         break;
        }
+      gdk_region_destroy (old_total_region);
     }
 
-  impl_window->outstanding_moves = g_list_concat (impl_window->outstanding_moves,
-                                                 moves_to_add);
-  
+  gdk_region_destroy (new_total_region);
+
+  if (!added_move)
+    {
+      move = gdk_window_region_move_new (new_dest_region, dx, dy);
+
+      if (l == NULL)
+       impl_window->outstanding_moves =
+         g_list_prepend (impl_window->outstanding_moves,
+                         move);
+      else
+       impl_window->outstanding_moves =
+         g_list_insert_before (impl_window->outstanding_moves,
+                               l->next, move);
+    }
 }
 
-/* Moves bits and update area by dx/dy in impl window
- * Takes ownership of region.
- */
+/* Moves bits and update area by dx/dy in impl window.
+   Takes ownership of region to avoid copy (because we may change it) */
 static void
 move_region_on_impl (GdkWindowObject *private,
                     GdkRegion *region, /* In impl window coords */
                     int dx, int dy)
 {
   GdkWindowObject *impl_window;
-  gboolean free_region;
 
   if ((dx == 0 && dy == 0) ||
       gdk_region_empty (region))
@@ -2575,38 +3052,41 @@ move_region_on_impl (GdkWindowObject *private,
       gdk_region_destroy (region);
       return;
     }
-  
-  free_region = TRUE;
-  impl_window = gdk_window_get_impl_window (private);
 
-  if (1) /* Enable flicker free handling of moves. */
-    {
-      free_region = FALSE;
+  impl_window = gdk_window_get_impl_window (private);
 
-      append_move_region (impl_window, region, dx, dy);
-    }
-  else
-    do_move_region_bits_on_impl (private,
-                                region, dx, dy);
-    
   /* Move any old invalid regions in the copy source area by dx/dy */
   if (impl_window->update_area)
     {
       GdkRegion *update_area;
-      
       update_area = gdk_region_copy (region);
+
       /* Convert from target to source */
       gdk_region_offset (update_area, -dx, -dy);
       gdk_region_intersect (update_area, impl_window->update_area);
-      gdk_region_subtract (impl_window->update_area, update_area);
+      /* We only copy the area, so keep the old update area invalid.
+        It would be safe to remove it too, as code that uses
+        move_region_on_impl generally also invalidate the source
+        area. However, it would just use waste cycles. */
+
       /* Convert back */
       gdk_region_offset (update_area, dx, dy);
       gdk_region_union (impl_window->update_area, update_area);
+
+      /* This area of the destination is now invalid,
+        so no need to copy to it.  */
+      gdk_region_subtract (region, update_area);
+
       gdk_region_destroy (update_area);
     }
 
-  if (free_region)
-    gdk_region_destroy (region);
+  if (1) /* Enable flicker free handling of moves. */
+    append_move_region (impl_window, region, dx, dy);
+  else
+    do_move_region_bits_on_impl (impl_window,
+                                region, dx, dy);
+
+  gdk_region_destroy (region);
 }
 
 /* Flushes all outstanding changes to the window, call this
@@ -2621,20 +3101,19 @@ gdk_window_flush_outstanding_moves (GdkWindow *window)
   GdkWindowRegionMove *move;
 
   private = (GdkWindowObject *) window;
-  
+
   impl_window = gdk_window_get_impl_window (private);
-  
+
   for (l = impl_window->outstanding_moves; l != NULL; l = l->next)
     {
       move = l->data;
 
-      do_move_region_bits_on_impl (private,
-                                  move->region, move->dx, move->dy);
+      do_move_region_bits_on_impl (impl_window,
+                                  move->dest_region, move->dx, move->dy);
 
-      gdk_region_destroy (move->region);
-      g_slice_free (GdkWindowRegionMove, move);
+      gdk_window_region_move_free (move);
     }
-  
+
   g_list_free (impl_window->outstanding_moves);
   impl_window->outstanding_moves = NULL;
 }
@@ -2652,7 +3131,7 @@ gdk_window_flush_recursive_helper (GdkWindowObject *window,
 {
   GdkWindowObject *child;
   GList *l;
-  
+
   for (l = window->children; l != NULL; l = l->next)
     {
       child = l->data;
@@ -2695,15 +3174,15 @@ gdk_window_get_offsets (GdkWindow *window,
 /**
  * gdk_window_get_internal_paint_info:
  * @window: a #GdkWindow
- * @real_drawable: location to store the drawable to which drawing should be 
+ * @real_drawable: location to store the drawable to which drawing should be
  *            done.
  * @x_offset: location to store the X offset between coordinates in @window,
- *            and the underlying window system primitive coordinates for 
+ *            and the underlying window system primitive coordinates for
  *            *@real_drawable.
  * @y_offset: location to store the Y offset between coordinates in @window,
  *            and the underlying window system primitive coordinates for
  *            *@real_drawable.
- * 
+ *
  * If you bypass the GDK layer and use windowing system primitives to
  * draw directly onto a #GdkWindow, then you need to deal with two
  * details: there may be an offset between GDK coordinates and windowing
@@ -2722,7 +3201,7 @@ gdk_window_get_internal_paint_info (GdkWindow    *window,
                                    gint         *y_offset)
 {
   gint x_off, y_off;
-  
+
   GdkWindowObject *private;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
@@ -2753,104 +3232,127 @@ gdk_window_get_internal_paint_info (GdkWindow    *window,
     *y_offset = y_off;
 }
 
-static void
-setup_clip_for_draw (GdkDrawable *drawable,
-                    GdkGC *gc,
-                    int old_clip_x, int old_clip_y)
+static GdkDrawable *
+start_draw_helper (GdkDrawable *drawable,
+                  GdkGC *gc,
+                  gint *x_offset_out,
+                  gint *y_offset_out)
 {
   GdkWindowObject *private = (GdkWindowObject *)drawable;
+  gint x_offset, y_offset;
+  GdkDrawable *impl;
+  gint old_clip_x = gc->clip_x_origin;
+  gint old_clip_y = gc->clip_y_origin;
   GdkRegion *clip;
+  guint32 clip_region_tag;
+  GdkWindowPaint *paint;
 
-  if (private->window_type == GDK_WINDOW_ROOT)
-    return;
-  
-  if (_gdk_gc_get_subwindow (gc) == GDK_CLIP_BY_CHILDREN)
-    clip = private->clip_region_with_children;
-  else
-    clip = private->clip_region;
-    
-  _gdk_gc_add_drawable_clip (gc,
-                            private->clip_tag,
-                            clip,
-                            /* If there was a clip origin set appart from the
-                             * window offset, need to take that into consideration */
-                            -old_clip_x, -old_clip_y);
-}
+  paint = NULL;
+  if (private->paint_stack)
+    paint = private->paint_stack->data;
 
-static void
-setup_clip_for_paint (GdkDrawable *drawable,
-                     GdkWindowPaint *paint,
-                     GdkGC *gc,
-                     int old_clip_x, int old_clip_y)
-{
-  _gdk_gc_add_drawable_clip (gc,
-                            paint->region_tag,
-                            /* This includes the window clip */
-                            paint->region,
-                            /* If there was a clip origin set appart from the
-                             * window offset, need to take that into consideration */
-                            -old_clip_x, -old_clip_y);
-}
-
-
-#define OFFSET_GC(gc)                                         \
-    gint x_offset, y_offset;                                 \
-    gint old_clip_x = gc->clip_x_origin;    \
-    gint old_clip_y = gc->clip_y_origin;    \
-    gint old_ts_x = gc->ts_x_origin;        \
-    gint old_ts_y = gc->ts_y_origin;        \
-    gdk_window_get_offsets (drawable, &x_offset, &y_offset);  \
-    if (x_offset != 0 || y_offset != 0)                      \
-      {                                                       \
-        gdk_gc_set_clip_origin (gc, old_clip_x - x_offset,    \
-                               old_clip_y - y_offset);       \
-        gdk_gc_set_ts_origin (gc, old_ts_x - x_offset,        \
-                             old_ts_y - y_offset);           \
-      }
-
-#define RESTORE_GC(gc)                                      \
-    if (x_offset != 0 || y_offset != 0)                    \
-     {                                                      \
-       gdk_gc_set_clip_origin (gc, old_clip_x, old_clip_y); \
-       gdk_gc_set_ts_origin (gc, old_ts_x, old_ts_y);       \
-     }
+  if (paint)
+    {
+      x_offset = paint->x_offset;
+      y_offset = paint->y_offset;
+    }
+  else
+    {
+      x_offset = -private->abs_x;
+      y_offset = -private->abs_y;
+    }
 
-#define SETUP_PAINT_GC_CLIP(gc)                             \
-      if (paint->uses_implicit)                                    \
-       setup_clip_for_paint (drawable, paint, gc, old_clip_x,  \
-                              old_clip_y);
+  if (x_offset != 0 || y_offset != 0)
+    {
+      gdk_gc_set_clip_origin (gc,
+                             old_clip_x - x_offset,
+                             old_clip_y - y_offset);
+      gdk_gc_set_ts_origin (gc,
+                           gc->ts_x_origin - x_offset,
+                           gc->ts_y_origin - y_offset);
+    }
 
-#define RESTORE_PAINT_GC_CLIP(gc) 
+  *x_offset_out = x_offset;
+  *y_offset_out = y_offset;
 
+  /* Add client side window clip region to gc */
+  clip = NULL;
+  if (paint)
+    {
+      /* Only need clipping if using implicit paint, otherwise
+        the pixmap is clipped when copying to the window in end_paint */
+      if (paint->uses_implicit)
+       {
+         /* This includes the window clip */
+         clip = paint->region;
+       }
+      clip_region_tag = paint->region_tag;
 
-#define SETUP_DIRECT_GC_CLIP(gc)                            \
-      gdk_window_flush ((GdkWindow *)drawable);\
-      setup_clip_for_draw (drawable, gc, old_clip_x, old_clip_y);
+      /* After having set up the drawable clip rect on a GC we need to make sure
+       * that we draw to th the impl, otherwise the pixmap code will reset the
+       * drawable clip. */
+      impl = ((GdkPixmapObject *)(paint->pixmap))->impl;
+    }
+  else
+    {
+      /* Drawing directly to the window, flush anything outstanding to
+        guarantee ordering. */
+      gdk_window_flush ((GdkWindow *)drawable);
 
-#define RESTORE_DIRECT_GC_CLIP(gc)
+      /* Don't clip when drawing to root or all native */
+      if (!_gdk_native_windows && private->window_type != GDK_WINDOW_ROOT)
+       {
+         if (_gdk_gc_get_subwindow (gc) == GDK_CLIP_BY_CHILDREN)
+           clip = private->clip_region_with_children;
+         else
+           clip = private->clip_region;
+       }
+      clip_region_tag = private->clip_tag;
+      impl = private->impl;
+    }
+
+  if (clip)
+    _gdk_gc_add_drawable_clip (gc,
+                              clip_region_tag, clip,
+                              /* If there was a clip origin set appart from the
+                               * window offset, need to take that into
+                               * consideration */
+                              -old_clip_x, -old_clip_y);
+
+  return impl;
+}
+
+#define BEGIN_DRAW                                     \
+  {                                                    \
+    GdkDrawable *impl;                                 \
+    gint x_offset, y_offset;                           \
+    gint old_clip_x = gc->clip_x_origin;               \
+    gint old_clip_y = gc->clip_y_origin;               \
+    gint old_ts_x = gc->ts_x_origin;                   \
+    gint old_ts_y = gc->ts_y_origin;                   \
+    impl = start_draw_helper (drawable, gc,            \
+                             &x_offset, &y_offset);
+
+#define END_DRAW                                           \
+    if (x_offset != 0 || y_offset != 0)                            \
+     {                                                      \
+       gdk_gc_set_clip_origin (gc, old_clip_x, old_clip_y); \
+       gdk_gc_set_ts_origin (gc, old_ts_x, old_ts_y);       \
+     }                                                      \
+  }
 
 static GdkGC *
 gdk_window_create_gc (GdkDrawable     *drawable,
-                      GdkGCValues     *values,
-                      GdkGCValuesMask  mask)
+                     GdkGCValues     *values,
+                     GdkGCValuesMask  mask)
 {
   g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
-  
+
   if (GDK_WINDOW_DESTROYED (drawable))
     return NULL;
 
   return gdk_gc_new_with_values (((GdkWindowObject *) drawable)->impl,
-                                 values, mask);
-}
-
-/* After having set up the drawable clip rect on a GC we need
- * to make sure that if we draw to a pixmap we draw to the impl,
- * otherwise the pixmap code will reset the drawable clip.
- */
-static GdkDrawable *
-pixmap_impl (GdkPixmap *pixmap)
-{
-  return ((GdkPixmapObject *)pixmap)->impl;
+                                values, mask);
 }
 
 static void
@@ -2862,29 +3364,13 @@ gdk_window_draw_rectangle (GdkDrawable *drawable,
                           gint         width,
                           gint         height)
 {
-  GdkWindowObject *private = (GdkWindowObject *)drawable;
-  OFFSET_GC (gc);
-
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
-  
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_rectangle (pixmap_impl (paint->pixmap), gc, filled,
-                          x - x_offset, y - y_offset, width, height);
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
-    {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_rectangle (private->impl, gc, filled,
-                         x - x_offset, y - y_offset, width, height);
-      RESTORE_DIRECT_GC_CLIP(gc);
-    }
 
-  RESTORE_GC (gc);
+  BEGIN_DRAW;
+  gdk_draw_rectangle (impl, gc, filled,
+                     x - x_offset, y - y_offset, width, height);
+  END_DRAW;
 }
 
 static void
@@ -2898,30 +3384,14 @@ gdk_window_draw_arc (GdkDrawable *drawable,
                     gint         angle1,
                     gint         angle2)
 {
-  GdkWindowObject *private = (GdkWindowObject *)drawable;
-  OFFSET_GC (gc);
-
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
-  
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_arc (pixmap_impl (paint->pixmap), gc, filled,
-                   x - x_offset, y - y_offset,
-                   width, height, angle1, angle2);
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
-    {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_arc (private->impl, gc, filled,
-                   x - x_offset, y - y_offset,
-                   width, height, angle1, angle2);
-      RESTORE_DIRECT_GC_CLIP(gc);
-    }
-  RESTORE_GC (gc);
+
+  BEGIN_DRAW;
+  gdk_draw_arc (impl, gc, filled,
+               x - x_offset, y - y_offset,
+               width, height, angle1, angle2);
+  END_DRAW;
 }
 
 static void
@@ -2931,18 +3401,17 @@ gdk_window_draw_polygon (GdkDrawable *drawable,
                         GdkPoint    *points,
                         gint         npoints)
 {
-  GdkWindowObject *private = (GdkWindowObject *)drawable;
   GdkPoint *new_points;
-  
-  OFFSET_GC (gc);
 
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
-  
+
+  BEGIN_DRAW;
+
   if (x_offset != 0 || y_offset != 0)
     {
       int i;
-      
+
       new_points = g_new (GdkPoint, npoints);
       for (i=0; i<npoints; i++)
        {
@@ -2953,24 +3422,12 @@ gdk_window_draw_polygon (GdkDrawable *drawable,
   else
     new_points = points;
 
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_polygon (pixmap_impl (paint->pixmap), gc, filled, new_points, npoints);
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
-    {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_polygon (private->impl, gc, filled, new_points, npoints);
-      RESTORE_DIRECT_GC_CLIP(gc);
-    }
-  
+  gdk_draw_polygon (impl, gc, filled, new_points, npoints);
+
   if (new_points != points)
     g_free (new_points);
 
-  RESTORE_GC (gc);
+  END_DRAW;
 }
 
 static void
@@ -2982,30 +3439,13 @@ gdk_window_draw_text (GdkDrawable *drawable,
                      const gchar *text,
                      gint         text_length)
 {
-  GdkWindowObject *private = (GdkWindowObject *)drawable;
-  OFFSET_GC (gc);
-
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
-  
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_text (pixmap_impl (paint->pixmap), font, gc, 
-                    x - x_offset, y - y_offset, text, text_length);
-
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
-    {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_text (private->impl, font, gc,
-                    x - x_offset, y - y_offset, text, text_length);
-      RESTORE_DIRECT_GC_CLIP(gc);
-    }
 
-  RESTORE_GC (gc);
+  BEGIN_DRAW;
+  gdk_draw_text (impl, font, gc,
+                x - x_offset, y - y_offset, text, text_length);
+  END_DRAW;
 }
 
 static void
@@ -3017,29 +3457,13 @@ gdk_window_draw_text_wc (GdkDrawable    *drawable,
                         const GdkWChar *text,
                         gint            text_length)
 {
-  GdkWindowObject *private = (GdkWindowObject *)drawable;
-  OFFSET_GC (gc);
-
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
-  
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_text_wc (pixmap_impl (paint->pixmap), font, gc, 
-                       x - x_offset, y - y_offset, text, text_length);
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
-    {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_text_wc (private->impl, font, gc,
-                       x - x_offset, y - y_offset, text, text_length);
-      RESTORE_DIRECT_GC_CLIP(gc);
-    }
-  
-  RESTORE_GC (gc);
+
+  BEGIN_DRAW;
+  gdk_draw_text_wc (impl, font, gc,
+                   x - x_offset, y - y_offset, text, text_length);
+  END_DRAW;
 }
 
 static GdkDrawable *
@@ -3051,18 +3475,18 @@ gdk_window_get_source_drawable (GdkDrawable *drawable)
   private = (GdkWindowObject *) window;
   if (GDK_DRAWABLE_GET_CLASS (private->impl)->get_source_drawable)
     return GDK_DRAWABLE_GET_CLASS (private->impl)->get_source_drawable (private->impl);
-  
+
   return drawable;
 }
 
 static GdkDrawable *
 gdk_window_get_composite_drawable (GdkDrawable *drawable,
-                                   gint         x,
-                                   gint         y,
-                                   gint         width,
-                                   gint         height,
-                                   gint        *composite_x_offset,
-                                   gint        *composite_y_offset)
+                                  gint         x,
+                                  gint         y,
+                                  gint         width,
+                                  gint         height,
+                                  gint        *composite_x_offset,
+                                  gint        *composite_y_offset)
 {
   GdkWindowObject *private = (GdkWindowObject *)drawable;
   GSList *list;
@@ -3094,14 +3518,14 @@ gdk_window_get_composite_drawable (GdkDrawable *drawable,
     {
       GdkWindowPaint *paint = list->data;
       GdkOverlapType overlap;
-      
+
       overlap = gdk_region_rect_in (paint->region, &rect);
-      
+
       if (overlap == GDK_OVERLAP_RECTANGLE_IN)
        {
          *composite_x_offset = paint->x_offset;
          *composite_y_offset = paint->y_offset;
-         
+
          return g_object_ref (paint->pixmap);
        }
       else if (overlap == GDK_OVERLAP_RECTANGLE_PART)
@@ -3119,13 +3543,13 @@ gdk_window_get_composite_drawable (GdkDrawable *drawable,
 
       rect.x += private->abs_x;
       rect.y += private->abs_y;
-      
+
       overlap = gdk_region_rect_in (implicit_paint->region, &rect);
       if (overlap == GDK_OVERLAP_RECTANGLE_IN)
        {
          *composite_x_offset = -private->abs_x + implicit_paint->x_offset;
          *composite_y_offset = -private->abs_y + implicit_paint->y_offset;
-         
+
          return g_object_ref (implicit_paint->pixmap);
        }
       else if (overlap == GDK_OVERLAP_RECTANGLE_PART)
@@ -3134,51 +3558,51 @@ gdk_window_get_composite_drawable (GdkDrawable *drawable,
 
   if (!overlap_buffer)
     return g_object_ref (_gdk_drawable_get_source_drawable (drawable));
-  
+
   tmp_pixmap = gdk_pixmap_new (drawable, width, height, -1);
   tmp_gc = _gdk_drawable_get_scratch_gc (tmp_pixmap, FALSE);
 
   source = _gdk_drawable_get_source_drawable (drawable);
-  
+
   /* Copy the current window contents */
   gdk_draw_drawable (tmp_pixmap,
-                     tmp_gc,
-                     GDK_WINDOW_OBJECT (source)->impl,
-                     x - *composite_x_offset,
-                     y - *composite_y_offset,
-                     0, 0,
-                     width, height);
+                    tmp_gc,
+                    GDK_WINDOW_OBJECT (source)->impl,
+                    x - *composite_x_offset,
+                    y - *composite_y_offset,
+                    0, 0,
+                    width, height);
 
   /* paint the backing stores */
   if (implicit_paint)
     {
       GdkWindowPaint *paint = list->data;
-      
+
       gdk_gc_set_clip_region (tmp_gc, paint->region);
       gdk_gc_set_clip_origin (tmp_gc, -x  - paint->x_offset, -y  - paint->y_offset);
-      
+
       gdk_draw_drawable (tmp_pixmap, tmp_gc, paint->pixmap,
                         x - paint->x_offset,
                         y - paint->y_offset,
                         0, 0, width, height);
     }
-  
+
   for (list = private->paint_stack; list != NULL; list = list->next)
     {
       GdkWindowPaint *paint = list->data;
 
       if (paint->uses_implicit)
        continue; /* We already copied this above */
-      
+
       gdk_gc_set_clip_region (tmp_gc, paint->region);
       gdk_gc_set_clip_origin (tmp_gc, -x, -y);
-      
+
       gdk_draw_drawable (tmp_pixmap, tmp_gc, paint->pixmap,
                         x - paint->x_offset,
                         y - paint->y_offset,
                         0, 0, width, height);
     }
-  
+
   /* Reset clip region of the cached GdkGC */
   gdk_gc_set_clip_region (tmp_gc, NULL);
 
@@ -3205,10 +3629,10 @@ gdk_window_get_clip_region (GdkDrawable *drawable)
       while (tmp_list)
        {
          GdkWindowPaint *paint = tmp_list->data;
-         
+
          gdk_region_union (paint_region, paint->region);
 
-          tmp_list = tmp_list->next;
+         tmp_list = tmp_list->next;
        }
 
       gdk_region_intersect (result, paint_region);
@@ -3235,36 +3659,82 @@ gdk_window_draw_drawable (GdkDrawable *drawable,
                          gint         xdest,
                          gint         ydest,
                          gint         width,
-                         gint         height)
+                         gint         height,
+                         GdkDrawable *original_src)
 {
   GdkWindowObject *private = (GdkWindowObject *)drawable;
-  OFFSET_GC (gc);
-  
+
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
 
-  /* If we have a backing pixmap draw to that */
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_drawable (pixmap_impl (paint->pixmap), gc,
-                         src, xsrc, ysrc,
-                        xdest - x_offset, ydest - y_offset, width, height);
+  BEGIN_DRAW;
 
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
+  /* Call the method directly to avoid getting the composite drawable again */
+  GDK_DRAWABLE_GET_CLASS (impl)->draw_drawable_with_src (impl, gc,
+                                                        src,
+                                                        xsrc, ysrc,
+                                                        xdest - x_offset,
+                                                        ydest - y_offset,
+                                                        width, height,
+                                                        original_src);
+
+  if (!private->paint_stack)
     {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_drawable (private->impl, gc,
-                        src, xsrc, ysrc,
-                        xdest - x_offset, ydest - y_offset,
-                        width, height);
-      RESTORE_DIRECT_GC_CLIP(gc);
+      /* We might have drawn from an obscured part of a client
+        side window, if so we need to send graphics exposures */
+      if (_gdk_gc_get_exposures (gc) &&
+         GDK_IS_WINDOW (original_src))
+       {
+         GdkRegion *exposure_region;
+         GdkRegion *clip;
+         GdkRectangle r;
+
+         r.x = xdest;
+         r.y = ydest;
+         r.width = width;
+         r.height = height;
+         exposure_region = gdk_region_rectangle (&r);
+
+         if (_gdk_gc_get_subwindow (gc) == GDK_CLIP_BY_CHILDREN)
+           clip = private->clip_region_with_children;
+         else
+           clip = private->clip_region;
+         gdk_region_intersect (exposure_region, clip);
+
+         clip = _gdk_gc_get_clip_region (gc);
+         if (clip)
+           {
+             gdk_region_offset (exposure_region,
+                                old_clip_x,
+                                old_clip_y);
+             gdk_region_intersect (exposure_region, clip);
+             gdk_region_offset (exposure_region,
+                                -old_clip_x,
+                                -old_clip_y);
+           }
+
+         /* Note: We don't clip by the clip mask if set, so this
+            may invalidate to much */
+
+         /* Remove the area that is correctly copied from the src.
+          * Note that xsrc/ysrc has been corrected for abs_x/y offsets already,
+          * which need to be undone */
+         clip = gdk_drawable_get_visible_region (original_src);
+         gdk_region_offset (clip,
+                            xdest - (xsrc - GDK_WINDOW_OBJECT (original_src)->abs_x),
+                            ydest - (ysrc - GDK_WINDOW_OBJECT (original_src)->abs_y));
+         gdk_region_subtract (exposure_region, clip);
+         gdk_region_destroy (clip);
+
+         gdk_window_invalidate_region (GDK_WINDOW (private),
+                                       exposure_region,
+                                       _gdk_gc_get_subwindow (gc) == GDK_INCLUDE_INFERIORS);
+
+         gdk_region_destroy (exposure_region);
+       }
     }
 
-  RESTORE_GC (gc);
+  END_DRAW;
 }
 
 static void
@@ -3273,14 +3743,13 @@ gdk_window_draw_points (GdkDrawable *drawable,
                        GdkPoint    *points,
                        gint         npoints)
 {
-  GdkWindowObject *private = (GdkWindowObject *)drawable;
   GdkPoint *new_points;
-  
-  OFFSET_GC (gc);
 
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
-  
+
+  BEGIN_DRAW;
+
   if (x_offset != 0 || y_offset != 0)
     {
       gint i;
@@ -3295,24 +3764,12 @@ gdk_window_draw_points (GdkDrawable *drawable,
   else
     new_points = points;
 
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_points (pixmap_impl (paint->pixmap), gc, new_points, npoints);
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
-    {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_points (private->impl, gc, new_points, npoints);
-      RESTORE_DIRECT_GC_CLIP(gc);
-    }
+  gdk_draw_points (impl, gc, new_points, npoints);
 
   if (new_points != points)
     g_free (new_points);
 
-  RESTORE_GC (gc);
+  END_DRAW;
 }
 
 static void
@@ -3321,14 +3778,13 @@ gdk_window_draw_segments (GdkDrawable *drawable,
                          GdkSegment  *segs,
                          gint         nsegs)
 {
-  GdkWindowObject *private = (GdkWindowObject *)drawable;
   GdkSegment *new_segs;
 
-  OFFSET_GC (gc);
-
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
-  
+
+  BEGIN_DRAW;
+
   if (x_offset != 0 || y_offset != 0)
     {
       gint i;
@@ -3345,24 +3801,12 @@ gdk_window_draw_segments (GdkDrawable *drawable,
   else
     new_segs = segs;
 
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_segments (pixmap_impl (paint->pixmap), gc, new_segs, nsegs);
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
-    {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_segments (private->impl, gc, new_segs, nsegs);
-      RESTORE_DIRECT_GC_CLIP(gc);
-    }
-  
+  gdk_draw_segments (impl, gc, new_segs, nsegs);
+
   if (new_segs != segs)
     g_free (new_segs);
 
-  RESTORE_GC (gc);
+  END_DRAW;
 }
 
 static void
@@ -3371,14 +3815,13 @@ gdk_window_draw_lines (GdkDrawable *drawable,
                       GdkPoint    *points,
                       gint         npoints)
 {
-  GdkWindowObject *private = (GdkWindowObject *)drawable;
   GdkPoint *new_points;
 
-  OFFSET_GC (gc);
-
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
-  
+
+  BEGIN_DRAW;
+
   if (x_offset != 0 || y_offset != 0)
     {
       gint i;
@@ -3393,24 +3836,12 @@ gdk_window_draw_lines (GdkDrawable *drawable,
   else
     new_points = points;
 
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_lines (pixmap_impl (paint->pixmap), gc, new_points, npoints);
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
-    {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_lines (private->impl, gc, new_points, npoints);
-      RESTORE_DIRECT_GC_CLIP(gc);
-    }
+  gdk_draw_lines (impl, gc, new_points, npoints);
 
   if (new_points != points)
     g_free (new_points);
 
-  RESTORE_GC (gc);
+  END_DRAW;
 }
 
 static void
@@ -3421,30 +3852,13 @@ gdk_window_draw_glyphs (GdkDrawable      *drawable,
                        gint              y,
                        PangoGlyphString *glyphs)
 {
-  GdkWindowObject *private = (GdkWindowObject *)drawable;
-
-  OFFSET_GC (gc);
-
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
-  
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
 
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_glyphs (pixmap_impl (paint->pixmap), gc, font, x - x_offset, y - y_offset, glyphs);
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
-    {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_glyphs (private->impl, gc, font,
-                      x - x_offset, y - y_offset, glyphs);
-      RESTORE_DIRECT_GC_CLIP(gc);
-    }
-
-  RESTORE_GC (gc);
+  BEGIN_DRAW;
+  gdk_draw_glyphs (impl, gc, font,
+                  x - x_offset, y - y_offset, glyphs);
+  END_DRAW;
 }
 
 static void
@@ -3456,14 +3870,13 @@ gdk_window_draw_glyphs_transformed (GdkDrawable      *drawable,
                                    gint              y,
                                    PangoGlyphString *glyphs)
 {
-  GdkWindowObject *private = (GdkWindowObject *)drawable;
   PangoMatrix tmp_matrix;
 
-  OFFSET_GC (gc);
-
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
 
+  BEGIN_DRAW;
+
   if (x_offset != 0 || y_offset != 0)
     {
       if (matrix)
@@ -3476,7 +3889,7 @@ gdk_window_draw_glyphs_transformed (GdkDrawable      *drawable,
       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;
@@ -3488,23 +3901,10 @@ gdk_window_draw_glyphs_transformed (GdkDrawable      *drawable,
          y -= y_offset * PANGO_SCALE;
        }
     }
-  
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
 
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_glyphs_transformed (pixmap_impl (paint->pixmap), gc, matrix, font, x, y, glyphs);
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
-    {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_glyphs_transformed (private->impl, gc, matrix, font, x, y, glyphs);
-      RESTORE_DIRECT_GC_CLIP(gc);
-    }
+  gdk_draw_glyphs_transformed (impl, gc, matrix, font, x, y, glyphs);
 
-  RESTORE_GC (gc);
+  END_DRAW;
 }
 
 typedef struct {
@@ -3591,15 +3991,14 @@ setup_backing_rect_method (BackingRectMethod *method, GdkWindow *window, GdkWind
 }
 
 static void
-gdk_window_clear_backing_rect (GdkWindow *window,
-                              gint       x,
-                              gint       y,
-                              gint       width,
-                              gint       height)
+gdk_window_clear_backing_region (GdkWindow *window,
+                                GdkRegion *region)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   GdkWindowPaint *paint = private->paint_stack->data;
   BackingRectMethod method;
+  GdkRegion *clip;
+  GdkRectangle clipbox;
 #if 0
   GTimer *timer;
   double elapsed;
@@ -3616,14 +4015,16 @@ gdk_window_clear_backing_rect (GdkWindow *window,
   method.gc = NULL;
   setup_backing_rect_method (&method, window, paint, 0, 0);
 
+  clip = gdk_region_copy (paint->region);
+  gdk_region_intersect (clip, region);
+  gdk_region_get_clipbox (clip, &clipbox);
+
+
   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);
+      gdk_cairo_region (method.cr, clip);
       cairo_fill (method.cr);
 
       cairo_destroy (method.cr);
@@ -3636,8 +4037,10 @@ gdk_window_clear_backing_rect (GdkWindow *window,
     {
       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);
+      gdk_gc_set_clip_region (method.gc, clip);
+      gdk_draw_rectangle (window, method.gc, TRUE,
+                         clipbox.x, clipbox.y,
+                         clipbox.width, clipbox.height);
       g_object_unref (method.gc);
 
 #if 0
@@ -3646,25 +4049,25 @@ gdk_window_clear_backing_rect (GdkWindow *window,
 #endif
     }
 
+  gdk_region_destroy (clip);
+
 #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)
+gdk_window_clear_backing_region_redirect (GdkWindow *window,
+                                         GdkRegion *region)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   GdkWindowRedirect *redirect = private->redirect;
   GdkRegion *clip_region;
+  GdkRectangle clipbox;
   gint x_offset, y_offset;
   BackingRectMethod method;
   GdkWindowPaint paint;
-  
+
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
@@ -3672,23 +4075,29 @@ gdk_window_clear_backing_rect_redirect (GdkWindow *window,
                                                        GDK_WINDOW (redirect->redirected),
                                                        TRUE,
                                                        &x_offset, &y_offset);
-  
-  paint.x_offset = x_offset;
-  paint.y_offset = y_offset;
+  gdk_region_intersect (clip_region, region);
+
+  /* offset is from redirected window origin to window origin, convert to
+     the offset from the redirected pixmap origin to the window origin */
+  x_offset += redirect->dest_x - redirect->src_x;
+  y_offset += redirect->dest_y - redirect->src_y;
+
+  /* Convert region to pixmap coords */
+  gdk_region_offset (clip_region, x_offset, y_offset);
+
+  paint.x_offset = 0;
+  paint.y_offset = 0;
   paint.pixmap = redirect->pixmap;
   paint.surface = _gdk_drawable_ref_cairo_surface (redirect->pixmap);
-  
+
   method.cr = NULL;
   method.gc = NULL;
-  setup_backing_rect_method (&method, window, &paint, 0, 0);
+  setup_backing_rect_method (&method, window, &paint, -x_offset, -y_offset);
 
   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);
 
@@ -3698,8 +4107,11 @@ gdk_window_clear_backing_rect_redirect (GdkWindow *window,
     {
       g_assert (method.gc != NULL);
 
+      gdk_region_get_clipbox (clip_region, &clipbox);
       gdk_gc_set_clip_region (method.gc, clip_region);
-      gdk_draw_rectangle (window, method.gc, TRUE, x, y, width, height);
+      gdk_draw_rectangle (redirect->pixmap, method.gc, TRUE,
+                         clipbox.x, clipbox.y,
+                         clipbox.width, clipbox.height);
       g_object_unref (method.gc);
 
     }
@@ -3709,16 +4121,15 @@ gdk_window_clear_backing_rect_redirect (GdkWindow *window,
 }
 
 static void
-gdk_window_clear_backing_rect_direct (GdkWindow *window,
-                                     gint       x,
-                                     gint       y,
-                                     gint       width,
-                                     gint       height)
+gdk_window_clear_backing_region_direct (GdkWindow *window,
+                                       GdkRegion *region)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   BackingRectMethod method;
   GdkWindowPaint paint;
-  
+  GdkRegion *clip;
+  GdkRectangle clipbox;
+
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
@@ -3726,19 +4137,20 @@ gdk_window_clear_backing_rect_direct (GdkWindow *window,
   paint.y_offset = 0;
   paint.pixmap = window;
   paint.surface = _gdk_drawable_ref_cairo_surface (window);
-  
+
   method.cr = NULL;
   method.gc = NULL;
   setup_backing_rect_method (&method, window, &paint, 0, 0);
 
+  clip = gdk_region_copy (private->clip_region_with_children);
+  gdk_region_intersect (clip, region);
+  gdk_region_get_clipbox (clip, &clipbox);
+
   if (method.cr)
     {
       g_assert (method.gc == NULL);
 
-      gdk_cairo_region (method.cr, private->clip_region_with_children);
-      cairo_clip (method.cr);
-      
-      cairo_rectangle (method.cr, x, y, width, height);
+      gdk_cairo_region (method.cr, clip);
       cairo_fill (method.cr);
 
       cairo_destroy (method.cr);
@@ -3747,12 +4159,15 @@ gdk_window_clear_backing_rect_direct (GdkWindow *window,
     {
       g_assert (method.gc != NULL);
 
-      gdk_gc_set_clip_region (method.gc, private->clip_region_with_children);
-      gdk_draw_rectangle (window, method.gc, TRUE, x, y, width, height);
+      gdk_gc_set_clip_region (method.gc, clip);
+      gdk_draw_rectangle (window, method.gc, TRUE,
+                         clipbox.x, clipbox.y,
+                         clipbox.width, clipbox.height);
       g_object_unref (method.gc);
 
     }
 
+  gdk_region_destroy (clip);
   cairo_surface_destroy (paint.surface);
 }
 
@@ -3760,7 +4175,7 @@ gdk_window_clear_backing_rect_direct (GdkWindow *window,
 /**
  * gdk_window_clear:
  * @window: a #GdkWindow
- * 
+ *
  * Clears an entire @window to the background color or background pixmap.
  **/
 void
@@ -3771,9 +4186,62 @@ gdk_window_clear (GdkWindow *window)
   g_return_if_fail (GDK_IS_WINDOW (window));
 
   gdk_drawable_get_size (GDK_DRAWABLE (window), &width, &height);
-  
+
   gdk_window_clear_area (window, 0, 0,
-                         width, height);
+                        width, height);
+}
+
+static gboolean
+clears_on_native (GdkWindowObject *private)
+{
+  GdkWindowObject *next;
+
+  next = private;
+  do
+    {
+      private = next;
+      if (gdk_window_has_impl (private))
+       return TRUE;
+      next = private->parent;
+    }
+  while (private->bg_pixmap == GDK_PARENT_RELATIVE_BG &&
+        next && next->window_type != GDK_WINDOW_ROOT);
+  return FALSE;
+}
+
+static void
+gdk_window_clear_region_internal (GdkWindow *window,
+                                 GdkRegion *region,
+                                 gboolean   send_expose)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+
+  if (private->paint_stack)
+    gdk_window_clear_backing_region (window, region);
+  else
+    {
+      if (private->redirect)
+       gdk_window_clear_backing_region_redirect (window, region);
+
+      if (GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_region &&
+         clears_on_native (private))
+       {
+         GdkRegion *copy;
+         copy = gdk_region_copy (region);
+         gdk_region_intersect (copy, private->clip_region_with_children);
+
+         GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_region
+           (window, copy, send_expose);
+
+         gdk_region_destroy (copy);
+       }
+      else
+       {
+         gdk_window_clear_backing_region_direct (window, region);
+         if (send_expose)
+           gdk_window_invalidate_region (window, region, FALSE);
+       }
+    }
 }
 
 static void
@@ -3785,38 +4253,33 @@ gdk_window_clear_area_internal (GdkWindow *window,
                                gboolean   send_expose)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkRectangle rect;
+  GdkRegion *region;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
 
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
   /* This is what XClearArea does, and e.g. GtkCList uses it,
      so we need to duplicate that */
   if (width == 0)
     width = private->width - x;
   if (height == 0)
     height = private->height - y;
-  
-  if (private->paint_stack)
-    gdk_window_clear_backing_rect (window, x, y, width, height);
-  else
-    {
-      if (private->redirect)
-       gdk_window_clear_backing_rect_redirect (window, x, y, width, height);
-      
-      gdk_window_clear_backing_rect_direct (window, x, y, width, height);
-      if (send_expose)
-       {
-         GdkRectangle rect;
-
-         rect.x = x;
-         rect.y = x;
-         rect.width = width;
-         rect.height = height;
-         
-         gdk_window_invalidate_rect (window, &rect, FALSE);
-       }
-    }
-}
 
+  rect.x = x;
+  rect.y = y;
+  rect.width = width;
+  rect.height = height;
+
+  region = gdk_region_rectangle (&rect);
+  gdk_window_clear_region_internal (window,
+                                   region,
+                                   FALSE);
+  gdk_region_destroy (region);
+
+}
 
 /**
  * gdk_window_clear_area:
@@ -3827,7 +4290,7 @@ gdk_window_clear_area_internal (GdkWindow *window,
  * @height: height of rectangle to clear
  *
  * Clears an area of @window to the background color or background pixmap.
- * 
+ *
  **/
 void
 gdk_window_clear_area (GdkWindow *window,
@@ -3855,14 +4318,14 @@ gdk_window_clear_area (GdkWindow *window,
  *
  * This function has a stupid name because it dates back to the mists
  * time, pre-GDK-1.0.
- * 
+ *
  **/
 void
 gdk_window_clear_area_e (GdkWindow *window,
-                        gint       x,
-                        gint       y,
-                        gint       width,
-                        gint       height)
+                        gint       x,
+                        gint       y,
+                        gint       width,
+                        gint       height)
 {
   gdk_window_clear_area_internal (window,
                                  x, y,
@@ -3872,42 +4335,23 @@ gdk_window_clear_area_e (GdkWindow *window,
 
 static void
 gdk_window_draw_image (GdkDrawable *drawable,
-                       GdkGC       *gc,
-                       GdkImage    *image,
-                       gint         xsrc,
-                       gint         ysrc,
-                       gint         xdest,
-                       gint         ydest,
-                       gint         width,
-                       gint         height)
+                      GdkGC       *gc,
+                      GdkImage    *image,
+                      gint         xsrc,
+                      gint         ysrc,
+                      gint         xdest,
+                      gint         ydest,
+                      gint         width,
+                      gint         height)
 {
-  GdkWindowObject *private = (GdkWindowObject *)drawable;
-
-  OFFSET_GC (gc);
-
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
-  
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_image (pixmap_impl (paint->pixmap), gc, image, xsrc, ysrc,
-                      xdest - x_offset, ydest - y_offset,
-                      width, height);
 
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
-    {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_image (private->impl, gc, image, xsrc, ysrc,
-                     xdest - x_offset, ydest - y_offset,
-                     width, height);
-      RESTORE_DIRECT_GC_CLIP(gc);
-    }
-
-  RESTORE_GC (gc);
+  BEGIN_DRAW;
+  gdk_draw_image (impl, gc, image, xsrc, ysrc,
+                 xdest - x_offset, ydest - y_offset,
+                 width, height);
+  END_DRAW;
 }
 
 static void
@@ -3925,6 +4369,7 @@ gdk_window_draw_pixbuf (GdkDrawable     *drawable,
                        gint             y_dither)
 {
   GdkWindowObject *private = (GdkWindowObject *)drawable;
+  GdkDrawableClass *klass;
 
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
@@ -3934,32 +4379,21 @@ gdk_window_draw_pixbuf (GdkDrawable     *drawable,
   if (!gc)
     gc = _gdk_drawable_get_scratch_gc (drawable, FALSE);
 
-  /* Need block to make OFFSET_GC macro to work */
-    {
-      OFFSET_GC (gc);
-  
-      if (private->paint_stack)
-       {
-         GdkWindowPaint *paint = private->paint_stack->data;
-         SETUP_PAINT_GC_CLIP (gc);
-         gdk_draw_pixbuf (pixmap_impl (paint->pixmap), gc, pixbuf, src_x, src_y,
-                          dest_x - x_offset, dest_y - y_offset,
-                          width, height,
-                          dither, x_dither - x_offset, y_dither - y_offset);
-         RESTORE_PAINT_GC_CLIP (gc);
-       }
-      else
-       {
-         SETUP_DIRECT_GC_CLIP(gc);
-         gdk_draw_pixbuf (private->impl, gc, pixbuf, src_x, src_y,
-                          dest_x - x_offset, dest_y - y_offset,
-                          width, height,
-                          dither, x_dither, y_dither);
-         RESTORE_DIRECT_GC_CLIP(gc);
-       }
-      
-      RESTORE_GC (gc);
-    }
+  BEGIN_DRAW;
+
+  klass = GDK_DRAWABLE_GET_CLASS (impl);
+
+  if (private->paint_stack)
+    klass->draw_pixbuf (impl, gc, pixbuf, src_x, src_y,
+                       dest_x - x_offset, dest_y - y_offset,
+                       width, height,
+                       dither, x_dither - x_offset, y_dither - y_offset);
+  else
+    klass->draw_pixbuf (impl, gc, pixbuf, src_x, src_y,
+                       dest_x - x_offset, dest_y - y_offset,
+                       width, height,
+                       dither, x_dither, y_dither);
+  END_DRAW;
 }
 
 static void
@@ -3968,14 +4402,13 @@ gdk_window_draw_trapezoids (GdkDrawable   *drawable,
                            GdkTrapezoid  *trapezoids,
                            gint           n_trapezoids)
 {
-  GdkWindowObject *private = (GdkWindowObject *)drawable;
   GdkTrapezoid *new_trapezoids = NULL;
 
-  OFFSET_GC (gc);
-
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
-  
+
+  BEGIN_DRAW;
+
   if (x_offset != 0 || y_offset != 0)
     {
       gint i;
@@ -3994,29 +4427,17 @@ gdk_window_draw_trapezoids (GdkDrawable   *drawable,
       trapezoids = new_trapezoids;
     }
 
-  if (private->paint_stack)
-    {
-      GdkWindowPaint *paint = private->paint_stack->data;
-      SETUP_PAINT_GC_CLIP (gc);
-      gdk_draw_trapezoids (pixmap_impl (paint->pixmap), gc, trapezoids, n_trapezoids);
-      RESTORE_PAINT_GC_CLIP (gc);
-    }
-  else
-    {
-      SETUP_DIRECT_GC_CLIP(gc);
-      gdk_draw_trapezoids (private->impl, gc, trapezoids, n_trapezoids);
-      RESTORE_DIRECT_GC_CLIP(gc);
-    }
-  
+  gdk_draw_trapezoids (impl, gc, trapezoids, n_trapezoids);
+
   g_free (new_trapezoids);
 
-  RESTORE_GC (gc);
+  END_DRAW;
 }
 
 static void
 gdk_window_real_get_size (GdkDrawable *drawable,
-                          gint *width,
-                          gint *height)
+                         gint *width,
+                         gint *height)
 {
   GdkWindowObject *private = (GdkWindowObject *)drawable;
 
@@ -4053,11 +4474,11 @@ gdk_window_real_get_screen (GdkDrawable *drawable)
 
 static void
 gdk_window_real_set_colormap (GdkDrawable *drawable,
-                              GdkColormap *cmap)
+                             GdkColormap *cmap)
 {
   GdkWindowObject *private;
-  
-  g_return_if_fail (GDK_IS_WINDOW (drawable));  
+
+  g_return_if_fail (GDK_IS_WINDOW (drawable));
 
   if (GDK_WINDOW_DESTROYED (drawable))
     return;
@@ -4067,8 +4488,8 @@ gdk_window_real_set_colormap (GdkDrawable *drawable,
   /* different colormap than parent, requires native window */
   if (!private->input_only &&
       cmap != gdk_drawable_get_colormap ((GdkDrawable *)(private->parent)))
-    gdk_window_set_has_native ((GdkWindow *)drawable, TRUE);
-  
+    gdk_window_ensure_native ((GdkWindow *)drawable);
+
   gdk_drawable_set_colormap (private->impl, cmap);
 }
 
@@ -4079,10 +4500,10 @@ gdk_window_real_get_colormap (GdkDrawable *drawable)
 
   if (GDK_WINDOW_DESTROYED (drawable))
     return NULL;
-  
+
   return gdk_drawable_get_colormap (((GdkWindowObject*)drawable)->impl);
 }
-                      
+
 static GdkImage*
 gdk_window_copy_to_image (GdkDrawable     *drawable,
                          GdkImage        *image,
@@ -4095,9 +4516,9 @@ gdk_window_copy_to_image (GdkDrawable     *drawable,
 {
   GdkWindowObject *private = (GdkWindowObject *) drawable;
   gint x_offset, y_offset;
-  
+
   g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
-  
+
   if (GDK_WINDOW_DESTROYED (drawable))
     return NULL;
 
@@ -4107,8 +4528,8 @@ gdk_window_copy_to_image (GdkDrawable     *drawable,
 
   /* TODO: Is this right? */
   x_offset = 0;
-  y_offset = 0; 
-  
+  y_offset = 0;
+
   return gdk_drawable_copy_to_image (private->impl,
                                     image,
                                     src_x - x_offset,
@@ -4150,10 +4571,10 @@ gdk_window_ref_cairo_surface (GdkDrawable *drawable)
     }
   else
     {
-      
+
       /* This will be drawing directly to the window, so flush implicit paint */
       gdk_window_flush ((GdkWindow *)drawable);
-      
+
       if (!private->cairo_surface)
        {
          int width, height;
@@ -4168,20 +4589,20 @@ gdk_window_ref_cairo_surface (GdkDrawable *drawable)
 
          /* TODO: Avoid the typecheck crap by adding virtual call */
          private->cairo_surface = _gdk_drawable_create_cairo_surface (source, width, height);
-         
+
          if (private->cairo_surface)
            {
-             cairo_surface_set_device_offset (private->cairo_surface, 
+             cairo_surface_set_device_offset (private->cairo_surface,
                                               private->abs_x,
                                               private->abs_y);
-             
+
              cairo_surface_set_user_data (private->cairo_surface, &gdk_window_cairo_key,
                                           drawable, gdk_window_cairo_surface_destroy);
            }
        }
       else
        cairo_surface_reference (private->cairo_surface);
-      
+
       surface = private->cairo_surface;
     }
 
@@ -4196,14 +4617,14 @@ gdk_window_set_cairo_clip (GdkDrawable *drawable,
 
   if (!private->paint_stack)
     {
+      cairo_reset_clip (cr);
+
       cairo_save (cr);
       cairo_identity_matrix (cr);
 
-      cairo_reset_clip (cr);
-      
       cairo_new_path (cr);
-      gdk_cairo_region (cr, private->clip_region);
-      
+      gdk_cairo_region (cr, private->clip_region_with_children);
+
       cairo_restore (cr);
       cairo_clip (cr);
     }
@@ -4213,17 +4634,16 @@ gdk_window_set_cairo_clip (GdkDrawable *drawable,
 
       /* Only needs to clip to region if piggybacking
         on an implicit paint pixmap */
+      cairo_reset_clip (cr);
       if (paint->uses_implicit)
        {
          cairo_save (cr);
          cairo_identity_matrix (cr);
-         
-         cairo_reset_clip (cr);
-         
+
          cairo_new_path (cr);
          gdk_cairo_region (cr, paint->region);
          cairo_restore (cr);
-         
+
          cairo_clip (cr);
        }
     }
@@ -4237,14 +4657,14 @@ static gboolean debug_updates = FALSE;
 
 static inline gboolean
 gdk_window_is_ancestor (GdkWindow *window,
-                        GdkWindow *ancestor)
+                       GdkWindow *ancestor)
 {
   while (window)
     {
       GdkWindow *parent = (GdkWindow*) ((GdkWindowObject*) window)->parent;
 
       if (parent == ancestor)
-        return TRUE;
+       return TRUE;
 
       window = parent;
     }
@@ -4268,52 +4688,52 @@ gdk_window_add_update_window (GdkWindow *window)
        *  children of "window" or from a differen hierarchy
        */
       if (!has_ancestor_in_list && gdk_window_is_ancestor (window, tmp->data))
-        has_ancestor_in_list = TRUE;
+       has_ancestor_in_list = TRUE;
 
       /* insert in reverse stacking order when adding around siblings,
        * so processing updates properly paints over lower stacked windows
        */
       if (parent == GDK_WINDOW_OBJECT (tmp->data)->parent)
-        {
-          gint index = g_list_index (parent->children, window);
-          for (; tmp && parent == GDK_WINDOW_OBJECT (tmp->data)->parent; tmp = tmp->next)
-            {
-              gint sibling_index = g_list_index (parent->children, tmp->data);
-              if (index > sibling_index)
-                break;
-              prev = tmp;
-            }
-          /* here, tmp got advanced past all lower stacked siblings */
-          tmp = g_slist_prepend (tmp, window);
-          if (prev)
-            prev->next = tmp;
-          else
-            update_windows = tmp;
-          return;
-        }
+       {
+         gint index = g_list_index (parent->children, window);
+         for (; tmp && parent == GDK_WINDOW_OBJECT (tmp->data)->parent; tmp = tmp->next)
+           {
+             gint sibling_index = g_list_index (parent->children, tmp->data);
+             if (index > sibling_index)
+               break;
+             prev = tmp;
+           }
+         /* here, tmp got advanced past all lower stacked siblings */
+         tmp = g_slist_prepend (tmp, window);
+         if (prev)
+           prev->next = tmp;
+         else
+           update_windows = tmp;
+         return;
+       }
 
       /*  if "window" has an ancestor in the list and tmp is one of
        *  "window's" children, insert "window" before tmp
        */
       if (has_ancestor_in_list && gdk_window_is_ancestor (tmp->data, window))
-        {
-          tmp = g_slist_prepend (tmp, window);
+       {
+         tmp = g_slist_prepend (tmp, window);
 
-          if (prev)
-            prev->next = tmp;
-          else
-            update_windows = tmp;
-          return;
-        }
+         if (prev)
+           prev->next = tmp;
+         else
+           update_windows = tmp;
+         return;
+       }
 
       /*  if we're at the end of the list and had an ancestor it it,
        *  append to the list
        */
       if (! tmp->next && has_ancestor_in_list)
-        {
-          tmp = g_slist_append (tmp, window);
-          return;
-        }
+       {
+         tmp = g_slist_append (tmp, window);
+         return;
+       }
 
       prev = tmp;
     }
@@ -4335,7 +4755,7 @@ static gboolean
 gdk_window_update_idle (gpointer data)
 {
   gdk_window_process_all_updates ();
-  
+
   return FALSE;
 }
 
@@ -4366,23 +4786,27 @@ gdk_window_schedule_update (GdkWindow *window)
 
 void
 _gdk_window_process_updates_recurse (GdkWindow *window,
-                                     GdkRegion *expose_region)
+                                    GdkRegion *expose_region)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   GdkWindowObject *child;
   GdkRegion *child_region;
   GdkRectangle r;
-  GList *l;
+  GList *l, *children;
 
   if (gdk_region_empty (expose_region))
     return;
-  
+
+  /* Make this reentrancy safe for expose handlers freeing windows */
+  children = g_list_copy (private->children);
+  g_list_foreach (children, (GFunc)g_object_ref, NULL);
+
   /* Iterate over children, starting at topmost */
-  for (l = private->children; l != NULL; l = l->next)
+  for (l = children; l != NULL; l = l->next)
     {
       child = l->data;
-      
-      if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
+
+      if (child->destroyed || !GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
        continue;
 
       /* Ignore offscreen children, as they don't draw in their parent and
@@ -4394,12 +4818,17 @@ _gdk_window_process_updates_recurse (GdkWindow *window,
       r.y = child->y;
       r.width = child->width;
       r.height = child->height;
-      
+
       child_region = gdk_region_rectangle (&r);
       if (child->shape)
-       gdk_region_intersect (child_region, child->shape);
-       
-      if (child->impl == private->impl) 
+       {
+         /* Adjust shape region to parent window coords */
+         gdk_region_offset (child->shape, child->x, child->y);
+         gdk_region_intersect (child_region, child->shape);
+         gdk_region_offset (child->shape, -child->x, -child->y);
+       }
+
+      if (child->impl == private->impl)
        {
          /* Client side child, expose */
          gdk_region_intersect (child_region, expose_region);
@@ -4407,7 +4836,7 @@ _gdk_window_process_updates_recurse (GdkWindow *window,
          gdk_region_offset (child_region, -child->x, -child->y);
          _gdk_window_process_updates_recurse ((GdkWindow *)child, child_region);
        }
-      else 
+      else
        {
          /* Native child, just remove area from expose region */
          gdk_region_subtract (expose_region, child_region);
@@ -4415,24 +4844,50 @@ _gdk_window_process_updates_recurse (GdkWindow *window,
       gdk_region_destroy (child_region);
     }
 
-  if (private->event_mask & GDK_EXPOSURE_MASK &&
-      !gdk_region_empty (expose_region))
+  g_list_foreach (children, (GFunc)g_object_unref, NULL);
+  g_list_free (children);
+
+  if (!gdk_region_empty (expose_region) &&
+      !private->destroyed)
     {
-      GdkEvent event;
-      
-      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);
-      
-      (*_gdk_event_func) (&event, _gdk_event_data);
-      
-      g_object_unref (window);
+      if (private->event_mask & GDK_EXPOSURE_MASK)
+       {
+         GdkEvent event;
+
+         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);
+
+         (*_gdk_event_func) (&event, _gdk_event_data);
+
+         g_object_unref (window);
+       }
+      else if (private->bg_pixmap != GDK_NO_BG)
+       {
+         /* No exposure mask set, so nothing will be drawn, the
+          * app relies on the background being what it specified
+          * for the window. So, we need to clear this manually.
+          *
+          * We use begin/end_paint around the clear so that we can
+          * piggyback on the implicit paint */
+
+         gdk_window_begin_paint_region (window, expose_region);
+         gdk_window_clear_region_internal (window, expose_region, FALSE);
+         gdk_window_end_paint (window);
+       }
     }
 }
 
+/* Process and remove any invalid area on the native window by creating
+ * expose events for the window and all non-native descendants.
+ * Also processes any outstanding moves on the window before doing
+ * any drawing. Note that its possible to have outstanding moves without
+ * any invalid area as we use the update idle mechanism to coalesce
+ * multiple moves as well as multiple invalidations.
+ */
 static void
 gdk_window_process_updates_internal (GdkWindow *window)
 {
@@ -4440,6 +4895,9 @@ gdk_window_process_updates_internal (GdkWindow *window)
   gboolean save_region = FALSE;
   GdkRectangle clip_box;
 
+  /* Ensure the window lives while updating it */
+  g_object_ref (window);
+
   /* If an update got queued during update processing, we can get a
    * window in the update queue that has an empty update_area.
    * just ignore it.
@@ -4448,59 +4906,147 @@ gdk_window_process_updates_internal (GdkWindow *window)
     {
       GdkRegion *update_area = private->update_area;
       private->update_area = NULL;
-      
-      if (_gdk_event_func && gdk_window_is_viewable (window))
+
+      if (_gdk_event_func && gdk_window_is_viewable (window)  &&
+         private->window_type != GDK_WINDOW_FOREIGN)
        {
-         GdkRectangle window_rect;
          GdkRegion *expose_region;
-         GdkRegion *window_region;
          gboolean end_implicit;
 
          /* Clip to part visible in toplevel */
          gdk_region_intersect (update_area, private->clip_region);
-         
-          if (debug_updates)
-            {
-              /* Make sure we see the red invalid area before redrawing. */
-              gdk_display_sync (gdk_drawable_get_display (window));
-              g_usleep (70000);
-            }
 
-         save_region = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->queue_antiexpose (window, update_area);
-         if (save_region)
-           expose_region = gdk_region_copy (update_area);
-         else
-           expose_region = update_area;
-         
-         window_rect.x = 0;
-         window_rect.y = 0;
-         window_rect.width = private->width;
-         window_rect.height = private->height;
-
-         window_region = gdk_region_rectangle (&window_rect);
-         gdk_region_intersect (expose_region,
-                               window_region);
-         gdk_region_destroy (window_region);
-
-         gdk_region_get_clipbox (expose_region, &clip_box);
+         if (debug_updates)
+           {
+             /* Make sure we see the red invalid area before redrawing. */
+             gdk_display_sync (gdk_drawable_get_display (window));
+             g_usleep (70000);
+           }
+
+         /* At this point we will be completely redrawing all of update_area.
+          * If we have any outstanding moves that end up moving stuff inside
+          * this area we don't actually need to move that as that part would
+          * be overdrawn by the expose anyway. So, in order to copy less data
+          * we remove these areas from the outstanding moves.
+          */
+         if (private->outstanding_moves)
+           {
+             GdkWindowRegionMove *move;
+             GdkRegion *remove;
+             GList *l, *prev;
+
+             remove = gdk_region_copy (update_area);
+             /* We iterate backwards, starting from the state that would be
+                if we had applied all the moves. */
+             for (l = g_list_last (private->outstanding_moves); l != NULL; l = prev)
+               {
+                 prev = l->prev;
+                 move = l->data;
+
+                 /* Don't need this area */
+                 gdk_region_subtract (move->dest_region, remove);
+
+                 /* However if any of the destination we do need has a source
+                    in the updated region we do need that as a destination for
+                    the earlier moves */
+                 gdk_region_offset (move->dest_region, -move->dx, -move->dy);
+                 gdk_region_subtract (remove, move->dest_region);
+
+                 if (gdk_region_empty (move->dest_region))
+                   {
+                     gdk_window_region_move_free (move);
+                     private->outstanding_moves =
+                       g_list_delete_link (private->outstanding_moves, l);
+                   }
+                 else /* move back */
+                   gdk_region_offset (move->dest_region, move->dx, move->dy);
+               }
+             gdk_region_destroy (remove);
+           }
+
+         /* By now we a set of window moves that should be applied, and then
+          * an update region that should be repainted. A trivial implementation
+          * would just do that in order, however in order to get nicer drawing
+          * we do some tricks:
+          *
+          * First of all, each subwindow expose may be double buffered by
+          * itself (depending on widget setting) via
+          * gdk_window_begin/end_paint(). But we also do an "implicit" paint,
+          * creating a single pixmap the size of the invalid area on the
+          * native window which all the individual normal paints will draw
+          * into. This way in the normal case there will be only one pixmap
+          * allocated and only once pixmap draw done for all the windows
+          * in this native window.
+          * There are a couple of reasons this may fail, for instance, some
+          * backends (like quartz) do its own double buffering, so we disable
+          * gdk double buffering there. Secondly, some subwindow could be
+          * non-double buffered and draw directly to the window outside a
+          * begin/end_paint pair. That will be lead to a gdk_window_flush
+          * which immediately executes all outstanding moves and paints+removes
+          * the implicit paint (further paints will allocate their own pixmap).
+          *
+          * Secondly, in the case of implicit double buffering we expose all
+          * the child windows into the implicit pixmap before we execute
+          * the outstanding moves. This way we minimize the time between
+          * doing the moves and rendering the new update area, thus minimizing
+          * flashing. Of course, if any subwindow is non-double buffered we
+          * well flush earlier than that.
+          *
+          * Thirdly, after having done the outstanding moves we queue an
+          * "antiexpose" on the area that will be drawn by the expose, which
+          * means that any invalid region on the native window side before
+          * the first expose drawing operation will be discarded, as it
+          * has by then been overdrawn with valid data. This means we can
+          * avoid doing the unnecessary repaint any outstanding expose events.
+          */
+
+         gdk_region_get_clipbox (update_area, &clip_box);
          end_implicit = gdk_window_begin_implicit_paint (window, &clip_box);
+         expose_region = gdk_region_copy (update_area);
+         if (!end_implicit)
+           {
+             /* Rendering is not double buffered by gdk, do outstanding
+              * moves and queue antiexposure immediately. No need to do
+              * any tricks */
+             gdk_window_flush_outstanding_moves (window);
+             save_region = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->queue_antiexpose (window, update_area);
+           }
+
+         /* Render the invalid areas to the implicit paint, by sending exposes.
+          * May flush if non-double buffered widget draw. */
          _gdk_windowing_window_process_updates_recurse (window, expose_region);
+
          if (end_implicit)
-           gdk_window_end_implicit_paint (window);
-         
-         if (expose_region != update_area)
-           gdk_region_destroy (expose_region);
+           {
+             /* Do moves right before exposes are rendered to the window */
+             gdk_window_flush_outstanding_moves (window);
+
+             /* By this time we know that any outstanding expose for this
+              * area is invalid and we can avoid it, so queue an antiexpose.
+              * However, it may be that due to an non-double buffered expose
+              * we have already started drawing to the window, so it would
+              * be to late to anti-expose now. Since this is merely an
+              * optimization we just avoid doing it at all in that case.
+              */
+             if (private->implicit_paint != NULL) /* didn't flush implicit paint */
+               save_region = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->queue_antiexpose (window, update_area);
+
+             gdk_window_end_implicit_paint (window);
+           }
+         gdk_region_destroy (expose_region);
        }
       if (!save_region)
        gdk_region_destroy (update_area);
     }
-  
+
   if (private->outstanding_moves)
     {
       /* Flush any outstanding moves, may happen if we moved a window but got
         no actual invalid area */
       gdk_window_flush_outstanding_moves (window);
     }
+
+  g_object_unref (window);
 }
 
 static void
@@ -4530,7 +5076,7 @@ flush_all_displays (void)
  *
  * Calls gdk_window_process_updates() for all windows (see #GdkWindow)
  * in the application.
- * 
+ *
  **/
 void
 gdk_window_process_all_updates (void)
@@ -4546,20 +5092,20 @@ gdk_window_process_all_updates (void)
 
   if (update_idle)
     g_source_remove (update_idle);
-  
+
   update_windows = NULL;
   update_idle = 0;
 
   _gdk_windowing_before_process_all_updates ();
 
   g_slist_foreach (old_update_windows, (GFunc)g_object_ref, NULL);
-  
+
   while (tmp_list)
     {
       GdkWindowObject *private = (GdkWindowObject *)tmp_list->data;
-      
+
       if (!GDK_WINDOW_DESTROYED (tmp_list->data))
-        {
+       {
          if (private->update_freeze_count ||
              gdk_window_is_toplevel_frozen (tmp_list->data))
            gdk_window_add_update_window ((GdkWindow *) private);
@@ -4585,7 +5131,7 @@ gdk_window_process_all_updates (void)
  * @window: a #GdkWindow
  * @update_children: whether to also process updates for child windows
  *
- * Sends one or more expose events to @window. The areas in each 
+ * Sends one or more expose events to @window. The areas in each
  * expose event will cover the entire update area for the window (see
  * gdk_window_invalidate_region() for details). Normally GDK calls
  * gdk_window_process_all_updates() on your behalf, so there's no
@@ -4593,7 +5139,7 @@ gdk_window_process_all_updates (void)
  * to be delivered immediately and synchronously (vs. the usual
  * case, where GDK delivers them in an idle handler). Occasionally
  * this is useful to produce nicer scrolling behavior, for example.
- * 
+ *
  **/
 void
 gdk_window_process_updates (GdkWindow *window,
@@ -4604,12 +5150,18 @@ gdk_window_process_updates (GdkWindow *window,
 
   g_return_if_fail (GDK_IS_WINDOW (window));
 
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  /* Make sure the window lives during the expose callouts */
+  g_object_ref (window);
+
   impl_window = gdk_window_get_impl_window (private);
   if ((impl_window->update_area ||
        impl_window->outstanding_moves) &&
       !impl_window->update_freeze_count &&
       !gdk_window_is_toplevel_frozen (window))
-    {      
+    {
       gdk_window_process_updates_internal ((GdkWindow *)impl_window);
       gdk_window_remove_update_window ((GdkWindow *)impl_window);
     }
@@ -4619,10 +5171,21 @@ gdk_window_process_updates (GdkWindow *window,
       /* process updates in reverse stacking order so composition or
        * painting over achieves the desired effect for offscreen windows
        */
-      GList *node;
-      for (node = g_list_last (private->children); node; node = node->prev)
-        gdk_window_process_updates (node->data, TRUE);
+      GList *node, *children;
+
+      children = g_list_copy (private->children);
+      g_list_foreach (children, (GFunc)g_object_ref, NULL);
+
+      for (node = g_list_last (children); node; node = node->prev)
+       {
+         gdk_window_process_updates (node->data, TRUE);
+         g_object_unref (node->data);
+       }
+
+      g_list_free (children);
     }
+
+  g_object_unref (window);
 }
 
 /**
@@ -4638,8 +5201,8 @@ gdk_window_process_updates (GdkWindow *window,
  **/
 void
 gdk_window_invalidate_rect (GdkWindow          *window,
-                            const GdkRectangle *rect,
-                            gboolean            invalidate_children)
+                           const GdkRectangle *rect,
+                           gboolean            invalidate_children)
 {
   GdkRectangle window_rect;
   GdkRegion *region;
@@ -4649,8 +5212,8 @@ gdk_window_invalidate_rect (GdkWindow          *window,
 
   if (GDK_WINDOW_DESTROYED (window))
     return;
-  
-  if (private->input_only || !GDK_WINDOW_IS_MAPPED (window))
+
+  if (private->input_only || !private->viewable)
     return;
 
   if (!rect)
@@ -4658,8 +5221,8 @@ gdk_window_invalidate_rect (GdkWindow          *window,
       window_rect.x = 0;
       window_rect.y = 0;
       gdk_drawable_get_size (GDK_DRAWABLE (window),
-                             &window_rect.width,
-                             &window_rect.height);
+                            &window_rect.width,
+                            &window_rect.height);
       rect = &window_rect;
     }
 
@@ -4670,25 +5233,25 @@ gdk_window_invalidate_rect (GdkWindow          *window,
 
 static void
 draw_ugly_color (GdkWindow       *window,
-                 const GdkRegion *region)
+                const GdkRegion *region)
 {
   /* Draw ugly color all over the newly-invalid region */
   GdkColor ugly_color = { 0, 50000, 10000, 10000 };
   GdkGC *ugly_gc;
   GdkRectangle clipbox;
-    
+
   ugly_gc = gdk_gc_new (window);
   gdk_gc_set_rgb_fg_color (ugly_gc, &ugly_color);
   gdk_gc_set_clip_region (ugly_gc, region);
 
   gdk_region_get_clipbox (region, &clipbox);
-  
+
   gdk_draw_rectangle (window,
                      ugly_gc,
                      TRUE,
                      clipbox.x, clipbox.y,
                      clipbox.width, clipbox.height);
-  
+
   g_object_unref (ugly_gc);
 }
 
@@ -4719,9 +5282,9 @@ draw_ugly_color (GdkWindow       *window,
  **/
 void
 gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
-                                     const GdkRegion *region,
-                                     gboolean       (*child_func) (GdkWindow *,
-                                                                   gpointer),
+                                    const GdkRegion *region,
+                                    gboolean       (*child_func) (GdkWindow *,
+                                                                  gpointer),
                                     gpointer   user_data)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
@@ -4733,8 +5296,11 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
 
   if (GDK_WINDOW_DESTROYED (window))
     return;
-  
-  if (private->input_only || !GDK_WINDOW_IS_MAPPED (window))
+
+  if (private->input_only ||
+      !private->viewable ||
+      gdk_region_empty (region) ||
+      private->window_type == GDK_WINDOW_ROOT)
     return;
 
   visible_region = gdk_drawable_get_visible_region (window);
@@ -4744,7 +5310,7 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
   while (tmp_list)
     {
       GdkWindowObject *child = tmp_list->data;
-      
+
       if (!child->input_only)
        {
          GdkRegion *child_region;
@@ -4755,24 +5321,24 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
          child_rect.width = child->width;
          child_rect.height = child->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_window_is_offscreen (child))
+             !gdk_window_is_offscreen (child))
            gdk_region_subtract (visible_region, child_region);
-         
+
          if (child_func && (*child_func) ((GdkWindow *)child, user_data))
            {
-              GdkRegion *tmp = gdk_region_copy (region);
+             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);
            }
 
@@ -4783,7 +5349,7 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
     }
 
   impl_window = gdk_window_get_impl_window (private);
-  
+
   if (!gdk_region_empty (visible_region)  ||
       /* Even if we're not exposing anything, make sure we process
         idles for windows with outstanding moves */
@@ -4791,8 +5357,8 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
        impl_window->update_area == NULL))
     {
       if (debug_updates)
-        draw_ugly_color (window, region);
-      
+       draw_ugly_color (window, region);
+
       /* Convert to impl coords */
       gdk_region_offset (visible_region, private->abs_x, private->abs_y);
       if (impl_window->update_area)
@@ -4803,11 +5369,11 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
        {
          gdk_window_add_update_window ((GdkWindow *)impl_window);
          impl_window->update_area = gdk_region_copy (visible_region);
-         
+
          gdk_window_schedule_update ((GdkWindow *)impl_window);
        }
     }
-  
+
   gdk_region_destroy (visible_region);
 }
 
@@ -4822,7 +5388,7 @@ true_predicate (GdkWindow *window,
  * gdk_window_invalidate_region:
  * @window: a #GdkWindow
  * @region: a #GdkRegion
- * @invalidate_children: %TRUE to also invalidate child windows 
+ * @invalidate_children: %TRUE to also invalidate child windows
  *
  * Adds @region to the update area for @window. The update area is the
  * region that needs to be redrawn, or "dirty region." The call
@@ -4849,7 +5415,7 @@ gdk_window_invalidate_region (GdkWindow       *window,
 {
   gdk_window_invalidate_maybe_recurse (window, region,
                                       invalidate_children ?
-                                        true_predicate : (gboolean (*) (GdkWindow *, gpointer))NULL,
+                                        true_predicate : (gboolean (*) (GdkWindow *, gpointer))NULL,
                                       NULL);
 }
 
@@ -4873,12 +5439,41 @@ gdk_window_invalidate_region (GdkWindow       *window,
  * This version of invalidation is used when you recieve expose events
  * from the native window system. It exposes the native window, plus
  * any non-native child windows (but not native child windows, as those would
- * have gotten their own expose events). 
+ * have gotten their own expose events).
  **/
 void
 _gdk_window_invalidate_for_expose (GdkWindow       *window,
-                                  const GdkRegion *region)
+                                  GdkRegion       *region)
 {
+  GdkWindowObject *private = (GdkWindowObject *) window;
+  GdkWindowRegionMove *move;
+  GdkRegion *move_region;
+  GList *l;
+
+  /* Any invalidations comming from the windowing system will
+     be in areas that may be moved by outstanding moves,
+     so we need to modify the expose region correspondingly,
+     otherwise we would expose in the wrong place, as the
+     outstanding moves will be copied before we draw the
+     exposes. */
+  for (l = private->outstanding_moves; l != NULL; l = l->next)
+    {
+      move = l->data;
+
+      /* covert to move source region */
+      move_region = gdk_region_copy (move->dest_region);
+      gdk_region_offset (move_region, -move->dx, -move->dy);
+
+      /* Move area of region that intersects with move source
+        by dx, dy of the move*/
+      gdk_region_intersect (move_region, region);
+      gdk_region_subtract (region, move_region);
+      gdk_region_offset (move_region, move->dx, move->dy);
+      gdk_region_union (region, move_region);
+
+      gdk_region_destroy (move_region);
+    }
+
   gdk_window_invalidate_maybe_recurse (window, region,
                                       (gboolean (*) (GdkWindow *, gpointer))gdk_window_has_no_impl,
                                       NULL);
@@ -4888,14 +5483,14 @@ _gdk_window_invalidate_for_expose (GdkWindow       *window,
 /**
  * gdk_window_get_update_area:
  * @window: a #GdkWindow
- * 
+ *
  * Transfers ownership of the update area from @window to the caller
  * of the function. That is, after calling this function, @window will
  * no longer have an invalid/dirty region; the update area is removed
  * from @window and handed to you. If a window has no update area,
  * gdk_window_get_update_area() returns %NULL. You are responsible for
  * calling gdk_region_destroy() on the returned region if it's non-%NULL.
- * 
+ *
  * Return value: the update area for @window
  **/
 GdkRegion *
@@ -4908,7 +5503,7 @@ gdk_window_get_update_area (GdkWindow *window)
   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 
   impl_window = gdk_window_get_impl_window (private);
-  
+
   if (impl_window->update_area)
     {
       tmp_region = gdk_region_copy (private->clip_region_with_children);
@@ -4930,10 +5525,10 @@ gdk_window_get_update_area (GdkWindow *window)
            {
              gdk_region_destroy (impl_window->update_area);
              impl_window->update_area = NULL;
-         
+
              gdk_window_remove_update_window ((GdkWindow *)impl_window);
            }
-         
+
          /* Convert from impl coords */
          gdk_region_offset (tmp_region, -private->abs_x, -private->abs_y);
          return tmp_region;
@@ -4947,7 +5542,7 @@ gdk_window_get_update_area (GdkWindow *window)
 /**
  * _gdk_window_clear_update_area:
  * @window: a #GdkWindow.
- * 
+ *
  * Internal function to clear the update area for a window. This
  * is called when the window is hidden or destroyed.
  **/
@@ -4970,7 +5565,7 @@ _gdk_window_clear_update_area (GdkWindow *window)
 /**
  * gdk_window_freeze_updates:
  * @window: a #GdkWindow
- * 
+ *
  * Temporarily freezes a window such that it won't receive expose
  * events.  The window will begin receiving expose events again when
  * gdk_window_thaw_updates() is called. If gdk_window_freeze_updates()
@@ -4992,7 +5587,7 @@ gdk_window_freeze_updates (GdkWindow *window)
 /**
  * gdk_window_thaw_updates:
  * @window: a #GdkWindow
- * 
+ *
  * Thaws a window frozen with gdk_window_freeze_updates().
  **/
 void
@@ -5002,10 +5597,11 @@ gdk_window_thaw_updates (GdkWindow *window)
   GdkWindowObject *impl_window;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
-  g_return_if_fail (private->update_freeze_count > 0);
 
   impl_window = gdk_window_get_impl_window (private);
-  
+
+  g_return_if_fail (impl_window->update_freeze_count > 0);
+
   if (--impl_window->update_freeze_count == 0)
     gdk_window_schedule_update (GDK_WINDOW (impl_window));
 }
@@ -5039,7 +5635,7 @@ gdk_window_freeze_toplevel_updates_libgtk_only (GdkWindow *window)
 /**
  * gdk_window_thaw_toplevel_updates_libgtk_only:
  * @window: a #GdkWindow
- * 
+ *
  * Thaws a window frozen with
  * gdk_window_freeze_toplevel_updates_libgtk_only().
  *
@@ -5083,7 +5679,7 @@ gdk_window_thaw_toplevel_updates_libgtk_only (GdkWindow *window)
  * usually more useful than calling gdk_window_set_debug_updates()
  * yourself, though you might want to use this function to enable
  * updates sometime after application startup time.
- * 
+ *
  **/
 void
 gdk_window_set_debug_updates (gboolean setting)
@@ -5099,8 +5695,8 @@ gdk_window_set_debug_updates (gboolean setting)
  * @height: desired height of the window
  * @new_width: location to store resulting width
  * @new_height: location to store resulting height
- * 
- * Constrains a desired width and height according to a 
+ *
+ * Constrains a desired width and height according to a
  * set of geometry hints (such as minimum and maximum size).
  */
 void
@@ -5127,7 +5723,7 @@ gdk_window_constrain_size (GdkGeometry *geometry,
   gint yinc = 1;
   gint max_width = G_MAXINT;
   gint max_height = G_MAXINT;
-  
+
 #define FLOOR(value, base)     ( ((gint) ((value) / (base))) * (base) )
 
   if ((flags & GDK_HINT_BASE_SIZE) && (flags & GDK_HINT_MIN_SIZE))
@@ -5163,12 +5759,12 @@ gdk_window_constrain_size (GdkGeometry *geometry,
       xinc = MAX (xinc, geometry->width_inc);
       yinc = MAX (yinc, geometry->height_inc);
     }
-  
+
   /* clamp width and height to min and max values
    */
   width = CLAMP (width, min_width, max_width);
   height = CLAMP (height, min_height, max_height);
-  
+
   /* shrink to base + N * inc
    */
   width = base_width + FLOOR (width - base_width, xinc);
@@ -5176,11 +5772,11 @@ gdk_window_constrain_size (GdkGeometry *geometry,
 
   /* constrain aspect ratio, according to:
    *
-   *                width     
+   *                width
    * min_aspect <= -------- <= max_aspect
-   *                height    
+   *                height
    */
-  
+
   if (flags & GDK_HINT_ASPECT &&
       geometry->min_aspect > 0 &&
       geometry->max_aspect > 0)
@@ -5193,17 +5789,17 @@ gdk_window_constrain_size (GdkGeometry *geometry,
          if (height - delta >= min_height)
            height -= delta;
          else
-           { 
+           {
              delta = FLOOR (height * geometry->min_aspect - width, xinc);
-             if (width + delta <= max_width) 
+             if (width + delta <= max_width)
                width += delta;
            }
        }
-      
+
       if (geometry->max_aspect * height < width)
        {
          delta = FLOOR (width - height * geometry->max_aspect, xinc);
-         if (width - delta >= min_width) 
+         if (width - delta >= min_width)
            width -= delta;
          else
            {
@@ -5215,7 +5811,7 @@ gdk_window_constrain_size (GdkGeometry *geometry,
     }
 
 #undef FLOOR
-  
+
   *new_width = width;
   *new_height = height;
 }
@@ -5231,9 +5827,9 @@ gdk_window_constrain_size (GdkGeometry *geometry,
  *      modifier mask
  *
  * Obtains the current pointer position and modifier state.
- * The position is given in coordinates relative to the upper left 
+ * 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
  * pointer isn't known to GDK
@@ -5248,7 +5844,7 @@ gdk_window_get_pointer (GdkWindow   *window,
   gint tmp_x, tmp_y;
   GdkModifierType tmp_mask;
   GdkWindow *child;
-  
+
   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
 
   if (window)
@@ -5261,7 +5857,7 @@ gdk_window_get_pointer (GdkWindow   *window,
 
       display = gdk_screen_get_display (screen);
       window = gdk_screen_get_root_window (screen);
-      
+
       GDK_NOTE (MULTIHEAD,
                g_message ("Passing NULL for window to gdk_window_get_pointer()\n"
                           "is not multihead safe"));
@@ -5277,7 +5873,7 @@ gdk_window_get_pointer (GdkWindow   *window,
     *mask = tmp_mask;
 
   _gdk_display_enable_motion_hints (display);
-  
+
   return child;
 }
 
@@ -5285,7 +5881,7 @@ gdk_window_get_pointer (GdkWindow   *window,
  * gdk_window_at_pointer:
  * @win_x: return location for origin of the window under the pointer
  * @win_y: return location for origin of the window under the pointer
- * 
+ *
  * Obtains the window underneath the mouse pointer, returning the
  * location of that window in @win_x, @win_y. Returns %NULL if the
  * window under the mouse pointer is not known to GDK (if the window
@@ -5294,7 +5890,7 @@ gdk_window_get_pointer (GdkWindow   *window,
  *
  * NOTE: For multihead-aware widgets or applications use
  * gdk_display_get_window_at_pointer() instead.
- * 
+ *
  * Return value: window under the mouse pointer
  **/
 GdkWindow*
@@ -5306,10 +5902,10 @@ gdk_window_at_pointer (gint *win_x,
 
 /**
  * gdk_get_default_root_window:
- * 
+ *
  * Obtains the root window (parent all other windows are inside)
  * for the default display and screen.
- * 
+ *
  * Return value: the default root window
  **/
 GdkWindow *
@@ -5321,14 +5917,14 @@ gdk_get_default_root_window (void)
 /**
  * gdk_window_foreign_new:
  * @anid: a native window handle.
- * 
+ *
  * Wraps a native window for the default display in a #GdkWindow.
  * This may fail if the window has been destroyed.
  *
  * For example in the X backend, a native window handle is an Xlib
  * <type>XID</type>.
- * 
- * Return value: the newly-created #GdkWindow wrapper for the 
+ *
+ * Return value: the newly-created #GdkWindow wrapper for the
  *    native window or %NULL if the window has been destroyed.
  **/
 GdkWindow *
@@ -5343,7 +5939,7 @@ get_all_native_children (GdkWindowObject *private,
 {
   GdkWindowObject *child;
   GList *l;
-  
+
   for (l = private->children; l != NULL; l = l->next)
     {
       child = l->data;
@@ -5373,7 +5969,13 @@ gdk_window_raise_internal (GdkWindow *window)
 
   /* Just do native raise for toplevels */
   if (private->parent == NULL ||
-      GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+      private->parent->window_type == GDK_WINDOW_ROOT ||
+      /* The restack_under codepath should work correctly even if the parent
+        is native, but it relies on the order of ->children to be correct,
+        and some apps like SWT reorder the x windows without gdks knowledge,
+        so we use raise directly in order to make these behave as before
+        when using native windows */
+      (gdk_window_has_impl (private) && gdk_window_has_impl (parent)))
     {
       GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (window);
     }
@@ -5404,39 +6006,107 @@ gdk_window_raise_internal (GdkWindow *window)
                                                                      native_children);
          else
            {
-             /* Right order, since native_chilren is bottom-opmost first */
+             /* Right order, since native_children is bottom-topmost first */
              for (l = native_children; l != NULL; l = l->next)
                GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (l->data);
            }
-         
+
          g_list_free (native_children);
        }
-      
+
     }
 }
 
-static void
-show_all_visible_impls (GdkWindowObject *private)
+/* Returns TRUE If the native window was mapped or unmapped */
+static gboolean
+set_viewable (GdkWindowObject *w,
+             gboolean val)
 {
   GdkWindowObject *child;
   GList *l;
-  
-  for (l = private->children; l != NULL; l = l->next)
+
+  if (w->viewable == val)
+    return FALSE;
+
+  w->viewable = val;
+
+  if (val)
+    recompute_visible_regions (w, FALSE, FALSE);
+
+  for (l = w->children; l != NULL; l = l->next)
     {
       child = l->data;
-      if (GDK_WINDOW_IS_MAPPED (child))
-       show_all_visible_impls (child);
+
+      if (GDK_WINDOW_IS_MAPPED (child) &&
+         child->window_type != GDK_WINDOW_FOREIGN)
+       set_viewable (child, val);
     }
-  
-  if (gdk_window_has_impl (private))
-    GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show ((GdkWindow *)private);
+
+  if (gdk_window_has_impl (w)  &&
+      w->window_type != GDK_WINDOW_FOREIGN &&
+      w->parent != NULL &&
+      w->parent->window_type != GDK_WINDOW_ROOT)
+    {
+      /* For most native windows we show/hide them not when they are
+       * mapped/unmapped, because that may not produce the correct results.
+       * For instance, if a native window have a non-native parent which is
+       * hidden, but its native parent is viewable then showing the window
+       * would make it viewable to X but its not viewable wrt the non-native
+       * hierarchy. In order to handle this we track the gdk side viewability
+       * and only map really viewable windows.
+       *
+       * There are two exceptions though:
+       *
+       * For foreign windows we don't want ever change the mapped state
+       * except when explicitly done via gdk_window_show/hide, as this may
+       * cause problems for client owning the foreign window when its window
+       * is suddenly mapped or unmapped.
+       *
+       * For toplevel windows embedded in a foreign window (e.g. a plug)
+       * we sometimes synthesize a map of a window, but the native
+       * window is really shown by the embedder, so we don't want to
+       * do the show ourselves. We can't really tell this case from the normal
+       * toplevel show as such toplevels are seen by gdk as parents of the
+       * root window, so we make an exception for all toplevels.
+       */
+
+      if (val)
+       GDK_WINDOW_IMPL_GET_IFACE (w->impl)->show ((GdkWindow *)w, FALSE);
+      else
+       GDK_WINDOW_IMPL_GET_IFACE (w->impl)->hide ((GdkWindow *)w);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* Returns TRUE If the native window was mapped or unmapped */
+gboolean
+_gdk_window_update_viewable (GdkWindow *window)
+{
+  GdkWindowObject *priv = (GdkWindowObject *)window;
+  gboolean viewable;
+
+  if (priv->window_type == GDK_WINDOW_FOREIGN ||
+      priv->window_type == GDK_WINDOW_ROOT)
+    viewable = TRUE;
+  else if (priv->parent == NULL ||
+          priv->parent->window_type == GDK_WINDOW_ROOT ||
+          priv->parent->viewable)
+    viewable = GDK_WINDOW_IS_MAPPED (priv);
+  else
+    viewable = FALSE;
+
+  return set_viewable (priv, viewable);
 }
 
 static void
 gdk_window_show_internal (GdkWindow *window, gboolean raise)
 {
   GdkWindowObject *private;
-  gboolean was_mapped;
+  gboolean was_mapped, was_viewable;
+  gboolean did_show;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
 
@@ -5445,7 +6115,8 @@ gdk_window_show_internal (GdkWindow *window, gboolean raise)
     return;
 
   was_mapped = GDK_WINDOW_IS_MAPPED (window);
-  
+  was_viewable = private->viewable;
+
   if (raise)
     /* Keep children in (reverse) stacking order */
     gdk_window_raise_internal (window);
@@ -5462,30 +6133,42 @@ gdk_window_show_internal (GdkWindow *window, gboolean raise)
       private->state = 0;
     }
 
-  if (!was_mapped && gdk_window_is_viewable (window))
-    show_all_visible_impls (private);
-  
-  if (!was_mapped)
+  did_show = _gdk_window_update_viewable (window);
+
+  /* If it was already viewable the backend show op won't be called, call it
+     again to ensure things happen right if the mapped tracking was not right
+     for e.g. a foreign window.
+     Dunno if this is strictly needed but its what happened pre-csw.
+     Also show if not done by gdk_window_update_viewable. */
+  if (gdk_window_has_impl (private) && (was_viewable || !did_show))
+    GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show ((GdkWindow *)private,
+                                                    !did_show ?
+                                                    was_mapped : TRUE);
+
+  if (!was_mapped && !gdk_window_has_impl (private))
     {
       if (private->event_mask & GDK_STRUCTURE_MASK)
        _gdk_make_event (GDK_WINDOW (private), GDK_MAP, NULL, FALSE);
-      
+
       if (private->parent && private->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
        _gdk_make_event (GDK_WINDOW (private), GDK_MAP, NULL, FALSE);
     }
-  
+
   if (!was_mapped || raise)
     {
       recompute_visible_regions (private, TRUE, FALSE);
-      
+
+      /* If any decendants became visible we need to send visibility notify */
+      gdk_window_update_visibility_recursively (private, NULL);
+
       if (gdk_window_is_viewable (window))
        {
-         _gdk_syntesize_crossing_events_for_geometry_change (window);
+         _gdk_synthesize_crossing_events_for_geometry_change (window);
          gdk_window_invalidate_rect (window, NULL, TRUE);
        }
     }
 }
-  
+
 /**
  * gdk_window_show_unraised:
  * @window: a #GdkWindow
@@ -5520,6 +6203,7 @@ void
 gdk_window_raise (GdkWindow *window)
 {
   GdkWindowObject *private;
+  GdkRegion *old_region, *new_region;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
 
@@ -5527,12 +6211,26 @@ gdk_window_raise (GdkWindow *window)
   if (private->destroyed)
     return;
 
+  old_region = NULL;
+  if (gdk_window_is_viewable (window) &&
+      !private->input_only)
+    old_region = gdk_region_copy (private->clip_region);
+
   /* Keep children in (reverse) stacking order */
   gdk_window_raise_internal (window);
 
   recompute_visible_regions (private, TRUE, FALSE);
 
-  gdk_window_invalidate_rect (window, NULL, TRUE);
+  if (old_region)
+    {
+      new_region = gdk_region_copy (private->clip_region);
+
+      gdk_region_subtract (new_region, old_region);
+      gdk_window_invalidate_region (window, new_region, TRUE);
+
+      gdk_region_destroy (old_region);
+      gdk_region_destroy (new_region);
+    }
 }
 
 static void
@@ -5552,7 +6250,13 @@ gdk_window_lower_internal (GdkWindow *window)
 
   /* Just do native lower for toplevels */
   if (private->parent == NULL ||
-      GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+      private->parent->window_type == GDK_WINDOW_ROOT ||
+      /* The restack_under codepath should work correctly even if the parent
+        is native, but it relies on the order of ->children to be correct,
+        and some apps like SWT reorder the x windows without gdks knowledge,
+        so we use lower directly in order to make these behave as before
+        when using native windows */
+      (gdk_window_has_impl (private) && gdk_window_has_impl (parent)))
     {
       GDK_WINDOW_IMPL_GET_IFACE (private->impl)->lower (window);
     }
@@ -5583,14 +6287,14 @@ gdk_window_lower_internal (GdkWindow *window)
                                                                      native_children);
          else
            {
-             /* Right order, since native_chilren is bottom-opmost first */
+             /* Right order, since native_children is bottom-topmost first */
              for (l = native_children; l != NULL; l = l->next)
                GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (l->data);
            }
-         
+
          g_list_free (native_children);
        }
-      
+
     }
 }
 
@@ -5600,9 +6304,9 @@ gdk_window_invalidate_in_parent (GdkWindowObject *private)
   GdkRectangle r, child;
 
   if (private->parent == NULL ||
-      GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+      private->parent->window_type == GDK_WINDOW_ROOT)
     return;
-  
+
   /* get the visible rectangle of the parent */
   r.x = r.y = 0;
   r.width = private->parent->width;
@@ -5648,8 +6352,8 @@ gdk_window_lower (GdkWindow *window)
   gdk_window_lower_internal (window);
 
   recompute_visible_regions (private, TRUE, FALSE);
-  
-  _gdk_syntesize_crossing_events_for_geometry_change (window);
+
+  _gdk_synthesize_crossing_events_for_geometry_change (window);
   gdk_window_invalidate_in_parent (private);
 }
 
@@ -5673,25 +6377,6 @@ gdk_window_show (GdkWindow *window)
   gdk_window_show_internal (window, TRUE);
 }
 
-static void
-hide_all_visible_impls (GdkWindowObject *private)
-{
-  GdkWindowObject *child;
-  GList *l;
-  
-  for (l = private->children; l != NULL; l = l->next)
-    {
-      child = l->data;
-      
-      if (GDK_WINDOW_IS_MAPPED (child))
-       hide_all_visible_impls (child);
-    }
-  
-  if (gdk_window_has_impl (private))
-    GDK_WINDOW_IMPL_GET_IFACE (private->impl)->hide ((GdkWindow *)private);
-}
-
-
 /**
  * gdk_window_hide:
  * @window: a #GdkWindow
@@ -5705,7 +6390,7 @@ void
 gdk_window_hide (GdkWindow *window)
 {
   GdkWindowObject *private;
-  gboolean was_mapped, was_viewable;
+  gboolean was_mapped, did_hide;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
 
@@ -5714,15 +6399,14 @@ gdk_window_hide (GdkWindow *window)
     return;
 
   was_mapped = GDK_WINDOW_IS_MAPPED (private);
-  was_viewable = gdk_window_is_viewable (window);
-  
+
   if (gdk_window_has_impl (private))
     {
 
       if (GDK_WINDOW_IS_MAPPED (window))
-        gdk_synthesize_window_state (window,
-                                     0,
-                                     GDK_WINDOW_STATE_WITHDRAWN);
+       gdk_synthesize_window_state (window,
+                                    0,
+                                    GDK_WINDOW_STATE_WITHDRAWN);
     }
   else if (was_mapped)
     {
@@ -5731,20 +6415,11 @@ gdk_window_hide (GdkWindow *window)
       /* May need to break grabs on children */
       display = gdk_drawable_get_display (window);
 
-      if (display->pointer_grab.window != NULL)
-       {
-         if (is_parent_of (window, display->pointer_grab.window))
-           {
-             /* Call this ourselves, even though gdk_display_pointer_ungrab
-                does so too, since we want to pass implicit == TRUE so the
-                broken grab event is generated */
-             _gdk_display_unset_has_pointer_grab (display,
-                                                  TRUE,
-                                                  FALSE,
-                                                  GDK_CURRENT_TIME);
-             gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
-           }
-       }
+      if (_gdk_display_end_pointer_grab (display,
+                                        _gdk_windowing_window_get_next_serial (display),
+                                        window,
+                                        TRUE))
+       gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
 
       if (display->keyboard_grab.window != NULL)
        {
@@ -5758,26 +6433,32 @@ gdk_window_hide (GdkWindow *window)
              gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
            }
        }
-      
+
       private->state = GDK_WINDOW_STATE_WITHDRAWN;
     }
 
-  if (was_viewable)
-    hide_all_visible_impls (private);
-  
+  did_hide = _gdk_window_update_viewable (window);
+
+  /* Hide foreign window as those are not handled by update_viewable. */
+  if (gdk_window_has_impl (private) && (!did_hide))
+    GDK_WINDOW_IMPL_GET_IFACE (private->impl)->hide ((GdkWindow *)private);
+
   recompute_visible_regions (private, TRUE, FALSE);
-  
-  if (was_mapped)
+
+  /* all decendants became non-visible, we need to send visibility notify */
+  gdk_window_update_visibility_recursively (private, NULL);
+
+  if (was_mapped && !gdk_window_has_impl (private))
     {
       if (private->event_mask & GDK_STRUCTURE_MASK)
        _gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE);
-      
+
       if (private->parent && private->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
        _gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE);
-      
-      _gdk_syntesize_crossing_events_for_geometry_change (GDK_WINDOW (private->parent));
+
+      _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (private->parent));
     }
-  
+
   /* Invalidate the rect */
   gdk_window_invalidate_in_parent (private);
 }
@@ -5803,22 +6484,22 @@ gdk_window_withdraw (GdkWindow *window)
     return;
 
   was_mapped = GDK_WINDOW_IS_MAPPED (private);
-  
+
   if (gdk_window_has_impl (private))
     {
       GDK_WINDOW_IMPL_GET_IFACE (private->impl)->withdraw (window);
-      
+
       if (was_mapped)
        {
          if (private->event_mask & GDK_STRUCTURE_MASK)
            _gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE);
-         
+
          if (private->parent && private->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
            _gdk_make_event (GDK_WINDOW (private), GDK_UNMAP, NULL, FALSE);
-         
-         _gdk_syntesize_crossing_events_for_geometry_change (GDK_WINDOW (private->parent));
+
+         _gdk_synthesize_crossing_events_for_geometry_change (GDK_WINDOW (private->parent));
        }
-      
+
       recompute_visible_regions (private, TRUE, FALSE);
     }
 }
@@ -5839,7 +6520,7 @@ gdk_window_set_events (GdkWindow       *window,
 {
   GdkWindowObject *private;
   GdkDisplay *display;
-  
+
 
   g_return_if_fail (GDK_IS_WINDOW (window));
 
@@ -5852,8 +6533,13 @@ gdk_window_set_events (GdkWindow       *window,
   if ((private->event_mask & GDK_POINTER_MOTION_HINT_MASK) &&
       !(event_mask & GDK_POINTER_MOTION_HINT_MASK))
     _gdk_display_enable_motion_hints (display);
-  
+
   private->event_mask = event_mask;
+
+  if (gdk_window_has_impl (private))
+    GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window,
+                                                          get_native_event_mask (private));
+
 }
 
 /**
@@ -5905,42 +6591,42 @@ gdk_window_move_resize_toplevel (GdkWindow *window,
   old_y = private->y;
 
   is_resize = (width != -1) || (height != -1);
-  
-  if (GDK_WINDOW_IS_MAPPED (window) &&
+
+  if (gdk_window_is_viewable (window) &&
       !private->input_only)
     {
       expose = TRUE;
       old_region = gdk_region_copy (private->clip_region);
     }
-  
+
   GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, with_move, x, y, width, height);
 
   dx = private->x - old_x;
   dy = private->y - old_y;
-  
+
   old_abs_x = private->abs_x;
   old_abs_y = private->abs_y;
 
   /* Avoid recomputing for pure toplevel moves, for performance reasons */
   if (is_resize)
     recompute_visible_regions (private, TRUE, FALSE);
-  
+
   if (expose)
     {
       new_region = gdk_region_copy (private->clip_region);
-      
+
       /* This is the newly exposed area (due to any resize),
        * X will expose it, but lets do that without the
        * roundtrip
        */
       gdk_region_subtract (new_region, old_region);
       gdk_window_invalidate_region (window, new_region, TRUE);
-      
+
       gdk_region_destroy (old_region);
       gdk_region_destroy (new_region);
     }
 
-  _gdk_syntesize_crossing_events_for_geometry_change (window);
+  _gdk_synthesize_crossing_events_for_geometry_change (window);
 }
 
 
@@ -5949,11 +6635,11 @@ move_native_children (GdkWindowObject *private)
 {
   GList *l;
   GdkWindowObject *child;
-  
+
   for (l = private->children; l; l = l->next)
     {
       child = l->data;
-      
+
       if (child->impl != private->impl)
        GDK_WINDOW_IMPL_GET_IFACE (child->impl)->move_resize ((GdkWindow *)child, TRUE, child->x, child->y, child->width, child->height);
       else
@@ -5971,11 +6657,14 @@ collect_native_child_region_helper (GdkWindowObject *window,
   GdkWindowObject *child;
   GdkRegion *tmp;
   GList *l;
-  
+
   for (l = window->children; l != NULL; l = l->next)
     {
       child = l->data;
 
+      if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only)
+       continue;
+
       if (child->impl != impl)
        {
          tmp = gdk_region_copy (child->clip_region);
@@ -5995,7 +6684,7 @@ collect_native_child_region_helper (GdkWindowObject *window,
                                            x_offset + child->x,
                                            y_offset + child->y);
     }
-  
+
   return FALSE;
 }
 
@@ -6004,14 +6693,14 @@ collect_native_child_region (GdkWindowObject *window,
                             gboolean include_this)
 {
   GdkRegion *region;
-  
-  if (include_this && gdk_window_has_impl (window))
+
+  if (include_this && gdk_window_has_impl (window) && window->viewable)
     return gdk_region_copy (window->clip_region);
 
   region = NULL;
-  
+
   collect_native_child_region_helper (window, window->impl, &region, 0, 0);
-  
+
   return region;
 }
 
@@ -6039,14 +6728,14 @@ gdk_window_move_resize_internal (GdkWindow *window,
     return;
 
   if (private->parent == NULL ||
-      GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_ROOT)
+      private->parent->window_type == GDK_WINDOW_ROOT)
     {
       gdk_window_move_resize_toplevel (window, with_move, x, y, width, height);
       return;
     }
 
   /* Handle child windows */
-  
+
   expose = FALSE;
   old_region = NULL;
 
@@ -6055,31 +6744,32 @@ gdk_window_move_resize_internal (GdkWindow *window,
   old_x = private->x;
   old_y = private->y;
 
-  if (GDK_WINDOW_IS_MAPPED (window) &&
+  old_native_child_region = NULL;
+  if (gdk_window_is_viewable (window) &&
       !private->input_only)
     {
       expose = TRUE;
-      
+
       old_region = gdk_region_copy (private->clip_region);
       /* Adjust region to parent window coords */
       gdk_region_offset (old_region, private->x, private->y);
-    }
 
-  old_native_child_region = collect_native_child_region (private, TRUE);
-  if (old_native_child_region)
-    {
-      /* Adjust region to parent window coords */
-      gdk_region_offset (old_native_child_region, private->x, private->y);
-      
-      /* Any native window move will immediately copy stuff to the destination, which may overwrite a
-       * source or destination for a delayed GdkWindowRegionMove. So, we need
-       * to flush those here for the parent window and all overlapped subwindows
-       * of it. And we need to do this before setting the new clips as those will be
-       * affecting this.
-       */
-      gdk_window_flush_recursive (private->parent);
+      old_native_child_region = collect_native_child_region (private, TRUE);
+      if (old_native_child_region)
+       {
+         /* Adjust region to parent window coords */
+         gdk_region_offset (old_native_child_region, private->x, private->y);
+
+         /* Any native window move will immediately copy stuff to the destination, which may overwrite a
+          * source or destination for a delayed GdkWindowRegionMove. So, we need
+          * to flush those here for the parent window and all overlapped subwindows
+          * of it. And we need to do this before setting the new clips as those will be
+          * affecting this.
+          */
+         gdk_window_flush_recursive (private->parent);
+       }
     }
+
   /* Set the new position and size */
   if (with_move)
     {
@@ -6095,10 +6785,10 @@ gdk_window_move_resize_internal (GdkWindow *window,
        height = 1;
       private->height = height;
     }
-  
+
   dx = private->x - old_x;
   dy = private->y - old_y;
-  
+
   old_abs_x = private->abs_x;
   old_abs_y = private->abs_y;
 
@@ -6111,7 +6801,7 @@ gdk_window_move_resize_internal (GdkWindow *window,
       /* Adjust region to parent window coords */
       gdk_region_offset (new_native_child_region, private->x, private->y);
     }
-  
+
   if (gdk_window_has_impl (private))
     {
       /* Do the actual move after recomputing things, as this will have set the shape to
@@ -6121,7 +6811,7 @@ gdk_window_move_resize_internal (GdkWindow *window,
   else if (old_abs_x != private->abs_x ||
           old_abs_y != private->abs_y)
     move_native_children (private);
-  
+
   if (expose)
     {
       new_region = gdk_region_copy (private->clip_region);
@@ -6136,10 +6826,10 @@ gdk_window_move_resize_internal (GdkWindow *window,
        *
        * new_region:
        * Everything in the old and new regions that is not copied must be
-       * invalidated (including children) as this is newly exposed 
+       * invalidated (including children) as this is newly exposed
        */
       copy_area = gdk_region_copy (new_region);
-      
+
       gdk_region_union (new_region, old_region);
 
       if (old_native_child_region)
@@ -6160,21 +6850,16 @@ gdk_window_move_resize_internal (GdkWindow *window,
          gdk_region_offset (new_native_child_region, dx, dy);
          gdk_region_subtract (copy_area, new_native_child_region);
        }
-      
+
       gdk_region_subtract (new_region, copy_area);
 
       /* Convert old region to impl coords */
       gdk_region_offset (old_region, -dx + private->abs_x - private->x, -dy + private->abs_y - private->y);
 
-      /* The old_region area is moved and we queue translations for all expose events
-        to it that will be sent before the copy operation */
-      GDK_WINDOW_IMPL_GET_IFACE (impl_window->impl)->queue_translation ((GdkWindow *)impl_window,
-                                                                       old_region, dx, dy);
-      
       /* convert from parent coords to impl */
       gdk_region_offset (copy_area, private->abs_x - private->x, private->abs_y - private->y);
 
-      move_region_on_impl (private, copy_area, dx, dy); /* Takes ownership of copy_area */
+      move_region_on_impl (impl_window, copy_area, dx, dy); /* takes ownership of copy_area */
 
       /* Invalidate affected part in the parent window
        *  (no higher window should be affected)
@@ -6192,8 +6877,8 @@ gdk_window_move_resize_internal (GdkWindow *window,
       gdk_region_destroy (old_native_child_region);
       gdk_region_destroy (new_native_child_region);
     }
-  
-  _gdk_syntesize_crossing_events_for_geometry_change (window);
+
+  _gdk_synthesize_crossing_events_for_geometry_change (window);
 }
 
 
@@ -6294,7 +6979,7 @@ gdk_window_scroll (GdkWindow *window,
 {
   GdkWindowObject *private = (GdkWindowObject *) window;
   GdkWindowObject *impl_window;
-  GdkRegion *source_area, *copy_area, *noncopy_area;
+  GdkRegion *copy_area, *noncopy_area;
   GdkRegion *old_native_child_region, *new_native_child_region;
   GList *tmp_list;
 
@@ -6318,19 +7003,19 @@ gdk_window_scroll (GdkWindow *window,
       gdk_window_flush_recursive (private);
     }
 
-  
+
   /* First move all child windows, without causing invalidation */
-  
+
   tmp_list = private->children;
   while (tmp_list)
     {
       GdkWindow *child = GDK_WINDOW (tmp_list->data);
       GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child);
-      
+
       /* Just update the positions, the bits will move with the copy */
       child_obj->x += dx;
       child_obj->y += dy;
-      
+
       tmp_list = tmp_list->next;
     }
 
@@ -6339,11 +7024,11 @@ gdk_window_scroll (GdkWindow *window,
   new_native_child_region = NULL;
   if (old_native_child_region)
     new_native_child_region = collect_native_child_region (private, FALSE);
-  
+
   move_native_children (private);
-  
+
   /* Then copy the actual bits of the window w/ child windows */
-  
+
   impl_window = gdk_window_get_impl_window (private);
 
   /* Calculate the area that can be gotten by copying the old area */
@@ -6354,7 +7039,7 @@ gdk_window_scroll (GdkWindow *window,
        * the native window move.
        */
       gdk_region_subtract (copy_area, old_native_child_region);
-      
+
       /* Don't copy any bits that would cause a read from the moved
         native windows, as we can't read that data */
       gdk_region_subtract (copy_area, new_native_child_region);
@@ -6366,22 +7051,11 @@ gdk_window_scroll (GdkWindow *window,
   noncopy_area = gdk_region_copy (private->clip_region);
   gdk_region_subtract (noncopy_area, copy_area);
 
-  /* Get window clip and convert to real window coords, this
-     area is moved and we queue translations for all expose events
-     to it that will be sent before the copy operation */
-
-  source_area = gdk_region_copy (private->clip_region);
-  /* convert from window coords to real parent */
-  gdk_region_offset (source_area, private->abs_x, private->abs_y);
-  GDK_WINDOW_IMPL_GET_IFACE (impl_window->impl)->queue_translation ((GdkWindow *)impl_window,
-                                                                   source_area, dx, dy);
-  gdk_region_destroy (source_area);
-  
   /* convert from window coords to impl */
   gdk_region_offset (copy_area, private->abs_x, private->abs_y);
 
-  move_region_on_impl (private, copy_area, dx, dy); /* Takes ownership of copy_area */
-   
+  move_region_on_impl (impl_window, copy_area, dx, dy); /* takes ownership of copy_area */
+
   /* Invalidate not copied regions */
   gdk_window_invalidate_region (window, noncopy_area, TRUE);
 
@@ -6392,8 +7066,8 @@ gdk_window_scroll (GdkWindow *window,
       gdk_region_destroy (old_native_child_region);
       gdk_region_destroy (new_native_child_region);
     }
-  
-  _gdk_syntesize_crossing_events_for_geometry_change (window);
+
+  _gdk_synthesize_crossing_events_for_geometry_change (window);
 }
 
 /**
@@ -6419,7 +7093,6 @@ gdk_window_move_region (GdkWindow       *window,
 {
   GdkWindowObject *private = (GdkWindowObject *) window;
   GdkWindowObject *impl_window;
-  GdkRegion *source_area;
   GdkRegion *nocopy_area;
   GdkRegion *copy_area;
 
@@ -6433,33 +7106,28 @@ gdk_window_move_region (GdkWindow       *window,
     return;
 
   impl_window = gdk_window_get_impl_window (private);
-  
+
   /* compute source regions */
-  source_area = gdk_region_copy (region);
-  gdk_region_intersect (source_area, private->clip_region_with_children);
+  copy_area = gdk_region_copy (region);
+  gdk_region_intersect (copy_area, private->clip_region_with_children);
 
   /* compute destination regions */
-  copy_area = gdk_region_copy (source_area);
   gdk_region_offset (copy_area, dx, dy);
   gdk_region_intersect (copy_area, private->clip_region_with_children);
 
-  /* invalidate parts of the region not covered by the copy */
+  /* Invalidate parts of the region (source and dest) not covered
+     by the copy */
   nocopy_area = gdk_region_copy (region);
   gdk_region_offset (nocopy_area, dx, dy);
+  gdk_region_union (nocopy_area, region);
   gdk_region_subtract (nocopy_area, copy_area);
-  gdk_window_invalidate_region (window, nocopy_area, FALSE);
-  gdk_region_destroy (nocopy_area);
 
-  gdk_region_offset (source_area, private->abs_x, private->abs_y);
-  GDK_WINDOW_IMPL_GET_IFACE (impl_window->impl)->queue_translation ((GdkWindow *)impl_window,
-                                                                   source_area, dx, dy);
-  
   /* convert from window coords to impl */
   gdk_region_offset (copy_area, private->abs_x, private->abs_y);
-  
-  move_region_on_impl (private, copy_area, dx, dy); /* Takes ownership of copy_area */
+  move_region_on_impl (impl_window, copy_area, dx, dy); /* Takes ownership of copy_area */
 
-  gdk_region_destroy (source_area);
+  gdk_window_invalidate_region (window, nocopy_area, FALSE);
+  gdk_region_destroy (nocopy_area);
 }
 
 /**
@@ -6487,7 +7155,7 @@ gdk_window_set_background (GdkWindow      *window,
   g_return_if_fail (GDK_IS_WINDOW (window));
 
   private = (GdkWindowObject *) window;
-  
+
   private->bg_color = *color;
   gdk_colormap_query_color (colormap, private->bg_color.pixel, &private->bg_color);
 
@@ -6495,10 +7163,12 @@ gdk_window_set_background (GdkWindow      *window,
       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
       private->bg_pixmap != GDK_NO_BG)
     g_object_unref (private->bg_pixmap);
-  
+
   private->bg_pixmap = NULL;
 
-  if (!GDK_WINDOW_DESTROYED (window) && gdk_window_has_impl (private))
+  if (!GDK_WINDOW_DESTROYED (window) &&
+      gdk_window_has_impl (private) &&
+      !private->input_only)
     GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, &private->bg_color);
 }
 
@@ -6546,7 +7216,7 @@ gdk_window_set_back_pixmap (GdkWindow *window,
       g_warning ("gdk_window_set_back_pixmap(): pixmap must have a colormap");
       return;
     }
-  
+
   if (private->bg_pixmap &&
       private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
       private->bg_pixmap != GDK_NO_BG)
@@ -6558,32 +7228,39 @@ gdk_window_set_back_pixmap (GdkWindow *window,
     private->bg_pixmap = g_object_ref (pixmap);
   else
     private->bg_pixmap = GDK_NO_BG;
-  
-  if (!GDK_WINDOW_DESTROYED (window) && gdk_window_has_impl (private))
+
+  if (!GDK_WINDOW_DESTROYED (window) &&
+      gdk_window_has_impl (private) &&
+      !private->input_only)
     GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, private->bg_pixmap);
 }
 
-static void
-update_cursor (GdkDisplay *display)
+/**
+ * gdk_window_get_cursor:
+ * @window: a #GdkWindow
+ * @cursor: a cursor
+ *
+ * Retrieves a #GdkCursor pointer for the cursor currently set on the
+ * specified #GdkWindow, or %NULL.  If the return value is %NULL then
+ * there is no custom cursor set on the specified window, and it is
+ * using the cursor for its parent window.
+ *
+ * Return value: a #GdkCursor, or %NULL. The returned object is owned
+ *   by the #GdkWindow and should not be unreferenced directly. Use
+ *   gdk_window_set_cursor() to unset the cursor of the window
+ *
+ * Since: 2.18
+ */
+GdkCursor *
+gdk_window_get_cursor (GdkWindow *window)
 {
-  GdkWindowObject *pointer_window, *cursor_window;
-  
-  pointer_window = (GdkWindowObject *)display->pointer_info.window_under_pointer;
-  
-  cursor_window = pointer_window;
-  while (cursor_window->cursor == NULL &&
-        cursor_window->parent != NULL &&
-        cursor_window->parent->window_type != GDK_WINDOW_ROOT)
-    cursor_window = cursor_window->parent;
+  GdkWindowObject *private;
 
-  if (display->pointer_grab.window != NULL &&
-      !is_parent_of (display->pointer_grab.window, (GdkWindow *)cursor_window))
-    cursor_window = (GdkWindowObject *)display->pointer_grab.window;
+  g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 
-  /* Set all cursors on toplevel, otherwise its tricky to keep track of
-   * which native window has what cursor set. */
-  GDK_WINDOW_IMPL_GET_IFACE (pointer_window->impl)->set_cursor (gdk_window_get_toplevel ((GdkWindow *)pointer_window),
-                                                               cursor_window->cursor);
+  private = (GdkWindowObject *) window;
+
+  return private->cursor;
 }
 
 /**
@@ -6591,10 +7268,10 @@ update_cursor (GdkDisplay *display)
  * @window: a #GdkWindow
  * @cursor: a cursor
  *
- * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new_for_display() 
- * or gdk_cursor_new_from_pixmap() to create the cursor. To make the cursor 
- * invisible, use %GDK_BLANK_CURSOR. Passing %NULL for the @cursor argument 
- * to gdk_window_set_cursor() means that @window will use the cursor of its 
+ * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new_for_display()
+ * or gdk_cursor_new_from_pixmap() to create the cursor. To make the cursor
+ * invisible, use %GDK_BLANK_CURSOR. 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
@@ -6620,8 +7297,14 @@ gdk_window_set_cursor (GdkWindow *window,
       if (cursor)
        private->cursor = gdk_cursor_ref (cursor);
 
-      if (is_parent_of (window, display->pointer_info.window_under_pointer))
+      if (_gdk_native_windows ||
+         private->window_type == GDK_WINDOW_ROOT ||
+          private->window_type == GDK_WINDOW_FOREIGN)
+        GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_cursor (window, cursor);
+      else if (_gdk_window_event_parent_of (window, display->pointer_info.window_under_pointer))
        update_cursor (display);
+
+      g_object_notify (G_OBJECT (window), "cursor");
     }
 }
 
@@ -6665,13 +7348,13 @@ gdk_window_get_geometry (GdkWindow *window,
                         gint      *height,
                         gint      *depth)
 {
-  GdkWindowObject *private;
+  GdkWindowObject *private, *parent;
 
   if (!window)
     {
       GDK_NOTE (MULTIHEAD,
                g_message ("gdk_window_get_geometry(): Window needs "
-                           "to be non-NULL to be multi head safe"));
+                          "to be non-NULL to be multi head safe"));
       window = gdk_screen_get_root_window ((gdk_screen_get_default ()));
     }
 
@@ -6682,9 +7365,21 @@ gdk_window_get_geometry (GdkWindow *window,
   if (!GDK_WINDOW_DESTROYED (window))
     {
       if (gdk_window_has_impl (private))
-       GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_geometry (window, x, y,
-                                                                width, height,
-                                                                depth);
+       {
+         GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_geometry (window, x, y,
+                                                                  width, height,
+                                                                  depth);
+         /* This reports the position wrt to the native parent, we need to convert
+            it to be relative to the client side parent */
+         parent = private->parent;
+         if (parent && !gdk_window_has_impl (parent))
+           {
+             if (x)
+               *x -= parent->abs_x;
+             if (y)
+               *y -= parent->abs_y;
+           }
+       }
       else
        {
          if (x)
@@ -6723,32 +7418,80 @@ gdk_window_get_origin (GdkWindow *window,
 
   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 
-  private = (GdkWindowObject *) window;
+  if (GDK_WINDOW_DESTROYED (window))
+    {
+      if (x)
+       *x = 0;
+      if (y)
+       *y = 0;
+      return 0;
+    }
   
-  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_origin (window, x, y);
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_root_coords (window,
+                                                             private->abs_x,
+                                                             private->abs_y,
+                                                             x, y);
 
-  if (x)
-    *x += private->abs_x;
-  if (y)
-    *y += private->abs_y;
-  
   return TRUE;
 }
 
+/**
+ * gdk_window_get_root_coords:
+ * @window: a #GdkWindow
+ * @x: X coordinate in window
+ * @y: Y coordinate in window
+ * @root_x: return location for X coordinate
+ * @root_y: return location for Y coordinate
+ *
+ * Obtains the position of a window position in root
+ * window coordinates. This is similar to
+ * gdk_window_get_origin() but allows you go pass
+ * in any position in the window, not just the origin.
+ */
+void
+gdk_window_get_root_coords (GdkWindow *window,
+                           gint       x,
+                           gint       y,
+                           gint      *root_x,
+                           gint      *root_y)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  if (GDK_WINDOW_DESTROYED (window))
+    {
+      if (x)
+       *root_x = x;
+      if (y)
+       *root_y = y;
+      return;
+    }
+  
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_root_coords (window,
+                                                             x + private->abs_x,
+                                                             y + private->abs_y,
+                                                             root_x, root_y);
+}
+
 
 /**
  * gdk_window_get_deskrelative_origin:
  * @window: a toplevel #GdkWindow
  * @x: return location for X coordinate
  * @y: return location for Y coordinate
- * 
+ *
  * This gets the origin of a #GdkWindow relative to
  * an Enlightenment-window-manager desktop. As long as you don't
  * assume that the user's desktop/workspace covers the entire
  * root window (i.e. you don't assume that the desktop begins
  * at root window coordinate 0,0) this function is not necessary.
  * It's deprecated for that reason.
- * 
+ *
  * Return value: not meaningful
  **/
 gboolean
@@ -6764,17 +7507,17 @@ gdk_window_get_deskrelative_origin (GdkWindow *window,
   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
 
   private = (GdkWindowObject *) window;
-  
+
   if (!GDK_WINDOW_DESTROYED (window))
     {
       return_val = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_deskrelative_origin (window, &tx, &ty);
-      
+
       if (x)
        *x = tx + private->abs_x;
       if (y)
        *y = ty + private->abs_y;
     }
-  
+
   return return_val;
 }
 
@@ -6805,7 +7548,7 @@ void
 gdk_window_shape_combine_mask (GdkWindow *window,
                               GdkBitmap *mask,
                               gint       x,
-                               gint       y)
+                              gint       y)
 {
   GdkWindowObject *private;
   GdkRegion *region;
@@ -6852,9 +7595,9 @@ gdk_window_shape_combine_mask (GdkWindow *window,
  */
 void
 gdk_window_shape_combine_region (GdkWindow       *window,
-                                 const GdkRegion *shape_region,
-                                 gint             offset_x,
-                                 gint             offset_y)
+                                const GdkRegion *shape_region,
+                                gint             offset_x,
+                                gint             offset_y)
 {
   GdkWindowObject *private;
   GdkRegion *old_region, *new_region, *diff;
@@ -6870,7 +7613,7 @@ gdk_window_shape_combine_region (GdkWindow       *window,
 
   if (private->shape)
     gdk_region_destroy (private->shape);
-  
+
   old_region = NULL;
   if (GDK_WINDOW_IS_MAPPED (window))
     old_region = gdk_region_copy (private->clip_region);
@@ -6878,11 +7621,11 @@ gdk_window_shape_combine_region (GdkWindow       *window,
   if (shape_region)
     {
       private->shape = gdk_region_copy (shape_region);
-      gdk_region_offset (private->shape, offset_x, offset_y);      
+      gdk_region_offset (private->shape, offset_x, offset_y);
     }
   else
     private->shape = NULL;
-  
+
   recompute_visible_regions (private, TRUE, FALSE);
 
   if (old_region)
@@ -6898,17 +7641,17 @@ gdk_window_shape_combine_region (GdkWindow       *window,
       gdk_region_destroy (diff);
 
       if (private->parent != NULL &&
-         GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
+         private->parent->window_type != GDK_WINDOW_ROOT)
        {
          /* New area in the non-root parent window, needs invalidation */
          diff = gdk_region_copy (old_region);
          gdk_region_subtract (diff, new_region);
-         
+
          /* Adjust region to parent window coords */
          gdk_region_offset (diff, private->x, private->y);
-         
+
          gdk_window_invalidate_region (GDK_WINDOW (private->parent), diff, TRUE);
-         
+
          gdk_region_destroy (diff);
        }
 
@@ -6926,18 +7669,18 @@ do_child_shapes (GdkWindow *window,
   GdkRegion *region;
 
   private = (GdkWindowObject *) window;
-  
+
   r.x = 0;
   r.y = 0;
   r.width = private->width;
   r.height = private->height;
-  
+
   region = gdk_region_rectangle (&r);
   remove_child_area (private, NULL, FALSE, region);
 
   if (merge && private->shape)
     gdk_region_subtract (region, private->shape);
-  
+
   gdk_window_shape_combine_region (window, region, 0, 0);
 }
 
@@ -6982,17 +7725,17 @@ gdk_window_merge_child_shapes (GdkWindow *window)
 /**
  * gdk_window_input_shape_combine_mask:
  * @window: a #GdkWindow
- * @mask: shape mask
+ * @mask: shape mask, or %NULL
  * @x: X position of shape mask with respect to @window
  * @y: Y position of shape mask with respect to @window
- * 
+ *
  * Like gdk_window_shape_combine_mask(), but the shape applies
  * only to event handling. Mouse events which happen while
- * the pointer position corresponds to an unset bit in the 
+ * the pointer position corresponds to an unset bit in the
  * mask will be passed on the window below @window.
  *
  * An input shape is typically used with RGBA windows.
- * The alpha channel of the window defines which pixels are 
+ * The alpha channel of the window defines which pixels are
  * invisible and allows for nicely antialiased borders,
  * and the input shape controls where the window is
  * "clickable".
@@ -7005,7 +7748,7 @@ gdk_window_merge_child_shapes (GdkWindow *window)
  *
  * Since: 2.10
  */
-void 
+void
 gdk_window_input_shape_combine_mask (GdkWindow *window,
                                     GdkBitmap *mask,
                                     gint       x,
@@ -7026,8 +7769,9 @@ gdk_window_input_shape_combine_mask (GdkWindow *window,
   gdk_window_input_shape_combine_region (window,
                                         region,
                                         x, y);
-  
-  gdk_region_destroy (region);
+
+  if (region != NULL)
+    gdk_region_destroy (region);
 }
 
 /**
@@ -7036,14 +7780,14 @@ gdk_window_input_shape_combine_mask (GdkWindow *window,
  * @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
- * 
+ *
  * Like gdk_window_shape_combine_region(), but the shape applies
  * only to event handling. Mouse events which happen while
- * the pointer position corresponds to an unset bit in the 
+ * the pointer position corresponds to an unset bit in the
  * mask will be passed on the window below @window.
  *
  * An input shape is typically used with RGBA windows.
- * The alpha channel of the window defines which pixels are 
+ * The alpha channel of the window defines which pixels are
  * invisible and allows for nicely antialiased borders,
  * and the input shape controls where the window is
  * "clickable".
@@ -7056,7 +7800,7 @@ gdk_window_input_shape_combine_mask (GdkWindow *window,
  *
  * Since: 2.10
  */
-void 
+void
 gdk_window_input_shape_combine_region (GdkWindow       *window,
                                       const GdkRegion *shape_region,
                                       gint             offset_x,
@@ -7077,7 +7821,7 @@ gdk_window_input_shape_combine_region (GdkWindow       *window,
   if (shape_region)
     {
       private->input_shape = gdk_region_copy (shape_region);
-      gdk_region_offset (private->input_shape, offset_x, offset_y);      
+      gdk_region_offset (private->input_shape, offset_x, offset_y);
     }
   else
     private->input_shape = NULL;
@@ -7086,7 +7830,7 @@ gdk_window_input_shape_combine_region (GdkWindow       *window,
     GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_shape_combine_region ((GdkWindow *)private, private->input_shape, 0, 0);
 
   /* Pointer may have e.g. moved outside window due to the input mask change */
-  _gdk_syntesize_crossing_events_for_geometry_change (window);
+  _gdk_synthesize_crossing_events_for_geometry_change (window);
 }
 
 static void
@@ -7098,12 +7842,12 @@ do_child_input_shapes (GdkWindow *window,
   GdkRegion *region;
 
   private = (GdkWindowObject *) window;
-  
+
   r.x = 0;
   r.y = 0;
   r.width = private->width;
   r.height = private->height;
-  
+
   region = gdk_region_rectangle (&r);
   remove_child_area (private, NULL, TRUE, region);
 
@@ -7111,7 +7855,7 @@ do_child_input_shapes (GdkWindow *window,
     gdk_region_subtract (region, private->shape);
   if (merge && private->input_shape)
     gdk_region_subtract (region, private->input_shape);
-  
+
   gdk_window_input_shape_combine_region (window, region, 0, 0);
 }
 
@@ -7119,7 +7863,7 @@ do_child_input_shapes (GdkWindow *window,
 /**
  * gdk_window_set_child_input_shapes:
  * @window: a #GdkWindow
- * 
+ *
  * Sets the input shape mask of @window to the union of input shape masks
  * for all children of @window, ignoring the input shape mask of @window
  * itself. Contrast with gdk_window_merge_child_input_shapes() which includes
@@ -7127,34 +7871,34 @@ do_child_input_shapes (GdkWindow *window,
  *
  * Since: 2.10
  **/
-void 
+void
 gdk_window_set_child_input_shapes (GdkWindow *window)
 {
   g_return_if_fail (GDK_IS_WINDOW (window));
-  
+
   do_child_input_shapes (window, FALSE);
 }
 
 /**
  * gdk_window_merge_child_input_shapes:
  * @window: a #GdkWindow
- * 
+ *
  * Merges the input shape masks for any child windows into the
  * input shape mask for @window. i.e. the union of all input masks
  * for @window and its children will become the new input mask
  * for @window. See gdk_window_input_shape_combine_mask().
  *
  * This function is distinct from gdk_window_set_child_input_shapes()
- * because it includes @window's input shape mask in the set of 
+ * because it includes @window's input shape mask in the set of
  * shapes to be merged.
  *
  * Since: 2.10
  **/
-void 
+void
 gdk_window_merge_child_input_shapes (GdkWindow *window)
 {
   g_return_if_fail (GDK_IS_WINDOW (window));
-  
+
   do_child_input_shapes (window, TRUE);
 }
 
@@ -7183,7 +7927,7 @@ gdk_window_set_static_gravities (GdkWindow *window,
 
   if (gdk_window_has_impl (private))
     return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_static_gravities (window, use_static);
-  
+
   return FALSE;
 }
 
@@ -7192,10 +7936,10 @@ gdk_window_set_static_gravities (GdkWindow *window,
  * @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 
+ * 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"/>
@@ -7211,7 +7955,7 @@ gdk_window_set_static_gravities (GdkWindow *window,
  * 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). 
+ * 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.
@@ -7220,7 +7964,7 @@ gdk_window_set_static_gravities (GdkWindow *window,
  */
 void
 gdk_window_set_composited (GdkWindow *window,
-                           gboolean   composited)
+                          gboolean   composited)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   GdkDisplay *display;
@@ -7233,7 +7977,7 @@ gdk_window_set_composited (GdkWindow *window,
     return;
 
   if (composited)
-    gdk_window_set_has_native (window, TRUE);
+    gdk_window_ensure_native (window);
 
   display = gdk_drawable_get_display (GDK_DRAWABLE (window));
 
@@ -7250,14 +7994,14 @@ gdk_window_set_composited (GdkWindow *window,
 
   if (GDK_WINDOW_IS_MAPPED (window))
     gdk_window_invalidate_in_parent (private);
-  
+
   private->composited = composited;
 }
 
 
 static void
 remove_redirect_from_children (GdkWindowObject   *private,
-                               GdkWindowRedirect *redirect)
+                              GdkWindowRedirect *redirect)
 {
   GList *l;
   GdkWindowObject *child;
@@ -7304,7 +8048,7 @@ gdk_window_remove_redirection (GdkWindow *window)
 
 static void
 apply_redirect_to_children (GdkWindowObject   *private,
-                            GdkWindowRedirect *redirect)
+                           GdkWindowRedirect *redirect)
 {
   GList *l;
   GdkWindowObject *child;
@@ -7351,11 +8095,11 @@ void
 gdk_window_redirect_to_drawable (GdkWindow   *window,
                                 GdkDrawable *drawable,
                                 gint         src_x,
-                                 gint         src_y,
+                                gint         src_y,
                                 gint         dest_x,
-                                 gint         dest_y,
+                                gint         dest_y,
                                 gint         width,
-                                 gint         height)
+                                gint         height)
 {
   GdkWindowObject *private;
 
@@ -7377,7 +8121,7 @@ gdk_window_redirect_to_drawable (GdkWindow   *window,
       if (height == -1)
        height = h;
     }
-  
+
   private->redirect = g_new0 (GdkWindowRedirect, 1);
   private->redirect->redirected = private;
   private->redirect->pixmap = g_object_ref (drawable);
@@ -7393,10 +8137,10 @@ gdk_window_redirect_to_drawable (GdkWindow   *window,
 
 static void
 window_get_size_rectangle (GdkWindow    *window,
-                           GdkRectangle *rect)
+                          GdkRectangle *rect)
 {
   GdkWindowObject *private = (GdkWindowObject *) window;
-  
+
   rect->x = rect->y = 0;
   rect->width = private->width;
   rect->height = private->height;
@@ -7422,8 +8166,8 @@ _gdk_window_calculate_full_clip_region (GdkWindow *window,
     *base_x_offset = 0;
   if (base_y_offset)
     *base_y_offset = 0;
-  
-  if (!GDK_WINDOW_IS_MAPPED (window) || private->input_only)
+
+  if (!private->viewable || private->input_only)
     return gdk_region_new ();
 
   window_get_size_rectangle (window, &visible_rect);
@@ -7438,10 +8182,10 @@ _gdk_window_calculate_full_clip_region (GdkWindow *window,
     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);
+        (parentwin == private || lastwin != (GdkWindowObject*) base_window);
        lastwin = parentwin, parentwin = lastwin->parent)
     {
       GList *cur;
@@ -7458,8 +8202,8 @@ _gdk_window_calculate_full_clip_region (GdkWindow *window,
 
       /* children is ordered in reverse stack order */
       for (cur = parentwin->children;
-           cur && cur->data != lastwin;
-           cur = cur->next)
+          cur && cur->data != lastwin;
+          cur = cur->next)
        {
          GdkWindow *child = cur->data;
          GdkWindowObject *child_private = (GdkWindowObject *)child;
@@ -7467,17 +8211,17 @@ _gdk_window_calculate_full_clip_region (GdkWindow *window,
          if (!GDK_WINDOW_IS_MAPPED (child) || child_private->input_only)
            continue;
 
-          /* Ignore offscreen children, as they don't draw in their parent and
+         /* Ignore offscreen children, as they don't draw in their parent and
           * don't take part in the clipping */
          if (gdk_window_is_offscreen (child_private))
            continue;
 
-          window_get_size_rectangle (child, &visible_rect);
+         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 ||
@@ -7485,18 +8229,18 @@ _gdk_window_calculate_full_clip_region (GdkWindow *window,
              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);
        }
-      
+
       /* Clip to the parent */
       window_get_size_rectangle ((GdkWindow *)parentwin, &visible_rect);
       /* Convert rect to "window" coords */
       visible_rect.x += - x_offset;
       visible_rect.y += - y_offset;
-      
+
       tmpreg = gdk_region_rectangle (&visible_rect);
       gdk_region_intersect (real_clip_region, tmpreg);
       gdk_region_destroy (tmpreg);
@@ -7532,16 +8276,106 @@ gdk_window_redirect_free (GdkWindowRedirect *redirect)
   g_free (redirect);
 }
 
+/* Gets the toplevel for a window as used for events,
+   i.e. including offscreen parents */
+static GdkWindowObject *
+get_event_parent (GdkWindowObject *window)
+{
+  if (window->window_type == GDK_WINDOW_OFFSCREEN)
+    return (GdkWindowObject *)gdk_offscreen_window_get_embedder ((GdkWindow *)window);
+  else
+    return window->parent;
+}
+
+/* Gets the toplevel for a window as used for events,
+   i.e. including offscreen parents going up to the native
+   toplevel */
+static GdkWindow *
+get_event_toplevel (GdkWindow *w)
+{
+  GdkWindowObject *private = GDK_WINDOW_OBJECT (w);
+  GdkWindowObject *parent;
+
+  while ((parent = get_event_parent (private)) != NULL &&
+        (parent->window_type != GDK_WINDOW_ROOT))
+    private = parent;
+
+  return GDK_WINDOW (private);
+}
+
+gboolean
+_gdk_window_event_parent_of (GdkWindow *parent,
+                            GdkWindow *child)
+{
+  GdkWindow *w;
+
+  w = child;
+  while (w != NULL)
+    {
+      if (w == parent)
+       return TRUE;
+
+      w = (GdkWindow *)get_event_parent ((GdkWindowObject *)w);
+    }
+
+  return FALSE;
+}
+
+static void
+update_cursor (GdkDisplay *display)
+{
+  GdkWindowObject *pointer_window, *cursor_window, *parent, *toplevel;
+  GdkPointerGrabInfo *grab;
+
+  pointer_window = (GdkWindowObject *)display->pointer_info.window_under_pointer;
+
+  cursor_window = pointer_window;
+  while (cursor_window->cursor == NULL &&
+        (parent = get_event_parent (cursor_window)) != NULL &&
+        parent->window_type != GDK_WINDOW_ROOT)
+    cursor_window = parent;
+
+  /* We ignore the serials here and just pick the last grab
+     we've sent, as that would shortly be used anyway. */
+  grab = _gdk_display_get_last_pointer_grab (display);
+  if (grab != NULL &&
+      !_gdk_window_event_parent_of (grab->window, (GdkWindow *)cursor_window))
+    cursor_window = (GdkWindowObject *)grab->window;
+
+  /* Set all cursors on toplevel, otherwise its tricky to keep track of
+   * which native window has what cursor set. */
+  toplevel = (GdkWindowObject *)get_event_toplevel ((GdkWindow *)pointer_window);
+  GDK_WINDOW_IMPL_GET_IFACE (toplevel->impl)->set_cursor
+    ((GdkWindow *)toplevel, cursor_window->cursor);
+}
+
+static void
+from_embedder (GdkWindowObject *window,
+              double embedder_x, double embedder_y,
+              double *offscreen_x, double *offscreen_y)
+{
+  g_signal_emit (window,
+                signals[FROM_EMBEDDER], 0,
+                embedder_x, embedder_y,
+                offscreen_x, offscreen_y,
+                NULL);
+}
+
 static void
 convert_coords_to_child (GdkWindowObject *child,
                         double x, double y,
                         double *child_x, double *child_y)
 {
-  *child_x = x - child->x;
-  *child_y = y - child->y;
-
-  if (child->offscreen_hooks)
-    child->offscreen_hooks->from_parent ((GdkWindow *)child, x, y, child_x, child_y);
+  if (gdk_window_is_offscreen (child))
+    {
+      from_embedder (child, x, y,
+                    child_x, child_y);
+    }
+  else
+    {
+      *child_x = x - child->x;
+      *child_y = y - child->y;
+    }
 }
 
 static gboolean
@@ -7549,7 +8383,7 @@ point_in_window (GdkWindowObject *window,
                 double x, double y)
 {
   return
-    x >= 0 &&  x < window->width &&
+    x >= 0 && x < window->width &&
     y >= 0 && y < window->height &&
     (window->shape == NULL ||
      gdk_region_point_in (window->shape,
@@ -7559,6 +8393,31 @@ point_in_window (GdkWindowObject *window,
                          x, y));
 }
 
+static GdkWindow *
+convert_native_coords_to_toplevel (GdkWindow *window,
+                                  double child_x, double child_y,
+                                  double *toplevel_x, double *toplevel_y)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  gdouble x, y;
+
+  x = child_x;
+  y = child_y;
+
+  while (private->parent != NULL &&
+        (private->parent->window_type != GDK_WINDOW_ROOT))
+    {
+      x += private->x;
+      y += private->y;
+      private = private->parent;
+    }
+
+  *toplevel_x = x;
+  *toplevel_y = y;
+
+  return (GdkWindow *)private;
+}
+
 static void
 convert_toplevel_coords_to_window (GdkWindow *window,
                                   gdouble    toplevel_x,
@@ -7567,31 +8426,85 @@ convert_toplevel_coords_to_window (GdkWindow *window,
                                   gdouble   *window_y)
 {
   GdkWindowObject *private;
+  GdkWindowObject *parent;
   gdouble x, y;
   GList *children, *l;
 
   private = GDK_WINDOW_OBJECT (window);
-  
+
   x = toplevel_x;
   y = toplevel_y;
 
   children = NULL;
-  while (private->parent != NULL &&
-        (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT))
+  while ((parent = get_event_parent (private)) != NULL &&
+        (parent->window_type != GDK_WINDOW_ROOT))
     {
       children = g_list_prepend (children, private);
-      private = private->parent;
+      private = parent;
     }
 
   for (l = children; l != NULL; l = l->next)
     convert_coords_to_child (l->data, x, y, &x, &y);
-  
+
   g_list_free (children);
-  
+
   *window_x = x;
   *window_y = y;
 }
 
+static GdkWindowObject *
+pick_embedded_child (GdkWindowObject *window,
+                     double x, double y)
+{
+  GdkWindowObject *res;
+
+  res = NULL;
+  g_signal_emit (window,
+                signals[PICK_EMBEDDED_CHILD], 0,
+                x, y, &res);
+
+  return res;
+}
+
+GdkWindow *
+_gdk_window_find_child_at (GdkWindow *window,
+                          int x, int y)
+{
+  GdkWindowObject *private, *sub;
+  double child_x, child_y;
+  GList *l;
+
+  private = (GdkWindowObject *)window;
+
+  if (point_in_window (private, x, y))
+    {
+      /* Children is ordered in reverse stack order, i.e. first is topmost */
+      for (l = private->children; l != NULL; l = l->next)
+       {
+         sub = l->data;
+
+         if (!GDK_WINDOW_IS_MAPPED (sub))
+           continue;
+
+         convert_coords_to_child (sub,
+                                  x, y,
+                                  &child_x, &child_y);
+         if (point_in_window (sub, child_x, child_y))
+           return (GdkWindow *)sub;
+       }
+
+      if (private->num_offscreen_children > 0)
+       {
+         sub = pick_embedded_child (private,
+                                    x, y);
+         if (sub)
+           return (GdkWindow *)sub;
+       }
+    }
+
+  return NULL;
+}
+
 GdkWindow *
 _gdk_window_find_descendant_at (GdkWindow *toplevel,
                                double x, double y,
@@ -7601,21 +8514,23 @@ _gdk_window_find_descendant_at (GdkWindow *toplevel,
   GdkWindowObject *private, *sub;
   double child_x, child_y;
   GList *l;
+  gboolean found;
 
   private = (GdkWindowObject *)toplevel;
-  
+
   if (point_in_window (private, x, y))
     {
-      do 
+      do
        {
+         found = FALSE;
          /* Children is ordered in reverse stack order, i.e. first is topmost */
          for (l = private->children; l != NULL; l = l->next)
            {
              sub = l->data;
 
-              if (!GDK_WINDOW_IS_MAPPED (sub))
-                continue;
-             
+             if (!GDK_WINDOW_IS_MAPPED (sub))
+               continue;
+
              convert_coords_to_child (sub,
                                       x, y,
                                       &child_x, &child_y);
@@ -7624,11 +8539,24 @@ _gdk_window_find_descendant_at (GdkWindow *toplevel,
                  x = child_x;
                  y = child_y;
                  private = sub;
+                 found = TRUE;
                  break;
                }
            }
+         if (!found &&
+             private->num_offscreen_children > 0)
+           {
+             sub = pick_embedded_child (private,
+                                        x, y);
+             if (sub)
+               {
+                 found = TRUE;
+                 private = sub;
+                 from_embedder (sub, x, y, &x, &y);
+               }
+           }
        }
-      while (l != NULL);
+      while (found);
     }
   else
     {
@@ -7640,10 +8568,40 @@ _gdk_window_find_descendant_at (GdkWindow *toplevel,
     *found_x = x;
   if (found_y)
     *found_y = y;
-  
+
   return (GdkWindow *)private;
 }
 
+/**
+ * gdk_window_beep:
+ * @window: a toplevel #GdkWindow
+ *
+ * Emits a short beep associated to @window in the appropriate
+ * display, if supported. Otherwise, emits a short beep on
+ * the display just as gdk_display_beep().
+ *
+ * Since: 2.12
+ **/
+void
+gdk_window_beep (GdkWindow *window)
+{
+  GdkDisplay *display;
+  GdkWindow *toplevel;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  toplevel = get_event_toplevel (window);
+  display = gdk_drawable_get_display (GDK_DRAWABLE (window));
+
+  if (toplevel && !gdk_window_is_offscreen ((GdkWindowObject *)toplevel))
+    _gdk_windowing_window_beep (toplevel);
+  else
+    gdk_display_beep (display);
+}
+
 static const guint type_masks[] = {
   GDK_SUBSTRUCTURE_MASK, /* GDK_DELETE                 = 0  */
   GDK_STRUCTURE_MASK, /* GDK_DESTROY                   = 1  */
@@ -7688,7 +8646,7 @@ G_STATIC_ASSERT (G_N_ELEMENTS (type_masks) == GDK_EVENT_LAST);
 /* send motion events if the right buttons are down */
 static guint
 update_evmask_for_button_motion (guint           evmask,
-                                 GdkModifierType mask)
+                                GdkModifierType mask)
 {
   if (evmask & GDK_BUTTON_MOTION_MASK &&
       mask & (GDK_BUTTON1_MASK |
@@ -7710,18 +8668,18 @@ static gboolean
 is_button_type (GdkEventType type)
 {
   return type == GDK_BUTTON_PRESS ||
-         type == GDK_2BUTTON_PRESS ||
-         type == GDK_3BUTTON_PRESS ||
-         type == GDK_BUTTON_RELEASE ||
-         type == GDK_SCROLL;
+        type == GDK_2BUTTON_PRESS ||
+        type == GDK_3BUTTON_PRESS ||
+        type == GDK_BUTTON_RELEASE ||
+        type == GDK_SCROLL;
 }
 
 static gboolean
 is_motion_type (GdkEventType type)
 {
   return type == GDK_MOTION_NOTIFY ||
-         type == GDK_ENTER_NOTIFY ||
-         type == GDK_LEAVE_NOTIFY;
+        type == GDK_ENTER_NOTIFY ||
+        type == GDK_LEAVE_NOTIFY;
 }
 
 static GdkWindowObject *
@@ -7736,14 +8694,14 @@ find_common_ancestor (GdkWindowObject *win1,
   while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
     {
       path1 = g_list_prepend (path1, tmp);
-      tmp = tmp->parent;
+      tmp = get_event_parent (tmp);
     }
 
   tmp = win2;
   while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
     {
       path2 = g_list_prepend (path2, tmp);
-      tmp = tmp->parent;
+      tmp = get_event_parent (tmp);
     }
 
   list1 = path1;
@@ -7776,6 +8734,8 @@ _gdk_make_event (GdkWindow    *window,
 
   event->any.window = g_object_ref (window);
   event->any.send_event = FALSE;
+  if (event_in_queue && event_in_queue->any.send_event)
+    event->any.send_event = TRUE;
 
   switch (type)
     {
@@ -7875,21 +8835,29 @@ send_crossing_event (GdkDisplay                 *display,
                     gint                        toplevel_y,
                     GdkModifierType             mask,
                     guint32                     time_,
-                    GdkEvent                   *event_in_queue)
+                    GdkEvent                   *event_in_queue,
+                    gulong                      serial)
 {
   GdkEvent *event;
   guint32 event_mask;
+  GdkPointerGrabInfo *grab;
+
+  grab = _gdk_display_has_pointer_grab (display, serial);
 
-  if (display->pointer_grab.window != NULL &&
-      !display->pointer_grab.owner_events &&
-      (GdkWindow *)window != display->pointer_grab.window)
+  if (grab != NULL &&
+      !grab->owner_events &&
+      (GdkWindow *)window != grab->window)
     return;
-  
+
   if (type == GDK_LEAVE_NOTIFY)
     event_mask = GDK_LEAVE_NOTIFY_MASK;
   else
     event_mask = GDK_ENTER_NOTIFY_MASK;
 
+  if (window->extension_events != 0)
+    GDK_WINDOW_IMPL_GET_IFACE (window->impl)->input_window_crossing ((GdkWindow *)window,
+                                                                    type == GDK_ENTER_NOTIFY);
+
   if (window->event_mask & event_mask)
     {
       event = _gdk_make_event ((GdkWindow *)window, type, event_in_queue, TRUE);
@@ -7908,7 +8876,7 @@ send_crossing_event (GdkDisplay                 *display,
       event->crossing.state = mask;
     }
 }
-  
+
 
 /* The coordinates are in the toplevel window that src/dest are in.
  * src and dest are always (if != NULL) in the same toplevel, as
@@ -7916,27 +8884,28 @@ send_crossing_event (GdkDisplay                 *display,
  * before crossing to another toplevel.
  */
 void
-_gdk_syntesize_crossing_events (GdkDisplay                 *display,
-                               GdkWindow                  *src,
-                               GdkWindow                  *dest,
-                               GdkCrossingMode             mode,
-                               gint                        toplevel_x,
-                               gint                        toplevel_y,
-                               GdkModifierType             mask,
-                               guint32                     time_,
-                               GdkEvent                   *event_in_queue)
+_gdk_synthesize_crossing_events (GdkDisplay                 *display,
+                                GdkWindow                  *src,
+                                GdkWindow                  *dest,
+                                GdkCrossingMode             mode,
+                                gint                        toplevel_x,
+                                gint                        toplevel_y,
+                                GdkModifierType             mask,
+                                guint32                     time_,
+                                GdkEvent                   *event_in_queue,
+                                gulong                      serial,
+                                gboolean                    non_linear)
 {
   GdkWindowObject *c;
   GdkWindowObject *win, *last, *next;
   GList *path, *list;
-  gboolean non_linear;
   GdkWindowObject *a;
   GdkWindowObject *b;
   GdkWindowObject *toplevel;
   GdkNotifyType notify_type;
 
   /* TODO: Don't send events to toplevel, as we get those from the windowing system */
-  
+
   a = (GdkWindowObject *)src;
   b = (GdkWindowObject *)dest;
   if (a == b)
@@ -7944,12 +8913,12 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
 
   c = find_common_ancestor (a, b);
 
-  non_linear = (c != a) && (c != b);
+  non_linear |= (c != a) && (c != b);
 
   if (a) /* There might not be a source (i.e. if no previous pointer_in_window) */
     {
       toplevel = (GdkWindowObject *)gdk_window_get_toplevel ((GdkWindow *)a);
-      
+
       /* Traverse up from a to (excluding) c sending leave events */
       if (non_linear)
        notify_type = GDK_NOTIFY_NONLINEAR;
@@ -7964,18 +8933,19 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
                           NULL,
                           toplevel_x, toplevel_y,
                           mask, time_,
-                          event_in_queue);
-     
+                          event_in_queue,
+                          serial);
+
       if (c != a)
        {
          if (non_linear)
            notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
          else
            notify_type = GDK_NOTIFY_VIRTUAL;
-         
+
          last = a;
-         win = a->parent;
-         while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT)
+         win = get_event_parent (a);
+         while (win != c && win->window_type != GDK_WINDOW_ROOT)
            {
              send_crossing_event (display, toplevel,
                                   win, GDK_LEAVE_NOTIFY,
@@ -7984,10 +8954,11 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
                                   (GdkWindow *)last,
                                   toplevel_x, toplevel_y,
                                   mask, time_,
-                                  event_in_queue);
-             
+                                  event_in_queue,
+                                  serial);
+
              last = win;
-             win = win->parent;
+             win = get_event_parent (win);
            }
        }
     }
@@ -7995,23 +8966,23 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
   if (b) /* Might not be a dest, e.g. if we're moving out of the window */
     {
       toplevel = (GdkWindowObject *)gdk_window_get_toplevel ((GdkWindow *)b);
-      
+
       /* Traverse down from c to b */
       if (c != b)
        {
          path = NULL;
-         win = b->parent;
-         while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT)
+         win = get_event_parent (b);
+         while (win != c && win->window_type != GDK_WINDOW_ROOT)
            {
              path = g_list_prepend (path, win);
-             win = win->parent;
+             win = get_event_parent (win);
            }
-         
+
          if (non_linear)
            notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
          else
            notify_type = GDK_NOTIFY_VIRTUAL;
-         
+
          list = path;
          while (list)
            {
@@ -8029,7 +9000,8 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
                                   (GdkWindow *)next,
                                   toplevel_x, toplevel_y,
                                   mask, time_,
-                                  event_in_queue);
+                                  event_in_queue,
+                                  serial);
            }
          g_list_free (path);
        }
@@ -8041,7 +9013,7 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
        notify_type = GDK_NOTIFY_ANCESTOR;
       else
        notify_type = GDK_NOTIFY_INFERIOR;
-      
+
       send_crossing_event (display, toplevel,
                           b, GDK_ENTER_NOTIFY,
                           mode,
@@ -8049,22 +9021,11 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
                           NULL,
                           toplevel_x, toplevel_y,
                           mask, time_,
-                          event_in_queue);
+                          event_in_queue,
+                          serial);
     }
 }
 
-static GdkWindow *
-get_toplevel (GdkWindow *w)
-{
-  GdkWindowObject *private = GDK_WINDOW_OBJECT (w);
-  
-  while (private->parent != NULL &&
-        (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT))
-    private = private->parent;
-
-  return GDK_WINDOW (private);
-}
-
 /* Returns the window inside the event window with the pointer in it
  * at the specified coordinates, or NULL if its not in any child of
  * the toplevel. It also takes into account !owner_events grabs.
@@ -8073,9 +9034,11 @@ static GdkWindow *
 get_pointer_window (GdkDisplay *display,
                    GdkWindow *event_window,
                    gdouble toplevel_x,
-                   gdouble toplevel_y)
+                   gdouble toplevel_y,
+                   gulong serial)
 {
   GdkWindow *pointer_window;
+  GdkPointerGrabInfo *grab;
 
   if (event_window == display->pointer_info.toplevel_under_pointer)
     pointer_window =
@@ -8085,11 +9048,12 @@ get_pointer_window (GdkDisplay *display,
   else
     pointer_window = NULL;
 
-  if (display->pointer_grab.window != NULL &&
-      !display->pointer_grab.owner_events &&
-      pointer_window != display->pointer_grab.window)
+  grab = _gdk_display_has_pointer_grab (display, serial);
+  if (grab != NULL &&
+      !grab->owner_events &&
+      pointer_window != grab->window)
     pointer_window = NULL;
-  
+
   return pointer_window;
 }
 
@@ -8099,6 +9063,11 @@ _gdk_display_set_window_under_pointer (GdkDisplay *display,
 {
   GdkWindowObject *private;
 
+  /* We don't track this if all native, and it can cause issues
+     with the update_cursor call below */
+  if (_gdk_native_windows)
+    return;
+
   private = (GdkWindowObject *)window;
 
   if (display->pointer_info.window_under_pointer)
@@ -8113,37 +9082,185 @@ _gdk_display_set_window_under_pointer (GdkDisplay *display,
   _gdk_display_enable_motion_hints (display);
 }
 
+/*
+ *--------------------------------------------------------------
+ * gdk_pointer_grab
+ *
+ *   Grabs the pointer to a specific window
+ *
+ * Arguments:
+ *   "window" is the window which will receive the grab
+ *   "owner_events" specifies whether events will be reported as is,
+ *     or relative to "window"
+ *   "event_mask" masks only interesting events
+ *   "confine_to" limits the cursor movement to the specified window
+ *   "cursor" changes the cursor for the duration of the grab
+ *   "time" specifies the time
+ *
+ * Results:
+ *
+ * Side effects:
+ *   requires a corresponding call to gdk_pointer_ungrab
+ *
+ *--------------------------------------------------------------
+ */
+GdkGrabStatus
+gdk_pointer_grab (GdkWindow *    window,
+                 gboolean        owner_events,
+                 GdkEventMask    event_mask,
+                 GdkWindow *     confine_to,
+                 GdkCursor *     cursor,
+                 guint32         time)
+{
+  GdkWindow *native;
+  GdkDisplay *display;
+  GdkGrabStatus res;
+  gulong serial;
+
+  g_return_val_if_fail (window != NULL, 0);
+  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+  g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
+
+  /* We need a native window for confine to to work, ensure we have one */
+  if (confine_to)
+    {
+      if (!gdk_window_ensure_native (confine_to))
+       {
+         g_warning ("Can't confine to grabbed window, not native");
+         confine_to = NULL;
+       }
+    }
+
+  /* Non-viewable client side window => fail */
+  if (!_gdk_window_has_impl (window) &&
+      !gdk_window_is_viewable (window))
+    return GDK_GRAB_NOT_VIEWABLE;
+
+  if (_gdk_native_windows)
+    native = window;
+  else
+    native = gdk_window_get_toplevel (window);
+  while (gdk_window_is_offscreen ((GdkWindowObject *)native))
+    {
+      native = gdk_offscreen_window_get_embedder (native);
+
+      if (native == NULL ||
+         (!_gdk_window_has_impl (native) &&
+          !gdk_window_is_viewable (native)))
+       return GDK_GRAB_NOT_VIEWABLE;
+
+      native = gdk_window_get_toplevel (native);
+    }
+
+  display = gdk_drawable_get_display (window);
+
+  serial = _gdk_windowing_window_get_next_serial (display);
+
+  res = _gdk_windowing_pointer_grab (window,
+                                    native,
+                                    owner_events,
+                                    event_mask,
+                                    confine_to,
+                                    cursor,
+                                    time);
+
+  if (res == GDK_GRAB_SUCCESS)
+    _gdk_display_add_pointer_grab (display,
+                                  window,
+                                  native,
+                                  owner_events,
+                                  event_mask,
+                                  serial,
+                                  time,
+                                  FALSE);
+
+  return res;
+}
+
+/**
+ * gdk_window_geometry_changed:
+ * @window: a #GdkWindow
+ *
+ * Since: 2.18
+ */
 void
-_gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
+gdk_window_geometry_changed (GdkWindow *window)
+{
+  _gdk_synthesize_crossing_events_for_geometry_change (window);
+}
+
+static gboolean
+do_synthesize_crossing_event (gpointer data)
 {
   GdkDisplay *display;
   GdkWindow *changed_toplevel;
+  GdkWindowObject *changed_toplevel_priv;
   GdkWindow *new_window_under_pointer;
+  gulong serial;
+
+  changed_toplevel = data;
+  changed_toplevel_priv = (GdkWindowObject *)changed_toplevel;
+
+  changed_toplevel_priv->synthesize_crossing_event_queued = FALSE;
+
+  if (GDK_WINDOW_DESTROYED (changed_toplevel))
+    return FALSE;
+
+  display = gdk_drawable_get_display (changed_toplevel);
+  serial = _gdk_windowing_window_get_next_serial (display);
 
-  changed_toplevel = get_toplevel (changed_window);
-  
-  display = gdk_drawable_get_display (changed_window);
   if (changed_toplevel == display->pointer_info.toplevel_under_pointer)
     {
       new_window_under_pointer =
        get_pointer_window (display, changed_toplevel,
                            display->pointer_info.toplevel_x,
-                           display->pointer_info.toplevel_y);
+                           display->pointer_info.toplevel_y,
+                           serial);
       if (new_window_under_pointer !=
          display->pointer_info.window_under_pointer)
        {
-         _gdk_syntesize_crossing_events (display,
-                                         display->pointer_info.window_under_pointer,
-                                         new_window_under_pointer,
-                                         GDK_CROSSING_NORMAL,
-                                         display->pointer_info.toplevel_x,
-                                         display->pointer_info.toplevel_y,
-                                         display->pointer_info.state,
-                                         GDK_CURRENT_TIME,
-                                         NULL);
+         _gdk_synthesize_crossing_events (display,
+                                          display->pointer_info.window_under_pointer,
+                                          new_window_under_pointer,
+                                          GDK_CROSSING_NORMAL,
+                                          display->pointer_info.toplevel_x,
+                                          display->pointer_info.toplevel_y,
+                                          display->pointer_info.state,
+                                          GDK_CURRENT_TIME,
+                                          NULL,
+                                          serial,
+                                          FALSE);
          _gdk_display_set_window_under_pointer (display, new_window_under_pointer);
        }
     }
+
+  return FALSE;
+}
+
+void
+_gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
+{
+  GdkDisplay *display;
+  GdkWindow *toplevel;
+  GdkWindowObject *toplevel_priv;
+
+  if (_gdk_native_windows)
+    return; /* We use the native crossing events if all native */
+
+  display = gdk_drawable_get_display (changed_window);
+
+  toplevel = get_event_toplevel (changed_window);
+  toplevel_priv = (GdkWindowObject *)toplevel;
+
+  if (toplevel == display->pointer_info.toplevel_under_pointer &&
+      !toplevel_priv->synthesize_crossing_event_queued)
+    {
+      toplevel_priv->synthesize_crossing_event_queued = TRUE;
+      g_idle_add_full (GDK_PRIORITY_EVENTS - 1,
+                      do_synthesize_crossing_event,
+                      g_object_ref (toplevel),
+                      g_object_unref);
+    }
 }
 
 /* Don't use for crossing events */
@@ -8152,28 +9269,23 @@ get_event_window (GdkDisplay                 *display,
                  GdkWindow                  *pointer_window,
                  GdkEventType                type,
                  GdkModifierType             mask,
-                 guint                      *evmask_out)
+                 guint                      *evmask_out,
+                 gulong                      serial)
 {
   guint evmask;
   GdkWindow *grab_window;
   GdkWindowObject *w;
+  GdkPointerGrabInfo *grab;
 
-  if ((display->pointer_grab.window != NULL && !display->pointer_grab.owner_events) ||
-      (type == GDK_BUTTON_RELEASE && display->pointer_grab.grab_one_pointer_release_event))
+  grab = _gdk_display_has_pointer_grab (display, serial);
+
+  if (grab != NULL && !grab->owner_events)
     {
-      evmask = display->pointer_grab.event_mask;
+      evmask = grab->event_mask;
       evmask = update_evmask_for_button_motion (evmask, mask);
 
-      if (type == GDK_BUTTON_RELEASE &&
-         display->pointer_grab.grab_one_pointer_release_event)
-       {
-         grab_window = display->pointer_grab.grab_one_pointer_release_event;
-         display->pointer_grab.grab_one_pointer_release_event = NULL;
-       }
-      else
-       grab_window = display->pointer_grab.window;
+      grab_window = grab->window;
 
-      
       if (evmask & type_masks[type])
        {
          if (evmask_out)
@@ -8197,20 +9309,20 @@ get_event_window (GdkDisplay                 *display,
          return (GdkWindow *)w;
        }
 
-      w = w->parent;
+      w = get_event_parent (w);
     }
 
-  if (display->pointer_grab.window != NULL &&
-      display->pointer_grab.owner_events)
+  if (grab != NULL &&
+      grab->owner_events)
     {
-      evmask = display->pointer_grab.event_mask;
+      evmask = grab->event_mask;
       evmask = update_evmask_for_button_motion (evmask, mask);
 
       if (evmask & type_masks[type])
        {
          if (evmask_out)
            *evmask_out = evmask;
-         return display->pointer_grab.window;
+         return grab->window;
        }
       else
        return NULL;
@@ -8224,34 +9336,126 @@ proxy_pointer_event (GdkDisplay                 *display,
                     GdkEvent                   *source_event,
                     gulong                      serial)
 {
-  GdkWindow *toplevel_window;
+  GdkWindow *toplevel_window, *event_window;
   GdkWindow *pointer_window;
-  GdkWindow *cursor_window;
   GdkEvent *event;
   guint state;
   gdouble toplevel_x, toplevel_y;
   guint32 time_;
+  gboolean non_linear;
 
-  toplevel_window = source_event->any.window;
+  event_window = source_event->any.window;
   gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
   gdk_event_get_state (source_event, &state);
   time_ = gdk_event_get_time (source_event);
+  toplevel_window = convert_native_coords_to_toplevel (event_window,
+                                                      toplevel_x, toplevel_y,
+                                                      &toplevel_x, &toplevel_y);
+
+  non_linear = FALSE;
+  if ((source_event->type == GDK_LEAVE_NOTIFY ||
+       source_event->type == GDK_ENTER_NOTIFY) &&
+      (source_event->crossing.detail == GDK_NOTIFY_NONLINEAR ||
+       source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))
+    non_linear = TRUE;
+
+  /* If we get crossing events with subwindow unexpectedly being NULL
+     that means there is a native subwindow that gdk doesn't know about.
+     We track these and forward them, with the correct virtual window
+     events inbetween.
+     This is important to get right, as metacity uses gdk for the frame
+     windows, but gdk doesn't know about the client windows reparented
+     into the frame. */
+  if (((source_event->type == GDK_LEAVE_NOTIFY &&
+       source_event->crossing.detail == GDK_NOTIFY_INFERIOR) ||
+       (source_event->type == GDK_ENTER_NOTIFY &&
+       (source_event->crossing.detail == GDK_NOTIFY_VIRTUAL ||
+        source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))) &&
+      source_event->crossing.subwindow == NULL)
+    {
+      /* Left for an unknown (to gdk) subwindow */
+
+      /* Send leave events from window under pointer to event window
+        that will get the subwindow == NULL window */
+      _gdk_synthesize_crossing_events (display,
+                                      display->pointer_info.window_under_pointer,
+                                      event_window,
+                                      source_event->crossing.mode,
+                                      toplevel_x, toplevel_y,
+                                      state, time_,
+                                      source_event,
+                                      serial,
+                                      non_linear);
+
+      /* Send subwindow == NULL event */
+      send_crossing_event (display,
+                          (GdkWindowObject *)toplevel_window,
+                          (GdkWindowObject *)event_window,
+                          source_event->type,
+                          source_event->crossing.mode,
+                          source_event->crossing.detail,
+                          NULL,
+                          toplevel_x,   toplevel_y,
+                          state, time_,
+                          source_event,
+                          serial);
+
+      _gdk_display_set_window_under_pointer (display, NULL);
+      return TRUE;
+    }
+
+  pointer_window = get_pointer_window (display, toplevel_window,
+                                      toplevel_x, toplevel_y, serial);
+
+  if (((source_event->type == GDK_ENTER_NOTIFY &&
+       source_event->crossing.detail == GDK_NOTIFY_INFERIOR) ||
+       (source_event->type == GDK_LEAVE_NOTIFY &&
+       (source_event->crossing.detail == GDK_NOTIFY_VIRTUAL ||
+        source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))) &&
+      source_event->crossing.subwindow == NULL)
+    {
+      /* Entered from an unknown (to gdk) subwindow */
+
+      /* Send subwindow == NULL event */
+      send_crossing_event (display,
+                          (GdkWindowObject *)toplevel_window,
+                          (GdkWindowObject *)event_window,
+                          source_event->type,
+                          source_event->crossing.mode,
+                          source_event->crossing.detail,
+                          NULL,
+                          toplevel_x,   toplevel_y,
+                          state, time_,
+                          source_event,
+                          serial);
+
+      /* Send enter events from event window to pointer_window */
+      _gdk_synthesize_crossing_events (display,
+                                      event_window,
+                                      pointer_window,
+                                      source_event->crossing.mode,
+                                      toplevel_x, toplevel_y,
+                                      state, time_,
+                                      source_event,
+                                      serial, non_linear);
+      _gdk_display_set_window_under_pointer (display, pointer_window);
+      return TRUE;
+    }
 
-  pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
   if (display->pointer_info.window_under_pointer != pointer_window)
     {
       /* Either a toplevel crossing notify that ended up inside a child window,
         or a motion notify that got into another child window  */
-      /* Different than last time, send crossing events */
-
-      _gdk_syntesize_crossing_events (display,
-                                     display->pointer_info.window_under_pointer,
-                                     pointer_window,
-                                     GDK_CROSSING_NORMAL,
-                                     toplevel_x, toplevel_y,
-                                     state, time_,
-                                     source_event);
 
+      /* Different than last time, send crossing events */
+      _gdk_synthesize_crossing_events (display,
+                                      display->pointer_info.window_under_pointer,
+                                      pointer_window,
+                                      GDK_CROSSING_NORMAL,
+                                      toplevel_x, toplevel_y,
+                                      state, time_,
+                                      source_event,
+                                      serial, non_linear);
       _gdk_display_set_window_under_pointer (display, pointer_window);
     }
   else if (source_event->type == GDK_MOTION_NOTIFY)
@@ -8264,10 +9468,11 @@ proxy_pointer_event (GdkDisplay                 *display,
                                    pointer_window,
                                    source_event->type,
                                    state,
-                                   &evmask);
+                                   &evmask,
+                                   serial);
 
       is_hint = FALSE;
-      
+
       if (event_win &&
          (evmask & GDK_POINTER_MOTION_HINT_MASK))
        {
@@ -8280,8 +9485,8 @@ proxy_pointer_event (GdkDisplay                 *display,
              display->pointer_info.motion_hint_serial = G_MAXULONG;
            }
        }
-      
-      if (event_win)
+
+      if (event_win && !display->ignore_core_events)
        {
          event = _gdk_make_event (event_win, GDK_MOTION_NOTIFY, source_event, FALSE);
          event->motion.time = time_;
@@ -8297,26 +9502,25 @@ proxy_pointer_event (GdkDisplay                 *display,
        }
     }
 
-  /* TODO: set cursor from cursor_window, or grab cursor */
-  cursor_window = pointer_window;
-  if (display->pointer_grab.window &&
-      (pointer_window == NULL ||
-       !is_parent_of (display->pointer_grab.window, pointer_window)))
-    cursor_window = display->pointer_grab.window;
-  /* Actually, this should probably happen in synthesize crossing so it works with geometry changes */
-
-  
   /* unlink all move events from queue.
      We handle our own, including our emulated masks. */
   return TRUE;
 }
 
+#define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \
+                            GDK_BUTTON2_MASK | \
+                            GDK_BUTTON3_MASK | \
+                            GDK_BUTTON4_MASK | \
+                            GDK_BUTTON5_MASK)
+
 static gboolean
-proxy_button_event (GdkEvent *source_event)
+proxy_button_event (GdkEvent *source_event,
+                   gulong serial)
 {
-  GdkWindow *toplevel_window;
+  GdkWindow *toplevel_window, *event_window;
   GdkWindow *event_win;
   GdkWindow *pointer_window;
+  GdkWindowObject *parent;
   GdkEvent *event;
   guint state;
   guint32 time_;
@@ -8326,58 +9530,60 @@ proxy_button_event (GdkEvent *source_event)
   GdkWindowObject *w;
 
   type = source_event->any.type;
-  toplevel_window = source_event->any.window;
+  event_window = source_event->any.window;
   gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
   gdk_event_get_state (source_event, &state);
   time_ = gdk_event_get_time (source_event);
   display = gdk_drawable_get_display (source_event->any.window);
+  toplevel_window = convert_native_coords_to_toplevel (event_window,
+                                                      toplevel_x, toplevel_y,
+                                                      &toplevel_x, &toplevel_y);
 
-  if ((type == GDK_BUTTON_PRESS || type == GDK_SCROLL) &&
-      display->pointer_grab.window == source_event->any.window &&
-      display->pointer_grab.implicit &&
-      !display->pointer_grab.converted_implicit)
+  if (type == GDK_BUTTON_PRESS &&
+      _gdk_display_has_pointer_grab (display, serial) == NULL)
     {
       pointer_window =
        _gdk_window_find_descendant_at (toplevel_window,
                                        toplevel_x, toplevel_y,
                                        NULL, NULL);
 
-      /* Find the actual event window, its what gets the grab */
+      /* Find the event window, that gets the grab */
       w = (GdkWindowObject *)pointer_window;
-      while (w != NULL && w->parent->window_type != GDK_WINDOW_ROOT)
+      while (w != NULL &&
+            (parent = get_event_parent (w)) != NULL &&
+            parent->window_type != GDK_WINDOW_ROOT)
        {
          if (w->event_mask & GDK_BUTTON_PRESS_MASK)
            break;
-         w = w->parent;
+         w = parent;
        }
       pointer_window = (GdkWindow *)w;
-      
-      if (pointer_window != NULL &&
-         pointer_window != source_event->any.window)
-       _gdk_display_set_has_pointer_grab (display,
-                                          pointer_window,
-                                          display->pointer_grab.native_window,
-                                          display->pointer_grab.owner_events,
-                                          gdk_window_get_events (pointer_window),
-                                          display->pointer_grab.serial,
-                                          display->pointer_grab.time,
-                                          display->pointer_grab.implicit);
-      display->pointer_grab.converted_implicit = TRUE;
-    }
-
-  pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
-  
+
+      _gdk_display_add_pointer_grab  (display,
+                                     pointer_window,
+                                     toplevel_window,
+                                     FALSE,
+                                     gdk_window_get_events (pointer_window),
+                                     serial,
+                                     time_,
+                                     TRUE);
+      _gdk_display_pointer_grab_update (display, serial);
+    }
+
+  pointer_window = get_pointer_window (display, toplevel_window,
+                                      toplevel_x, toplevel_y,
+                                      serial);
+
   event_win = get_event_window (display,
                                pointer_window,
-                               type,
-                               state,
-                               NULL);
+                               type, state,
+                               NULL, serial);
 
-  if (event_win == NULL)
+  if (event_win == NULL || display->ignore_core_events)
     return TRUE;
-  
+
   event = _gdk_make_event (event_win, type, source_event, FALSE);
-  
+
   switch (type)
     {
     case GDK_BUTTON_PRESS:
@@ -8390,11 +9596,11 @@ proxy_button_event (GdkEvent *source_event)
       event->button.y_root = source_event->button.y_root;
       event->button.state = state;
       event->button.device = source_event->button.device;
-      
+
       if (type == GDK_BUTTON_PRESS)
        _gdk_event_button_generate (display, event);
       return TRUE;
-      
+
     case GDK_SCROLL:
       event->scroll.direction = source_event->scroll.direction;
       convert_toplevel_coords_to_window (event_win,
@@ -8405,7 +9611,7 @@ proxy_button_event (GdkEvent *source_event)
       event->scroll.state = state;
       event->scroll.device = source_event->scroll.device;
       return TRUE;
-      
+
     default:
       return FALSE;
     }
@@ -8419,7 +9625,7 @@ gdk_window_print (GdkWindowObject *window,
                  int indent)
 {
   GdkRectangle r;
-  
+
   g_print ("%*s%p: [%s] %d,%d %dx%d", indent, "", window,
           window->user_data ? g_type_name_from_instance (window->user_data) : "no widget",
           window->x, window->y,
@@ -8432,22 +9638,22 @@ gdk_window_print (GdkWindowObject *window,
       g_print (" impl(0x%lx)", gdk_x11_drawable_get_xid (GDK_DRAWABLE (window)));
 #endif
     }
-  
+
   if (window->input_only)
     g_print (" input-only");
 
   if (!gdk_window_is_visible ((GdkWindow *)window))
     g_print (" hidden");
-    
+
   g_print (" abs[%d,%d]",
           window->abs_x, window->abs_y);
-  
+
   gdk_region_get_clipbox (window->clip_region, &r);
   if (gdk_region_empty (window->clip_region))
     g_print (" clipbox[empty]");
   else
     g_print (" clipbox[%d,%d %dx%d]", r.x, r.y, r.width, r.height);
-  
+
   g_print ("\n");
 }
 
@@ -8464,7 +9670,7 @@ gdk_window_print_tree (GdkWindow *window,
 
   if (private->input_only && !include_input_only)
     return;
-  
+
   gdk_window_print (private, indent);
 
   for (l = private->children; l != NULL; l = l->next)
@@ -8473,6 +9679,22 @@ gdk_window_print_tree (GdkWindow *window,
 
 #endif /* DEBUG_WINDOW_PRINTING */
 
+static gboolean
+is_input_event (GdkDisplay *display,
+               GdkEvent *event)
+{
+  GdkDevice *core_pointer;
+
+  core_pointer = gdk_display_get_core_pointer (display);
+  if ((event->type == GDK_MOTION_NOTIFY &&
+       event->motion.device != core_pointer) ||
+      ((event->type == GDK_BUTTON_PRESS ||
+       event->type == GDK_BUTTON_RELEASE) &&
+       event->button.device != core_pointer))
+    return TRUE;
+  return FALSE;
+}
+
 void
 _gdk_windowing_got_event (GdkDisplay *display,
                          GList      *event_link,
@@ -8484,14 +9706,58 @@ _gdk_windowing_got_event (GdkDisplay *display,
   gdouble x, y;
   gboolean unlink_event;
   guint old_state, old_button;
+  GdkPointerGrabInfo *button_release_grab;
+  gboolean is_toplevel;
+
+  if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
+    display->last_event_time = gdk_event_get_time (event);
+
+  _gdk_display_pointer_grab_update (display,
+                                   serial);
 
   event_window = event->any.window;
   if (!event_window)
     return;
-  
+
+  if (_gdk_native_windows)
+    {
+      if (event->type == GDK_BUTTON_PRESS &&
+         _gdk_display_has_pointer_grab (display, serial) == NULL)
+       {
+         _gdk_display_add_pointer_grab  (display,
+                                         event_window,
+                                         event_window,
+                                         FALSE,
+                                         gdk_window_get_events (event_window),
+                                         serial,
+                                         gdk_event_get_time (event),
+                                         TRUE);
+         _gdk_display_pointer_grab_update (display,
+                                           serial);
+       }
+      if (event->type == GDK_BUTTON_RELEASE)
+       {
+         button_release_grab =
+           _gdk_display_has_pointer_grab (display, serial);
+         if (button_release_grab &&
+             button_release_grab->implicit &&
+             (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
+           {
+             button_release_grab->serial_end = serial;
+             button_release_grab->implicit_ungrab = TRUE;
+             _gdk_display_pointer_grab_update (display, serial);
+           }
+       }
+
+      if (event->type == GDK_BUTTON_PRESS)
+       _gdk_event_button_generate (display, event);
+
+      return;
+    }
+
   event_private = GDK_WINDOW_OBJECT (event_window);
 
-#ifdef DEBUG_WINDOW_PRINTING  
+#ifdef DEBUG_WINDOW_PRINTING
   if (event->type == GDK_KEY_PRESS &&
       (event->key.keyval == 0xa7 ||
        event->key.keyval == 0xbd))
@@ -8500,54 +9766,92 @@ _gdk_windowing_got_event (GdkDisplay *display,
                             event->key.keyval == 0xbd);
     }
 #endif
-  
+
+  if (event->type == GDK_VISIBILITY_NOTIFY)
+    {
+      event_private->native_visibility = event->visibility.state;
+      gdk_window_update_visibility_recursively (event_private,
+                                               event_private);
+      return;
+    }
+
+  if (is_input_event (display, event))
+    return;
+
   if (!(is_button_type (event->type) ||
        is_motion_type (event->type)) ||
-      GDK_WINDOW_TYPE (event_private) == GDK_WINDOW_ROOT)
+      event_private->window_type == GDK_WINDOW_ROOT)
     return;
 
-  if (event_private->parent != NULL &&
-      GDK_WINDOW_TYPE (event_private->parent) != GDK_WINDOW_ROOT)
-    {
-      GEnumValue *event_type_value, *window_type_value;
+  is_toplevel =
+    event_private->parent == NULL ||
+    event_private->parent->window_type == GDK_WINDOW_ROOT;
+
+  if ((event->type == GDK_ENTER_NOTIFY ||
+       event->type == GDK_LEAVE_NOTIFY) &&
+      (event->crossing.mode == GDK_CROSSING_GRAB ||
+       event->crossing.mode == GDK_CROSSING_UNGRAB) &&
+      (_gdk_display_has_pointer_grab (display, serial) ||
+       event->crossing.detail == GDK_NOTIFY_INFERIOR))
+    {
+      /* We synthesize all crossing events due to grabs ourselves,
+       * so we ignore the native ones caused by our native pointer_grab
+       * calls. Otherwise we would proxy these crossing event and cause
+       * multiple copies of crossing events for grabs.
+       *
+       * We do want to handle grabs from other clients though, as for
+       * instance alt-tab in metacity causes grabs like these and
+       * we want to handle those. Thus the has_pointer_grab check.
+       *
+       * Implicit grabs on child windows create some grabbing events
+       * that are sent before the button press. This means we can't
+       * detect these with the has_pointer_grab check (as the implicit
+       * grab is only noticed when we get button press event), so we
+       * detect these events by checking for INFERIOR enter or leave
+       * events. These should never be a problem to filter out.
+       */
 
-      if (GDK_WINDOW_TYPE (event_private) == GDK_WINDOW_FOREIGN)
-       return;
-      
-      event_type_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (GDK_TYPE_EVENT_TYPE),
-                                          event->type);
-      window_type_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (GDK_TYPE_WINDOW_TYPE),
-                                           event_private->window_type);
-      
-     /* We should only get these events on toplevel windows */
-      g_warning ("got unexpected event of type %s on non-toplevel window (gtype %s, type %d)",
-                event_type_value->value_name,
-                window_type_value->value_name,
-                GDK_WINDOW_TYPE (event_window));
-      return;
-    }
+      /* We ended up in this window after some (perhaps other clients)
+        grab, so update the toplevel_under_window state */
+      if (is_toplevel &&
+         event->type == GDK_ENTER_NOTIFY &&
+         event->crossing.mode == GDK_CROSSING_UNGRAB)
+       {
+         if (display->pointer_info.toplevel_under_pointer)
+           g_object_unref (display->pointer_info.toplevel_under_pointer);
+         display->pointer_info.toplevel_under_pointer = g_object_ref (event_window);
+       }
 
-  /* Store last pointer window and position/state */
-  if (event->type == GDK_ENTER_NOTIFY &&
-      event->crossing.detail != GDK_NOTIFY_INFERIOR)
-    {
-      if (display->pointer_info.toplevel_under_pointer)
-       g_object_unref (display->pointer_info.toplevel_under_pointer);
-      display->pointer_info.toplevel_under_pointer = g_object_ref (event_window);
+      unlink_event = TRUE;
+      goto out;
     }
-  else if (event->type == GDK_LEAVE_NOTIFY &&
-          event->crossing.detail != GDK_NOTIFY_INFERIOR &&
-          display->pointer_info.toplevel_under_pointer == event_window)
+
+  /* Track toplevel_under_pointer */
+  if (is_toplevel)
     {
-      if (display->pointer_info.toplevel_under_pointer)
-       g_object_unref (display->pointer_info.toplevel_under_pointer);
-      display->pointer_info.toplevel_under_pointer = NULL;
+      if (event->type == GDK_ENTER_NOTIFY &&
+         event->crossing.detail != GDK_NOTIFY_INFERIOR)
+       {
+         if (display->pointer_info.toplevel_under_pointer)
+           g_object_unref (display->pointer_info.toplevel_under_pointer);
+         display->pointer_info.toplevel_under_pointer = g_object_ref (event_window);
+       }
+      else if (event->type == GDK_LEAVE_NOTIFY &&
+              event->crossing.detail != GDK_NOTIFY_INFERIOR &&
+              display->pointer_info.toplevel_under_pointer == event_window)
+       {
+         if (display->pointer_info.toplevel_under_pointer)
+           g_object_unref (display->pointer_info.toplevel_under_pointer);
+         display->pointer_info.toplevel_under_pointer = NULL;
+       }
     }
 
+  /* Store last pointer window and position/state */
   old_state = display->pointer_info.state;
   old_button = display->pointer_info.button;
-  
+
   gdk_event_get_coords (event, &x, &y);
+  convert_native_coords_to_toplevel (event_window, x, y,  &x, &y);
   display->pointer_info.toplevel_x = x;
   display->pointer_info.toplevel_y = y;
   gdk_event_get_state (event, &display->pointer_info.state);
@@ -8558,15 +9862,31 @@ _gdk_windowing_got_event (GdkDisplay *display,
   if (display->pointer_info.state != old_state ||
       display->pointer_info.button != old_button)
     _gdk_display_enable_motion_hints (display);
+
   unlink_event = FALSE;
   if (is_motion_type (event->type))
     unlink_event = proxy_pointer_event (display,
-                                        event,
+                                       event,
                                        serial);
   else if (is_button_type (event->type))
-    unlink_event = proxy_button_event (event);
+    unlink_event = proxy_button_event (event,
+                                      serial);
+
+  if (event->type == GDK_BUTTON_RELEASE)
+    {
+      button_release_grab =
+       _gdk_display_has_pointer_grab (display, serial);
+      if (button_release_grab &&
+         button_release_grab->implicit &&
+         (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
+       {
+         button_release_grab->serial_end = serial;
+         button_release_grab->implicit_ungrab = TRUE;
+         _gdk_display_pointer_grab_update (display, serial);
+       }
+    }
 
+ out:
   if (unlink_event)
     {
       _gdk_event_queue_remove_link (display, event_link);
@@ -8575,5 +9895,87 @@ _gdk_windowing_got_event (GdkDisplay *display,
     }
 }
 
+
+static GdkWindow *
+get_extension_event_window (GdkDisplay                 *display,
+                           GdkWindow                  *pointer_window,
+                           GdkEventType                type,
+                           gulong                      serial)
+{
+  guint evmask;
+  GdkWindow *grab_window;
+  GdkWindowObject *w;
+  GdkPointerGrabInfo *grab;
+
+  grab = _gdk_display_has_pointer_grab (display, serial);
+
+  if (grab != NULL && !grab->owner_events)
+    {
+      evmask = grab->event_mask;
+
+      grab_window = grab->window;
+
+      if (evmask & type_masks[type])
+       return grab_window;
+      else
+       return NULL;
+    }
+
+  w = (GdkWindowObject *)pointer_window;
+  while (w != NULL)
+    {
+      evmask = w->extension_events;
+
+      if (evmask & type_masks[type])
+       return (GdkWindow *)w;
+
+      w = get_event_parent (w);
+    }
+
+  if (grab != NULL &&
+      grab->owner_events)
+    {
+      evmask = grab->event_mask;
+
+      if (evmask & type_masks[type])
+       return grab->window;
+      else
+       return NULL;
+    }
+
+  return NULL;
+}
+
+
+GdkWindow *
+_gdk_window_get_input_window_for_event (GdkWindow *native_window,
+                                       GdkEventType event_type,
+                                       int x, int y,
+                                       gulong serial)
+{
+  GdkDisplay *display;
+  GdkWindow *toplevel_window;
+  GdkWindow *pointer_window;
+  GdkWindow *event_win;
+  gdouble toplevel_x, toplevel_y;
+
+  toplevel_x = x;
+  toplevel_y = y;
+
+  display = gdk_drawable_get_display (native_window);
+  toplevel_window = convert_native_coords_to_toplevel (native_window,
+                                                      toplevel_x, toplevel_y,
+                                                      &toplevel_x, &toplevel_y);
+  pointer_window = get_pointer_window (display, toplevel_window,
+                                      toplevel_x, toplevel_y, serial);
+  event_win = get_extension_event_window (display,
+                                         pointer_window,
+                                         event_type,
+                                         serial);
+
+  return event_win;
+}
+
+
 #define __GDK_WINDOW_C__
 #include "gdkaliasdef.c"