diff --git a/gdk/Makefile.am b/gdk/Makefile.am
index af3abae..2bf2ae0 100644
--- a/gdk/Makefile.am
+++ b/gdk/Makefile.am
@@ -92,6 +92,7 @@ gdk_public_h_sources =				\
 	gdktestutils.h				\
 	gdktypes.h				\
 	gdkvisual.h				\
+	gdkwindowimpl.h				\
 	gdkwindow.h
 
 gdk_built_public_sources =			\
@@ -108,6 +109,7 @@ gdk_c_sources =                 \
 	gdkcolor.c		\
 	gdkcursor.c		\
 	gdkdisplay.c		\
+	gdkdisplaymanager.c	\
 	gdkdnd.c		\
 	gdkdraw.c		\
 	gdkevents.c     	\
@@ -119,7 +121,7 @@ gdk_c_sources =                 \
 	gdkimage.c		\
 	gdkinternals.h  	\
 	gdkintl.h		\
-	gdkdisplaymanager.c	\
+	gdkoffscreenwindow.c	\
 	gdkpango.c		\
 	gdkpixbuf-drawable.c	\
 	gdkpixbuf-render.c	\
@@ -133,7 +135,8 @@ gdk_c_sources =                 \
 	gdkscreen.c		\
 	gdkselection.c		\
 	gdkvisual.c		\
-	gdkwindow.c
+	gdkwindow.c		\
+	gdkwindowimpl.c
 
 gdk_built_sources =				\
 	gdkaliasdef.c				\
diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols
index 9f81c6c..7e383d0 100644
--- a/gdk/gdk.symbols
+++ b/gdk/gdk.symbols
@@ -252,12 +252,6 @@ gdk_visual_type_get_type G_GNUC_CONST
 #endif
 #endif
 
-#if IN_HEADER(__GDK_PIXMAP_H__)
-#if IN_FILE(__GDK_PIXMAP_X11_C__)
-gdk_bitmap_create_from_data
-#endif
-#endif
-
 #if IN_HEADER(__GDK_FONT_H__)
 #if IN_FILE(__GDK_FONT_C__)
 #ifndef GDK_DISABLE_DEPRECATED
@@ -646,6 +640,31 @@ gdk_window_impl_x11_get_type G_GNUC_CONST
 #if IN_HEADER(__GDK_WINDOW_H__)
 #if IN_FILE(__GDK_WINDOW_C__)
 gdk_get_default_root_window
+gdk_window_new
+gdk_window_show_unraised
+gdk_window_show
+gdk_window_hide
+gdk_window_withdraw
+gdk_window_get_events
+gdk_window_set_events
+gdk_window_raise
+gdk_window_lower
+gdk_window_move
+gdk_window_resize
+gdk_window_move_resize
+gdk_window_scroll
+gdk_window_move_region
+gdk_window_set_background
+gdk_window_set_back_pixmap
+gdk_window_set_cursor
+gdk_window_get_geometry
+gdk_window_get_origin
+gdk_window_shape_combine_mask
+gdk_window_shape_combine_region
+gdk_window_set_child_shapes
+gdk_window_merge_child_shapes
+gdk_window_set_static_gravities
+gdk_window_reparent
 gdk_window_add_filter
 gdk_window_at_pointer
 gdk_window_begin_paint_rect
@@ -695,29 +714,11 @@ gdk_window_register_dnd
 #endif
 
 #if IN_HEADER(__GDK_WINDOW_H__)
-#if IN_FILE(__GDK_GEOMETRY_X11_C__)
-gdk_window_scroll
-gdk_window_move_region
-#endif
-#endif
-
-#if IN_HEADER(__GDK_WINDOW_H__)
 #if IN_FILE(__GDK_WINDOW_X11_C__)
-gdk_window_new
 gdk_window_foreign_new_for_display
+gdk_window_focus
 gdk_window_lookup
 gdk_window_lookup_for_display
-gdk_window_show_unraised
-gdk_window_show
-gdk_window_hide
-gdk_window_withdraw
-gdk_window_move
-gdk_window_resize
-gdk_window_move_resize
-gdk_window_reparent
-gdk_window_raise
-gdk_window_lower
-gdk_window_focus
 #ifndef GDK_DISABLE_DEPRECATED
 gdk_window_set_hints
 gdk_window_get_deskrelative_origin
@@ -733,17 +734,8 @@ gdk_window_set_title
 gdk_window_set_role
 gdk_window_set_startup_id
 gdk_window_set_transient_for
-gdk_window_set_background
-gdk_window_set_back_pixmap
-gdk_window_set_cursor
-gdk_window_get_geometry
-gdk_window_get_origin
 gdk_window_get_root_origin
 gdk_window_get_frame_extents
-gdk_window_get_events
-gdk_window_set_events
-gdk_window_shape_combine_mask
-gdk_window_shape_combine_region
 gdk_window_input_shape_combine_mask
 gdk_window_input_shape_combine_region
 gdk_window_set_override_redirect
@@ -769,11 +761,8 @@ gdk_window_set_group
 gdk_window_get_decorations
 gdk_window_set_decorations
 gdk_window_set_functions
-gdk_window_set_child_shapes
-gdk_window_merge_child_shapes
 gdk_window_set_child_input_shapes
 gdk_window_merge_child_input_shapes
-gdk_window_set_static_gravities
 gdk_window_begin_move_drag
 gdk_window_begin_resize_drag
 gdk_window_enable_synchronized_configure
@@ -922,23 +911,24 @@ gdk_pixbuf_render_to_drawable_alpha
 
 #if IN_HEADER(__GDK_PIXMAP_H__)
 #if IN_FILE(__GDK_PIXMAP_C__)
+gdk_bitmap_create_from_data
 gdk_pixmap_colormap_create_from_xpm
+gdk_pixmap_create_from_data
 gdk_pixmap_create_from_xpm
 gdk_pixmap_colormap_create_from_xpm_d
 gdk_pixmap_create_from_xpm_d
 gdk_pixmap_get_type G_GNUC_CONST
+gdk_pixmap_new
 #endif
 #endif
 
 #if IN_HEADER(__GDK_PIXMAP_H__)
 #if IN_FILE(__GDK_PIXMAP_X11_C__)
-gdk_pixmap_create_from_data
 gdk_pixmap_foreign_new
 gdk_pixmap_foreign_new_for_display
 gdk_pixmap_foreign_new_for_screen
 gdk_pixmap_lookup
 gdk_pixmap_lookup_for_display
-gdk_pixmap_new
 #endif
 #endif
 
diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index 769d086..ac43b21 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -22,9 +22,11 @@
  */
 
 #include <config.h>
+#include <math.h>
 #include <glib.h>
 #include "gdk.h"		/* gdk_event_send_client_message() */
 #include "gdkdisplay.h"
+#include "gdkwindowimpl.h"
 #include "gdkinternals.h"
 #include "gdkmarshalers.h"
 #include "gdkscreen.h"
@@ -60,6 +62,14 @@ static GdkWindow* singlehead_default_window_get_pointer (GdkWindow       *window
 static GdkWindow* singlehead_default_window_at_pointer  (GdkScreen       *screen,
 							 gint            *win_x,
 							 gint            *win_y);
+static GdkWindow *gdk_window_real_window_get_pointer     (GdkDisplay       *display,
+                                                          GdkWindow        *window,
+                                                          gint             *x,
+                                                          gint             *y,
+                                                          GdkModifierType  *mask);
+static GdkWindow *gdk_display_real_get_window_at_pointer (GdkDisplay       *display,
+                                                          gint             *win_x,
+                                                          gint             *win_y);
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
@@ -67,8 +77,8 @@ static char *gdk_sm_client_id;
 
 static const GdkDisplayPointerHooks default_pointer_hooks = {
   _gdk_windowing_get_pointer,
-  _gdk_windowing_window_get_pointer,
-  _gdk_windowing_window_at_pointer
+  gdk_window_real_window_get_pointer,
+  gdk_display_real_get_window_at_pointer
 };
 
 static const GdkDisplayPointerHooks singlehead_pointer_hooks = {
@@ -471,6 +481,73 @@ gdk_display_get_pointer (GdkDisplay      *display,
     *mask = tmp_mask;
 }
 
+static GdkWindow*
+gdk_display_real_get_window_at_pointer (GdkDisplay *display,
+                                        gint       *win_x,
+                                        gint       *win_y)
+{
+  GdkWindow *window;
+
+  window =_gdk_windowing_window_at_pointer (display, win_x, win_y);
+
+  if (window && GDK_WINDOW_OBJECT (window)->offscreen_children)
+    {
+      GdkWindow *child;
+      gdouble child_x, child_y;
+
+      child =  _gdk_window_get_offscreen_window_child_at (window,
+                                                          *win_x, *win_y,
+                                                          &child_x, &child_y);
+      *win_x = floor (child_x + 0.5);
+      *win_y = floor (child_y + 0.5);
+
+      return child;
+    }
+
+  return window;
+}
+
+static GdkWindow *
+gdk_window_real_window_get_pointer (GdkDisplay       *display,
+                                    GdkWindow        *window,
+                                    gint             *x,
+                                    gint             *y,
+                                    GdkModifierType  *mask)
+{
+  GdkWindowObject *private;
+  GdkWindow *event_window;
+  GdkWindow *pointer_window;
+  gint tmpx, tmpy;
+
+  private = (GdkWindowObject *) window;
+
+  event_window = _gdk_window_get_offscreen_event_window (window);
+
+  pointer_window = _gdk_windowing_window_get_pointer (display,
+                                                      event_window,
+                                                      &tmpx, &tmpy,
+                                                      mask);
+
+  /* Convert to offscreen if needed */
+  _gdk_offscreen_window_transform_coords (event_window,
+                                          window,
+                                          &tmpx, &tmpy);
+  if (x)
+    *x = tmpx;
+  if (y)
+    *y = tmpy;
+
+  /* If the pointer is in a window with offscreen children, recalculate pointer
+   * window, as the pointer it might be in an offscreen child.
+   */
+  if (pointer_window != NULL &&
+      GDK_WINDOW_OBJECT (pointer_window)->offscreen_children)
+    pointer_window = gdk_display_real_get_window_at_pointer (display,
+                                                             &tmpx, &tmpy);
+
+  return pointer_window;
+}
+
 /**
  * gdk_display_get_window_at_pointer:
  * @display: a #GdkDisplay
@@ -582,8 +659,8 @@ singlehead_default_window_get_pointer (GdkWindow       *window,
 				       gint            *y,
 				       GdkModifierType *mask)
 {
-  return _gdk_windowing_window_get_pointer (gdk_drawable_get_display (window),
-					    window, x, y, mask);
+  return gdk_window_real_window_get_pointer (gdk_drawable_get_display (window),
+                                             window, x, y, mask);
 }
 
 static GdkWindow*
@@ -591,8 +668,8 @@ singlehead_default_window_at_pointer  (GdkScreen       *screen,
 				       gint            *win_x,
 				       gint            *win_y)
 {
-  return _gdk_windowing_window_at_pointer (gdk_screen_get_display (screen),
-					   win_x, win_y);
+  return gdk_display_real_get_window_at_pointer (gdk_screen_get_display (screen),
+                                                 win_x, win_y);
 }
 
 /**
diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c
index 66cac16..9f7295f 100644
--- a/gdk/gdkdraw.c
+++ b/gdk/gdkdraw.c
@@ -48,6 +48,7 @@ static GdkDrawable* gdk_drawable_real_get_composite_drawable (GdkDrawable  *draw
 							      gint          height,
 							      gint         *composite_x_offset,
 							      gint         *composite_y_offset);
+static GdkDrawable *gdk_drawable_real_get_source_drawable    (GdkDrawable  *drawable);
 static GdkRegion *  gdk_drawable_real_get_visible_region     (GdkDrawable  *drawable);
 static void         gdk_drawable_real_draw_pixbuf            (GdkDrawable  *drawable,
 							      GdkGC        *gc,
@@ -70,6 +71,7 @@ gdk_drawable_class_init (GdkDrawableClass *klass)
 {
   klass->get_image = gdk_drawable_real_get_image;
   klass->get_composite_drawable = gdk_drawable_real_get_composite_drawable;
+  klass->get_source_drawable = gdk_drawable_real_get_source_drawable;
   /* Default implementation for clip and visible region is the same */
   klass->get_clip_region = gdk_drawable_real_get_visible_region;
   klass->get_visible_region = gdk_drawable_real_get_visible_region;
@@ -1187,7 +1189,13 @@ gdk_drawable_real_get_image (GdkDrawable     *drawable,
   return gdk_drawable_copy_to_image (drawable, NULL, x, y, 0, 0, width, height);
 }
 
-static GdkDrawable*
+static GdkDrawable *
+gdk_drawable_real_get_source_drawable (GdkDrawable *drawable)
+{
+  return drawable;
+}
+
+static GdkDrawable *
 gdk_drawable_real_get_composite_drawable (GdkDrawable *drawable,
                                           gint         x,
                                           gint         y,
@@ -1773,5 +1781,22 @@ _gdk_drawable_get_scratch_gc (GdkDrawable *drawable,
     }
 }
 
+/**
+ * _gdk_drawable_get_source_drawable:
+ * @drawable: a #GdkDrawable
+ *
+ * Returns a drawable for the passed @drawable that is guaranteed to be
+ * usable to create a pixmap (e.g.: not an offscreen window).
+ *
+ * Since: 2.16
+ */
+GdkDrawable *
+_gdk_drawable_get_source_drawable (GdkDrawable *drawable)
+{
+  g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
+
+  return GDK_DRAWABLE_GET_CLASS (drawable)->get_source_drawable (drawable);
+}
+
 #define __GDK_DRAW_C__
 #include "gdkaliasdef.c"
diff --git a/gdk/gdkdrawable.h b/gdk/gdkdrawable.h
index bbd6a4d..1f031cd 100644
--- a/gdk/gdkdrawable.h
+++ b/gdk/gdkdrawable.h
@@ -195,8 +195,9 @@ struct _GdkDrawableClass
 
   cairo_surface_t *(*ref_cairo_surface) (GdkDrawable *drawable);
 
+  GdkDrawable *(*get_source_drawable) (GdkDrawable *drawable);
+
   /* Padding for future expansion */
-  void         (*_gdk_reserved4)  (void);
   void         (*_gdk_reserved5)  (void);
   void         (*_gdk_reserved6)  (void);
   void         (*_gdk_reserved7)  (void);
diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c
index b7b49b1..caba4f1 100644
--- a/gdk/gdkevents.c
+++ b/gdk/gdkevents.c
@@ -79,6 +79,25 @@ _gdk_event_queue_find_first (GdkDisplay *display)
 }
 
 /**
+ * _gdk_event_queue_prepend:
+ * @display: a #GdkDisplay
+ * @event: Event to prepend.
+ *
+ * Prepends an event before the head of the event queue.
+ *
+ * Returns: the newly prepended list node.
+ **/
+GList*
+_gdk_event_queue_prepend (GdkDisplay *display,
+			  GdkEvent   *event)
+{
+  display->queued_events = g_list_prepend (display->queued_events, event);
+  if (!display->queued_tail)
+    display->queued_tail = display->queued_events;
+  return display->queued_events;
+}
+
+/**
  * _gdk_event_queue_append:
  * @display: a #GdkDisplay
  * @event: Event to append.
@@ -102,6 +121,46 @@ _gdk_event_queue_append (GdkDisplay *display,
 }
 
 /**
+ * _gdk_event_queue_append_after:
+ * @display: a #GdkDisplay
+ * @after_event: Append after this event.
+ * @event: Event to append.
+ *
+ * Appends an event after the specified event, or if it isn't in
+ * the queue, onto the tail of the event queue.
+ *
+ * Returns: the newly appended list node.
+ *
+ * Since: 2.16
+ */
+GList *
+_gdk_event_queue_append_after (GdkDisplay *display,
+                               GdkEvent   *after_event,
+                               GdkEvent   *event)
+{
+  GList *tmp_list = display->queued_events;
+
+  while (tmp_list)
+    {
+      GdkEvent *list_event = tmp_list->data;
+
+      if (list_event == after_event)
+        {
+          tmp_list->next = g_list_prepend (tmp_list->next, event);
+
+          if (display->queued_tail == tmp_list)
+            display->queued_tail = tmp_list->next;
+
+          return tmp_list->next;
+        }
+
+      tmp_list = g_list_next (tmp_list);
+    }
+
+  return _gdk_event_queue_append (display, event);
+}
+
+/**
  * _gdk_event_queue_remove_link:
  * @display: a #GdkDisplay
  * @node: node to remove
@@ -541,6 +600,7 @@ gdk_event_get_time (const GdkEvent *event)
       case GDK_CONFIGURE:
       case GDK_FOCUS_CHANGE:
       case GDK_NOTHING:
+      case GDK_DAMAGE:
       case GDK_DELETE:
       case GDK_DESTROY:
       case GDK_EXPOSE:
@@ -611,6 +671,7 @@ gdk_event_get_state (const GdkEvent        *event,
       case GDK_SELECTION_NOTIFY:
       case GDK_PROXIMITY_IN:
       case GDK_PROXIMITY_OUT:
+      case GDK_DAMAGE:
       case GDK_DRAG_ENTER:
       case GDK_DRAG_LEAVE:
       case GDK_DRAG_MOTION:
@@ -1043,13 +1104,18 @@ gdk_synthesize_click (GdkDisplay *display,
 		      gint	  nclicks)
 {
   GdkEvent temp_event;
+  GdkEvent *event_copy;
+  GList *link;
   
   g_return_if_fail (event != NULL);
   
   temp_event = *event;
   temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
-  
-  gdk_display_put_event (display, &temp_event);
+
+  event_copy = gdk_event_copy (&temp_event);
+  link = _gdk_event_queue_append (display, event_copy);
+
+  _gdk_event_rewrite_for_offscreen (display, link, event_copy);
 }
 
 void
diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
index 809992c..ba2c82a 100644
--- a/gdk/gdkevents.h
+++ b/gdk/gdkevents.h
@@ -146,7 +146,8 @@ typedef enum
   GDK_WINDOW_STATE      = 32,
   GDK_SETTING           = 33,
   GDK_OWNER_CHANGE      = 34,
-  GDK_GRAB_BROKEN       = 35
+  GDK_GRAB_BROKEN       = 35,
+  GDK_DAMAGE            = 36
 } GdkEventType;
 
 /* Event masks. (Used to select what types of events a window
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index a52bef1..1c07d7a 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -180,13 +180,18 @@ extern gchar     *_gdk_display_arg_name;
 void      _gdk_events_queue  (GdkDisplay *display);
 GdkEvent* _gdk_event_unqueue (GdkDisplay *display);
 
-GList* _gdk_event_queue_find_first  (GdkDisplay *display);
-void   _gdk_event_queue_remove_link (GdkDisplay *display,
-				     GList      *node);
-GList*  _gdk_event_queue_append     (GdkDisplay *display,
-				     GdkEvent   *event);
-void _gdk_event_button_generate     (GdkDisplay *display,
-				     GdkEvent   *event);
+GList* _gdk_event_queue_find_first   (GdkDisplay *display);
+void   _gdk_event_queue_remove_link  (GdkDisplay *display,
+				      GList      *node);
+GList* _gdk_event_queue_prepend      (GdkDisplay *display,
+				      GdkEvent   *event);
+GList* _gdk_event_queue_append       (GdkDisplay *display,
+				      GdkEvent   *event);
+GList* _gdk_event_queue_append_after (GdkDisplay *display,
+                                      GdkEvent   *after_event,
+                                      GdkEvent   *event);
+void   _gdk_event_button_generate    (GdkDisplay *display,
+				      GdkEvent   *event);
 
 void gdk_synthesize_window_state (GdkWindow     *window,
                                   GdkWindowState unset_flags,
@@ -219,6 +224,8 @@ GdkImage *_gdk_drawable_copy_to_image (GdkDrawable  *drawable,
 
 cairo_surface_t *_gdk_drawable_ref_cairo_surface (GdkDrawable *drawable);
 
+GdkDrawable *_gdk_drawable_get_source_drawable (GdkDrawable *drawable);
+
 /* GC caching */
 GdkGC *_gdk_drawable_get_scratch_gc (GdkDrawable *drawable,
 				     gboolean     graphics_exposures);
@@ -233,11 +240,30 @@ void _gdk_gc_update_context (GdkGC          *gc,
  * Interfaces used by windowing code *
  *************************************/
 
-void       _gdk_window_destroy           (GdkWindow   *window,
-					  gboolean     foreign_destroy);
-void       _gdk_window_clear_update_area (GdkWindow   *window);
-
-void       _gdk_screen_close             (GdkScreen   *screen);
+GdkPixmap *_gdk_pixmap_new               (GdkDrawable    *drawable,
+                                          gint            width,
+                                          gint            height,
+                                          gint            depth);
+GdkPixmap *_gdk_pixmap_create_from_data  (GdkDrawable    *drawable,
+                                          const gchar    *data,
+                                          gint            width,
+                                          gint            height,
+                                          gint            depth,
+                                          const GdkColor *fg,
+                                          const GdkColor *bg);
+GdkPixmap *_gdk_bitmap_create_from_data  (GdkDrawable    *drawable,
+                                          const gchar    *data,
+                                          gint            width,
+                                          gint            height);
+
+GdkWindow *_gdk_window_new               (GdkWindow      *window,
+                                          GdkWindowAttr  *attributes,
+                                          gint            attributes_mask);
+void       _gdk_window_destroy           (GdkWindow      *window,
+					  gboolean        foreign_destroy);
+void       _gdk_window_clear_update_area (GdkWindow      *window);
+
+void       _gdk_screen_close             (GdkScreen      *screen);
 
 const char *_gdk_get_sm_client_id (void);
 
@@ -276,16 +302,6 @@ gchar *_gdk_windowing_substitute_screen_number (const gchar *display_name,
 void     _gdk_windowing_window_get_offsets      (GdkWindow  *window,
 						 gint       *x_offset,
 						 gint       *y_offset);
-void     _gdk_windowing_window_clear_area       (GdkWindow  *window,
-						 gint        x,
-						 gint        y,
-						 gint        width,
-						 gint        height);
-void     _gdk_windowing_window_clear_area_e     (GdkWindow  *window,
-						 gint        x,
-						 gint        y,
-						 gint        width,
-						 gint        height);
 
 void       _gdk_windowing_get_pointer        (GdkDisplay       *display,
 					      GdkScreen       **screen,
@@ -305,6 +321,10 @@ GdkWindow* _gdk_windowing_window_at_pointer  (GdkDisplay       *display,
 gint _gdk_windowing_get_bits_for_depth (GdkDisplay *display,
 					gint        depth);
 
+GdkWindow* _gdk_window_new                        (GdkWindow     *parent,
+						   GdkWindowAttr *attributes,
+						   gint           attributes_mask);
+
 #define GDK_WINDOW_IS_MAPPED(window) ((((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_WITHDRAWN) == 0)
 
 /* Called before processing updates for a window. This gives the windowing
@@ -429,6 +449,55 @@ char *_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context,
 void  _gdk_windowing_launch_failed         (GAppLaunchContext *context, 
 				            const char        *startup_notify_id);
 
+void _gdk_windowing_grab_broken          (GdkDisplay *display);
+void _gdk_windowing_update_implicit_grab (GdkWindow  *old_grab,
+                                          GdkWindow  *new_grab,
+                                          guint       event_mask,
+                                          guint32     time_);
+
+/*****************************
+ * offscreen window routines *
+ *****************************/
+
+GdkWindow* _gdk_window_new_offscreen                 (GdkWindow     *parent,
+                                                      GdkWindowAttr *attributes,
+                                                      gint           attributes_mask,
+                                                      gboolean       toplevel);
+void       _gdk_offscreen_window_destroy             (GdkWindow     *window,
+                                                      gboolean       recursing);
+void       _gdk_offscreen_window_set_pointer_grab    (GdkWindow     *old_grab_window,
+                                                      GdkWindow     *old_native_grab_window,
+                                                      GdkWindow     *grab_window,
+                                                      gboolean       owner_events,
+                                                      guint          event_mask,
+                                                      guint32        time_);
+void       _gdk_offscreen_window_unset_pointer_grab  (GdkWindow     *window,
+                                                      gboolean       regrab,
+                                                      gboolean       grab_one_button_release,
+                                                      guint32        time_);
+GdkRegion *_gdk_window_calculate_full_clip_region    (GdkWindow     *window,
+                                                      GdkWindow     *base_window,
+                                                      GdkGC         *gc,
+                                                      gboolean       do_children,
+                                                      gint          *base_x_offset,
+                                                      gint          *base_y_offset);
+void       _gdk_event_rewrite_for_offscreen          (GdkDisplay    *display,
+                                                      GList         *event_node,
+                                                      GdkEvent      *event);
+void       _gdk_window_add_offscreen_child           (GdkWindow     *window);
+void       _gdk_window_remove_offscreen_child        (GdkWindow     *window);
+GdkWindow *_gdk_window_get_offscreen_window_child_at (GdkWindow     *parent,
+                                                      gdouble        x,
+                                                      gdouble        y,
+                                                      gdouble       *win_x_out,
+                                                      gdouble       *win_y_out);
+GdkWindow *_gdk_window_get_offscreen_event_window    (GdkWindow     *window);
+void       _gdk_offscreen_window_transform_coords    (GdkWindow     *event_window,
+                                                      GdkWindow     *relative_window,
+                                                      gint          *x,
+                                                      gint          *y);
+gboolean   _gdk_window_is_toplevel_offscreen         (GdkWindow     *child);
+
 
 /************************************
  * Initialization and exit routines *
diff --git a/gdk/gdkoffscreenwindow.c b/gdk/gdkoffscreenwindow.c
new file mode 100644
index 0000000..fadb616
--- /dev/null
+++ b/gdk/gdkoffscreenwindow.c
@@ -0,0 +1,2564 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2005.  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/. 
+ */
+
+#include <config.h>
+#include <math.h>
+#include "gdk.h"
+#include "gdkwindow.h"
+#include "gdkinternals.h"
+#include "gdkwindowimpl.h"
+#include "gdkpixmap.h"
+#include "gdkdrawable.h"
+#include "gdktypes.h"
+#include "gdkscreen.h"
+#include "gdkgc.h"
+#include "gdkcolor.h"
+#include "gdkcursor.h"
+#include "gdkalias.h"
+
+/* LIMITATIONS:
+ *
+ * Offscreen windows must be child windows
+ * Offscreen windows can't be the child of a foreign window,
+ *   nor contain foreign windows
+ * All drawing must be within begin/end_paint
+ * The confine_window argument of pointer grabs doesn't work
+ * GDK_POINTER_MOTION_HINT_MASK isn't effective
+ * You can't reparent between offscreen windows and normal windows
+ */
+
+/* TODO:
+
+ * change expose order so that children are exposed before parent, to
+   avoid double drawing due to damage from children coming after parent expose.
+   Event with the right order we will expose twice, although both with an
+   uptodate pixmap.
+   Not sure how to fix this. Perhaps with a get_and_clear_damage() call?
+
+ * gtk_widget_reparent should unrealize/realize if the new parent GdkWindow is
+   offscreen and widget is not, or if the new parent is not offscreen and the
+   widget is. The problem is, how do you know what the new parent GdkWindow is
+   before gtk_container_add()?
+   
+ * Unite the API for all 3 kinds of redirection? how?
+
+ * support scroll button events
+
+ * support cursors in offscreen windows
+
+ * XIM support (is this possible?)
+
+ * Introduce generic "this point in the window in root/other window coords"
+   operation in gtk
+
+ * dnd drop positions wrong with transformed windows. Needs above point
+   transformation.
+
+ * various menu popup positions wrong with transformed widgets.  Needs above
+   point transformation.
+ 
+ */
+
+typedef struct _GdkOffscreenWindow      GdkOffscreenWindow;
+typedef struct _GdkOffscreenWindowClass GdkOffscreenWindowClass;
+
+struct _GdkOffscreenWindow
+{
+  GdkDrawable parent_instance;
+
+  GdkWindow *wrapper;
+  gint width, height;
+  GdkCursor *cursor;
+  GdkColormap *colormap;
+  GdkScreen *screen;
+
+  /* same window if this is the toplevel */
+  GdkOffscreenWindow *toplevel_offscreen;
+  
+  /* computed position in pixmap:
+   *   abs: position of top left corner of window in pixmap
+   *   llim: lower limit of visible part of window
+   *         this can be != abs if the window is outside its parent
+   *   lim: upper limit of visible part of window
+   */
+  gint abs_x, abs_y;
+  gint lim_x, lim_y;
+  gint llim_x, llim_y; 
+};
+ 
+struct _GdkOffscreenWindowClass 
+{
+  GdkDrawableClass parent_class;
+};
+
+#define GDK_TYPE_OFFSCREEN_WINDOW            (gdk_offscreen_window_get_type())
+#define GDK_OFFSCREEN_WINDOW(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindow))
+#define GDK_IS_OFFSCREEN_WINDOW(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_OFFSCREEN_WINDOW))
+#define GDK_OFFSCREEN_WINDOW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
+#define GDK_IS_OFFSCREEN_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_OFFSCREEN_WINDOW))
+#define GDK_OFFSCREEN_WINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_OFFSCREEN_WINDOW, GdkOffscreenWindowClass))
+
+static void       gdk_offscreen_window_impl_iface_init    (GdkWindowImplIface         *iface);
+static void       send_crossing_events                    (GdkWindowOffscreenChildren *offscreen_children,
+							   GdkWindow                  *event_window,
+							   GdkWindow                  *src,
+							   GdkWindow                  *dest,
+							   GdkCrossingMode             mode,
+							   int                         event_x,
+							   int                         event_y,
+							   GdkModifierType             mask,
+							   guint32                     time_,
+							   gboolean                    do_first,
+							   gboolean                    do_last);
+static GdkWindow *gdk_offscreen_window_get_window_at      (GdkWindow                  *window,
+						           gdouble                     x,
+                                                           gdouble                     y,
+                                                           gdouble                    *win_x,
+                                                           gdouble                    *win_y);
+static void       gdk_offscreen_window_hide               (GdkWindow                  *window);
+static void       gdk_offscreen_window_clear_area         (GdkWindow                  *window,
+							   gint                        x,
+							   gint                        y,
+							   gint                        width,
+							   gint                        height,
+							   gboolean                    send_expose);
+static GdkRegion *gdk_offscreen_window_get_visible_region (GdkDrawable                *drawable);
+
+static void convert_event_coords_to_window (GdkWindow *event_window,
+					    GdkWindow *window,
+					    gdouble    event_x,
+                                            gdouble    event_y,
+					    gdouble   *window_x,
+                                            gdouble   *window_y);
+
+G_DEFINE_TYPE_WITH_CODE (GdkOffscreenWindow,
+                         gdk_offscreen_window,
+                         GDK_TYPE_DRAWABLE,
+			 G_IMPLEMENT_INTERFACE (GDK_TYPE_WINDOW_IMPL,
+						gdk_offscreen_window_impl_iface_init));
+
+
+static void
+gdk_offscreen_window_finalize (GObject *object)
+{
+  GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (object);
+
+  if (offscreen->cursor)
+    gdk_cursor_unref (offscreen->cursor);
+
+  offscreen->cursor = NULL;
+}
+
+static void
+gdk_offscreen_window_init (GdkOffscreenWindow *window)
+{
+}
+
+void
+_gdk_offscreen_window_destroy (GdkWindow *window,
+                               gboolean   recursing)
+{
+  GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
+  GdkOffscreenWindow *offscreen;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+
+  if (offscreen->toplevel_offscreen == offscreen && private->parent)
+    _gdk_window_remove_offscreen_child (GDK_WINDOW (private->parent));
+
+  if (!recursing)
+    gdk_offscreen_window_hide (window);
+
+  g_object_unref (offscreen->colormap);
+  offscreen->colormap = NULL;
+}
+
+static gboolean 
+is_parent_of (GdkWindow *parent,
+              GdkWindow *child)
+{
+  GdkWindow *w;
+  
+  w = child;
+  while (w != NULL)
+    {
+      if (w == parent)
+	return TRUE;
+
+      w = gdk_window_get_parent (w);
+    }
+  
+  return FALSE;
+}
+
+static GdkGC *
+gdk_offscreen_window_create_gc (GdkDrawable     *drawable,
+				GdkGCValues     *values,
+				GdkGCValuesMask  values_mask)
+{
+  GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
+  GdkWindowObject *private;
+
+  private = GDK_WINDOW_OBJECT (offscreen->wrapper);
+
+  return gdk_gc_new_with_values (private->redirect->pixmap, values, values_mask);
+}
+
+static GdkImage*
+gdk_offscreen_window_copy_to_image (GdkDrawable    *drawable,
+				    GdkImage       *image,
+				    gint            src_x,
+				    gint            src_y,
+				    gint            dest_x,
+				    gint            dest_y,
+				    gint            width,
+				    gint            height)
+{
+  /* TODO */
+  return NULL;
+}
+
+static cairo_surface_t *
+gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable)
+{
+  g_error ("Attempt to get a cairo surface directly for an offscreen "
+           "window. This is not supported, you must use "
+           "gdk_window_begin_paint_region().");
+
+  return NULL;
+}
+
+
+
+static void
+gdk_offscreen_window_empty_draw_op (GdkDrawable *drawable)
+{
+  /* All actual rendering is done in gdkwindow.c */
+}
+
+static GdkWindow *
+find_offscreen_child (GdkWindow *window,
+                      gdouble    x,
+                      gdouble    y)
+{
+  GdkWindowObject *private = (GdkWindowObject *) window;
+  GdkWindow *hit_window;
+  
+  hit_window = NULL;
+
+  if (private->offscreen_hooks &&
+      private->offscreen_hooks->find_offscreen_child)
+    hit_window = private->offscreen_hooks->find_offscreen_child (window, x, y);
+
+  return hit_window;
+}
+
+
+static void
+window_to_parent (GdkWindow *window,
+                  gdouble    x,
+                  gdouble    y,
+		  gdouble   *parent_x,
+                  gdouble   *parent_y)
+{
+  GdkWindowObject *private = (GdkWindowObject *) window;
+
+  /* Default value if no handler */
+  *parent_x = x + private->x;
+  *parent_y = y + private->y;
+
+  if (private->offscreen_hooks &&
+      private->offscreen_hooks->window_to_parent)
+    private->offscreen_hooks->window_to_parent (window,
+                                                x, y,
+                                                parent_x, parent_y);
+}
+
+static void
+parent_to_window (GdkWindow *window,
+                  gdouble    x,
+                  gdouble    y,
+		  gdouble   *window_x,
+                  gdouble   *window_y)
+{
+  GdkWindowObject *private = (GdkWindowObject *) window;
+
+  /* Default value if no handler */
+  *window_x = x - private->x;
+  *window_y = y - private->y;
+
+  if (private->offscreen_hooks &&
+      private->offscreen_hooks->parent_to_window)
+    private->offscreen_hooks->parent_to_window (window,
+                                                x, y,
+                                                window_x, window_y);
+}
+
+
+static GdkColormap*
+gdk_offscreen_window_get_colormap (GdkDrawable *drawable)
+{
+  GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
+  
+  return offscreen->colormap;
+}
+
+static void
+gdk_offscreen_window_set_colormap (GdkDrawable *drawable,
+				   GdkColormap*colormap)
+{
+  GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
+
+  if (colormap && GDK_WINDOW_DESTROYED (offscreen->wrapper))
+    return;
+
+  if (offscreen->colormap == colormap)
+    return;
+  
+  if (offscreen->colormap)
+    g_object_unref (offscreen->colormap);
+
+  offscreen->colormap = colormap;
+  if (offscreen->colormap)
+    g_object_ref (offscreen->colormap);
+}
+
+
+static gint
+gdk_offscreen_window_get_depth (GdkDrawable *drawable)
+{
+  GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
+
+  return gdk_drawable_get_depth (offscreen->wrapper);
+}
+
+static void
+gdk_offscreen_window_get_size (GdkDrawable *drawable,
+			       gint         *width,
+			       gint         *height)
+{
+  GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
+
+  if (width)
+    *width = offscreen->width;
+  if (height)
+    *height = offscreen->height;
+}
+
+static GdkScreen*
+gdk_offscreen_window_get_screen (GdkDrawable *drawable)
+{
+  GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
+  
+  return offscreen->screen;
+}
+
+static GdkVisual*
+gdk_offscreen_window_get_visual (GdkDrawable    *drawable)
+{
+  GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
+  
+  return gdk_drawable_get_visual (offscreen->wrapper);
+}
+
+static void
+gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
+{
+  GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  
+  object_class->finalize = gdk_offscreen_window_finalize;
+
+  drawable_class->create_gc = gdk_offscreen_window_create_gc;
+  drawable_class->_copy_to_image = gdk_offscreen_window_copy_to_image;
+  drawable_class->ref_cairo_surface = gdk_offscreen_window_ref_cairo_surface;
+  drawable_class->set_colormap = gdk_offscreen_window_set_colormap;
+  drawable_class->get_colormap = gdk_offscreen_window_get_colormap;
+  drawable_class->get_depth = gdk_offscreen_window_get_depth;
+  drawable_class->get_size = gdk_offscreen_window_get_size;
+  drawable_class->get_screen = gdk_offscreen_window_get_screen;
+  drawable_class->get_visual = gdk_offscreen_window_get_visual;
+  drawable_class->get_clip_region = gdk_offscreen_window_get_visible_region;
+  drawable_class->get_visible_region = gdk_offscreen_window_get_visible_region;
+
+  /* All actual rendering is done in gdkwindow.c with the redirect */
+  drawable_class->draw_drawable = (gpointer)gdk_offscreen_window_empty_draw_op;
+  drawable_class->draw_rectangle = (gpointer)gdk_offscreen_window_empty_draw_op;
+  drawable_class->draw_points = (gpointer)gdk_offscreen_window_empty_draw_op;
+  drawable_class->draw_arc = (gpointer)gdk_offscreen_window_empty_draw_op;
+  drawable_class->draw_polygon = (gpointer)gdk_offscreen_window_empty_draw_op;
+  drawable_class->draw_text = (gpointer)gdk_offscreen_window_empty_draw_op;
+  drawable_class->draw_text_wc = (gpointer)gdk_offscreen_window_empty_draw_op;
+  drawable_class->draw_segments = (gpointer)gdk_offscreen_window_empty_draw_op;
+  drawable_class->draw_lines = (gpointer)gdk_offscreen_window_empty_draw_op;
+  drawable_class->draw_image = (gpointer)gdk_offscreen_window_empty_draw_op;
+  drawable_class->draw_pixbuf = (gpointer)gdk_offscreen_window_empty_draw_op;
+}
+
+static void
+recompute_abs_positions (GdkWindow *window,
+			 gint       parent_x,
+                         gint       parent_y,
+			 gint       parent_llim_x,
+                         gint       parent_llim_y,
+			 gint       parent_lim_x,
+                         gint       parent_lim_y)
+{
+  GdkWindowObject *private = (GdkWindowObject *) window;
+  GdkOffscreenWindow *offscreen;
+  GList *l;
+  gint x, y;
+  
+  if (!GDK_WINDOW_IS_MAPPED (window))
+    return;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+  
+  offscreen->abs_x = parent_x + private->x;
+  offscreen->abs_y = parent_y + private->y;
+
+  x = MAX (parent_llim_x, offscreen->abs_x);
+  x = MIN (x, parent_lim_x);
+  offscreen->llim_x = x;
+
+  y = MAX (parent_llim_y, offscreen->abs_y);
+  y = MIN (y, parent_lim_y);
+  offscreen->llim_y = y;
+
+  x = MIN (parent_lim_x, offscreen->abs_x + offscreen->width);
+  x = MAX (x, offscreen->llim_x);
+  offscreen->lim_x = x;
+
+  y = MIN (parent_lim_y, offscreen->abs_y + offscreen->height);
+  y = MAX (y, offscreen->llim_y);
+  offscreen->lim_y = y;
+  
+  g_assert (offscreen->llim_x <= offscreen->lim_x);
+  g_assert (offscreen->llim_y <= offscreen->lim_y);
+  
+  for (l = private->children; l; l = l->next)
+    recompute_abs_positions (l->data,
+			     offscreen->abs_x, offscreen->abs_y,
+			     offscreen->llim_x, offscreen->llim_y,
+			     offscreen->lim_x, offscreen->lim_y);
+}
+
+
+static void
+recompute_window (GdkWindow *window)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkOffscreenWindow *offscreen, *parent_offscreen;
+  GdkWindowObject *parent_private;
+  GList *l;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+
+  if (offscreen->toplevel_offscreen == offscreen)
+    {
+      offscreen->abs_x = 0;
+      offscreen->abs_y = 0;
+      offscreen->llim_x = 0;
+      offscreen->llim_y = 0;
+      offscreen->lim_x = offscreen->width;
+      offscreen->lim_y = offscreen->height;
+
+      for (l = private->children; l; l = l->next)
+	recompute_abs_positions (l->data,
+				 offscreen->abs_x, offscreen->abs_y,
+				 offscreen->llim_x, offscreen->llim_y,
+				 offscreen->lim_x, offscreen->lim_y);
+    }
+  else
+    {
+      parent_private = private->parent;
+      parent_offscreen = GDK_OFFSCREEN_WINDOW (parent_private->impl);
+      recompute_abs_positions (window,
+			       parent_offscreen->abs_x,
+			       parent_offscreen->abs_y,
+			       parent_offscreen->llim_x,
+			       parent_offscreen->llim_y,
+			       parent_offscreen->lim_x,
+			       parent_offscreen->lim_y);
+    }
+}
+
+
+/**
+ * gdk_window_new_offscreen:
+ * @parent: a #GdkWindow
+ * @attributes: attributes of the new window
+ * @attributes_mask: mask indicating which fields in @attributes are valid
+ * 
+ * Creates a new offscreen #GdkWindow child using the attributes from 
+ * @attributes. See #GdkWindowAttr and #GdkWindowAttributesType for
+ * more details.
+
+ * Being offscreen means that the window will not automatically
+ * rendered to the parent window, instead it is drawn to a pixmap that
+ * is availible with gdk_window_get_offscreen_pixmap(). You can use
+ * this pixmap to render the window however you want. When the
+ * offscreen pixmap is drawn into, damage events are sent to the
+ * window, so the GtkWidget::damage_event signal handler can be used
+ * to make sure the parent window is updated.
+ *
+ * All children of an offscreen window are automatically turned into
+ * offscreen windows that share the offscreen pixmap with the window
+ * created using gdk_window_new_offscreen(). You can nest offscreen
+ * windows, but at least one ancestor must be a non-offscreen window.
+ *
+ * To correctly support offscreen children a parent window should
+ * catch the GdkWindow::find-offscreen-child signal on the parent
+ * window. Additionally, if you render the child transformed you need
+ * to implement GdkWindow::parent-to-window-coordinate and
+ * GdkWindow::window-to-parent-coordinate to get coordinates correct
+ * in e.g. pointer events.
+ *
+ * Offscreen windows have some limitations:
+ * <itemizedlist>
+ * <listitem><para>They can't be toplevel windows.</para></listitem>
+ * <listitem><para>They can't contain foreign windows, nor be children
+ * of foreign windows. This means #GtkPlug/#GtkSocket do not work
+ * with them.</para></listitem>
+ * <listitem><para>X specific features like XVideo and GLX doesn't
+ * work.</para></listitem>
+ * <listitem><para>All rendering must be done inside 
+ * gdk_window_begin_paint_region() and gdk_window_end_paint()
+ * calls.</para></listitem>
+ * <listitem><para>The confine_window argument of pointer grabs
+ * does not work</para></listitem>
+ * <listitem><para>The %GDK_POINTER_MOTION_HINT_MASK mask is not
+ * effective</para></listitem>
+ * <listitem><para>You can't reparent between offscreen windows and
+ * normal windows</para></listitem>
+ * </itemizedlist>
+ * 
+ * 
+ * Return value: the new #GdkWindow
+ **/
+GdkWindow*
+gdk_window_new_offscreen (GdkWindow     *parent,
+			  GdkWindowAttr *attributes,
+			  gint           attributes_mask)
+{
+  return _gdk_window_new_offscreen (parent, attributes, attributes_mask, TRUE);
+}
+
+GdkWindow*
+_gdk_window_new_offscreen (GdkWindow     *parent,
+			   GdkWindowAttr *attributes,
+			   gint           attributes_mask,
+			   gboolean       toplevel)
+{
+  GdkWindow *window;
+  GdkWindowObject *parent_private;
+  GdkWindowObject *private;
+  GdkOffscreenWindow *offscreen;
+  int x, y;
+  GdkScreen *screen;
+  GdkVisual *visual;
+
+  g_return_val_if_fail (attributes != NULL, NULL);
+  
+  if (parent == NULL ||
+      (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT) ||
+      (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN) ||
+      (attributes->window_type != GDK_WINDOW_CHILD) )
+    {
+      g_warning ("Only child offscreen windows allowed");
+      return NULL;
+    }
+
+  if (GDK_WINDOW_DESTROYED (parent))
+    return NULL;
+  
+  parent_private = (GdkWindowObject*) parent;
+  
+  window = g_object_new (GDK_TYPE_WINDOW, NULL);
+  private = (GdkWindowObject *)window;
+  private->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+  offscreen->wrapper = window;
+
+  private->parent = (GdkWindowObject *)parent;
+  
+  screen = gdk_drawable_get_screen (parent);
+
+  offscreen->screen = screen;
+  
+  if (attributes_mask & GDK_WA_X)
+    x = attributes->x;
+  else
+    x = 0;
+  
+  if (attributes_mask & GDK_WA_Y)
+    y = attributes->y;
+  else
+    y = 0;
+  
+  private->x = x;
+  private->y = y;
+  offscreen->width = (attributes->width > 1) ? (attributes->width) : (1);
+  offscreen->height = (attributes->height > 1) ? (attributes->height) : (1);
+
+  private->window_type = GDK_WINDOW_CHILD;
+
+  if (attributes_mask & GDK_WA_VISUAL)
+    visual = attributes->visual;
+  else
+    visual = gdk_screen_get_system_visual (screen);
+
+  private->event_mask = attributes->event_mask;
+  
+  if (attributes->wclass == GDK_INPUT_OUTPUT)
+    {
+      private->input_only = FALSE;
+      private->depth = visual->depth;
+
+      if (attributes_mask & GDK_WA_COLORMAP)
+        offscreen->colormap = g_object_ref (attributes->colormap);
+      else
+	{
+	  if (gdk_screen_get_system_visual (screen) == visual)
+            {
+	      offscreen->colormap = gdk_screen_get_system_colormap (screen);
+              g_object_ref (offscreen->colormap);
+            }
+	  else
+            offscreen->colormap = gdk_colormap_new (visual, FALSE);
+	}
+
+      private->bg_color.red = private->bg_color.green = private->bg_color.blue = 0;
+      private->bg_color.pixel = 0; 
+      private->bg_pixmap = NULL;
+    }
+  else
+    {
+      private->depth = 0;
+      private->input_only = TRUE;
+      offscreen->colormap = gdk_screen_get_system_colormap (screen);
+      g_object_ref (offscreen->colormap);
+    }
+
+  if (private->parent)
+    {
+      private->parent->children = g_list_prepend (private->parent->children, window);
+      
+      if (toplevel)
+	_gdk_window_add_offscreen_child (GDK_WINDOW (private->parent));
+    }
+  
+  /* Inherit redirection from parent */
+  private->redirect = private->parent->redirect;
+  
+  if (toplevel)
+    {
+      GdkPixmap *pixmap;
+      
+      offscreen->toplevel_offscreen = offscreen;
+      offscreen->abs_x = 0;
+      offscreen->abs_y = 0;
+      offscreen->llim_x = 0;
+      offscreen->llim_y = 0;
+      offscreen->lim_x = offscreen->width;
+      offscreen->lim_y = offscreen->height;
+
+      pixmap = gdk_pixmap_new (parent,
+			       offscreen->width,
+			       offscreen->height,
+			       private->depth);
+      gdk_window_redirect_to_drawable (window,
+				       pixmap, 0, 0, 0, 0,
+				       offscreen->width,
+				       offscreen->height);
+      g_object_unref (pixmap);
+    }
+  else
+    {
+      GdkOffscreenWindow *parent_offscreen = GDK_OFFSCREEN_WINDOW (parent_private->impl);
+
+      offscreen->toplevel_offscreen = parent_offscreen->toplevel_offscreen;
+      recompute_abs_positions (window,
+			       parent_offscreen->abs_x, parent_offscreen->abs_y,
+			       parent_offscreen->llim_x, parent_offscreen->llim_y,
+			       parent_offscreen->lim_x, parent_offscreen->lim_y);
+    }
+
+
+  return window;
+}
+
+static gboolean
+gdk_offscreen_window_reparent (GdkWindow *window,
+			       GdkWindow *new_parent,
+			       gint       x,
+			       gint       y)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkWindowObject *new_parent_private = (GdkWindowObject *)new_parent;
+  GdkOffscreenWindow *offscreen;
+  gboolean was_mapped;
+
+  /* Can't reparent offscreen window to toplevel */
+  if (!new_parent)
+    return FALSE;
+
+  if (!gdk_window_is_offscreen (new_parent))
+    {
+      g_warning ("Can't reparent offscreen window to native parent");
+      return FALSE;
+    }
+
+  /* No input-output children of input-only windows */
+  if (new_parent_private->input_only && !private->input_only)
+    return FALSE;
+
+  /* Don't create loops in hierarchy */
+  if (is_parent_of (window, new_parent))
+    return FALSE;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+
+  was_mapped = GDK_WINDOW_IS_MAPPED (window);
+  
+  gdk_window_hide (window);
+
+  if (private->parent)
+    {
+      private->parent->children = g_list_remove (private->parent->children, window);
+      if (offscreen->toplevel_offscreen == offscreen)
+	_gdk_window_remove_offscreen_child (GDK_WINDOW (private->parent));
+    }
+
+  private->parent = new_parent_private;
+  private->x = x;
+  private->y = y;
+  
+  private->parent->children = g_list_prepend (private->parent->children, window);
+  if (offscreen->toplevel_offscreen == offscreen)
+    _gdk_window_add_offscreen_child (GDK_WINDOW (private->parent));
+  else
+    {
+      GdkOffscreenWindow *parent_offscreen = GDK_OFFSCREEN_WINDOW (new_parent_private->impl);
+
+      offscreen->toplevel_offscreen = parent_offscreen->toplevel_offscreen;
+      recompute_abs_positions (window,
+			       parent_offscreen->abs_x, parent_offscreen->abs_y,
+			       parent_offscreen->llim_x, parent_offscreen->llim_y,
+			       parent_offscreen->lim_x, parent_offscreen->lim_y);
+    }
+
+  return was_mapped;
+}
+
+/**
+ * gdk_window_is_offscreen:
+ * @window: a #GdkWindow
+ *
+ * Returns: %TRUE if the window is an offscreen window
+ **/
+gboolean
+gdk_window_is_offscreen (GdkWindow *window)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+
+  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+
+  return GDK_IS_OFFSCREEN_WINDOW (private->impl);
+}
+
+gboolean
+_gdk_window_is_toplevel_offscreen (GdkWindow *window)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkOffscreenWindow *offscreen;
+
+  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+
+  if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
+    return FALSE;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+
+  return offscreen->toplevel_offscreen == offscreen;
+}
+
+
+/**
+ * gdk_window_get_offscreen_pixmap:
+ * @window: a #GdkWindow
+ *
+ * Gets the offscreen pixmap that an offscreen window renders into. If
+ * you need to keep this around over window resizes, you need to add a
+ * reference to it.
+ * 
+ * Returns: The offscreen pixmap, or NULL if not offscreen
+ **/
+GdkPixmap *
+gdk_window_get_offscreen_pixmap (GdkWindow *window)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+
+  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+
+  if (!GDK_IS_OFFSCREEN_WINDOW (private->impl))
+    return NULL;
+  
+  return private->redirect->pixmap;
+}
+
+static void
+offscreen_visible_rect (GdkOffscreenWindow *offscreen,
+                        GdkRectangle       *rect)
+{
+  rect->x = offscreen->llim_x - offscreen->abs_x;
+  rect->y = offscreen->llim_y - offscreen->abs_y;
+  rect->width = offscreen->lim_x - offscreen->llim_x;
+  rect->height = offscreen->lim_y - offscreen->llim_y;
+}
+
+static GdkRegion *
+gdk_offscreen_window_get_visible_region (GdkDrawable *drawable)
+{
+  GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (drawable);
+  GdkRectangle rect;
+
+  offscreen_visible_rect (offscreen, &rect);
+
+  return gdk_region_rectangle (&rect);
+}
+
+static void
+gdk_offscreen_window_invalidate_visible (GdkWindow *window)
+{
+  GdkRectangle r;
+
+  offscreen_visible_rect (window, &r);
+  gdk_window_invalidate_rect (window, &r, TRUE);
+}
+
+static void
+gdk_offscreen_window_raise (GdkWindow *window)
+{
+  /* gdk_window_raise already changed the stacking order */
+  gdk_offscreen_window_invalidate_visible (window);
+}
+
+static void
+gdk_offscreen_window_invalidate_in_parent (GdkWindowObject *private)
+{
+  GdkRectangle r, child;
+  GdkOffscreenWindow *offscreen;
+  
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+  
+  offscreen_visible_rect (GDK_WINDOW (private->parent), &r);
+  
+  child.x = private->x;
+  child.y = private->y;
+  child.width = offscreen->width;
+  child.height = offscreen->height;
+  
+  gdk_rectangle_intersect (&r, &child, &r);
+  
+  gdk_window_invalidate_rect (GDK_WINDOW (private->parent), &r, TRUE);
+}
+
+
+static void
+gdk_offscreen_window_lower (GdkWindow *window)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkOffscreenWindow *offscreen;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+  
+  /* gdk_window_lower already changed the stacking order */
+
+  /* Invalidate the rect */
+  if (offscreen->toplevel_offscreen != offscreen)
+    gdk_offscreen_window_invalidate_in_parent (private);
+}
+
+static void
+send_pointer_events_for_geometry_change (GdkWindow *window)
+{
+  GdkWindow *mousewin, *event_window;
+  GdkWindowOffscreenChildren *offscreen_children;
+  
+  event_window = _gdk_window_get_offscreen_event_window (window);
+  offscreen_children = GDK_WINDOW_OBJECT (event_window)->offscreen_children;
+  /* The window the pointer is in might have changed */
+  if (offscreen_children->window_under_pointer != NULL)
+    {
+      mousewin = _gdk_window_get_offscreen_window_child_at (event_window,
+							    offscreen_children->last_mouse_x,
+							    offscreen_children->last_mouse_y,
+							    NULL, NULL);
+      send_crossing_events (offscreen_children,
+			    event_window,
+			    offscreen_children->window_under_pointer, mousewin,
+			    GDK_CROSSING_NORMAL,
+			    offscreen_children->last_mouse_x, offscreen_children->last_mouse_y,
+			    offscreen_children->last_state, GDK_CURRENT_TIME,
+			    TRUE, TRUE);
+    }
+}
+
+static void
+gdk_offscreen_window_move_region (GdkWindow       *window,
+                                  const GdkRegion *region,
+                                  gint             dx,
+                                  gint             dy)
+{
+  GdkRegion *dest_region;
+  
+  dest_region = gdk_region_copy (region);
+  gdk_region_offset (dest_region, dx, dy);
+
+  /* Really cheesy implementation that just exposes
+     both regions */
+  gdk_window_invalidate_region (window, region, FALSE);
+  gdk_window_invalidate_region (window, dest_region, FALSE);
+  
+}
+
+static void
+gdk_offscreen_window_scroll (GdkWindow *window,
+			     gint       dx,
+			     gint       dy)
+{
+  GdkWindowObject *obj = GDK_WINDOW_OBJECT (window);
+  GList *tmp_list;
+  
+  /* Move the current invalid region */
+  if (obj->update_area)
+    gdk_region_offset (obj->update_area, dx, dy);
+
+/* We currently scroll in a pretty lame way, we move all
+   the subwindows, then re-expose the whole window */
+  
+  tmp_list = obj->children;
+  while (tmp_list)
+    {
+      GdkWindow *child = GDK_WINDOW (tmp_list->data);
+      GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child);
+
+      child_obj->x += dx;
+      child_obj->y += dx;
+      recompute_window (child);
+      
+      tmp_list = tmp_list->next;
+    }
+
+  gdk_window_invalidate_rect (window, NULL, TRUE);
+  send_pointer_events_for_geometry_change (window);
+}
+
+static void
+gdk_offscreen_window_move_resize_internal (GdkWindow *window,
+					   gint       x,
+					   gint       y,
+					   gint       width,
+					   gint       height,
+					   gboolean   send_expose_events)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkOffscreenWindow *offscreen, *toplevel;
+  gint dx, dy, dw, dh;
+  GdkRegion *old_region;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+  toplevel = offscreen->toplevel_offscreen;
+
+  if (width < 1)
+    width = 1;
+  if (height < 1)
+    height = 1;
+
+  if (private->destroyed)
+    return;
+
+  if (private->input_only)
+    send_expose_events = FALSE;
+
+  old_region = NULL;
+  if (GDK_WINDOW_IS_MAPPED (private) && send_expose_events)
+    {
+      old_region = _gdk_window_calculate_full_clip_region (window,
+							   toplevel->wrapper,
+							   NULL, FALSE,
+							   NULL, NULL);
+      /* Adjust region to parent window coords */
+      gdk_region_offset (old_region, private->x, private->y);
+    }
+  
+  dx = x - private->x;
+  dy = y - private->y;
+  dw = width - offscreen->width;
+  dh = height - offscreen->height;
+  
+  private->x = x;
+  private->y = y;
+  offscreen->width = width;
+  offscreen->height = height;
+  
+  if (GDK_WINDOW_IS_MAPPED (private))
+    {
+      recompute_window (window);
+
+      if (send_expose_events)
+	{
+	  if (offscreen == toplevel)
+	    {
+	      if (dw != 0 || dh != 0)
+		{
+		  GdkGC *gc;
+		  GdkPixmap *old_pixmap;
+		  
+		  old_pixmap = private->redirect->pixmap;
+		  private->redirect->pixmap = gdk_pixmap_new (GDK_DRAWABLE (old_pixmap),
+							      offscreen->width,
+							      offscreen->height,
+							      private->depth);
+		  private->redirect->width = offscreen->width;
+		  private->redirect->height = offscreen->height;
+		  
+		  gc = _gdk_drawable_get_scratch_gc (private->redirect->pixmap, FALSE);
+		  gdk_draw_drawable (private->redirect->pixmap,
+				     gc,
+				     old_pixmap,
+				     0,0, 0, 0,
+				     -1, -1);
+		  g_object_unref (old_pixmap);
+		  
+		}
+	      gdk_window_invalidate_rect (window, NULL, TRUE);
+	    }
+	  else
+	    {
+	      GdkRegion *new_region;
+	      
+	      new_region = _gdk_window_calculate_full_clip_region (window,
+								   toplevel->wrapper,
+								   NULL, FALSE,
+								   NULL, NULL);
+	      /* Adjust region to parent window coords */
+	      gdk_region_offset (new_region, private->x, private->y);
+	      gdk_region_union (new_region, old_region);
+	      
+	      /* Here we could optimize by copying areas that overlaps both
+	       * new_region and old_region, but we just expose everything instead */
+	      
+	      /* Invalidate regions in new_region */
+	      gdk_window_invalidate_region (GDK_WINDOW (private->parent), new_region, TRUE);
+	      
+	      gdk_region_destroy (new_region);
+	    }
+	}
+
+      send_pointer_events_for_geometry_change (window);
+    }
+
+  if (old_region != NULL)
+    gdk_region_destroy (old_region);
+
+}
+
+static void
+gdk_offscreen_window_move (GdkWindow *window,
+			   gint x, gint y)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkOffscreenWindow *offscreen;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+  
+  gdk_offscreen_window_move_resize_internal (window, x, y,
+					     offscreen->width,
+					     offscreen->height,
+					     TRUE);
+}
+
+static void
+gdk_offscreen_window_resize (GdkWindow *window,
+			     gint width, gint height)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkOffscreenWindow *offscreen;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+  
+  gdk_offscreen_window_move_resize_internal (window,
+					     private->x, private->y,
+					     width,
+					     height,
+					     TRUE);
+}
+
+static void
+gdk_offscreen_window_move_resize (GdkWindow *window,
+				  gint x, gint y,
+				  gint width, gint height)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkOffscreenWindow *offscreen;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+  
+  gdk_offscreen_window_move_resize_internal (window, x, y,
+					     width, height,
+					     TRUE);
+}
+
+static gboolean
+all_parents_shown (GdkWindowObject *private)
+{
+  private = (GdkWindowObject *)private->parent;
+  
+  while (private != NULL &&
+	 GDK_WINDOW_IS_MAPPED (private) &&
+	 GDK_IS_OFFSCREEN_WINDOW (private->impl))
+    {
+      private = (GdkWindowObject *)private->parent;
+    }
+
+  return
+    private == NULL || !GDK_IS_OFFSCREEN_WINDOW (private->impl);
+}
+
+static const guint type_masks[] = {
+  GDK_SUBSTRUCTURE_MASK, /* GDK_DELETE		= 0, */
+  GDK_STRUCTURE_MASK, /* GDK_DESTROY		= 1, */
+  GDK_EXPOSURE_MASK, /* GDK_EXPOSE		= 2, */
+  GDK_POINTER_MOTION_MASK, /* GDK_MOTION_NOTIFY	= 3, */
+  GDK_BUTTON_PRESS_MASK, /* GDK_BUTTON_PRESS	= 4, */
+  GDK_BUTTON_PRESS_MASK, /* GDK_2BUTTON_PRESS	= 5, */
+  GDK_BUTTON_PRESS_MASK, /* GDK_3BUTTON_PRESS	= 6, */
+  GDK_BUTTON_RELEASE_MASK, /* GDK_BUTTON_RELEASE	= 7, */
+  GDK_KEY_PRESS_MASK, /* GDK_KEY_PRESS	= 8, */
+  GDK_KEY_RELEASE_MASK, /* GDK_KEY_RELEASE	= 9, */
+  GDK_ENTER_NOTIFY_MASK, /* GDK_ENTER_NOTIFY	= 10, */
+  GDK_LEAVE_NOTIFY_MASK, /* GDK_LEAVE_NOTIFY	= 11, */
+  GDK_FOCUS_CHANGE_MASK, /* GDK_FOCUS_CHANGE	= 12, */
+  GDK_STRUCTURE_MASK, /* GDK_CONFIGURE		= 13, */
+  GDK_VISIBILITY_NOTIFY_MASK, /* GDK_MAP		= 14, */
+  GDK_VISIBILITY_NOTIFY_MASK, /* GDK_UNMAP		= 15, */
+  GDK_PROPERTY_CHANGE_MASK, /* GDK_PROPERTY_NOTIFY	= 16, */
+  GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_CLEAR	= 17, */
+  GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_REQUEST = 18, */
+  GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_NOTIFY	= 19, */
+  GDK_PROXIMITY_IN_MASK, /* GDK_PROXIMITY_IN	= 20, */
+  GDK_PROXIMITY_OUT_MASK, /* GDK_PROXIMITY_OUT	= 21, */
+  GDK_ALL_EVENTS_MASK, /* GDK_DRAG_ENTER        = 22, */
+  GDK_ALL_EVENTS_MASK, /* GDK_DRAG_LEAVE        = 23, */
+  GDK_ALL_EVENTS_MASK, /* GDK_DRAG_MOTION       = 24, */
+  GDK_ALL_EVENTS_MASK, /* GDK_DRAG_STATUS       = 25, */
+  GDK_ALL_EVENTS_MASK, /* GDK_DROP_START        = 26, */
+  GDK_ALL_EVENTS_MASK, /* GDK_DROP_FINISHED     = 27, */
+  GDK_ALL_EVENTS_MASK, /* GDK_CLIENT_EVENT	= 28, */
+  GDK_VISIBILITY_NOTIFY_MASK, /* GDK_VISIBILITY_NOTIFY = 29, */
+  GDK_EXPOSURE_MASK, /* GDK_NO_EXPOSE		= 30, */
+  GDK_SCROLL_MASK /* GDK_SCROLL            = 31 */
+  /* Later additions: */
+  /* GDK_WINDOW_STATE      = 32 */
+  /* GDK_SETTING           = 33 */
+  /* GDK_OWNER_CHANGE      = 34 */
+  /* GDK_GRAB_BROKEN       = 35 */
+};
+
+static GdkWindow *
+get_target_window_for_event (GdkWindow *window,
+			     GdkEventType type,
+			     gboolean recurse)
+{
+  guint32 evmask;
+  GdkWindow *w;
+  gboolean was_offscreen;
+
+  w = window;
+  while (w != NULL && GDK_WINDOW_OBJECT (w)->window_type != GDK_WINDOW_ROOT)
+    {
+      evmask = GDK_WINDOW_OBJECT (w)->event_mask;
+
+      if (evmask & type_masks[type])
+	return w;
+
+      if (!recurse)
+	break;
+
+      /* skip over parent of toplevel, to avoid event recursion */
+      was_offscreen = gdk_window_is_offscreen (w);
+      w = gdk_window_get_parent (w);
+      if (was_offscreen && !gdk_window_is_offscreen (w))
+	w = gdk_window_get_parent (w);
+    }
+  
+  return NULL;
+}
+
+/* send motion events if the right buttons are down */
+static guint
+update_evmask_for_button_motion (guint           evmask,
+                                 GdkModifierType mask)
+{
+  if ((evmask & GDK_BUTTON_MOTION_MASK) &&
+      (mask & (GDK_BUTTON1_MASK |
+	       GDK_BUTTON2_MASK |
+	       GDK_BUTTON3_MASK |
+	       GDK_BUTTON4_MASK |
+	       GDK_BUTTON5_MASK)))
+    evmask |= GDK_POINTER_MOTION_MASK;
+  
+  if (((evmask & GDK_BUTTON1_MOTION_MASK) && (mask & GDK_BUTTON1_MASK)) ||
+      ((evmask & GDK_BUTTON2_MOTION_MASK) && (mask & GDK_BUTTON2_MASK)) ||
+      ((evmask & GDK_BUTTON3_MOTION_MASK) && (mask & GDK_BUTTON3_MASK)))
+    evmask |= GDK_POINTER_MOTION_MASK;
+  
+  return evmask;
+}
+
+static GdkWindow *
+get_target_window_for_pointer_event (GdkWindowOffscreenChildren *offscreen_children,
+				     GdkWindow *window,
+				     GdkEventType type,
+				     GdkModifierType mask)
+{
+  guint evmask;
+  gboolean crossing_event;
+  GdkWindow *w, *grab_window;
+
+  /* crossing events don't propagate up like other types of events */
+  crossing_event = (type == GDK_ENTER_NOTIFY || type == GDK_LEAVE_NOTIFY);
+
+  if ((offscreen_children->pointer_grab_window != NULL &&
+       !offscreen_children->pointer_grab_owner_events) ||
+      (type == GDK_BUTTON_RELEASE &&
+       offscreen_children->grab_one_pointer_release_event))
+    {
+      evmask = offscreen_children->pointer_grab_event_mask;
+      evmask = update_evmask_for_button_motion (evmask, mask);
+
+      if (type == GDK_BUTTON_RELEASE &&
+	  offscreen_children->grab_one_pointer_release_event)
+	{
+	  grab_window = offscreen_children->grab_one_pointer_release_event;
+	  offscreen_children->grab_one_pointer_release_event = NULL;
+	}
+      else
+	grab_window = offscreen_children->pointer_grab_window;
+      
+      if ((evmask & type_masks[type]) &&
+          (!crossing_event || window == grab_window))
+	return grab_window;
+      else
+	return NULL;
+    }
+
+  w = window;
+  while (w != NULL)
+    {
+      evmask = GDK_WINDOW_OBJECT(window)->event_mask;
+      evmask = update_evmask_for_button_motion (evmask, mask);
+
+      if (evmask & type_masks[type])
+	return w;
+
+      if (crossing_event)
+	break;
+
+      w = gdk_window_get_parent (w);
+    }
+
+  if (offscreen_children->pointer_grab_window != NULL &&
+      offscreen_children->pointer_grab_owner_events)
+    {
+      evmask = offscreen_children->pointer_grab_event_mask;
+      evmask = update_evmask_for_button_motion (evmask, mask);
+      
+      if ((evmask & type_masks[type]) &&
+	  (!crossing_event || window == offscreen_children->pointer_grab_window))
+	return offscreen_children->pointer_grab_window;
+      else
+	return NULL;
+    }
+
+  return NULL;
+}
+
+static GdkEvent *
+make_gdk_event (GdkWindow    *window,
+		GdkEventType  type,
+		GdkEvent     *append_after)
+{
+  GdkEvent *event = gdk_event_new (type);
+  guint32 the_time;
+
+  the_time = gdk_event_get_time (append_after);
+  
+  event->any.window = g_object_ref (window);
+  event->any.send_event = FALSE;
+  switch (type)
+    {
+    case GDK_MOTION_NOTIFY:
+      event->motion.time = the_time;
+      event->motion.axes = NULL;
+      break;
+    case GDK_BUTTON_PRESS:
+    case GDK_2BUTTON_PRESS:
+    case GDK_3BUTTON_PRESS:
+    case GDK_BUTTON_RELEASE:
+      event->button.time = the_time;
+      event->button.axes = NULL;
+      break;
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+      event->key.time = the_time;
+      break;
+    case GDK_ENTER_NOTIFY:
+    case GDK_LEAVE_NOTIFY:
+      event->crossing.time = the_time;
+      break;
+      
+    case GDK_PROPERTY_NOTIFY:
+      event->property.time = the_time;
+      break;
+      
+    case GDK_SELECTION_CLEAR:
+    case GDK_SELECTION_REQUEST:
+    case GDK_SELECTION_NOTIFY:
+      event->selection.time = the_time;
+      break;
+    case GDK_PROXIMITY_IN:
+    case GDK_PROXIMITY_OUT:
+      event->proximity.time = the_time;
+      break;
+    case GDK_DRAG_ENTER:
+    case GDK_DRAG_LEAVE:
+    case GDK_DRAG_MOTION:
+    case GDK_DRAG_STATUS:
+    case GDK_DROP_START:
+    case GDK_DROP_FINISHED:
+      event->dnd.time = the_time;
+      break;
+      
+    case GDK_FOCUS_CHANGE:
+    case GDK_CONFIGURE:
+    case GDK_MAP:
+    case GDK_UNMAP:
+    case GDK_CLIENT_EVENT:
+    case GDK_VISIBILITY_NOTIFY:
+    case GDK_NO_EXPOSE:
+    case GDK_SCROLL:
+    case GDK_DELETE:
+    case GDK_DESTROY:
+    case GDK_EXPOSE:
+    default:
+      break;
+    }
+
+  if (append_after)
+    _gdk_event_queue_append_after (gdk_drawable_get_display (window), append_after, event);
+  else
+    _gdk_event_queue_append (gdk_drawable_get_display (window), event);
+  
+  return event;
+}
+
+static void
+send_map_events (GdkWindowObject *private)
+{
+  GList *l;
+  GdkWindowObject *parent_private = private->parent;
+  GdkWindow *event_win;
+  GdkOffscreenWindow *offscreen, *parent_offscreen;
+  
+  if (!GDK_WINDOW_IS_MAPPED (private))
+    return;
+
+  event_win = get_target_window_for_event ((GdkWindow *)private, GDK_MAP, FALSE);
+  if (event_win)
+    make_gdk_event (event_win, GDK_MAP, NULL);
+  
+  if (private->input_only)
+    return;
+
+  if (!parent_private)
+    parent_private = private;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+  if (GDK_IS_OFFSCREEN_WINDOW (parent_private->impl))
+    {
+      parent_offscreen = GDK_OFFSCREEN_WINDOW (parent_private->impl);
+      
+      if (((offscreen->abs_x > parent_offscreen->lim_x) ||
+	   (offscreen->abs_y > parent_offscreen->lim_y) ||
+	   (offscreen->lim_x < parent_offscreen->llim_x) ||
+	   (offscreen->lim_y < parent_offscreen->llim_y)))
+	return;
+    }
+
+  gdk_window_clear ((GdkWindow *)private);
+
+  for (l = private->children; l; l = l->next)
+    send_map_events (l->data);
+}
+
+static void
+gdk_offscreen_window_show (GdkWindow *window, gboolean raise)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkOffscreenWindow *offscreen;
+
+  if (GDK_WINDOW_IS_MAPPED (window))
+    return;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+
+  private->state = 0;
+
+  /* gdk_window_show already changed the stacking order if needed */
+  
+  if (all_parents_shown (private))
+    {
+      recompute_window (window);
+      
+      send_map_events (private);
+      send_pointer_events_for_geometry_change (window);
+      
+      if (private->input_only)
+	return;
+
+      gdk_window_clear_area_e (window, 0, 0,
+			       offscreen->width, offscreen->height);
+    }
+}
+
+
+static void
+gdk_offscreen_window_hide (GdkWindow *window)
+{
+  GdkWindowObject *private;
+  GdkWindow *event_win;
+  GdkOffscreenWindow *offscreen;
+  GdkWindow *grab_window;
+  
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowObject*) window;
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+
+  if (GDK_WINDOW_IS_MAPPED (private))
+    {
+      GdkEvent *event;
+      GdkRectangle r;
+      GdkDisplay *display;
+
+      /* May need to break grabs on children */
+      display = gdk_drawable_get_display (window);
+      if (gdk_pointer_grab_info_libgtk_only (display,
+					     &grab_window, NULL))
+	{
+	  if (is_parent_of (window, grab_window))
+	    {
+	      _gdk_offscreen_window_unset_pointer_grab (grab_window, FALSE, FALSE, GDK_CURRENT_TIME);
+	      gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
+	      _gdk_windowing_grab_broken (display);
+	    }
+	}
+      
+      event_win = get_target_window_for_event (window, GDK_UNMAP, FALSE);
+      if (event_win)
+	event = make_gdk_event (event_win, GDK_UNMAP, NULL);
+      
+      r.x = offscreen->llim_x;
+      r.y = offscreen->llim_y;
+      r.width = offscreen->lim_x - r.x;
+      r.height = offscreen->lim_y - r.y;
+
+      private->state = GDK_WINDOW_STATE_WITHDRAWN;
+
+      send_pointer_events_for_geometry_change (window);
+      
+      /* Invalidate the rect */
+      if (offscreen->toplevel_offscreen != offscreen)
+	gdk_offscreen_window_invalidate_in_parent (private);
+    }
+}
+
+static void
+gdk_offscreen_window_withdraw (GdkWindow *window)
+{
+}
+
+static GdkEventMask  
+gdk_offscreen_window_get_events (GdkWindow *window)
+{
+  return GDK_WINDOW_OBJECT (window)->event_mask;
+}
+
+static void          
+gdk_offscreen_window_set_events (GdkWindow       *window,
+				 GdkEventMask     event_mask)
+{
+  GDK_WINDOW_OBJECT (window)->event_mask = event_mask;
+}
+
+
+static void
+gdk_offscreen_window_clear_area (GdkWindow *window,
+				 gint       x,
+				 gint       y,
+				 gint       width,
+				 gint       height,
+				 gboolean   send_expose)
+{
+  GdkRectangle visible, rect;
+
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  /* Actual drawing is done by gdkwindow.c */
+  
+  if (send_expose)
+    {
+      offscreen_visible_rect (window, &visible);
+
+      rect.x = x;
+      rect.y = x;
+      rect.width = width;
+      rect.height = height;
+      gdk_rectangle_intersect (&rect, &visible, &rect);
+      
+      gdk_window_invalidate_rect (window, &rect, TRUE);
+    }
+}
+
+static void
+gdk_offscreen_window_set_background (GdkWindow      *window,
+				     const GdkColor *color)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkColormap *colormap = gdk_drawable_get_colormap (window);
+  
+  private->bg_color = *color;
+  gdk_colormap_query_color (colormap, private->bg_color.pixel, &private->bg_color);
+
+  if (private->bg_pixmap &&
+      private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
+      private->bg_pixmap != GDK_NO_BG)
+    g_object_unref (private->bg_pixmap);
+  
+  private->bg_pixmap = NULL;
+}
+
+static void
+gdk_offscreen_window_set_back_pixmap (GdkWindow *window,
+				      GdkPixmap *pixmap,
+				      gboolean   parent_relative)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (pixmap == NULL || !parent_relative);
+  g_return_if_fail (pixmap == NULL || gdk_drawable_get_depth (window) == gdk_drawable_get_depth (pixmap));
+
+  if (pixmap && !gdk_drawable_get_colormap (pixmap))
+    {
+      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)
+    g_object_unref (private->bg_pixmap);
+
+  if (parent_relative)
+    private->bg_pixmap = GDK_PARENT_RELATIVE_BG;
+  else
+    {
+      if (pixmap)
+	{
+	  g_object_ref (pixmap);
+	  private->bg_pixmap = pixmap;
+	}
+      else
+	private->bg_pixmap = GDK_NO_BG;
+    }
+}
+
+static void
+gdk_offscreen_window_get_offsets (GdkWindow *window,
+				  gint      *x_offset,
+				  gint      *y_offset)
+{
+  *x_offset = 0;
+  *y_offset = 0;
+}
+
+static GdkWindow *
+gdk_offscreen_window_get_window_at (GdkWindow *window,
+				    gdouble    x,
+                                    gdouble    y,
+				    gdouble   *win_x,
+                                    gdouble   *win_y)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkOffscreenWindow *offscreen;
+  GdkWindow *return_val;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+  
+  return_val = NULL;
+  
+  if ((x >= 0) && (x < offscreen->width) &&
+      (y >= 0) && (y < offscreen->height))
+    {
+      GdkWindowObject *sub;
+      GdkOffscreenWindow *sub_offscreen;
+      gdouble subx = x, suby = y;
+
+      for (sub = private; sub; private = sub)
+	{
+	  GList *ltmp;
+
+	  /* This assumes children is ordered in reverse stack order */
+	  for (ltmp = private->children; ltmp; ltmp = ltmp->next)
+	    {
+	      sub = ltmp->data;
+
+	      if (!GDK_WINDOW_IS_MAPPED (sub))
+		continue;
+
+	      sub_offscreen = GDK_OFFSCREEN_WINDOW (sub->impl);
+	      
+	      if (subx >= sub->x &&
+		  (subx < (sub_offscreen->width + sub->x)) &&
+		  (suby >= sub->y) &&
+		  (suby < (sub_offscreen->height + sub->y)))
+		{
+		  subx -= sub->x;
+		  suby -= sub->y;
+		  break;
+		}
+	    }
+
+	  if (!ltmp)
+	    {
+	      sub = NULL;
+	      break;
+	    }
+	}
+
+      if (win_x)
+	*win_x = subx;
+      if (win_y)
+	*win_y = suby;
+
+      return_val = (GdkWindow *)private;
+    }
+  
+  return return_val;
+}
+
+GdkWindow *
+_gdk_window_get_offscreen_window_child_at (GdkWindow *parent,
+					   gdouble    x,
+					   gdouble    y,
+					   gdouble   *win_x_out,
+					   gdouble   *win_y_out)
+{
+  GdkWindow *target;
+  GdkWindow *child;
+  GdkWindowObject *parent_private;
+  gdouble win_x, win_y;
+
+  parent_private = GDK_WINDOW_OBJECT (parent);
+  if (parent_private && parent_private->offscreen_children)
+    {
+      child = find_offscreen_child (parent, x, y);
+      if (child)
+	{
+	  parent_to_window (child, x, y, &win_x, &win_y);
+	  target = gdk_offscreen_window_get_window_at (child,
+                                                       win_x, win_y,
+                                                       &win_x, &win_y);
+	  return _gdk_window_get_offscreen_window_child_at (target,
+                                                            win_x, win_y,
+                                                            win_x_out, win_y_out);
+	}
+    }
+
+  if (win_x_out)
+    *win_x_out = x;
+  if (win_y_out)
+    *win_y_out = y;
+  
+  return parent;
+}
+
+static GdkWindow *
+find_common_ancestor (GdkWindow *win1,
+		      GdkWindow *win2)
+{
+  GdkWindowObject *tmp;
+  GList *path1 = NULL, *path2 = NULL;
+  GList *list1, *list2;
+  
+  tmp = GDK_WINDOW_OBJECT (win1);
+  while (tmp) 
+    {
+      path1 = g_list_prepend (path1, tmp);
+      tmp = tmp->parent;
+    }
+
+  tmp = GDK_WINDOW_OBJECT (win2);
+  while (tmp) 
+    {
+      path2 = g_list_prepend (path2, tmp);
+      tmp = tmp->parent;
+    }
+  
+  list1 = path1;
+  list2 = path2;
+  tmp = NULL;
+  while (list1 && list2 && (list1->data == list2->data)) 
+    {
+      tmp = (GdkWindowObject *)list1->data;
+      list1 = g_list_next (list1);
+      list2 = g_list_next (list2);
+    }
+  g_list_free (path1);
+  g_list_free (path2);
+  
+  return GDK_WINDOW (tmp);
+}
+
+
+/* x, y are in toplevel coords */
+static void
+send_crossing_events (GdkWindowOffscreenChildren *offscreen_children,
+		      GdkWindow *event_window,
+		      GdkWindow *src,
+		      GdkWindow *dest,
+		      GdkCrossingMode mode,
+		      int event_x, int event_y,
+		      GdkModifierType mask,
+		      guint32 time_,
+		      gboolean do_first,
+                      gboolean do_last)
+{
+  GdkWindow *c;
+  GdkWindow *win, *last, *next;
+  GdkEvent *event;
+  GList *path, *list;
+  gboolean non_linear;
+  GdkWindow *a;
+  GdkWindow *b;
+  GdkWindow *event_win;
+
+  if ((mode == GDK_CROSSING_NORMAL) &&
+      (dest == offscreen_children->window_under_pointer))
+    return;
+
+  if (src)
+    a = src;
+  else
+    a = event_window;
+
+  if (dest)
+    b = dest;
+  else
+    b = event_window;
+
+  if (a == b)
+    return;
+
+  c = find_common_ancestor (a, b);
+  if (c == NULL)
+    return;
+
+  non_linear = (c != a) && (c != b);
+
+  event_win = get_target_window_for_pointer_event (offscreen_children, a, GDK_LEAVE_NOTIFY, mask);
+  if (do_first && event_win)
+    {
+      event = make_gdk_event (event_win, GDK_LEAVE_NOTIFY, NULL);
+      event->crossing.time = time_;
+      event->crossing.subwindow = NULL;
+      convert_event_coords_to_window (event_window,
+				      event_win, event_x, event_y,
+				      &event->crossing.x, &event->crossing.y);
+      event->crossing.x_root = event_x;
+      event->crossing.y_root = event_y;
+      event->crossing.mode = mode;
+      if (non_linear)
+	event->crossing.detail = GDK_NOTIFY_NONLINEAR;
+      else if (c == a)
+	event->crossing.detail = GDK_NOTIFY_INFERIOR;
+      else
+	event->crossing.detail = GDK_NOTIFY_ANCESTOR;
+      event->crossing.focus = FALSE;
+      event->crossing.state = mask;
+    }
+  
+  /* Traverse up from a to (excluding) c */
+  if (c != a)
+    {
+      last = a;
+      win = GDK_WINDOW (GDK_WINDOW_OBJECT (a)->parent);
+      while (win != c)
+	{
+	  event_win = get_target_window_for_pointer_event (offscreen_children, win, GDK_LEAVE_NOTIFY, mask);
+	  if (event_win)
+	    {
+	      event = make_gdk_event (event_win, GDK_LEAVE_NOTIFY, NULL);
+	      event->crossing.time = time_;
+	      event->crossing.subwindow = g_object_ref (last);
+	      convert_event_coords_to_window (event_window,
+					      event_win, event_x, event_y,
+					      &event->crossing.x, &event->crossing.y);
+	      event->crossing.x_root = event_x;
+	      event->crossing.y_root = event_y;
+	      event->crossing.mode = mode;
+	      if (non_linear)
+		event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
+	      else
+		event->crossing.detail = GDK_NOTIFY_VIRTUAL;
+	      event->crossing.focus = FALSE;
+	      event->crossing.state = mask;
+	    }
+	  last = win;
+	  win = GDK_WINDOW (GDK_WINDOW_OBJECT (win)->parent);
+	}
+    }
+  
+  /* Traverse down from c to b */
+  if (c != b) 
+    {
+      path = NULL;
+      win = GDK_WINDOW (GDK_WINDOW_OBJECT (b)->parent);
+      while (win != c)
+	{
+	  path = g_list_prepend (path, win);
+	  win = GDK_WINDOW( GDK_WINDOW_OBJECT (win)->parent);
+	}
+      
+      list = path;
+      while (list) 
+	{
+	  win = (GdkWindow *)list->data;
+	  list = g_list_next (list);
+	  if (list)
+	    next = (GdkWindow *)list->data;
+	  else 
+	    next = b;
+	  
+	  event_win = get_target_window_for_pointer_event (offscreen_children, win, GDK_ENTER_NOTIFY, mask);
+	  if (event_win)
+	    {
+	      event = make_gdk_event (event_win, GDK_ENTER_NOTIFY, NULL);
+	      event->crossing.time = time_;
+	      event->crossing.subwindow = g_object_ref (next);
+	      convert_event_coords_to_window (event_window,
+					      event_win, event_x, event_y,
+					      &event->crossing.x, &event->crossing.y);
+	      event->crossing.x_root = event_x;
+	      event->crossing.y_root = event_y;
+	      event->crossing.mode = mode;
+	      if (non_linear)
+		event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
+	      else
+		event->crossing.detail = GDK_NOTIFY_VIRTUAL;
+	      event->crossing.focus = FALSE;
+	      event->crossing.state = mask;
+	    }
+	}
+      g_list_free (path);
+    }
+
+  event_win = get_target_window_for_pointer_event (offscreen_children, b, GDK_ENTER_NOTIFY, mask);
+  if (do_last && event_win)
+    {
+      event = make_gdk_event (event_win, GDK_ENTER_NOTIFY, NULL);
+      event->crossing.time = time_;
+      event->crossing.subwindow = NULL;
+      convert_event_coords_to_window (event_window,
+				      event_win, event_x, event_y,
+				      &event->crossing.x, &event->crossing.y);
+      event->crossing.x_root = event_x;
+      event->crossing.y_root = event_y;
+      event->crossing.mode = mode;
+      if (non_linear)
+	event->crossing.detail = GDK_NOTIFY_NONLINEAR;
+      else if (c == a)
+	event->crossing.detail = GDK_NOTIFY_ANCESTOR;
+      else
+	event->crossing.detail = GDK_NOTIFY_INFERIOR;
+      event->crossing.focus = FALSE;
+      event->crossing.state = mask;
+    }
+
+  if (mode != GDK_CROSSING_GRAB &&
+      mode != GDK_CROSSING_UNGRAB &&
+      dest != offscreen_children->window_under_pointer)
+    {
+      if (offscreen_children->window_under_pointer)
+	g_object_unref (offscreen_children->window_under_pointer);
+      offscreen_children->window_under_pointer = NULL;
+      if (dest)
+	offscreen_children->window_under_pointer = g_object_ref (dest);
+    }
+}
+
+/* Find the first enclosing non-offscreen window.
+ * This window is the one used to get events to the
+ * offscreen windows
+ */
+GdkWindow *
+_gdk_window_get_offscreen_event_window (GdkWindow *window)
+{
+  GdkWindowObject *private;
+  GdkOffscreenWindow *offscreen;
+  GdkWindow *toplevel;
+
+  while (window != NULL && gdk_window_is_offscreen (window))
+    {
+      private = (GdkWindowObject *)window;
+      offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+      toplevel = offscreen->toplevel_offscreen->wrapper;
+      window = GDK_WINDOW (GDK_WINDOW_OBJECT (toplevel)->parent);
+    }
+  
+  return window;
+}
+
+static void
+convert_event_coords_to_window (GdkWindow *event_window,
+				GdkWindow *window,
+				gdouble    event_x,
+                                gdouble    event_y,
+				gdouble   *window_x,
+                                gdouble   *window_y)
+{
+  GdkOffscreenWindow *offscreen, *toplevel_offscreen;
+  GdkWindow *toplevel_parent;
+
+  if (event_window == window)
+    {
+      *window_x = event_x;
+      *window_y = event_y;
+      return;
+    }
+  
+  offscreen = GDK_OFFSCREEN_WINDOW (GDK_WINDOW_OBJECT (window)->impl);
+  
+  toplevel_offscreen = offscreen->toplevel_offscreen;
+  toplevel_parent = GDK_WINDOW (GDK_WINDOW_OBJECT (toplevel_offscreen->wrapper)->parent);
+  if (toplevel_parent != event_window)
+    convert_event_coords_to_window (event_window,
+				    toplevel_parent,
+				    event_x, event_y,
+				    &event_x, &event_y);
+  
+  /* Convert to toplevel coords */
+  parent_to_window (toplevel_offscreen->wrapper, event_x, event_y,
+		    &event_x, &event_y);
+  /* Convert to window coords */
+  *window_x = event_x - offscreen->abs_x;
+  *window_y = event_y - offscreen->abs_y;
+}
+
+static void
+convert_window_coords_to_event (GdkWindow *event_window,
+				GdkWindow *window,
+				gdouble    window_x,
+                                gdouble    window_y,
+				gdouble   *event_x,
+                                gdouble   *event_y)
+{
+  GdkOffscreenWindow *offscreen, *toplevel_offscreen;
+  GdkWindow *toplevel_parent;
+
+  offscreen = GDK_OFFSCREEN_WINDOW (GDK_WINDOW_OBJECT (window)->impl);
+  toplevel_offscreen = offscreen->toplevel_offscreen;
+  toplevel_parent = GDK_WINDOW (GDK_WINDOW_OBJECT (toplevel_offscreen->wrapper)->parent);
+
+  /* Convert to toplevel coords */
+  window_x += offscreen->abs_x;
+  window_y += offscreen->abs_y;
+
+  /* Convert to parent toplevel coords */
+  window_to_parent (toplevel_offscreen->wrapper,
+		    window_x, window_y,
+		    &window_x, &window_y);
+  if (toplevel_parent != event_window)
+    convert_window_coords_to_event (event_window,
+				    toplevel_parent,
+				    window_x, window_y,
+				    &window_x, &window_y);
+  *event_x = window_x;
+  *event_y = window_y;
+}
+
+
+static gboolean
+proxy_pointer_event (GdkWindow                  *pointer_window,
+		     gdouble                     event_x,
+                     gdouble                     event_y,
+		     GdkEvent                   *source_event,
+		     GdkWindowOffscreenChildren *offscreen_children)
+{
+  GdkWindow *event_win, *cursor_window;
+  gboolean crossing_event;
+  gboolean sent_motion;
+  GdkEvent *event;
+  guint state;
+  guint32 time_;
+  
+  gdk_event_get_state (source_event, &state);
+  time_ = gdk_event_get_time (source_event);
+
+  crossing_event =
+    source_event->type == GDK_ENTER_NOTIFY ||
+    source_event->type == GDK_LEAVE_NOTIFY;
+  if (crossing_event)
+    {
+      GdkEventCrossing *crossing = &source_event->crossing;
+
+      if (crossing->mode == GDK_CROSSING_GRAB)
+	{
+	  if (crossing->type == GDK_LEAVE_NOTIFY &&
+	      offscreen_children->window_under_pointer != NULL)
+	    {
+	      send_crossing_events (offscreen_children, source_event->any.window,
+				    offscreen_children->window_under_pointer,
+				    NULL,
+				    GDK_CROSSING_GRAB,
+				    event_x, event_y, state, time_,
+				    TRUE, FALSE);
+	    }
+	  if (crossing->type == GDK_ENTER_NOTIFY &&
+	      offscreen_children->pointer_grab_window != NULL)
+	    {
+	      send_crossing_events (offscreen_children, source_event->any.window,
+				    NULL, offscreen_children->pointer_grab_window,
+				    GDK_CROSSING_GRAB,
+				    event_x, event_y, state, time_,
+				    FALSE, TRUE);
+	    }
+	}
+      
+      if (crossing->mode == GDK_CROSSING_UNGRAB)
+	{
+	  if (crossing->type == GDK_LEAVE_NOTIFY &&
+	      offscreen_children->pointer_grab_window != NULL)
+	    {
+	      send_crossing_events (offscreen_children, source_event->any.window,
+				    offscreen_children->pointer_grab_window,
+				    NULL,
+				    GDK_CROSSING_UNGRAB,
+                                    event_x, event_y, state, time_,
+				    TRUE, FALSE);
+	    }
+	  if (crossing->type == GDK_ENTER_NOTIFY &&
+	      offscreen_children->window_under_pointer != NULL)
+	    {
+	      send_crossing_events (offscreen_children, source_event->any.window,
+				    NULL,
+				    offscreen_children->window_under_pointer,
+				    GDK_CROSSING_UNGRAB,
+				    event_x, event_y, state, time_,
+				    FALSE, TRUE);
+	    }
+	}
+    }
+  
+  cursor_window = pointer_window;
+  if (offscreen_children->pointer_grab_window &&
+      (pointer_window == NULL ||
+       !is_parent_of (offscreen_children->pointer_grab_window, pointer_window)))
+    cursor_window = offscreen_children->pointer_grab_window;
+  
+  /* TODO: set cursor from cursor_window, or grab cursor */
+
+  sent_motion = FALSE;
+  if (!crossing_event &&
+      (offscreen_children->window_under_pointer == pointer_window ||
+       (offscreen_children->pointer_grab_window != NULL &&
+	!offscreen_children->pointer_grab_owner_events)))
+    {
+      /* send motion events */
+      event_win = get_target_window_for_pointer_event (offscreen_children, pointer_window, GDK_MOTION_NOTIFY, state);
+      if (event_win)
+	{
+	  sent_motion = TRUE;
+	  event = make_gdk_event (event_win, GDK_MOTION_NOTIFY, source_event);
+	  event->motion.time = time_;
+	  convert_event_coords_to_window (source_event->any.window,
+					  event_win, event_x, event_y,
+					  &event->motion.x, &event->motion.y);
+	  event->motion.x_root = event_x; /* TODO: right? */
+	  event->motion.y_root = event_y;
+	  event->motion.state = state;
+	  event->motion.is_hint = FALSE;
+	  event->motion.device = NULL;
+	  if (source_event && source_event->type == GDK_MOTION_NOTIFY)
+	    event->motion.device = source_event->motion.device;
+	}
+    }
+
+  send_crossing_events (offscreen_children,
+			source_event->any.window,
+			offscreen_children->window_under_pointer,
+			pointer_window,
+			GDK_CROSSING_NORMAL,
+			event_x, event_y,
+			state, time_,
+			TRUE, TRUE);
+
+
+  /* unlink move event from parent if we sent a motion event */
+  return source_event->type == GDK_MOTION_NOTIFY && sent_motion;
+}
+
+static gboolean
+is_button_type (GdkEventType type)
+{
+  return type == GDK_BUTTON_PRESS ||
+         type == GDK_2BUTTON_PRESS ||
+         type == GDK_3BUTTON_PRESS ||
+         type == GDK_BUTTON_RELEASE;
+}
+
+static gboolean
+is_motion_type (GdkEventType type)
+{
+  return type == GDK_MOTION_NOTIFY ||
+         type == GDK_ENTER_NOTIFY ||
+         type == GDK_LEAVE_NOTIFY;
+}
+
+static gboolean
+proxy_button_event (GdkWindow *pointer_window,
+		    gdouble event_x, gint event_y,
+		    GdkEvent *source_event,
+		    GdkWindowOffscreenChildren *offscreen_children)
+{
+  GdkWindow *event_win;
+  GdkEvent *event;
+  guint state;
+  guint32 time_;
+  GdkEventType type;
+  
+  type = source_event->any.type;
+  gdk_event_get_state (source_event, &state);
+  time_ = gdk_event_get_time (source_event);
+
+  if (type == GDK_BUTTON_PRESS && pointer_window != NULL)
+    _gdk_windowing_update_implicit_grab (source_event->any.window,
+                                         pointer_window,
+                                         gdk_window_get_events (pointer_window),
+                                         time_);
+  
+  event_win = get_target_window_for_pointer_event (offscreen_children,
+                                                   pointer_window,
+                                                   type,
+                                                   state);
+  if (event_win && event_win != source_event->any.window)
+    {
+      event = make_gdk_event (event_win, type, source_event);
+      event->button.time = time_;
+      event->button.button = source_event->button.button;
+      convert_event_coords_to_window (source_event->any.window,
+				      event_win, event_x, event_y,
+				      &event->button.x, &event->button.y);
+      event->button.x_root = event_x;
+      event->button.y_root = event_y;
+      event->button.state = state;
+      event->button.device = NULL;
+      if (source_event && is_button_type (type))
+	event->button.device = source_event->button.device;
+      return TRUE;
+    }
+  return FALSE;
+}
+
+static gint
+gdk_offscreen_window_get_origin (GdkWindow *window,
+				 gint      *x,
+				 gint      *y)
+{
+  GdkWindow *event_window;
+  int parent_x, parent_y;
+  gdouble event_x, event_y;
+
+  event_window = _gdk_window_get_offscreen_event_window (window);
+
+  convert_window_coords_to_event (event_window, window,
+				  0.0, 0.0,
+                                  &event_x, &event_y);
+  
+  gdk_window_get_origin (event_window, &parent_x, &parent_y);
+
+  if (x)
+    *x = floor (event_x + 0.5) + parent_x;
+  if (y)
+    *y = floor (event_y + 0.5) + parent_y;
+  
+  return TRUE;
+}
+
+static void
+gdk_offscreen_window_shape_combine_mask (GdkWindow *window,
+                                         GdkBitmap *mask,
+                                         gint       x,
+                                         gint       y)
+{
+}
+
+static void
+gdk_offscreen_window_shape_combine_region (GdkWindow       *window,
+                                           const GdkRegion *shape_region,
+                                           gint             offset_x,
+                                           gint             offset_y)
+{
+}
+
+static void
+gdk_offscreen_window_set_child_shapes (GdkWindow *window)
+{
+}
+
+static void
+gdk_offscreen_window_merge_child_shapes (GdkWindow *window)
+{
+}
+
+static gboolean 
+gdk_offscreen_window_set_static_gravities (GdkWindow *window,
+					   gboolean   use_static)
+{
+  return TRUE;
+}
+
+static void
+gdk_offscreen_window_set_cursor (GdkWindow *window,
+				 GdkCursor *cursor)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkOffscreenWindow *offscreen;
+  
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+
+  if (offscreen->cursor)
+    {
+      gdk_cursor_unref (offscreen->cursor);
+      offscreen->cursor = NULL;
+    }
+
+  if (cursor)
+    offscreen->cursor = gdk_cursor_ref (cursor);
+
+  /* TODO: The cursor is never actually used... */
+}
+
+static void
+gdk_offscreen_window_get_geometry (GdkWindow *window,
+				   gint      *x,
+				   gint      *y,
+				   gint      *width,
+				   gint      *height,
+				   gint      *depth)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkOffscreenWindow *offscreen;
+  
+  offscreen = GDK_OFFSCREEN_WINDOW (private->impl);
+  
+  g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
+  
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      if (x)
+	*x = private->x;
+      if (y)
+	*y = private->y;
+      if (width)
+	*width = offscreen->width;
+      if (height)
+	*height = offscreen->width;
+      if (depth)
+	*depth = private->depth;
+    }
+}
+
+void
+_gdk_offscreen_window_transform_coords (GdkWindow       *event_window,
+					GdkWindow       *relative_window,
+					gint            *x,
+					gint            *y)
+{
+  gdouble window_x, window_y;
+  
+  if (relative_window != event_window)
+    {
+      /* The relative window is an offscreen window */
+      convert_event_coords_to_window (event_window, relative_window,
+				      *x, *y,
+				      &window_x, &window_y);
+      *x = floor (window_x + 0.5);
+      *y = floor (window_y + 0.5);
+    }
+}
+
+void
+_gdk_offscreen_window_set_pointer_grab (GdkWindow *old_grab_window,
+					GdkWindow *old_native_grab_window,
+					GdkWindow *grab_window,
+					gboolean owner_events,
+					guint event_mask,
+					guint32 time_)
+{
+  GdkDisplay *display;
+  GdkWindow *crossing_start, *event_window;
+  GdkWindowOffscreenChildren *offscreen_children;
+  gint wx, wy;
+
+  display = gdk_drawable_get_display (grab_window);
+  event_window = _gdk_window_get_offscreen_event_window (grab_window);
+  offscreen_children = GDK_WINDOW_OBJECT (event_window)->offscreen_children;
+
+  /* Normal GRAB events are sent by listening for enter and leave
+   * events on the parent of the toplevel, which is then proxied
+   * into the offscreen where we create them. However, there are two
+   * cases where X will not send these events:
+   * * When there is already a grab on the parent of the toplevel
+   *   offscreen grab window 
+   * * When there is no grab, but the pointer is already in the
+   *   parent of the toplevel offscreen grab window
+   * In these cases we need to generate our own grab crossing events.
+   */
+  crossing_start = NULL;
+  if (old_grab_window != NULL && old_native_grab_window == event_window)
+    crossing_start = old_grab_window;
+  
+  if (old_grab_window == NULL &&
+      _gdk_windowing_window_at_pointer (display, &wx, &wy) == event_window)
+    crossing_start = offscreen_children->window_under_pointer;
+  
+  if (crossing_start != NULL)
+    {
+      /* TODO: Hmmm, is this totally right if start is in another toplevel? */
+      send_crossing_events (offscreen_children,
+			    event_window,
+			    crossing_start, 
+			    grab_window,
+			    GDK_CROSSING_GRAB,
+			    /* These may be stale... */
+			    offscreen_children->last_mouse_x,
+			    offscreen_children->last_mouse_y,
+			    offscreen_children->last_state,
+			    time_, TRUE, TRUE);
+    }
+
+
+  /* TODO: What about the case of grabbing the toplevel parent, when
+     an offscreen child of it is grabbed or has the pointer? */
+  
+  if (offscreen_children->pointer_grab_window != NULL)
+    g_object_unref (offscreen_children->pointer_grab_window);
+
+  offscreen_children->pointer_grab_window = g_object_ref (grab_window);
+  offscreen_children->pointer_grab_owner_events = owner_events;
+  offscreen_children->pointer_grab_event_mask = event_mask;
+}
+
+void
+_gdk_offscreen_window_unset_pointer_grab (GdkWindow *window,
+					  gboolean regrab,
+					  gboolean grab_one_pointer_release_event,
+					  guint32 time_)
+{
+  GdkWindow *event_window;
+  GdkWindowOffscreenChildren *offscreen_children;
+  GdkDisplay *display;
+  gint wx, wy;
+
+  display = gdk_drawable_get_display (window);
+  event_window = _gdk_window_get_offscreen_event_window (window);
+  offscreen_children = GDK_WINDOW_OBJECT (event_window)->offscreen_children;
+
+  g_assert (offscreen_children->pointer_grab_window != NULL);
+
+  if (grab_one_pointer_release_event)
+    offscreen_children->grab_one_pointer_release_event = offscreen_children->pointer_grab_window;
+
+  g_object_unref (offscreen_children->pointer_grab_window);
+  offscreen_children->pointer_grab_window = NULL;
+
+  /* Normal UNGRAB events are sent by listening for enter and leave
+   * events on the parent of the toplevel, which is then proxied
+   * into the offscreen where we create them. However, there are two
+   * cases where X will not send these events:
+   * * When this ungrab is due to a new grab on the parent of the toplevel
+   *   offscreen grab window.
+   * * When there is no new grab, and the pointer is already in the
+   *   parent of the toplevel offscreen grab window
+   * In the first case we send the right GRAB events from the grab, but
+   * in the second case we need to generate our own UNGRAB crossing events.
+   */
+  if (!regrab &&
+      _gdk_windowing_window_at_pointer (display, &wx, &wy) == event_window)
+    {
+      GdkWindow *crossing_end = offscreen_children->window_under_pointer;
+      
+      send_crossing_events (offscreen_children, event_window,
+			    window, 
+			    crossing_end,
+			    GDK_CROSSING_UNGRAB,
+			    /* These may be stale... */
+			    offscreen_children->last_mouse_x,
+			    offscreen_children->last_mouse_y,
+			    offscreen_children->last_state,
+			    time_, TRUE, TRUE);
+    }
+}
+
+void
+_gdk_event_rewrite_for_offscreen (GdkDisplay *display,
+				  GList      *event_link,
+				  GdkEvent   *event)
+{
+  GdkWindow *event_window;
+  GdkWindow *pointer_window;
+  GdkWindowObject *event_private;
+  GdkWindowOffscreenChildren *offscreen_children;
+  gboolean is_grab;
+  gdouble x,y;
+  gboolean unlink_event;
+  
+  event_window = event->any.window;
+  event_private = GDK_WINDOW_OBJECT (event_window);
+  if (!event_window || !event_private->offscreen_children)
+    return;
+
+  if (!(is_button_type (event->type) || is_motion_type (event->type)))
+    return;
+
+  offscreen_children = event_private->offscreen_children;
+
+  gdk_event_get_coords (event, &x, &y);
+  offscreen_children->last_mouse_x = x;
+  offscreen_children->last_mouse_y = y;
+  
+  gdk_event_get_state (event, &offscreen_children->last_state);
+
+  pointer_window = _gdk_window_get_offscreen_window_child_at (event_window,
+                                                              x, y,
+                                                              NULL, NULL);
+  if (pointer_window == event_window)
+    pointer_window = NULL;
+  
+  is_grab = FALSE;
+  if (offscreen_children->pointer_grab_window)
+    is_grab = TRUE;
+
+  unlink_event = FALSE;
+  if (is_motion_type (event->type))
+    unlink_event = proxy_pointer_event (pointer_window, x, y,
+                                        event,
+                                        offscreen_children);
+
+  if (is_button_type (event->type))
+    unlink_event = proxy_button_event (pointer_window, x, y,
+                                       event,
+                                       offscreen_children);
+
+  if (unlink_event)
+    {
+      _gdk_event_queue_remove_link (display, event_link);
+      g_list_free_1 (event_link);
+      gdk_event_free (event);
+    }
+}
+
+/**
+ * gdk_window_set_offscreen_hooks:
+ * @window: a #GdkWindow
+ * @hooks: a table of pointers to functions for handling offscreen
+ *   window coordinates translations
+ *
+ * Sets the parent-to-window and window-to-parent coordinates
+ * translation functions for offscreen windows.
+ *
+ * This function is useful for complex widgets employing
+ * offscreen windows.
+ */
+void
+gdk_window_set_offscreen_hooks (GdkWindow               *window,
+                                const GdkOffscreenHooks *hooks)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (hooks != NULL);
+
+  private = (GdkWindowObject *) window;
+
+  private->offscreen_hooks = hooks;
+}
+
+static void
+gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
+{
+  iface->show = gdk_offscreen_window_show;
+  iface->hide = gdk_offscreen_window_hide;
+  iface->withdraw = gdk_offscreen_window_withdraw;
+  iface->raise = gdk_offscreen_window_raise;
+  iface->lower = gdk_offscreen_window_lower;
+  iface->move = gdk_offscreen_window_move;
+  iface->resize = gdk_offscreen_window_resize;
+  iface->move_resize = gdk_offscreen_window_move_resize;
+  iface->scroll = gdk_offscreen_window_scroll;
+  iface->move_region = gdk_offscreen_window_move_region;
+  iface->set_background = gdk_offscreen_window_set_background;
+  iface->set_back_pixmap = gdk_offscreen_window_set_back_pixmap;
+  iface->get_events = gdk_offscreen_window_get_events;
+  iface->set_events = gdk_offscreen_window_set_events;
+  iface->clear_area = gdk_offscreen_window_clear_area;
+  iface->reparent = gdk_offscreen_window_reparent;
+  iface->set_cursor = gdk_offscreen_window_set_cursor;
+  iface->get_geometry = gdk_offscreen_window_get_geometry;
+  iface->get_origin = gdk_offscreen_window_get_origin;
+  iface->shape_combine_mask = gdk_offscreen_window_shape_combine_mask;
+  iface->shape_combine_region = gdk_offscreen_window_shape_combine_region;
+  iface->set_child_shapes = gdk_offscreen_window_set_child_shapes;
+  iface->merge_child_shapes = gdk_offscreen_window_merge_child_shapes;
+  iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
+  iface->get_offsets = gdk_offscreen_window_get_offsets;
+}
diff --git a/gdk/gdkpixmap.c b/gdk/gdkpixmap.c
index fdd9764..52da86d 100644
--- a/gdk/gdkpixmap.c
+++ b/gdk/gdkpixmap.c
@@ -229,6 +229,48 @@ gdk_pixmap_finalize (GObject *object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+GdkPixmap *
+gdk_pixmap_new (GdkDrawable *drawable,
+                gint         width,
+                gint         height,
+                gint         depth)
+{
+  GdkDrawable *source_drawable;
+
+  source_drawable = _gdk_drawable_get_source_drawable (drawable);
+  return _gdk_pixmap_new (source_drawable, width, height, depth);
+}
+
+GdkPixmap *
+gdk_bitmap_create_from_data (GdkDrawable *drawable,
+                             const gchar *data,
+                             gint         width,
+                             gint         height)
+{
+  GdkDrawable *source_drawable;
+
+  source_drawable = _gdk_drawable_get_source_drawable (drawable);
+  return _gdk_bitmap_create_from_data (source_drawable, data, width, height);
+}
+
+GdkPixmap*
+gdk_pixmap_create_from_data (GdkDrawable    *drawable,
+                             const gchar    *data,
+                             gint            width,
+                             gint            height,
+                             gint            depth,
+                             const GdkColor *fg,
+                             const GdkColor *bg)
+{
+  GdkDrawable *source_drawable;
+
+  source_drawable = _gdk_drawable_get_source_drawable (drawable);
+  return _gdk_pixmap_create_from_data (source_drawable,
+                                       data, width, height,
+                                       depth, fg,bg);
+}
+
+
 static GdkGC *
 gdk_pixmap_create_gc (GdkDrawable     *drawable,
                       GdkGCValues     *values,
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 323450a..c055b6b 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -27,6 +27,7 @@
 
 #include <config.h>
 #include "gdkwindow.h"
+#include "gdkwindowimpl.h"
 #include "gdkinternals.h"
 #include "gdk.h"		/* For gdk_rectangle_union() */
 #include "gdkpixmap.h"
@@ -47,6 +48,14 @@ struct _GdkWindowPaint
   cairo_surface_t *surface;
 };
 
+typedef struct {
+  GdkRegion *old_region;
+  gint old_clip_x_origin;
+  gint old_clip_y_origin;
+  gint x_offset;
+  gint y_offset;
+} GdkWindowClipData;
+
 static GdkGC *gdk_window_create_gc      (GdkDrawable     *drawable,
                                          GdkGCValues     *values,
                                          GdkGCValuesMask  mask);
@@ -171,6 +180,7 @@ static void         gdk_window_real_set_colormap (GdkDrawable *drawable,
 						  GdkColormap *cmap);
 static GdkColormap* gdk_window_real_get_colormap (GdkDrawable *drawable);
 
+static GdkDrawable* gdk_window_get_source_drawable    (GdkDrawable *drawable);
 static GdkDrawable* gdk_window_get_composite_drawable (GdkDrawable *drawable,
 						       gint         x,
 						       gint         y,
@@ -182,6 +192,7 @@ static GdkRegion*   gdk_window_get_clip_region        (GdkDrawable *drawable);
 static GdkRegion*   gdk_window_get_visible_region     (GdkDrawable *drawable);
 
 static void gdk_window_free_paint_stack (GdkWindow *window);
+static void gdk_window_raise_internal   (GdkWindow *window);
 
 static void gdk_window_init       (GdkWindowObject      *window);
 static void gdk_window_class_init (GdkWindowObjectClass *klass);
@@ -191,6 +202,17 @@ static void gdk_window_clear_backing_rect (GdkWindow *window,
 					   gint       y,
 					   gint       width,
 					   gint       height);
+static void setup_redirect_clip           (GdkWindow         *window,
+					   GdkGC             *gc,
+					   GdkWindowClipData *data);
+static void reset_redirect_clip           (GdkWindow         *offscreen,
+					   GdkGC             *gc,
+					   GdkWindowClipData *data);
+static void gdk_window_redirect_free      (GdkWindowRedirect *redirect);
+static void apply_redirect_to_children    (GdkWindowObject   *private,
+					   GdkWindowRedirect *redirect);
+static void remove_redirect_from_children (GdkWindowObject   *private,
+					   GdkWindowRedirect *redirect);
 
 static gpointer parent_class = NULL;
 
@@ -243,8 +265,6 @@ gdk_window_init (GdkWindowObject *window)
   window->window_type = GDK_WINDOW_CHILD;
 
   window->state = GDK_WINDOW_STATE_WITHDRAWN;
-  
-  window->impl = g_object_new (_gdk_window_impl_get_type (), NULL);
 }
 
 static void
@@ -283,6 +303,7 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
   drawable_class->get_clip_region = gdk_window_get_clip_region;
   drawable_class->get_visible_region = gdk_window_get_visible_region;
   drawable_class->get_composite_drawable = gdk_window_get_composite_drawable;
+  drawable_class->get_source_drawable = gdk_window_get_source_drawable;
 }
 
 static void
@@ -311,6 +332,96 @@ gdk_window_finalize (GObject *object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+/**
+ * gdk_window_new:
+ * @parent: a #GdkWindow, or %NULL to create the window as a child of
+ *   the default root window for the default display.
+ * @attributes: attributes of the new window
+ * @attributes_mask: mask indicating which fields in @attributes are valid
+ * 
+ * Creates a new #GdkWindow using the attributes from
+ * @attributes. See #GdkWindowAttr and #GdkWindowAttributesType for
+ * more details.  Note: to use this on displays other than the default
+ * display, @parent must be specified.
+ * 
+ * Return value: the new #GdkWindow
+ **/
+GdkWindow*
+gdk_window_new (GdkWindow     *parent,
+		GdkWindowAttr *attributes,
+		gint           attributes_mask)
+{
+  GdkWindow *window;
+  GdkWindowObject *private, *parent_private;
+  
+  g_return_val_if_fail (attributes != NULL, NULL);
+
+  if (parent && gdk_window_is_offscreen (parent))
+    window = _gdk_window_new_offscreen (parent, attributes, attributes_mask, FALSE);
+  else
+    window = _gdk_window_new (parent, attributes, attributes_mask);
+
+  /* Inherit redirection from parent */
+  if (parent != NULL)
+    {
+      parent_private = GDK_WINDOW_OBJECT (parent);
+      private = GDK_WINDOW_OBJECT (window);
+      private->redirect = parent_private->redirect;
+    }
+  
+  return window;
+}
+
+/**
+ * gdk_window_reparent:
+ * @window: a #GdkWindow
+ * @new_parent: new parent to move @window into
+ * @x: X location inside the new parent
+ * @y: Y location inside the new parent
+ *
+ * Reparents @window into the given @new_parent. The window being
+ * reparented will be unmapped as a side effect.
+ * 
+ **/
+void
+gdk_window_reparent (GdkWindow *window,
+		     GdkWindow *new_parent,
+		     gint       x,
+		     gint       y)
+{
+  GdkWindowObject *private;
+  gboolean show;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent));
+  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      (new_parent && GDK_WINDOW_DESTROYED (new_parent)))
+    return;
+
+  private = (GdkWindowObject *) window;
+
+  /* Break up redirection if inherited */
+  if (private->redirect && private->redirect->redirected != private)
+    {
+      remove_redirect_from_children (private, private->redirect);
+      private->redirect = NULL;
+    }
+  
+  show = GDK_WINDOW_IMPL_GET_IFACE (private->impl)->reparent (window, new_parent, x, y);
+
+  /* Inherit parent redirect if we don't have our own */
+  if (private->parent && private->redirect == NULL)
+    {
+      private->redirect = private->parent->redirect;
+      apply_redirect_to_children (private, private->redirect);
+    }
+
+  if (show)
+    gdk_window_show (window);
+}
+
 static void
 window_remove_filters (GdkWindow *window)
 {
@@ -438,14 +549,23 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
 	      
 	      g_list_free (children);
 	    }
-	  
-	  _gdk_windowing_window_destroy (window, recursing, foreign_destroy);
+
+          if (gdk_window_is_offscreen (window))
+            _gdk_offscreen_window_destroy (window, recursing);
+          else
+            _gdk_windowing_window_destroy (window, recursing, foreign_destroy);
+
 	  private->parent = NULL;
 	  private->destroyed = TRUE;
 
 	  window_remove_filters (window);
 
           gdk_drawable_set_colormap (GDK_DRAWABLE (window), NULL);
+
+	  /* If we own the redirect, free it */
+	  if (private->redirect && private->redirect->redirected == private)
+	    gdk_window_redirect_free (private->redirect);
+	  private->redirect = NULL;
 	}
       break;
     }
@@ -1078,7 +1198,7 @@ gdk_window_end_paint (GdkWindow *window)
 
   tmp_gc = _gdk_drawable_get_scratch_gc (window, FALSE);
 
-  _gdk_windowing_window_get_offsets (window, &x_offset, &y_offset);
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (window, &x_offset, &y_offset);
 
   gdk_gc_set_clip_region (tmp_gc, paint->region);
   gdk_gc_set_clip_origin (tmp_gc, - x_offset, - y_offset);
@@ -1089,6 +1209,20 @@ gdk_window_end_paint (GdkWindow *window)
                      clip_box.x - x_offset, clip_box.y - y_offset,
                      clip_box.width, clip_box.height);
 
+  if (private->redirect)
+    {
+      GdkWindowClipData data;
+      
+      setup_redirect_clip (window, tmp_gc, &data);
+      gdk_draw_drawable (private->redirect->pixmap, tmp_gc, paint->pixmap,
+			 clip_box.x - paint->x_offset,
+			 clip_box.y - paint->y_offset,
+			 clip_box.x + data.x_offset,
+			 clip_box.y + data.y_offset,
+			 clip_box.width, clip_box.height);
+      reset_redirect_clip (window, tmp_gc, &data);
+    }
+  
   /* Reset clip region of the cached GdkGC */
   gdk_gc_set_clip_region (tmp_gc, NULL);
 
@@ -1168,7 +1302,7 @@ gdk_window_get_offsets (GdkWindow *window,
       *y_offset = paint->y_offset;
     }
   else
-    _gdk_windowing_window_get_offsets (window, x_offset, y_offset);
+    GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (window, x_offset, y_offset);
 }
 
 /**
@@ -1282,7 +1416,7 @@ gdk_window_draw_rectangle (GdkDrawable *drawable,
     {
       GdkWindowPaint *paint = private->paint_stack->data;
       gdk_draw_rectangle (paint->pixmap, gc, filled,
-			  x - x_offset, y - y_offset, width, height);
+                          x - x_offset, y - y_offset, width, height);
     }
   else
     gdk_draw_rectangle (private->impl, gc, filled,
@@ -1423,7 +1557,18 @@ gdk_window_draw_text_wc (GdkDrawable    *drawable,
   RESTORE_GC (gc);
 }
 
-static GdkDrawable*
+static GdkDrawable *
+gdk_window_get_source_drawable (GdkDrawable *drawable)
+{
+  GdkWindow *window = GDK_WINDOW (drawable);
+
+  if (gdk_window_is_offscreen (window))
+    return gdk_window_get_offscreen_pixmap (window);
+
+  return drawable;
+}
+
+static GdkDrawable *
 gdk_window_get_composite_drawable (GdkDrawable *drawable,
                                    gint         x,
                                    gint         y,
@@ -1438,13 +1583,16 @@ gdk_window_get_composite_drawable (GdkDrawable *drawable,
   GdkRectangle rect;
   GdkGC *tmp_gc;
   gboolean overlap_buffer;
+  gboolean is_offscreen;
 
-  _gdk_windowing_window_get_offsets (drawable,
-				     composite_x_offset,
-				     composite_y_offset);
-  
-  if ((GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable))
-      || private->paint_stack == NULL)
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (GDK_WINDOW (drawable),
+                                                          composite_x_offset,
+                                                          composite_y_offset);
+
+  is_offscreen = gdk_window_is_offscreen (GDK_WINDOW (drawable));
+
+  if ((GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable)) ||
+      (!is_offscreen && private->paint_stack == NULL))
     {
       /* No backing store */
       return g_object_ref (drawable);
@@ -1481,7 +1629,7 @@ gdk_window_get_composite_drawable (GdkDrawable *drawable,
 	}
     }
 
-  if (!overlap_buffer)
+  if (!overlap_buffer && !is_offscreen)
     return g_object_ref (drawable);
 
   tmp_pixmap = gdk_pixmap_new (drawable, width, height, -1);
@@ -1946,6 +2094,65 @@ gdk_window_clear_backing_rect (GdkWindow *window,
 #endif
 }
 
+static void
+gdk_window_clear_backing_rect_redirect (GdkWindow *window,
+					gint       x,
+					gint       y,
+					gint       width,
+					gint       height)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkWindowRedirect *redirect = private->redirect;
+  GdkRegion *clip_region;
+  gint x_offset, y_offset;
+  BackingRectMethod method;
+  GdkWindowPaint paint;
+  
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  paint.x_offset = x_offset;
+  paint.y_offset = y_offset;
+  paint.pixmap = redirect->pixmap;
+  paint.surface = _gdk_drawable_ref_cairo_surface (redirect->pixmap);
+  
+  clip_region = _gdk_window_calculate_full_clip_region (window,
+							GDK_WINDOW (redirect->redirected),
+							NULL, TRUE,
+							&x_offset, &y_offset);
+  
+
+  method.cr = NULL;
+  method.gc = NULL;
+  setup_backing_rect_method (&method, window, &paint, 0, 0);
+
+  if (method.cr)
+    {
+      g_assert (method.gc == NULL);
+
+      cairo_rectangle (method.cr, x, y, width, height);
+      cairo_clip (method.cr);
+
+      gdk_cairo_region (method.cr, clip_region);
+      cairo_fill (method.cr);
+
+      cairo_destroy (method.cr);
+    }
+  else
+    {
+      g_assert (method.gc != NULL);
+
+      gdk_gc_set_clip_region (method.gc, clip_region);
+      gdk_draw_rectangle (window, method.gc, TRUE, x, y, width, height);
+      g_object_unref (method.gc);
+
+    }
+
+  gdk_region_destroy (clip_region);
+  cairo_surface_destroy (paint.surface);
+}
+
+
 /**
  * gdk_window_clear:
  * @window: a #GdkWindow
@@ -1988,11 +2195,19 @@ gdk_window_clear_area (GdkWindow *window,
 
   g_return_if_fail (window != NULL);
   g_return_if_fail (GDK_IS_WINDOW (window));
-  
+
   if (private->paint_stack)
     gdk_window_clear_backing_rect (window, x, y, width, height);
   else
-    _gdk_windowing_window_clear_area (window, x, y, width, height);
+    {
+      if (private->redirect)
+	gdk_window_clear_backing_rect_redirect (window, x, y, width, height);
+
+      GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_area (window,
+                                                             x, y,
+                                                             width, height,
+                                                             FALSE);
+    }
 }
 
 /**
@@ -2025,7 +2240,13 @@ gdk_window_clear_area_e (GdkWindow *window,
   if (private->paint_stack)
     gdk_window_clear_backing_rect (window, x, y, width, height);
 
-  _gdk_windowing_window_clear_area_e (window, x, y, width, height);
+  if (private->redirect)
+    gdk_window_clear_backing_rect_redirect (window, x, y, width, height);
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->clear_area (window,
+                                                         x, y,
+                                                         width, height,
+                                                         TRUE);
 }
 
 static void
@@ -2236,6 +2457,7 @@ gdk_window_copy_to_image (GdkDrawable     *drawable,
 			  gint             width,
 			  gint             height)
 {
+  GdkWindowObject *private = (GdkWindowObject *) drawable;
   gint x_offset, y_offset;
   
   g_return_val_if_fail (GDK_IS_WINDOW (drawable), NULL);
@@ -2247,9 +2469,10 @@ gdk_window_copy_to_image (GdkDrawable     *drawable,
    * we can ignore the paint stack.
    */
   
-  _gdk_windowing_window_get_offsets (drawable, &x_offset, &y_offset);
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_offsets (drawable,
+                                                          &x_offset, &y_offset);
   
-  return gdk_drawable_copy_to_image (((GdkWindowObject*)drawable)->impl,
+  return gdk_drawable_copy_to_image (private->impl,
 				     image,
 				     src_x - x_offset,
 				     src_y - y_offset,
@@ -2343,8 +2566,9 @@ gdk_window_process_updates_internal (GdkWindow *window)
               gdk_display_sync (gdk_drawable_get_display (window));
               g_usleep (70000);
             }
-          
-	  save_region = _gdk_windowing_window_queue_antiexpose (window, update_area);
+
+          if (!gdk_window_is_offscreen (window))
+            save_region = _gdk_windowing_window_queue_antiexpose (window, update_area);
 
 	  if (save_region)
 	    expose_region = gdk_region_copy (update_area);
@@ -2629,7 +2853,18 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
       return;
     }
 
-  visible_region = gdk_drawable_get_visible_region (window);
+  /* windows that a redirection has ben setup for need to be considered
+   * fully visible, in order to avoid missing redirected paint ops
+   * anywhere in the window area.
+   */
+  if (private->redirect && private->redirect->redirected == private)
+    {
+      GdkRectangle visible_rect = { 0, 0, 0, 0 };
+      gdk_drawable_get_size (GDK_DRAWABLE (window), &visible_rect.width, &visible_rect.height);
+      visible_region = gdk_region_rectangle (&visible_rect);
+    }
+  else
+    visible_region = gdk_drawable_get_visible_region (window);
   gdk_region_intersect (visible_region, region);
 
   tmp_list = private->children;
@@ -2651,7 +2886,8 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
 	  
 	  /* remove child area from the invalid area of the parent */
 	  if (GDK_WINDOW_IS_MAPPED (child) && !child->shaped &&
-	      !child->composited)
+	      !child->composited &&
+              !_gdk_window_is_toplevel_offscreen (GDK_WINDOW (child)))
 	    gdk_region_subtract (visible_region, child_region);
 	  
 	  if (child_func && (*child_func) ((GdkWindow *)child, user_data))
@@ -2678,7 +2914,7 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
     {
       if (debug_updates)
         draw_ugly_color (window, region);
-      
+
       if (private->update_area)
 	{
 	  gdk_region_union (private->update_area, visible_region);
@@ -3164,6 +3400,741 @@ gdk_window_foreign_new (GdkNativeWindow anid)
 }
 
 /**
+ * gdk_window_show_unraised:
+ * @window: a #GdkWindow
+ *
+ * Shows a #GdkWindow onscreen, but does not modify its stacking
+ * order. In contrast, gdk_window_show() will raise the window
+ * to the top of the window stack.
+ *
+ * On the X11 platform, in Xlib terms, this function calls
+ * XMapWindow() (it also updates some internal GDK state, which means
+ * that you can't really use XMapWindow() directly on a GDK window).
+ */
+void
+gdk_window_show_unraised (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window, FALSE);
+}
+
+static inline void
+gdk_window_raise_internal (GdkWindow *window)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkWindowObject *parent;
+
+  parent = private->parent;
+
+  if (parent)
+    {
+      parent->children = g_list_remove (parent->children, window);
+      parent->children = g_list_prepend (parent->children, window);
+    }
+}
+
+/**
+ * gdk_window_show:
+ * @window: a #GdkWindow
+ *
+ * Like gdk_window_show_unraised(), but also raises the window to the
+ * top of the window stack (moves the window to the front of the
+ * Z-order).
+ *
+ * This function maps a window so it's visible onscreen. Its opposite
+ * is gdk_window_hide().
+ *
+ * When implementing a #GtkWidget, you should call this function on the widget's
+ * #GdkWindow as part of the "map" method.
+ */
+void
+gdk_window_show (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  /* Keep children in (reverse) stacking order */
+  gdk_window_raise_internal (window);
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show (window, TRUE);
+}
+
+/**
+ * gdk_window_hide:
+ * @window: a #GdkWindow
+ *
+ * For toplevel windows, withdraws them, so they will no longer be
+ * known to the window manager; for all windows, unmaps them, so
+ * they won't be displayed. Normally done automatically as
+ * part of gtk_widget_hide().
+ */
+void
+gdk_window_hide (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->hide (window);
+}
+
+/**
+ * gdk_window_withdraw:
+ * @window: a toplevel #GdkWindow
+ *
+ * Withdraws a window (unmaps it and asks the window manager to forget about it).
+ * This function is not really useful as gdk_window_hide() automatically
+ * withdraws toplevel windows before hiding them.
+ **/
+void
+gdk_window_withdraw (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->withdraw (window);
+}
+
+/**
+ * gdk_window_set_events:
+ * @window: a #GdkWindow
+ * @event_mask: event mask for @window
+ *
+ * The event mask for a window determines which events will be reported
+ * for that window. For example, an event mask including #GDK_BUTTON_PRESS_MASK
+ * means the window should report button press events. The event mask
+ * is the bitwise OR of values from the #GdkEventMask enumeration.
+ **/
+void
+gdk_window_set_events (GdkWindow       *window,
+		       GdkEventMask     event_mask)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_events (window, event_mask);
+}
+
+/**
+ * gdk_window_get_events:
+ * @window: a #GdkWindow
+ *
+ * Gets the event mask for @window. See gdk_window_set_events().
+ *
+ * Return value: event mask for @window
+ **/
+GdkEventMask
+gdk_window_get_events (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return 0;
+
+  return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_events (window);
+}
+
+/**
+ * gdk_window_raise:
+ * @window: a #GdkWindow
+ *
+ * Raises @window to the top of the Z-order (stacking order), so that
+ * other windows with the same parent window appear below @window.
+ * This is true whether or not the windows are visible.
+ *
+ * If @window is a toplevel, the window manager may choose to deny the
+ * request to move the window in the Z-order, gdk_window_raise() only
+ * requests the restack, does not guarantee it.
+ */
+void
+gdk_window_raise (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  /* Keep children in (reverse) stacking order */
+  gdk_window_raise_internal (window);
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->raise (window);
+}
+
+static void
+gdk_window_lower_internal (GdkWindow *window)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkWindowObject *parent;
+
+  parent = private->parent;
+  if (parent)
+    {
+      parent->children = g_list_remove (parent->children, window);
+      parent->children = g_list_append (parent->children, window);
+    }
+}
+
+/**
+ * gdk_window_lower:
+ * @window: a #GdkWindow
+ *
+ * Lowers @window to the bottom of the Z-order (stacking order), so that
+ * other windows with the same parent window appear above @window.
+ * This is true whether or not the other windows are visible.
+ *
+ * If @window is a toplevel, the window manager may choose to deny the
+ * request to move the window in the Z-order, gdk_window_lower() only
+ * requests the restack, does not guarantee it.
+ *
+ * Note that gdk_window_show() raises the window again, so don't call this
+ * function before gdk_window_show(). (Try gdk_window_show_unraised().)
+ */
+void
+gdk_window_lower (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  /* Keep children in (reverse) stacking order */
+  gdk_window_lower_internal (window);
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->lower (window);
+}
+
+/**
+ * gdk_window_move:
+ * @window: a #GdkWindow
+ * @x: X coordinate relative to window's parent
+ * @y: Y coordinate relative to window's parent
+ *
+ * Repositions a window relative to its parent window.
+ * For toplevel windows, window managers may ignore or modify the move;
+ * you should probably use gtk_window_move() on a #GtkWindow widget
+ * anyway, instead of using GDK functions. For child windows,
+ * the move will reliably succeed.
+ *
+ * If you're also planning to resize the window, use gdk_window_move_resize()
+ * to both move and resize simultaneously, for a nicer visual effect.
+ **/
+void
+gdk_window_move (GdkWindow *window,
+		 gint       x,
+		 gint       y)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move (window, x, y);
+}
+
+/**
+ * gdk_window_resize:
+ * @window: a #GdkWindow
+ * @width: new width of the window
+ * @height: new height of the window
+ *
+ * Resizes @window; for toplevel windows, asks the window manager to resize
+ * the window. The window manager may not allow the resize. When using GTK+,
+ * use gtk_window_resize() instead of this low-level GDK function.
+ *
+ * Windows may not be resized below 1x1.
+ *
+ * If you're also planning to move the window, use gdk_window_move_resize()
+ * to both move and resize simultaneously, for a nicer visual effect.
+ **/
+void
+gdk_window_resize (GdkWindow *window,
+		   gint       width,
+		   gint       height)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->resize (window, width, height);
+}
+
+
+/**
+ * gdk_window_move_resize:
+ * @window: a #GdkWindow
+ * @x: new X position relative to window's parent
+ * @y: new Y position relative to window's parent
+ * @width: new width
+ * @height: new height
+ *
+ * Equivalent to calling gdk_window_move() and gdk_window_resize(),
+ * except that both operations are performed at once, avoiding strange
+ * visual effects. (i.e. the user may be able to see the window first
+ * move, then resize, if you don't use gdk_window_move_resize().)
+ **/
+void
+gdk_window_move_resize (GdkWindow *window,
+			gint       x,
+			gint       y,
+			gint       width,
+			gint       height)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_resize (window, x, y, width, height);
+}
+
+
+/**
+ * gdk_window_scroll:
+ * @window: a #GdkWindow
+ * @dx: Amount to scroll in the X direction
+ * @dy: Amount to scroll in the Y direction
+ *
+ * Scroll the contents of @window, both pixels and children, by the
+ * given amount. @window itself does not move. Portions of the window
+ * that the scroll operation brings in from offscreen areas are
+ * invalidated. The invalidated region may be bigger than what would
+ * strictly be necessary.
+ *
+ * For X11, a minimum area will be invalidated if the window has no
+ * subwindows, or if the edges of the window's parent do not extend
+ * beyond the edges of the window. In other cases, a multi-step process
+ * is used to scroll the window which may produce temporary visual
+ * artifacts and unnecessary invalidations.
+ **/
+void
+gdk_window_scroll (GdkWindow *window,
+		   gint       dx,
+		   gint       dy)
+{
+  GdkWindowObject *private = (GdkWindowObject *) window;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if (dx == 0 && dy == 0)
+    return;
+
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->scroll (window, dx, dy);
+}
+
+/**
+ * gdk_window_move_region:
+ * @window: a #GdkWindow
+ * @region: The #GdkRegion to move
+ * @dx: Amount to move in the X direction
+ * @dy: Amount to move in the Y direction
+ *
+ * Move the part of @window indicated by @region by @dy pixels in the Y
+ * direction and @dx pixels in the X direction. The portions of @region
+ * that not covered by the new position of @region are invalidated.
+ *
+ * Child windows are not moved.
+ *
+ * Since: 2.8
+ */
+void
+gdk_window_move_region (GdkWindow       *window,
+			const GdkRegion *region,
+			gint             dx,
+			gint             dy)
+{
+  GdkWindowObject *private = (GdkWindowObject *) window;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (region != NULL);
+
+  if (dx == 0 && dy == 0)
+    return;
+
+  if (private->destroyed)
+    return;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->move_region (window, region, dx, dy);
+}
+
+/**
+ * gdk_window_set_background:
+ * @window: a #GdkWindow
+ * @color: an allocated #GdkColor
+ *
+ * Sets the background color of @window. (However, when using GTK+,
+ * set the background of a widget with gtk_widget_modify_bg() - if
+ * you're an application - or gtk_style_set_background() - if you're
+ * implementing a custom widget.)
+ *
+ * The @color must be allocated; gdk_rgb_find_color() is the best way
+ * to allocate a color.
+ *
+ * See also gdk_window_set_back_pixmap().
+ */
+void
+gdk_window_set_background (GdkWindow      *window,
+			   const GdkColor *color)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_background (window, color);
+}
+
+/**
+ * gdk_window_set_back_pixmap:
+ * @window: a #GdkWindow
+ * @pixmap: a #GdkPixmap, or %NULL
+ * @parent_relative: whether the tiling origin is at the origin of
+ *   @window's parent
+ *
+ * Sets the background pixmap of @window. May also be used to set a
+ * background of "None" on @window, by setting a background pixmap
+ * of %NULL.
+ *
+ * A background pixmap will be tiled, positioning the first tile at
+ * the origin of @window, or if @parent_relative is %TRUE, the tiling
+ * will be done based on the origin of the parent window (useful to
+ * align tiles in a parent with tiles in a child).
+ *
+ * A background pixmap of %NULL means that the window will have no
+ * background.  A window with no background will never have its
+ * background filled by the windowing system, instead the window will
+ * contain whatever pixels were already in the corresponding area of
+ * the display.
+ *
+ * The windowing system will normally fill a window with its background
+ * when the window is obscured then exposed, and when you call
+ * gdk_window_clear().
+ */
+void
+gdk_window_set_back_pixmap (GdkWindow *window,
+			    GdkPixmap *pixmap,
+			    gboolean   parent_relative)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_back_pixmap (window, pixmap, parent_relative);
+}
+
+/**
+ * gdk_window_set_cursor:
+ * @window: a #GdkWindow
+ * @cursor: a cursor
+ *
+ * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new() or
+ * gdk_cursor_new_from_pixmap() to create the cursor.
+ * To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create
+ * a cursor with no pixels in it. Passing %NULL for the @cursor argument
+ * to gdk_window_set_cursor() means that @window will use the cursor of
+ * its parent window. Most windows should use this default.
+ */
+void
+gdk_window_set_cursor (GdkWindow *window,
+		       GdkCursor *cursor)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_cursor (window, cursor);
+}
+
+/**
+ * gdk_window_get_geometry:
+ * @window: a #GdkWindow
+ * @x: return location for X coordinate of window (relative to its parent)
+ * @y: return location for Y coordinate of window (relative to its parent)
+ * @width: return location for width of window
+ * @height: return location for height of window
+ * @depth: return location for bit depth of window
+ *
+ * Any of the return location arguments to this function may be %NULL,
+ * if you aren't interested in getting the value of that field.
+ *
+ * The X and Y coordinates returned are relative to the parent window
+ * of @window, which for toplevels usually means relative to the
+ * window decorations (titlebar, etc.) rather than relative to the
+ * root window (screen-size background window).
+ *
+ * On the X11 platform, the geometry is obtained from the X server,
+ * so reflects the latest position of @window; this may be out-of-sync
+ * with the position of @window delivered in the most-recently-processed
+ * #GdkEventConfigure. gdk_window_get_position() in contrast gets the
+ * position from the most recent configure event.
+ *
+ * <note>
+ * If @window is not a toplevel, it is <emphasis>much</emphasis> better
+ * to call gdk_window_get_position() and gdk_drawable_get_size() instead,
+ * because it avoids the roundtrip to the X server and because
+ * gdk_drawable_get_size() supports the full 32-bit coordinate space,
+ * whereas gdk_window_get_geometry() is restricted to the 16-bit
+ * coordinates of X11.
+ *</note>
+ **/
+void
+gdk_window_get_geometry (GdkWindow *window,
+			 gint      *x,
+			 gint      *y,
+			 gint      *width,
+			 gint      *height,
+			 gint      *depth)
+{
+  GdkWindowObject *private;
+
+  if (!window)
+    {
+      GDK_NOTE (MULTIHEAD,
+		g_message ("gdk_window_get_geometry(): Window needs "
+                           "to be non-NULL to be multi head safe"));
+      window = gdk_screen_get_root_window ((gdk_screen_get_default ()));
+    }
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_geometry (window, x, y,
+							       width, height,
+                                                               depth);
+    }
+}
+
+/**
+ * gdk_window_get_origin:
+ * @window: a #GdkWindow
+ * @x: return location for X coordinate
+ * @y: return location for Y coordinate
+ *
+ * Obtains the position of a window in root window coordinates.
+ * (Compare with gdk_window_get_position() and
+ * gdk_window_get_geometry() which return the position of a window
+ * relative to its parent window.)
+ *
+ * Return value: not meaningful, ignore
+ */
+gint
+gdk_window_get_origin (GdkWindow *window,
+		       gint      *x,
+		       gint      *y)
+{
+  GdkWindowObject *private;
+
+  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+
+  private = (GdkWindowObject *) window;
+
+  return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->get_origin (window, x, y);
+}
+
+/**
+ * gdk_window_shape_combine_mask:
+ * @window: a #GdkWindow
+ * @mask: shape mask
+ * @x: X position of shape mask with respect to @window
+ * @y: Y position of shape mask with respect to @window
+ *
+ * Applies a shape mask to @window. Pixels in @window corresponding to
+ * set bits in the @mask will be visible; pixels in @window
+ * corresponding to unset bits in the @mask will be transparent. This
+ * gives a non-rectangular window.
+ *
+ * If @mask is %NULL, the shape mask will be unset, and the @x/@y
+ * parameters are not used.
+ *
+ * On the X11 platform, this uses an X server extension which is
+ * widely available on most common platforms, but not available on
+ * very old X servers, and occasionally the implementation will be
+ * buggy. On servers without the shape extension, this function
+ * will do nothing.
+ *
+ * This function works on both toplevel and child windows.
+ */
+void
+gdk_window_shape_combine_mask (GdkWindow *window,
+			       GdkBitmap *mask,
+			       gint       x,
+                               gint       y)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_mask (window, mask, x, y);
+}
+
+/**
+ * gdk_window_shape_combine_region:
+ * @window: a #GdkWindow
+ * @shape_region: region of window to be non-transparent
+ * @offset_x: X position of @shape_region in @window coordinates
+ * @offset_y: Y position of @shape_region in @window coordinates
+ *
+ * Makes pixels in @window outside @shape_region be transparent,
+ * so that the window may be nonrectangular. See also
+ * gdk_window_shape_combine_mask() to use a bitmap as the mask.
+ *
+ * If @shape_region is %NULL, the shape will be unset, so the whole
+ * window will be opaque again. @offset_x and @offset_y are ignored
+ * if @shape_region is %NULL.
+ *
+ * On the X11 platform, this uses an X server extension which is
+ * widely available on most common platforms, but not available on
+ * very old X servers, and occasionally the implementation will be
+ * buggy. On servers without the shape extension, this function
+ * will do nothing.
+ *
+ * This function works on both toplevel and child windows.
+ */
+void
+gdk_window_shape_combine_region (GdkWindow       *window,
+                                 const GdkRegion *shape_region,
+                                 gint             offset_x,
+                                 gint             offset_y)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region (window, shape_region, offset_x, offset_y);
+}
+
+/**
+ * gdk_window_set_child_shapes:
+ * @window: a #GdkWindow
+ *
+ * Sets the shape mask of @window to the union of shape masks
+ * for all children of @window, ignoring the shape mask of @window
+ * itself. Contrast with gdk_window_merge_child_shapes() which includes
+ * the shape mask of @window in the masks to be merged.
+ **/
+void
+gdk_window_set_child_shapes (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_child_shapes (window);
+}
+
+/**
+ * gdk_window_merge_child_shapes:
+ * @window: a #GdkWindow
+ *
+ * Merges the shape masks for any child windows into the
+ * shape mask for @window. i.e. the union of all masks
+ * for @window and its children will become the new mask
+ * for @window. See gdk_window_shape_combine_mask().
+ *
+ * This function is distinct from gdk_window_set_child_shapes()
+ * because it includes @window's shape mask in the set of shapes to
+ * be merged.
+ */
+void
+gdk_window_merge_child_shapes (GdkWindow *window)
+{
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->merge_child_shapes (window);
+}
+
+
+/**
+ * gdk_window_set_static_gravities:
+ * @window: a #GdkWindow
+ * @use_static: %TRUE to turn on static gravity
+ *
+ * Set the bit gravity of the given window to static, and flag it so
+ * all children get static subwindow gravity. This is used if you are
+ * implementing scary features that involve deep knowledge of the
+ * windowing system. Don't worry about it unless you have to.
+ *
+ * Return value: %TRUE if the server supports static gravity
+ */
+gboolean
+gdk_window_set_static_gravities (GdkWindow *window,
+				 gboolean   use_static)
+{
+  GdkWindowObject *private;
+
+  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+
+  private = (GdkWindowObject *) window;
+
+  return GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_static_gravities (window, use_static);
+}
+
+/**
  * gdk_window_set_composited:
  * @window: a #GdkWindow
  * @composited: %TRUE to set the window as composited
@@ -3223,5 +4194,391 @@ gdk_window_set_composited (GdkWindow *window,
   private->composited = composited;
 }
 
+
+static void
+remove_redirect_from_children (GdkWindowObject *private, GdkWindowRedirect *redirect)
+{
+  GList *l;
+  GdkWindowObject *child;
+
+  for (l = private->children; l != NULL; l = l->next)
+    {
+      child = l->data;
+
+      /* Don't redirect this child if it already has another redirect */
+      if (child->redirect == redirect)
+	{
+	  child->redirect = NULL;
+	  remove_redirect_from_children (child, redirect);
+	}
+    }
+}
+
+/**
+ * gdk_window_remove_redirection:
+ * @window: a #GdkWindow
+ *
+ * Removes and active redirection started by
+ * gdk_window_redirect_to_drawable().
+ **/
+void
+gdk_window_remove_redirection (GdkWindow *window)
+{
+  GdkWindowObject *private;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  if (private->redirect &&
+      private->redirect->redirected == private)
+    {
+      remove_redirect_from_children (private, private->redirect);
+      gdk_window_redirect_free (private->redirect);
+      private->redirect = NULL;
+    }
+}
+
+static void
+apply_redirect_to_children (GdkWindowObject *private, GdkWindowRedirect *redirect)
+{
+  GList *l;
+  GdkWindowObject *child;
+
+  for (l = private->children; l != NULL; l = l->next)
+    {
+      child = l->data;
+
+      /* Don't redirect this child if it already has another redirect */
+      if (!child->redirect)
+	{
+	  child->redirect = redirect;
+	  apply_redirect_to_children (child, redirect);
+	}
+    }
+}
+
+/**
+ * gdk_window_redirect_to_drawable:
+ * @window: a #GdkWindow
+ * @drawable: a #GdkDrawable
+ * src_x: x position in @window
+ * src_y: y position in @window
+ * dest_x: x position in @drawable
+ * dest_y: y position in @drawable
+ * width: width of redirection
+ * height: height of redirection
+ *
+ * Redirects drawing into @windows so that drawing to the
+ * window in the rectangle specified by @src_x, @src_y,
+ * @width and @height is also drawn into @drawable at
+ * @dest_x, @dest_y.
+ *
+ * Only drawing between gdk_window_begin_paint_region() and
+ * gdk_window_end_paint() is redirected.
+ *
+ * Redirection is active until gdk_window_remove_redirection()
+ * is called.
+ *
+ * This function should not be used on windows created by
+ * gdk_window_new_offscreen(), as that is implemented using
+ * redirection.
+ **/
+void
+gdk_window_redirect_to_drawable (GdkWindow *window,
+				 GdkDrawable *drawable,
+				 gint src_x, gint src_y,
+				 gint dest_x, gint dest_y,
+				 gint width, gint height)
+{
+  GdkWindowObject *private;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_DRAWABLE (drawable));
+  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
+
+  private = (GdkWindowObject *) window;
+
+  if (private->redirect)
+    gdk_window_remove_redirection (window);
+
+  if (width == -1 || height == -1)
+    {
+      gint w, h;
+      gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
+      if (width == -1)
+	width = w;
+      if (height == -1)
+	height = h;
+    }
+  
+  private->redirect = g_new0 (GdkWindowRedirect, 1);
+  private->redirect->redirected = private;
+  private->redirect->pixmap = g_object_ref (drawable);
+  private->redirect->src_x = src_x;
+  private->redirect->src_y = src_y;
+  private->redirect->dest_x = dest_x;
+  private->redirect->dest_y = dest_y;
+  private->redirect->width = width;
+  private->redirect->height = height;
+
+  apply_redirect_to_children (private, private->redirect);
+}
+
+static void
+window_get_size_rectangle (GdkWindow    *window,
+                           GdkRectangle *rect)
+{
+  rect->x = rect->y = 0;
+  gdk_drawable_get_size (GDK_DRAWABLE (window), &rect->width, &rect->height);
+}
+
+/* Calculates the real clipping region for a window, in window coordinates,
+ * taking into account other windows, gc clip region and gc clip mask.
+ */
+GdkRegion *
+_gdk_window_calculate_full_clip_region (GdkWindow *window,
+					GdkWindow *base_window,
+					GdkGC *gc,
+					gboolean do_children,
+					gint *base_x_offset,
+					gint *base_y_offset)
+{
+  GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
+  GdkRectangle visible_rect;
+  GdkRegion *real_clip_region, *tmpreg;
+  gint x_offset, y_offset;
+  GdkWindowObject *parentwin, *lastwin;
+
+  if (base_x_offset)
+    *base_x_offset = 0;
+  if (base_y_offset)
+    *base_y_offset = 0;
+  
+  if (!GDK_WINDOW_IS_MAPPED (window) || private->input_only)
+    return gdk_region_new ();
+
+  window_get_size_rectangle (window, &visible_rect);
+
+  /* windows that a redirection has ben setup for need to be considered
+   * fully visible, in order to avoid missing redirected paint ops
+   * anywhere in the window area.
+   */
+  if (private->redirect && private->redirect->redirected == private)
+    return gdk_region_rectangle (&visible_rect);
+
+  /* real_clip_region is in window coordinates */
+  real_clip_region = gdk_region_rectangle (&visible_rect);
+
+  x_offset = y_offset = 0;
+
+  lastwin = private;
+  if (do_children)
+    parentwin = lastwin;
+  else
+    parentwin = lastwin->parent;
+  
+  /* Remove the areas of all overlapping windows above parentwin in the hiearachy */
+  for (; parentwin != NULL && (parentwin == private || lastwin != (GdkWindowObject *)base_window);
+       lastwin = parentwin, parentwin = lastwin->parent)
+    {
+      GList *cur;
+      GdkRectangle real_clip_rect;
+      gboolean is_offscreen;
+
+      if (parentwin != private)
+	{
+	  x_offset += GDK_WINDOW_OBJECT (lastwin)->x;
+	  y_offset += GDK_WINDOW_OBJECT (lastwin)->y;
+	}
+
+      is_offscreen = gdk_window_is_offscreen (GDK_WINDOW (parentwin));
+
+      /* children is ordered in reverse stack order */
+      for (cur = GDK_WINDOW_OBJECT (parentwin)->children;
+           cur && cur->data != lastwin;
+           cur = cur->next)
+	{
+	  GdkWindow *child = cur->data;
+	  GdkWindowObject *child_private = (GdkWindowObject *)child;
+
+	  if (!GDK_WINDOW_IS_MAPPED (child) || child_private->input_only)
+	    continue;
+
+          /* Ignore toplevel offscreen children */
+          if (_gdk_window_is_toplevel_offscreen (child))
+            continue;
+
+          window_get_size_rectangle (child, &visible_rect);
+
+	  /* Convert rect to "window" coords */
+	  visible_rect.x += child_private->x - x_offset;
+	  visible_rect.y += child_private->y - y_offset;
+	  
+	  /* This shortcut is really necessary for performance when there are a lot of windows */
+	  gdk_region_get_clipbox (real_clip_region, &real_clip_rect);
+	  if (visible_rect.x >= real_clip_rect.x + real_clip_rect.width ||
+	      visible_rect.x + visible_rect.width <= real_clip_rect.x ||
+	      visible_rect.y >= real_clip_rect.y + real_clip_rect.height ||
+	      visible_rect.y + visible_rect.height <= real_clip_rect.y)
+	    continue;
+	  
+	  tmpreg = gdk_region_rectangle (&visible_rect);
+	  gdk_region_subtract (real_clip_region, tmpreg);
+	  gdk_region_destroy (tmpreg);
+	}
+      
+    }
+
+  if (gc)
+    {
+      GdkRegion *clip_region = _gdk_gc_get_clip_region (gc);
+      
+      if (clip_region)
+	{
+	  /* clip_region is relative to gc clip origin which is relative to the window */
+	  /* offset it to window relative: */
+	  tmpreg = gdk_region_copy (clip_region);
+	  gdk_region_offset (real_clip_region,
+			     gc->clip_x_origin,
+			     gc->clip_y_origin);
+	  /* Intersect it with window hierarchy cliprect: */
+	  gdk_region_intersect (real_clip_region, tmpreg);
+	  gdk_region_destroy (tmpreg);
+	}
+    }
+
+  if (base_x_offset)
+    *base_x_offset = x_offset;
+  if (base_y_offset)
+    *base_y_offset = y_offset;
+
+  return real_clip_region;
+}
+
+static void
+gdk_window_add_damage (GdkWindow *toplevel,
+		       GdkRegion *damaged_region)
+{
+  GdkDisplay *display;
+  GdkEvent event = { 0, };
+  event.expose.type = GDK_DAMAGE;
+  event.expose.window = toplevel;
+  event.expose.send_event = FALSE;
+  event.expose.region = damaged_region;
+  gdk_region_get_clipbox (event.expose.region, &event.expose.area);
+  display = gdk_drawable_get_display (event.expose.window);
+  _gdk_event_queue_append (display, gdk_event_copy (&event));
+}
+
+static void
+setup_redirect_clip (GdkWindow         *window,
+		     GdkGC             *gc,
+		     GdkWindowClipData *data)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkRegion *visible_region;
+  GdkRectangle dest_rect;
+  GdkRegion *tmpreg;
+  GdkWindow *toplevel;
+
+  data->old_region = _gdk_gc_get_clip_region (gc);
+  if (data->old_region) 
+    data->old_region = gdk_region_copy (data->old_region);
+
+  data->old_clip_x_origin = gc->clip_x_origin;
+  data->old_clip_y_origin = gc->clip_y_origin;
+
+  toplevel = GDK_WINDOW (private->redirect->redirected);
+  
+  /* Get the clip region for gc clip rect + window hierarchy in
+     window relative coords */
+  visible_region =
+    _gdk_window_calculate_full_clip_region (window, toplevel,
+					    gc, TRUE,
+					    &data->x_offset, 
+					    &data->y_offset);
+
+  /* Compensate for the source pos/size */
+  data->x_offset -= private->redirect->src_x;
+  data->y_offset -= private->redirect->src_y;
+  dest_rect.x = -data->x_offset;
+  dest_rect.y = -data->y_offset;
+  dest_rect.width = private->redirect->width;
+  dest_rect.height = private->redirect->height;
+  tmpreg = gdk_region_rectangle (&dest_rect);
+  gdk_region_intersect (visible_region, tmpreg);
+  gdk_region_destroy (tmpreg);
+
+  /* Compensate for the dest pos */
+  data->x_offset += private->redirect->dest_x;
+  data->y_offset += private->redirect->dest_y;
+
+  gdk_gc_set_clip_region (gc, visible_region); /* This resets clip origin! */
+
+  /* offset clip and tiles from window coords to pixmaps coords */
+  gdk_gc_offset (gc, -data->x_offset, -data->y_offset);
+
+  /* Offset region to abs coords and add to damage */
+  gdk_region_offset (visible_region, data->x_offset, data->y_offset);
+  gdk_window_add_damage (toplevel, visible_region);
+  
+  gdk_region_destroy (visible_region);
+}
+
+static void
+reset_redirect_clip (GdkWindow *offscreen, GdkGC *gc, GdkWindowClipData *data)
+{
+  /* offset back */
+  gdk_gc_offset (gc, data->x_offset, data->y_offset);
+
+  /* reset old clip */
+  gdk_gc_set_clip_region (gc, data->old_region);
+  if (data->old_region)
+    gdk_region_destroy (data->old_region);
+  gdk_gc_set_clip_origin (gc, data->old_clip_x_origin, data->old_clip_y_origin);
+}
+
+static void
+gdk_window_redirect_free (GdkWindowRedirect *redirect)
+{
+  g_object_unref (redirect->pixmap);
+  g_free (redirect);
+}
+
+void
+_gdk_window_add_offscreen_child (GdkWindow *window)
+{
+  GdkWindowObject *obj = (GdkWindowObject*) window;
+
+  if (obj->offscreen_children)
+    obj->offscreen_children->n_offscreen_children++;
+  else
+    {
+      obj->offscreen_children = g_slice_new0 (GdkWindowOffscreenChildren);
+      obj->offscreen_children->n_offscreen_children = 1;
+    }
+}
+
+void
+_gdk_window_remove_offscreen_child (GdkWindow *window)
+{
+  GdkWindowObject *obj = (GdkWindowObject*) window;
+
+  g_return_if_fail (obj->offscreen_children != NULL);
+
+  if (obj->offscreen_children)
+    {
+      g_return_if_fail (obj->offscreen_children->n_offscreen_children > 0);
+
+      obj->offscreen_children->n_offscreen_children--;
+      if (obj->offscreen_children->n_offscreen_children == 0)
+        {
+          g_slice_free (GdkWindowOffscreenChildren, obj->offscreen_children);
+          obj->offscreen_children = NULL;
+        }
+    }
+}
+
 #define __GDK_WINDOW_C__
 #include "gdkaliasdef.c"
diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
index f0ee7f5..7ff07a5 100644
--- a/gdk/gdkwindow.h
+++ b/gdk/gdkwindow.h
@@ -33,9 +33,12 @@
 
 G_BEGIN_DECLS
 
-typedef struct _GdkGeometry           GdkGeometry;
-typedef struct _GdkWindowAttr	      GdkWindowAttr;
-typedef struct _GdkPointerHooks	      GdkPointerHooks;
+typedef struct _GdkGeometry                GdkGeometry;
+typedef struct _GdkWindowAttr	           GdkWindowAttr;
+typedef struct _GdkPointerHooks	           GdkPointerHooks;
+typedef struct _GdkOffscreenHooks          GdkOffscreenHooks;
+typedef struct _GdkWindowRedirect          GdkWindowRedirect;
+typedef struct _GdkWindowOffscreenChildren GdkWindowOffscreenChildren;
 
 /* Classes of windows.
  *   InputOutput: Almost every window should be of this type. Such windows
@@ -243,9 +246,62 @@ struct _GdkPointerHooks
                                    gint            *win_y);
 };
 
+struct _GdkOffscreenHooks
+{
+  void       (*parent_to_window)     (GdkWindow *window,
+                                      gdouble    parent_x,
+                                      gdouble    parent_y,
+                                      gdouble   *win_x,
+                                      gdouble   *win_y);
+  void       (*window_to_parent)     (GdkWindow *window,
+                                      gdouble    win_x,
+                                      gdouble    win_y,
+                                      gdouble   *parent_x,
+                                      gdouble   *parent_y);
+  GdkWindow* (*find_offscreen_child) (GdkWindow *window,
+                                      gdouble    x,
+                                      gdouble    y);
+};
+
+struct _GdkWindowOffscreenChildren
+{
+  gint n_offscreen_children;
+
+  /* The window with the mouse in it, or NULL if the pointer is not inside
+   *  an offscreen child. A pointer grab doesn't affect this.
+   */
+  GdkWindow *window_under_pointer;
+
+  gdouble last_mouse_x, last_mouse_y;
+  guint32 last_state;
+
+  GdkWindow *pointer_grab_window;
+  gboolean pointer_grab_owner_events;
+
+  GdkWindow *grab_one_pointer_release_event;
+  guint pointer_grab_event_mask;
+};
+
 typedef struct _GdkWindowObject GdkWindowObject;
 typedef struct _GdkWindowObjectClass GdkWindowObjectClass;
 
+struct _GdkWindowRedirect
+{
+  GdkWindowObject *redirected;
+  GdkDrawable *pixmap;
+
+  gint src_x;
+  gint src_y;
+  gint dest_x;
+  gint dest_y;
+  gint width;
+  gint height;
+
+  GdkRegion *damage;
+  guint damage_idle;
+};
+
+
 #define GDK_TYPE_WINDOW              (gdk_window_object_get_type ())
 #define GDK_WINDOW(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WINDOW, GdkWindow))
 #define GDK_WINDOW_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WINDOW, GdkWindowObjectClass))
@@ -300,6 +356,10 @@ struct _GdkWindowObject
   GdkEventMask event_mask;
 
   guint update_and_descendants_freeze_count;
+
+  GdkWindowRedirect *redirect;
+  GdkWindowOffscreenChildren *offscreen_children;
+  const GdkOffscreenHooks *offscreen_hooks;
 };
 
 struct _GdkWindowObjectClass
@@ -638,6 +698,27 @@ GdkPointerHooks *gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks);
 
 GdkWindow *gdk_get_default_root_window (void);
 
+/* Offscreen redirection */
+GdkWindow *gdk_window_new_offscreen          (GdkWindow     *parent,
+                                              GdkWindowAttr *attributes,
+                                              gint           attributes_mask);
+
+gboolean   gdk_window_is_offscreen           (GdkWindow     *window);
+GdkPixmap *gdk_window_get_offscreen_pixmap   (GdkWindow     *window);
+
+void       gdk_window_redirect_to_drawable   (GdkWindow     *window,
+                                              GdkDrawable   *drawable,
+                                              gint           src_x,
+                                              gint           src_y,
+                                              gint           dest_x,
+                                              gint           dest_y,
+                                              gint           width,
+                                              gint           height);
+void       gdk_window_remove_redirection     (GdkWindow     *window);
+
+void       gdk_window_set_offscreen_hooks    (GdkWindow               *window,
+                                              const GdkOffscreenHooks *hooks);
+
 #ifndef GDK_DISABLE_DEPRECATED
 #define GDK_ROOT_PARENT()             (gdk_get_default_root_window ())
 #define gdk_window_get_size            gdk_drawable_get_size
diff --git a/gdk/gdkwindowimpl.c b/gdk/gdkwindowimpl.c
new file mode 100644
index 0000000..32923d1
--- /dev/null
+++ b/gdk/gdkwindowimpl.c
@@ -0,0 +1,57 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * 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/. 
+ */
+
+#include <config.h>
+#include "gdkwindowimpl.h"
+#include "gdkinternals.h"
+
+static void
+gdk_window_impl_base_init (gpointer g_class)
+{
+}
+
+GType                   
+gdk_window_impl_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo info = {
+	sizeof (GdkWindowImplIface),
+	gdk_window_impl_base_init,
+	NULL,
+	NULL,
+      };
+
+      type = g_type_register_static (G_TYPE_INTERFACE,
+                                     g_intern_static_string ("GdkWindowImpl"),
+                                     &info, 0);
+      g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+    }
+
+  return type;
+}
diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h
new file mode 100644
index 0000000..65b6fac
--- /dev/null
+++ b/gdk/gdkwindowimpl.h
@@ -0,0 +1,129 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * 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/. 
+ */
+
+#ifndef __GDK_WINDOW_IMPL_H__
+#define __GDK_WINDOW_IMPL_H__
+
+#include <gdk/gdkwindow.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_WINDOW_IMPL           (gdk_window_impl_get_type ())
+#define GDK_WINDOW_IMPL(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_WINDOW_IMPL, GdkWindowImpl))
+#define GDK_IS_WINDOW_IMPL(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_WINDOW_IMPL))
+#define GDK_WINDOW_IMPL_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GDK_TYPE_WINDOW_IMPL, GdkWindowImplIface))
+
+typedef struct _GdkWindowImpl       GdkWindowImpl;
+typedef struct _GdkWindowImplIface  GdkWindowImplIface;
+
+struct _GdkWindowImplIface
+{
+  GTypeInterface g_iface;
+
+  void         (* show)                 (GdkWindow       *window,
+                                         gboolean         raise);
+  void         (* hide)                 (GdkWindow       *window);
+  void         (* withdraw)             (GdkWindow       *window);
+  void         (* raise)                (GdkWindow       *window);
+  void         (* lower)                (GdkWindow       *window);
+
+  void         (* move)                 (GdkWindow       *window,
+                                         gint             x,
+                                         gint             y);
+  void         (* resize)               (GdkWindow       *window,
+                                         gint             width,
+                                         gint             height);
+  void         (* move_resize)          (GdkWindow       *window,
+                                         gint             x,
+                                         gint             y,
+                                         gint             width,
+                                         gint             height);
+  void         (* move_region)          (GdkWindow       *window,
+                                         const GdkRegion *region,
+                                         gint             dx,
+                                         gint             dy);
+  void         (* scroll)               (GdkWindow       *window,
+                                         gint             dx,
+                                         gint             dy);
+
+  void         (* clear_area)           (GdkWindow       *window,
+                                         gint             x,
+                                         gint             y,
+                                         gint             width,
+                                         gint             height,
+                                         gboolean         send_expose);
+  void         (* set_background)       (GdkWindow       *window,
+                                         const GdkColor  *color);
+  void         (* set_back_pixmap)      (GdkWindow       *window,
+                                         GdkPixmap       *pixmap,
+                                         gboolean         parent_relative);
+
+  GdkEventMask (* get_events)           (GdkWindow       *window);
+  void         (* set_events)           (GdkWindow       *window,
+                                         GdkEventMask     event_mask);
+  
+  gboolean     (* reparent)             (GdkWindow       *window,
+                                         GdkWindow       *new_parent,
+                                         gint             x,
+                                         gint             y);
+  
+  void         (* set_cursor)           (GdkWindow       *window,
+                                         GdkCursor       *cursor);
+
+  void         (* get_geometry)         (GdkWindow       *window,
+                                         gint            *x,
+                                         gint            *y,
+                                         gint            *width,
+                                         gint            *height,
+                                         gint            *depth);
+  gint         (* get_origin)           (GdkWindow       *window,
+                                         gint            *x,
+                                         gint            *y);
+  void         (* get_offsets)          (GdkWindow       *window,
+                                         gint            *x_offset,
+                                         gint            *y_offset);
+
+  void         (* shape_combine_mask)   (GdkWindow       *window,
+                                         GdkBitmap       *mask,
+                                         gint             x,
+                                         gint             y);
+  void         (* shape_combine_region) (GdkWindow       *window,
+                                         const GdkRegion *shape_region,
+                                         gint             offset_x,
+                                         gint             offset_y);
+  void         (* set_child_shapes)     (GdkWindow       *window);
+  void         (* merge_child_shapes)   (GdkWindow       *window);
+
+  gboolean     (* set_static_gravities) (GdkWindow       *window,
+				         gboolean         use_static);
+};
+
+/* Interface Functions */
+GType gdk_window_impl_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_WINDOW_IMPL_H__ */
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 1cb5f67..0c03482 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -576,7 +576,7 @@ _gdk_x11_display_is_root_window (GdkDisplay *display,
  */
 void
 gdk_display_pointer_ungrab (GdkDisplay *display,
-			    guint32     time)
+			    guint32     time_)
 {
   Display *xdisplay;
   GdkDisplayX11 *display_x11;
@@ -586,14 +586,21 @@ gdk_display_pointer_ungrab (GdkDisplay *display,
   display_x11 = GDK_DISPLAY_X11 (display);
   xdisplay = GDK_DISPLAY_XDISPLAY (display);
   
-  _gdk_input_ungrab_pointer (display, time);
-  XUngrabPointer (xdisplay, time);
+  _gdk_input_ungrab_pointer (display, time_);
+  XUngrabPointer (xdisplay, time_);
   XFlush (xdisplay);
 
-  if (time == GDK_CURRENT_TIME || 
+  if (time_ == GDK_CURRENT_TIME || 
       display_x11->pointer_xgrab_time == GDK_CURRENT_TIME ||
-      !XSERVER_TIME_IS_LATER (display_x11->pointer_xgrab_time, time))
-    display_x11->pointer_xgrab_window = NULL;
+      !XSERVER_TIME_IS_LATER (display_x11->pointer_xgrab_time, time_))
+    {
+      GdkWindow *xgrab_window = GDK_WINDOW (display_x11->pointer_xgrab_window);
+
+      if (gdk_window_is_offscreen (xgrab_window))
+        _gdk_offscreen_window_unset_pointer_grab (xgrab_window, FALSE, FALSE, time_);
+
+      display_x11->pointer_xgrab_window = NULL;
+    }
 }
 
 /**
@@ -1308,7 +1315,9 @@ gdk_display_store_clipboard (GdkDisplay    *display,
 {
   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
   Atom clipboard_manager, save_targets;
-  
+
+  g_return_if_fail (!gdk_window_is_offscreen (clipboard_window));
+
   clipboard_manager = gdk_x11_get_xatom_by_name_for_display (display, "CLIPBOARD_MANAGER");
   save_targets = gdk_x11_get_xatom_by_name_for_display (display, "SAVE_TARGETS");
 
diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h
index ffd0461..d515a74 100644
--- a/gdk/x11/gdkdisplay-x11.h
+++ b/gdk/x11/gdkdisplay-x11.h
@@ -98,12 +98,14 @@ struct _GdkDisplayX11
    * window is NULL, then the other associated fields are ignored
    */
   GdkWindowObject *pointer_xgrab_window;
+  GdkWindowObject *pointer_xgrab_native_window;
   gulong pointer_xgrab_serial;
   gboolean pointer_xgrab_owner_events;
   gboolean pointer_xgrab_implicit;
   guint32 pointer_xgrab_time;
 
   GdkWindowObject *keyboard_xgrab_window;
+  GdkWindowObject *keyboard_xgrab_native_window;
   gulong keyboard_xgrab_serial;
   gboolean keyboard_xgrab_owner_events;
   guint32 keyboard_xgrab_time;
@@ -169,6 +171,9 @@ struct _GdkDisplayX11
 
   /* Alpha mask picture format */
   XRenderPictFormat *mask_format;
+
+  /* The offscreen window that has the pointer in it (if any) */
+  GdkWindow *active_offscreen_window;
 };
 
 struct _GdkDisplayX11Class
diff --git a/gdk/x11/gdkdnd-x11.c b/gdk/x11/gdkdnd-x11.c
index f910431..4089545 100644
--- a/gdk/x11/gdkdnd-x11.c
+++ b/gdk/x11/gdkdnd-x11.c
@@ -2987,6 +2987,7 @@ gdk_drag_begin (GdkWindow     *window,
   GdkDragContext *new_context;
   
   g_return_val_if_fail (window != NULL, NULL);
+  g_return_val_if_fail (!gdk_window_is_offscreen (window), NULL);
 
   new_context = gdk_drag_context_new ();
   new_context->is_source = TRUE;
@@ -3186,6 +3187,12 @@ gdk_drag_find_window_for_screen (GdkDragContext  *context,
 
   g_return_if_fail (context != NULL);
 
+  if (gdk_window_is_offscreen (drag_window))
+    {
+      *dest_window = NULL;
+      return;
+    }
+
   display = GDK_WINDOW_DISPLAY (context->source_window);
 
   window_cache = drag_context_find_window_cache (context, screen);
@@ -3261,6 +3268,7 @@ gdk_drag_motion (GdkDragContext *context,
   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
 
   g_return_val_if_fail (context != NULL, FALSE);
+  g_return_val_if_fail (dest_window == NULL || !gdk_window_is_offscreen (dest_window), FALSE);
 
   private->old_actions = context->actions;
   context->actions = possible_actions;
diff --git a/gdk/x11/gdkdrawable-x11.c b/gdk/x11/gdkdrawable-x11.c
index 67ba37c..2ab375b 100644
--- a/gdk/x11/gdkdrawable-x11.c
+++ b/gdk/x11/gdkdrawable-x11.c
@@ -870,7 +870,15 @@ gdk_x11_drawable_get_xid (GdkDrawable *drawable)
   GdkDrawable *impl;
   
   if (GDK_IS_WINDOW (drawable))
-    impl = ((GdkPixmapObject *)drawable)->impl;
+    {
+      if (gdk_window_is_offscreen (GDK_WINDOW (drawable)))
+        {
+          g_warning (G_STRLOC " drawable is an offscreen window");
+          return None;
+        }
+
+      impl = ((GdkPixmapObject *)drawable)->impl;
+    }
   else if (GDK_IS_PIXMAP (drawable))
     impl = ((GdkPixmapObject *)drawable)->impl;
   else
diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c
index a537ffc..bae944c 100644
--- a/gdk/x11/gdkevents-x11.c
+++ b/gdk/x11/gdkevents-x11.c
@@ -313,7 +313,9 @@ gdk_event_get_graphics_expose (GdkWindow *window)
   GdkEvent *event;
   
   g_return_val_if_fail (window != NULL, NULL);
-  
+
+  window = _gdk_window_get_offscreen_event_window (window);
+
   XIfEvent (GDK_WINDOW_XDISPLAY (window), &xevent, 
 	    graphics_expose_predicate, (XPointer) window);
   
@@ -942,6 +944,14 @@ gdk_event_translate (GdkDisplay *display,
     
   if (window != NULL)
     {
+      /* Rewrite keyboard grabs to offscreen windows */
+      if ((xevent->type == KeyPress || xevent->type == KeyRelease) &&
+          window_private == display_x11->keyboard_xgrab_native_window)
+        {
+          window_private = display_x11->keyboard_xgrab_window;
+          window = (GdkWindow *) window_private;
+        }
+
       window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
       
       /* Move key events on focus window to the real toplevel, and
@@ -1042,9 +1052,7 @@ gdk_event_translate (GdkDisplay *display,
   return_val = TRUE;
 
   if (window)
-    {
-      _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
-    }
+    _gdk_x11_window_get_offsets (window, &xoffset, &yoffset);
   else
     {
       xoffset = 0;
@@ -2299,6 +2307,7 @@ _gdk_events_queue (GdkDisplay *display)
       if (gdk_event_translate (display, event, &xevent, FALSE))
 	{
 	  ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
+          _gdk_event_rewrite_for_offscreen (display, node, event);
 	}
       else
 	{
diff --git a/gdk/x11/gdkgeometry-x11.c b/gdk/x11/gdkgeometry-x11.c
index 367f26c..b5869ef 100644
--- a/gdk/x11/gdkgeometry-x11.c
+++ b/gdk/x11/gdkgeometry-x11.c
@@ -192,9 +192,9 @@ static void gdk_window_clip_changed       (GdkWindow          *window,
 					   GdkRectangle       *new_clip);
 
 void
-_gdk_windowing_window_get_offsets (GdkWindow *window,
-				   gint      *x_offset,
-				   gint      *y_offset)
+_gdk_x11_window_get_offsets (GdkWindow *window,
+                             gint      *x_offset,
+                             gint      *y_offset)
 {
   GdkWindowImplX11 *impl =
     GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
@@ -395,25 +395,10 @@ gdk_window_guffaw_scroll (GdkWindow    *window,
   g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &parent_pos);
 }
 
-/**
- * gdk_window_scroll:
- * @window: a #GdkWindow
- * @dx: Amount to scroll in the X direction
- * @dy: Amount to scroll in the Y direction
- * 
- * Scroll the contents of @window, both pixels and children, by the given
- * amount. @window itself does not move.  Portions of the window that the scroll
- * operation brings in from offscreen areas are invalidated. The invalidated
- * region may be bigger than what would strictly be necessary.  (For X11, a
- * minimum area will be invalidated if the window has no subwindows, or if the
- * edges of the window's parent do not extend beyond the edges of the window. In
- * other cases, a multi-step process is used to scroll the window which may
- * produce temporary visual artifacts and unnecessary invalidations.)
- **/
 void
-gdk_window_scroll (GdkWindow *window,
-		   gint       dx,
-		   gint       dy)
+_gdk_x11_window_scroll (GdkWindow *window,
+                        gint       dx,
+                        gint       dy)
 {
   gboolean can_guffaw_scroll = FALSE;
   GdkRegion *invalidate_region;
@@ -421,17 +406,9 @@ gdk_window_scroll (GdkWindow *window,
   GdkWindowObject *obj;
   GdkRectangle src_rect, dest_rect;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-
-  if (GDK_WINDOW_DESTROYED (window))
-    return;
-  
   obj = GDK_WINDOW_OBJECT (window);
   impl = GDK_WINDOW_IMPL_X11 (obj->impl);  
 
-  if (dx == 0 && dy == 0)
-    return;
-  
   /* Move the current invalid region */
   if (obj->update_area)
     gdk_region_offset (obj->update_area, dx, dy);
@@ -483,26 +460,11 @@ gdk_window_scroll (GdkWindow *window,
     gdk_window_guffaw_scroll (window, dx, dy);
 }
 
-/**
- * gdk_window_move_region:
- * @window: a #GdkWindow
- * @region: The #GdkRegion to move
- * @dx: Amount to move in the X direction
- * @dy: Amount to move in the Y direction
- * 
- * Move the part of @window indicated by @region by @dy pixels in the Y 
- * direction and @dx pixels in the X direction. The portions of @region 
- * that not covered by the new position of @region are invalidated.
- * 
- * Child windows are not moved.
- * 
- * Since: 2.8
- **/
 void
-gdk_window_move_region (GdkWindow       *window,
-			const GdkRegion *region,
-			gint             dx,
-			gint             dy)
+_gdk_x11_window_move_region (GdkWindow       *window,
+                             const GdkRegion *region,
+                             gint             dx,
+                             gint             dy)
 {
   GdkWindowImplX11 *impl;
   GdkWindowObject *private;
@@ -514,18 +476,9 @@ gdk_window_move_region (GdkWindow       *window,
   GdkRectangle dest_extents;
   GdkGC *gc;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  g_return_if_fail (region != NULL);
-  
-  if (GDK_WINDOW_DESTROYED (window))
-    return;
-  
   private = GDK_WINDOW_OBJECT (window);
   impl = GDK_WINDOW_IMPL_X11 (private->impl);  
 
-  if (dx == 0 && dy == 0)
-    return;
-
   window_clip = gdk_region_rectangle (&impl->position_info.clip_rect);
 
   /* compute source regions */
@@ -902,6 +855,9 @@ gdk_window_premove (GdkWindow          *window,
   gint d_xoffset, d_yoffset;
   GdkWindowParentPos this_pos;
 
+  if (gdk_window_is_offscreen (window))
+    return;
+
   obj = (GdkWindowObject *) window;
   impl = GDK_WINDOW_IMPL_X11 (obj->impl);
   
@@ -942,6 +898,9 @@ gdk_window_postmove (GdkWindow          *window,
   gint d_xoffset, d_yoffset;
   GdkWindowParentPos this_pos;
 
+  if (gdk_window_is_offscreen (window))
+    return;
+
   obj = (GdkWindowObject *) window;
   impl = GDK_WINDOW_IMPL_X11 (obj->impl);
   
diff --git a/gdk/x11/gdkinput.c b/gdk/x11/gdkinput.c
index 8d87479..669215b 100644
--- a/gdk/x11/gdkinput.c
+++ b/gdk/x11/gdkinput.c
@@ -207,7 +207,7 @@ gdk_device_get_history  (GdkDevice         *device,
   int tmp_n_events = 0;
   int i;
 
-  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+  g_return_val_if_fail (GDK_IS_ONSCREEN_WINDOW (window), FALSE);
 
   if (GDK_WINDOW_DESTROYED (window))
     /* Nothing */ ;
@@ -303,7 +303,7 @@ gdk_input_set_extension_events (GdkWindow *window, gint mask,
   GdkDisplayX11 *display_x11;
 
   g_return_if_fail (window != NULL);
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
   window_private = (GdkWindowObject*) window;
   display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c
index 0399b9c..58c55cd 100644
--- a/gdk/x11/gdkmain-x11.c
+++ b/gdk/x11/gdkmain-x11.c
@@ -191,6 +191,7 @@ gdk_pointer_grab (GdkWindow *	  window,
 {
   gint return_val;
   GdkCursorPrivate *cursor_private;
+  GdkWindow *native;
   GdkDisplayX11 *display_x11;
   guint xevent_mask;
   Window xwindow;
@@ -202,13 +203,18 @@ gdk_pointer_grab (GdkWindow *	  window,
   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);
-  
-  display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
+
+  native = _gdk_window_get_offscreen_event_window (window);
+
+  if (confine_to)
+    confine_to = _gdk_window_get_offscreen_event_window (confine_to);
+
+  display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (native));
 
   cursor_private = (GdkCursorPrivate*) cursor;
   
-  xwindow = GDK_WINDOW_XID (window);
-  serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
+  xwindow = GDK_WINDOW_XID (native);
+  serial = NextRequest (GDK_WINDOW_XDISPLAY (native));
   
   if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
     xconfine_to = None;
@@ -230,7 +236,7 @@ gdk_pointer_grab (GdkWindow *	  window,
 	xevent_mask |= _gdk_event_mask_table[i];
     }
   
-  return_val = _gdk_input_grab_pointer (window,
+  return_val = _gdk_input_grab_pointer (native,
 					owner_events,
 					event_mask,
 					confine_to,
@@ -239,14 +245,14 @@ gdk_pointer_grab (GdkWindow *	  window,
   if (return_val == GrabSuccess || 
       G_UNLIKELY (!display_x11->trusted_client && return_val == AlreadyGrabbed))
     {
-      if (!GDK_WINDOW_DESTROYED (window))
+      if (!GDK_WINDOW_DESTROYED (native))
 	{
 #ifdef G_ENABLE_DEBUG
 	  if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
 	    return_val = GrabSuccess;
 	  else
 #endif
-	    return_val = XGrabPointer (GDK_WINDOW_XDISPLAY (window),
+	    return_val = XGrabPointer (GDK_WINDOW_XDISPLAY (native),
 				       xwindow,
 				       owner_events,
 				       xevent_mask,
@@ -263,11 +269,25 @@ gdk_pointer_grab (GdkWindow *	  window,
     {
       if (display_x11->pointer_xgrab_window != NULL &&
 	  display_x11->pointer_xgrab_window != (GdkWindowObject *)window)
-	generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window),
-				    FALSE, display_x11->pointer_xgrab_implicit,
-				    window);
+        {
+          if (gdk_window_is_offscreen (GDK_WINDOW (display_x11->pointer_xgrab_window)))
+            _gdk_offscreen_window_unset_pointer_grab (GDK_WINDOW (display_x11->pointer_xgrab_window),
+                                                      TRUE, FALSE, time);
+
+	  generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window),
+                                      FALSE, display_x11->pointer_xgrab_implicit,
+                                      window);
+        }
+
+      if (gdk_window_is_offscreen (window))
+        _gdk_offscreen_window_set_pointer_grab (GDK_WINDOW (display_x11->pointer_xgrab_window),
+                                                GDK_WINDOW (display_x11->pointer_xgrab_native_window),
+                                                window,
+                                                owner_events, event_mask,
+                                                time);
 
       display_x11->pointer_xgrab_window = (GdkWindowObject *)window;
+      display_x11->pointer_xgrab_native_window = (GdkWindowObject *)native;
       display_x11->pointer_xgrab_serial = serial;
       display_x11->pointer_xgrab_owner_events = owner_events;
       display_x11->pointer_xgrab_time = time;
@@ -342,23 +362,26 @@ gdk_keyboard_grab (GdkWindow *	   window,
   gint return_val;
   unsigned long serial;
   GdkDisplayX11 *display_x11;
-  
+  GdkWindow *native;
+
   g_return_val_if_fail (window != NULL, 0);
   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
-  
-  display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
 
-  serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
+  native = _gdk_window_get_offscreen_event_window (window);
 
-  if (!GDK_WINDOW_DESTROYED (window))
+  display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (native));
+
+  serial = NextRequest (GDK_WINDOW_XDISPLAY (native));
+
+  if (!GDK_WINDOW_DESTROYED (native))
     {
 #ifdef G_ENABLE_DEBUG
       if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
 	return_val = GrabSuccess;
       else
 #endif
-	return_val = XGrabKeyboard (GDK_WINDOW_XDISPLAY (window),
-				    GDK_WINDOW_XID (window),
+	return_val = XGrabKeyboard (GDK_WINDOW_XDISPLAY (native),
+				    GDK_WINDOW_XID (native),
 				    owner_events,
 				    GrabModeAsync, GrabModeAsync,
 				    time);
@@ -378,6 +401,7 @@ gdk_keyboard_grab (GdkWindow *	   window,
 				    TRUE, FALSE, window);
       
       display_x11->keyboard_xgrab_window = (GdkWindowObject *)window;
+      display_x11->keyboard_xgrab_native_window = (GdkWindowObject *)native;
       display_x11->keyboard_xgrab_serial = serial;
       display_x11->keyboard_xgrab_owner_events = owner_events;
       display_x11->keyboard_xgrab_time = time;      
@@ -386,6 +410,19 @@ gdk_keyboard_grab (GdkWindow *	   window,
   return gdk_x11_convert_grab_status (return_val);
 }
 
+void
+_gdk_windowing_grab_broken (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window),
+                              FALSE,
+                              display_x11->pointer_xgrab_implicit,
+                              NULL);
+
+  display_x11->pointer_xgrab_window = NULL;
+}
+
 /**
  * gdk_keyboard_grab_info_libgtk_only:
  * @display: the display for which to get the grab information
@@ -443,13 +480,18 @@ _gdk_xgrab_check_unmap (GdkWindow *window,
       serial >= display_x11->pointer_xgrab_serial)
     {
       GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
-      GdkWindowObject *tmp = display_x11->pointer_xgrab_window;
+      GdkWindowObject *tmp = display_x11->pointer_xgrab_native_window;
 
       while (tmp && tmp != private)
 	tmp = tmp->parent;
 
       if (tmp)
-	{	  
+        {
+          if (gdk_window_is_offscreen (GDK_WINDOW (display_x11->pointer_xgrab_window)))
+            _gdk_offscreen_window_unset_pointer_grab (GDK_WINDOW (display_x11->pointer_xgrab_window),
+                                                      FALSE, FALSE,
+                                                      GDK_CURRENT_TIME);
+
 	  generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window),
 				      FALSE, display_x11->pointer_xgrab_implicit, 
 				      NULL);
@@ -488,15 +530,22 @@ _gdk_xgrab_check_destroy (GdkWindow *window)
 {
   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
   
-  if ((GdkWindowObject *)window == display_x11->pointer_xgrab_window)
+  if ((GdkWindowObject *)window == display_x11->pointer_xgrab_native_window &&
+      display_x11->pointer_xgrab_window != NULL)
     {
+      if (gdk_window_is_offscreen (GDK_WINDOW (display_x11->pointer_xgrab_window)))
+        _gdk_offscreen_window_unset_pointer_grab (GDK_WINDOW (display_x11->pointer_xgrab_window),
+                                                  FALSE, FALSE,
+                                                  GDK_CURRENT_TIME);
+
       generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window),
 				  FALSE, display_x11->pointer_xgrab_implicit,
 				  NULL);
       display_x11->pointer_xgrab_window = NULL;
     }
 
-  if ((GdkWindowObject *)window ==  display_x11->keyboard_xgrab_window)
+  if ((GdkWindowObject *)window == display_x11->keyboard_xgrab_native_window &&
+      display_x11->keyboard_xgrab_window != NULL)
     {
       generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window),
 				  TRUE, FALSE, NULL);
@@ -530,6 +579,7 @@ _gdk_xgrab_check_button_event (GdkWindow *window,
       if (!display_x11->pointer_xgrab_window)
 	{
 	  display_x11->pointer_xgrab_window = (GdkWindowObject *)window;
+          display_x11->pointer_xgrab_native_window = (GdkWindowObject *)window;
 	  display_x11->pointer_xgrab_serial = xevent->xany.serial;
 	  display_x11->pointer_xgrab_owner_events = FALSE;
 	  display_x11->pointer_xgrab_time = xevent->xbutton.time;
@@ -541,6 +591,11 @@ _gdk_xgrab_check_button_event (GdkWindow *window,
 	  display_x11->pointer_xgrab_implicit &&
 	  (xevent->xbutton.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (xevent->xbutton.button - 1))) == 0)
 	{
+          if (gdk_window_is_offscreen (GDK_WINDOW (display_x11->pointer_xgrab_window)))
+            _gdk_offscreen_window_unset_pointer_grab (GDK_WINDOW (display_x11->pointer_xgrab_window),
+                                                      FALSE, TRUE,
+                                                      xevent->xbutton.time);
+
 	  display_x11->pointer_xgrab_window = NULL;
 	}
       break;
@@ -550,6 +605,27 @@ _gdk_xgrab_check_button_event (GdkWindow *window,
 }
 
 void
+_gdk_windowing_update_implicit_grab (GdkWindow *old_grab,
+                                     GdkWindow *new_grab,
+                                     guint      event_mask,
+                                     guint32    time)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (old_grab));
+
+  if (display_x11->pointer_xgrab_window == GDK_WINDOW_OBJECT (old_grab) &&
+      display_x11->pointer_xgrab_implicit)
+    {
+      if (gdk_window_is_offscreen (new_grab))
+        _gdk_offscreen_window_set_pointer_grab (GDK_WINDOW (display_x11->pointer_xgrab_window),
+                                                GDK_WINDOW (display_x11->pointer_xgrab_native_window),
+                                                new_grab, FALSE,
+                                                event_mask, time);
+
+     display_x11->pointer_xgrab_window = GDK_WINDOW_OBJECT (new_grab);
+   }
+}
+
+void
 _gdk_windowing_display_set_sm_client_id (GdkDisplay  *display,
 					 const gchar *sm_client_id)
 {
diff --git a/gdk/x11/gdkpixmap-x11.c b/gdk/x11/gdkpixmap-x11.c
index 3dc72a6..f34bfc0 100644
--- a/gdk/x11/gdkpixmap-x11.c
+++ b/gdk/x11/gdkpixmap-x11.c
@@ -137,10 +137,10 @@ gdk_pixmap_impl_x11_get_size   (GdkDrawable *drawable,
 }
 
 GdkPixmap*
-gdk_pixmap_new (GdkDrawable *drawable,
-		gint         width,
-		gint         height,
-		gint         depth)
+_gdk_pixmap_new (GdkDrawable *drawable,
+                 gint         width,
+                 gint         height,
+                 gint         depth)
 {
   GdkPixmap *pixmap;
   GdkDrawableImplX11 *draw_impl;
@@ -194,10 +194,10 @@ gdk_pixmap_new (GdkDrawable *drawable,
 }
 
 GdkPixmap *
-gdk_bitmap_create_from_data (GdkDrawable *drawable,
-			     const gchar *data,
-			     gint         width,
-			     gint         height)
+_gdk_bitmap_create_from_data (GdkDrawable *drawable,
+                              const gchar *data,
+                              gint         width,
+                              gint         height)
 {
   GdkPixmap *pixmap;
   GdkDrawableImplX11 *draw_impl;
@@ -238,13 +238,13 @@ gdk_bitmap_create_from_data (GdkDrawable *drawable,
 }
 
 GdkPixmap*
-gdk_pixmap_create_from_data (GdkDrawable    *drawable,
-			     const gchar    *data,
-			     gint            width,
-			     gint            height,
-			     gint            depth,
-			     const GdkColor *fg,
-			     const GdkColor *bg)
+_gdk_pixmap_create_from_data (GdkDrawable    *drawable,
+			      const gchar    *data,
+			      gint            width,
+			      gint            height,
+			      gint            depth,
+			      const GdkColor *fg,
+			      const GdkColor *bg)
 {
   GdkPixmap *pixmap;
   GdkDrawableImplX11 *draw_impl;
diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h
index 5033c4a..a9c357e 100644
--- a/gdk/x11/gdkprivate-x11.h
+++ b/gdk/x11/gdkprivate-x11.h
@@ -128,6 +128,14 @@ void _gdk_window_process_expose    (GdkWindow     *window,
                                     gulong         serial,
                                     GdkRectangle  *area);
 
+void _gdk_x11_window_scroll        (GdkWindow       *window,
+                                    gint             dx,
+                                    gint             dy);
+void _gdk_x11_window_move_region   (GdkWindow       *window,
+                                    const GdkRegion *region,
+                                    gint             dx,
+                                    gint             dy);
+
 void     _gdk_selection_window_destroyed   (GdkWindow            *window);
 gboolean _gdk_selection_filter_clear_event (XSelectionClearEvent *event);
 
@@ -207,5 +215,6 @@ extern gboolean          _gdk_synchronize;
 #define GDK_WINDOW_DISPLAY(win)       (GDK_SCREEN_X11 (GDK_WINDOW_SCREEN (win))->display)
 #define GDK_WINDOW_XROOTWIN(win)      (GDK_SCREEN_X11 (GDK_WINDOW_SCREEN (win))->xroot_window)
 #define GDK_GC_DISPLAY(gc)            (GDK_SCREEN_DISPLAY (GDK_GC_X11(gc)->screen))
+#define GDK_IS_ONSCREEN_WINDOW(win)   (GDK_IS_WINDOW (win) && !gdk_window_is_offscreen ((win)))
 
 #endif /* __GDK_PRIVATE_X11_H__ */
diff --git a/gdk/x11/gdkproperty-x11.c b/gdk/x11/gdkproperty-x11.c
index 7095125..8ef11c9 100644
--- a/gdk/x11/gdkproperty-x11.c
+++ b/gdk/x11/gdkproperty-x11.c
@@ -541,7 +541,7 @@ gdk_property_get (GdkWindow   *window,
   Atom xtype;
   int res;
 
-  g_return_val_if_fail (!window || GDK_IS_WINDOW (window), FALSE);
+  g_return_val_if_fail (!window || GDK_IS_ONSCREEN_WINDOW (window), FALSE);
 
   if (!window)
     {
@@ -550,6 +550,8 @@ gdk_property_get (GdkWindow   *window,
       
       GDK_NOTE (MULTIHEAD, g_message ("gdk_property_get(): window is NULL\n"));
     }
+  else if (gdk_window_is_offscreen (window))
+    return FALSE;
 
   if (GDK_WINDOW_DESTROYED (window))
     return FALSE;
@@ -675,7 +677,7 @@ gdk_property_change (GdkWindow    *window,
   Atom xproperty;
   Atom xtype;
 
-  g_return_if_fail (!window || GDK_IS_WINDOW (window));
+  g_return_if_fail (!window || GDK_IS_ONSCREEN_WINDOW (window));
 
   if (!window)
     {
@@ -686,7 +688,8 @@ gdk_property_change (GdkWindow    *window,
       
       GDK_NOTE (MULTIHEAD, g_message ("gdk_property_change(): window is NULL\n"));
     }
-
+  else if (gdk_window_is_offscreen (window))
+    return;
 
   if (GDK_WINDOW_DESTROYED (window))
     return;
@@ -726,7 +729,7 @@ void
 gdk_property_delete (GdkWindow *window,
 		     GdkAtom    property)
 {
-  g_return_if_fail (!window || GDK_IS_WINDOW (window));
+  g_return_if_fail (!window || GDK_IS_ONSCREEN_WINDOW (window));
 
   if (!window)
     {
@@ -736,6 +739,8 @@ gdk_property_delete (GdkWindow *window,
       GDK_NOTE (MULTIHEAD, 
 		g_message ("gdk_property_delete(): window is NULL\n"));
     }
+  else if (gdk_window_is_offscreen (window))
+    return;
 
   if (GDK_WINDOW_DESTROYED (window))
     return;
diff --git a/gdk/x11/gdkselection-x11.c b/gdk/x11/gdkselection-x11.c
index 88d2729..e29546b 100644
--- a/gdk/x11/gdkselection-x11.c
+++ b/gdk/x11/gdkselection-x11.c
@@ -141,7 +141,7 @@ gdk_selection_owner_set_for_display (GdkDisplay *display,
 
   if (owner) 
     {
-      if (GDK_WINDOW_DESTROYED (owner))
+      if (GDK_WINDOW_DESTROYED (owner) || gdk_window_is_offscreen (owner))
 	return FALSE;
       
       xdisplay = GDK_WINDOW_XDISPLAY (owner);
@@ -231,7 +231,7 @@ gdk_selection_convert (GdkWindow *requestor,
 
   g_return_if_fail (selection != GDK_NONE);
   
-  if (GDK_WINDOW_DESTROYED (requestor))
+  if (GDK_WINDOW_DESTROYED (requestor) || gdk_window_is_offscreen (requestor))
     return;
 
   display = GDK_WINDOW_DISPLAY (requestor);
@@ -279,10 +279,11 @@ gdk_selection_property_get (GdkWindow  *requestor,
 
   g_return_val_if_fail (requestor != NULL, 0);
   g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
+  g_return_val_if_fail (GDK_IS_ONSCREEN_WINDOW (requestor), 0);
   
   display = GDK_WINDOW_DISPLAY (requestor);
 
-  if (GDK_WINDOW_DESTROYED (requestor))
+  if (GDK_WINDOW_DESTROYED (requestor) || gdk_window_is_offscreen (requestor))
     goto err;
 
   t = NULL;
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index b316bc5..acc23a0 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -41,6 +41,7 @@
 #include "gdk.h"
 
 #include "gdkwindow.h"
+#include "gdkwindowimpl.h"
 #include "gdkasync.h"
 #include "gdkinputprivate.h"
 #include "gdkdisplay-x11.h"
@@ -115,7 +116,8 @@ static void         gdk_window_impl_x11_get_size    (GdkDrawable *drawable,
 						     gint *width,
 						     gint *height);
 static GdkRegion*  gdk_window_impl_x11_get_visible_region (GdkDrawable *drawable);
-static void gdk_window_impl_x11_finalize   (GObject            *object);
+static void        gdk_window_impl_x11_finalize   (GObject            *object);
+static void        gdk_window_impl_iface_init     (GdkWindowImplIface *iface);
 
 #define WINDOW_IS_TOPLEVEL(window)		   \
   (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \
@@ -129,7 +131,11 @@ static void gdk_window_impl_x11_finalize   (GObject            *object);
     (( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 ))     \
   )
 
-G_DEFINE_TYPE (GdkWindowImplX11, gdk_window_impl_x11, GDK_TYPE_DRAWABLE_IMPL_X11)
+G_DEFINE_TYPE_WITH_CODE (GdkWindowImplX11,
+                         gdk_window_impl_x11,
+                         GDK_TYPE_DRAWABLE_IMPL_X11,
+                         G_IMPLEMENT_INTERFACE (GDK_TYPE_WINDOW_IMPL,
+                                                gdk_window_impl_iface_init));
 
 GType
 _gdk_window_impl_get_type (void)
@@ -294,7 +300,8 @@ _gdk_x11_window_tmp_unset_bg (GdkWindow *window,
 
   if (private->input_only || private->destroyed ||
       (private->window_type != GDK_WINDOW_ROOT &&
-       !GDK_WINDOW_IS_MAPPED (window)))
+       !GDK_WINDOW_IS_MAPPED (window)) ||
+       gdk_window_is_offscreen (window))
     {
       return;
     }
@@ -326,7 +333,8 @@ _gdk_x11_window_tmp_reset_bg (GdkWindow *window,
 
   if (private->input_only || private->destroyed ||
       (private->window_type != GDK_WINDOW_ROOT &&
-       !GDK_WINDOW_IS_MAPPED (window)))
+       !GDK_WINDOW_IS_MAPPED (window)) ||
+       gdk_window_is_offscreen (window))
     {
       return;
     }
@@ -448,7 +456,10 @@ _gdk_windowing_window_init (GdkScreen * screen)
 				   gdk_screen_get_system_colormap (screen));
 
   screen_x11->root_window = g_object_new (GDK_TYPE_WINDOW, NULL);
-  private = (GdkWindowObject *)screen_x11->root_window;
+
+  private = (GdkWindowObject *) screen_x11->root_window;
+  private->impl = g_object_new (_gdk_window_impl_get_type (), NULL);
+
   impl = GDK_WINDOW_IMPL_X11 (private->impl);
   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
   
@@ -647,24 +658,10 @@ setup_toplevel_window (GdkWindow *window,
   ensure_sync_counter (window);
 }
 
-/**
- * gdk_window_new:
- * @parent: a #GdkWindow, or %NULL to create the window as a child of
- *   the default root window for the default display.
- * @attributes: attributes of the new window
- * @attributes_mask: mask indicating which fields in @attributes are valid
- * 
- * Creates a new #GdkWindow using the attributes from
- * @attributes. See #GdkWindowAttr and #GdkWindowAttributesType for
- * more details.  Note: to use this on displays other than the default
- * display, @parent must be specified.
- * 
- * Return value: the new #GdkWindow
- **/
-GdkWindow*
-gdk_window_new (GdkWindow     *parent,
-		GdkWindowAttr *attributes,
-		gint           attributes_mask)
+GdkWindow *
+_gdk_window_new (GdkWindow     *parent,
+		 GdkWindowAttr *attributes,
+		 gint           attributes_mask)
 {
   GdkWindow *window;
   GdkWindowObject *private;
@@ -711,7 +708,10 @@ gdk_window_new (GdkWindow     *parent,
   xparent = GDK_WINDOW_XID (parent);
   
   window = g_object_new (GDK_TYPE_WINDOW, NULL);
-  private = (GdkWindowObject *)window;
+
+  private = (GdkWindowObject *) window;
+  private->impl = g_object_new (_gdk_window_impl_get_type (), NULL);
+
   impl = GDK_WINDOW_IMPL_X11 (private->impl);
   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
   draw_impl->wrapper = GDK_DRAWABLE (window);
@@ -1026,7 +1026,10 @@ gdk_window_foreign_new_for_display (GdkDisplay     *display,
     XFree (children);
   
   window = g_object_new (GDK_TYPE_WINDOW, NULL);
-  private = (GdkWindowObject *)window;
+
+  private = (GdkWindowObject *) window;
+  private->impl = g_object_new (_gdk_window_impl_get_type (), NULL);
+
   impl = GDK_WINDOW_IMPL_X11 (private->impl);
   draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl);
   draw_impl->wrapper = GDK_DRAWABLE (window);
@@ -1214,7 +1217,7 @@ gdk_window_destroy_notify (GdkWindow *window)
 {
   GdkWindowImplX11 *window_impl;
 
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   
   window_impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl);
 
@@ -1414,16 +1417,14 @@ set_initial_hints (GdkWindow *window)
 }
 
 static void
-show_window_internal (GdkWindow *window,
-                      gboolean   raise)
+gdk_window_x11_show (GdkWindow *window,
+                     gboolean   raise)
 {
   GdkWindowObject *private;
   GdkDisplay *display;
   GdkDisplayX11 *display_x11;
   GdkToplevelX11 *toplevel;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
   private = (GdkWindowObject*) window;
   if (!private->destroyed)
     {
@@ -1478,50 +1479,6 @@ show_window_internal (GdkWindow *window,
     }
 }
 
-/**
- * gdk_window_show_unraised:
- * @window: a #GdkWindow
- *
- * Shows a #GdkWindow onscreen, but does not modify its stacking
- * order. In contrast, gdk_window_show() will raise the window
- * to the top of the window stack.
- *
- * On the X11 platform, in Xlib terms, this function calls
- * XMapWindow() (it also updates some internal GDK state, which means
- * that you can't really use XMapWindow() directly on a GDK window).
- * 
- **/
-void
-gdk_window_show_unraised (GdkWindow *window)
-{
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
-  show_window_internal (window, FALSE);
-}
-
-/**
- * gdk_window_show:
- * @window: a #GdkWindow
- *
- * Like gdk_window_show_unraised(), but also raises the window to the
- * top of the window stack (moves the window to the front of the
- * Z-order).
- *
- * This function maps a window so it's visible onscreen. Its opposite
- * is gdk_window_hide().
- *
- * When implementing a #GtkWidget, you should call this function on the widget's
- * #GdkWindow as part of the "map" method.
- * 
- **/
-void
-gdk_window_show (GdkWindow *window)
-{
-  g_return_if_fail (GDK_IS_WINDOW (window));
-
-  show_window_internal (window, TRUE);
-}
-
 static void
 pre_unmap (GdkWindow *window)
 {
@@ -1571,23 +1528,11 @@ post_unmap (GdkWindow *window)
     }
 }
 
-/**
- * gdk_window_hide:
- * @window: a #GdkWindow
- *
- * For toplevel windows, withdraws them, so they will no longer be
- * known to the window manager; for all windows, unmaps them, so
- * they won't be displayed. Normally done automatically as
- * part of gtk_widget_hide().
- * 
- **/
-void
-gdk_window_hide (GdkWindow *window)
+static void
+gdk_window_x11_hide (GdkWindow *window)
 {
   GdkWindowObject *private;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-
   private = (GdkWindowObject*) window;
 
   /* We'll get the unmap notify eventually, and handle it then,
@@ -1632,22 +1577,11 @@ gdk_window_hide (GdkWindow *window)
     }
 }
 
-/**
- * gdk_window_withdraw:
- * @window: a toplevel #GdkWindow
- * 
- * Withdraws a window (unmaps it and asks the window manager to forget about it).
- * This function is not really useful as gdk_window_hide() automatically
- * withdraws toplevel windows before hiding them.
- * 
- **/
-void
-gdk_window_withdraw (GdkWindow *window)
+static void
+gdk_window_x11_withdraw (GdkWindow *window)
 {
   GdkWindowObject *private;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
   private = (GdkWindowObject*) window;
   if (!private->destroyed)
     {
@@ -1667,33 +1601,16 @@ gdk_window_withdraw (GdkWindow *window)
     }
 }
 
-/**
- * gdk_window_move:
- * @window: a #GdkWindow
- * @x: X coordinate relative to window's parent
- * @y: Y coordinate relative to window's parent
- *
- * Repositions a window relative to its parent window.
- * For toplevel windows, window managers may ignore or modify the move;
- * you should probably use gtk_window_move() on a #GtkWindow widget
- * anyway, instead of using GDK functions. For child windows,
- * the move will reliably succeed.
- *
- * If you're also planning to resize the window, use gdk_window_move_resize()
- * to both move and resize simultaneously, for a nicer visual effect.
- **/
-void
-gdk_window_move (GdkWindow *window,
-		 gint       x,
-		 gint       y)
+static void
+gdk_window_x11_move (GdkWindow *window,
+                     gint       x,
+                     gint       y)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   GdkWindowImplX11 *impl;
 
-  g_return_if_fail (GDK_IS_WINDOW (window));
-
   impl = GDK_WINDOW_IMPL_X11 (private->impl);
-	  
+
   if (!GDK_WINDOW_DESTROYED (window))
     {
       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
@@ -1716,37 +1633,20 @@ gdk_window_move (GdkWindow *window,
     }
 }
 
-/**
- * gdk_window_resize:
- * @window: a #GdkWindow
- * @width: new width of the window
- * @height: new height of the window
- *
- * Resizes @window; for toplevel windows, asks the window manager to resize
- * the window. The window manager may not allow the resize. When using GTK+,
- * use gtk_window_resize() instead of this low-level GDK function.
- *
- * Windows may not be resized below 1x1.
- * 
- * If you're also planning to move the window, use gdk_window_move_resize()
- * to both move and resize simultaneously, for a nicer visual effect.
- **/
-void
-gdk_window_resize (GdkWindow *window,
-		   gint       width,
-		   gint       height)
+static void
+gdk_window_x11_resize (GdkWindow *window,
+                       gint       width,
+                       gint       height)
 {
   GdkWindowObject *private;
-  
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
+
   if (width < 1)
     width = 1;
   if (height < 1)
     height = 1;
 
   private = (GdkWindowObject*) window;
-  
+
   if (!GDK_WINDOW_DESTROYED (window))
     {
       if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
@@ -1780,35 +1680,21 @@ gdk_window_resize (GdkWindow *window,
     }
 }
 
-/**
- * gdk_window_move_resize:
- * @window: a #GdkWindow
- * @x: new X position relative to window's parent
- * @y: new Y position relative to window's parent
- * @width: new width
- * @height: new height
- *
- * Equivalent to calling gdk_window_move() and gdk_window_resize(),
- * except that both operations are performed at once, avoiding strange
- * visual effects. (i.e. the user may be able to see the window first
- * move, then resize, if you don't use gdk_window_move_resize().)
- **/
-void
-gdk_window_move_resize (GdkWindow *window,
-			gint       x,
-			gint       y,
-			gint       width,
-			gint       height)
+static void
+gdk_window_x11_move_resize (GdkWindow *window,
+                            gint       x,
+                            gint       y,
+                            gint       width,
+                            gint       height)
 {
   GdkWindowObject *private;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-
   if (width < 1)
     width = 1;
+
   if (height < 1)
     height = 1;
-  
+
   private = (GdkWindowObject*) window;
 
   if (!GDK_WINDOW_DESTROYED (window))
@@ -1843,39 +1729,24 @@ gdk_window_move_resize (GdkWindow *window,
     }
 }
 
-/**
- * gdk_window_reparent:
- * @window: a #GdkWindow
- * @new_parent: new parent to move @window into
- * @x: X location inside the new parent
- * @y: Y location inside the new parent
- *
- * Reparents @window into the given @new_parent. The window being
- * reparented will be unmapped as a side effect.
- * 
- **/
-void
-gdk_window_reparent (GdkWindow *window,
-		     GdkWindow *new_parent,
-		     gint       x,
-		     gint       y)
+static gboolean
+gdk_window_x11_reparent (GdkWindow *window,
+                         GdkWindow *new_parent,
+                         gint       x,
+                         gint       y)
 {
   GdkWindowObject *window_private;
   GdkWindowObject *parent_private;
   GdkWindowObject *old_parent_private;
   GdkWindowImplX11 *impl;
   gboolean was_toplevel;
-  
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent));
-  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
 
-  if (GDK_WINDOW_DESTROYED (window) ||
-      (new_parent && GDK_WINDOW_DESTROYED (new_parent)))
+  if (new_parent && gdk_window_is_offscreen (new_parent))
     {
-      return;
+      g_warning ("Can't reparent a X11 window to an offscreen parent");
+      return FALSE;
     }
-  
+
   if (!new_parent)
     new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window));
 
@@ -1883,7 +1754,7 @@ gdk_window_reparent (GdkWindow *window,
   old_parent_private = (GdkWindowObject*)window_private->parent;
   parent_private = (GdkWindowObject*) new_parent;
   impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
-  
+
   XReparentWindow (GDK_WINDOW_XDISPLAY (window),
 		   GDK_WINDOW_XID (window),
 		   GDK_WINDOW_XID (new_parent),
@@ -1891,13 +1762,13 @@ gdk_window_reparent (GdkWindow *window,
 
   window_private->x = x;
   window_private->y = y;
-  
+
   /* From here on, we treat parents of type GDK_WINDOW_FOREIGN like
    * the root window
    */
   if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
     new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window));
-  
+
   window_private->parent = (GdkWindowObject *)new_parent;
 
   /* Switch the window type as appropriate */
@@ -1907,7 +1778,7 @@ gdk_window_reparent (GdkWindow *window,
     case GDK_WINDOW_ROOT:
     case GDK_WINDOW_FOREIGN:
       was_toplevel = WINDOW_IS_TOPLEVEL (window);
-      
+
       if (impl->toplevel_window_type != -1)
 	GDK_WINDOW_TYPE (window) = impl->toplevel_window_type;
       else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
@@ -1934,7 +1805,7 @@ gdk_window_reparent (GdkWindow *window,
 		  XDestroyWindow (GDK_WINDOW_XDISPLAY (window), impl->toplevel->focus_window);
 		  _gdk_xid_table_remove (GDK_WINDOW_DISPLAY (window), impl->toplevel->focus_window);
 		}
-		
+
 	      gdk_toplevel_x11_free_contents (GDK_WINDOW_DISPLAY (window), 
 					      impl->toplevel);
 	      g_free (impl->toplevel);
@@ -1945,88 +1816,42 @@ gdk_window_reparent (GdkWindow *window,
 
   if (old_parent_private)
     old_parent_private->children = g_list_remove (old_parent_private->children, window);
-  
+
   if ((old_parent_private &&
        (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) ||
       (!old_parent_private && parent_private->guffaw_gravity))
     gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity);
-  
+
   parent_private->children = g_list_prepend (parent_private->children, window);
   _gdk_window_init_position (GDK_WINDOW (window_private));
-}
 
-void
-_gdk_windowing_window_clear_area (GdkWindow *window,
-				  gint       x,
-				  gint       y,
-				  gint       width,
-				  gint       height)
-{
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
-  if (!GDK_WINDOW_DESTROYED (window))
-    XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
-		x, y, width, height, False);
+  return TRUE;
 }
 
-void
-_gdk_windowing_window_clear_area_e (GdkWindow *window,
-				    gint       x,
-				    gint       y,
-				    gint       width,
-				    gint       height)
+static void
+gdk_window_x11_clear_area (GdkWindow *window,
+                           gint       x,
+                           gint       y,
+                           gint       width,
+                           gint       height,
+                           gboolean   send_expose)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
   if (!GDK_WINDOW_DESTROYED (window))
     XClearArea (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
-		x, y, width, height, True);
+		x, y, width, height,
+                send_expose);
 }
 
-
-/**
- * gdk_window_raise:
- * @window: a #GdkWindow
- * 
- * Raises @window to the top of the Z-order (stacking order), so that
- * other windows with the same parent window appear below @window.
- * This is true whether or not the windows are visible.
- *
- * If @window is a toplevel, the window manager may choose to deny the
- * request to move the window in the Z-order, gdk_window_raise() only
- * requests the restack, does not guarantee it.
- * 
- **/
-void
-gdk_window_raise (GdkWindow *window)
+static void
+gdk_window_x11_raise (GdkWindow *window)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
   if (!GDK_WINDOW_DESTROYED (window))
     XRaiseWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
 }
 
-/**
- * gdk_window_lower:
- * @window: a #GdkWindow
- * 
- * Lowers @window to the bottom of the Z-order (stacking order), so that
- * other windows with the same parent window appear above @window.
- * This is true whether or not the other windows are visible.
- *
- * If @window is a toplevel, the window manager may choose to deny the
- * request to move the window in the Z-order, gdk_window_lower() only
- * requests the restack, does not guarantee it.
- *
- * Note that gdk_window_show() raises the window again, so don't call this
- * function before gdk_window_show(). (Try gdk_window_show_unraised().)
- * 
- **/
-void
-gdk_window_lower (GdkWindow *window)
+static void
+gdk_window_x11_lower (GdkWindow *window)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
   if (!GDK_WINDOW_DESTROYED (window))
     XLowerWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
 }
@@ -2130,9 +1955,9 @@ gdk_window_focus (GdkWindow *window,
 {
   GdkDisplay *display;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   display = GDK_WINDOW_DISPLAY (window);
@@ -2202,9 +2027,9 @@ gdk_window_set_hints (GdkWindow *window,
 {
   XSizeHints size_hints;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
   
   size_hints.flags = 0;
@@ -2257,9 +2082,9 @@ gdk_window_set_type_hint (GdkWindow        *window,
   GdkDisplay *display;
   Atom atom;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   display = gdk_drawable_get_display (window);
@@ -2443,9 +2268,9 @@ gdk_window_set_modal_hint (GdkWindow *window,
 {
   GdkWindowObject *private;
 
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   private = (GdkWindowObject*) window;
@@ -2478,10 +2303,10 @@ gdk_window_set_skip_taskbar_hint (GdkWindow *window,
 {
   GdkToplevelX11 *toplevel;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
   
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   toplevel = _gdk_x11_window_get_toplevel (window);
@@ -2515,10 +2340,10 @@ gdk_window_set_skip_pager_hint (GdkWindow *window,
 {
   GdkToplevelX11 *toplevel;
     
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
   
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   toplevel = _gdk_x11_window_get_toplevel (window);
@@ -2546,10 +2371,10 @@ gdk_window_set_urgency_hint (GdkWindow *window,
 {
   GdkToplevelX11 *toplevel;
     
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
   
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   toplevel = _gdk_x11_window_get_toplevel (window);
@@ -2594,9 +2419,9 @@ gdk_window_set_geometry_hints (GdkWindow         *window,
 {
   XSizeHints size_hints;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
   
   size_hints.flags = 0;
@@ -2858,10 +2683,10 @@ gdk_window_set_title (GdkWindow   *window,
   Display *xdisplay;
   Window xwindow;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   g_return_if_fail (title != NULL);
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
   
   display = gdk_drawable_get_display (window);
@@ -2908,7 +2733,7 @@ gdk_window_set_role (GdkWindow   *window,
 {
   GdkDisplay *display;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
   display = gdk_drawable_get_display (window);
 
@@ -2976,7 +2801,7 @@ void
 gdk_window_set_transient_for (GdkWindow *window, 
 			      GdkWindow *parent)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   
   if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent))
     XSetTransientForHint (GDK_WINDOW_XDISPLAY (window), 
@@ -2984,31 +2809,13 @@ gdk_window_set_transient_for (GdkWindow *window,
 			  GDK_WINDOW_XID (parent));
 }
 
-/**
- * gdk_window_set_background:
- * @window: a #GdkWindow
- * @color: an allocated #GdkColor
- *
- * Sets the background color of @window. (However, when using GTK+,
- * set the background of a widget with gtk_widget_modify_bg() - if
- * you're an application - or gtk_style_set_background() - if you're
- * implementing a custom widget.)
- *
- * The @color must be allocated; gdk_rgb_find_color() is the best way
- * to allocate a color.
- *
- * See also gdk_window_set_back_pixmap().
- * 
- **/
-void
-gdk_window_set_background (GdkWindow      *window,
-			   const GdkColor *color)
+static void
+gdk_window_x11_set_background (GdkWindow      *window,
+                               const GdkColor *color)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   GdkColormap *colormap = gdk_drawable_get_colormap (window);
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
   if (!GDK_WINDOW_DESTROYED (window))
     XSetWindowBackground (GDK_WINDOW_XDISPLAY (window),
 			  GDK_WINDOW_XID (window), color->pixel);
@@ -3024,42 +2831,14 @@ gdk_window_set_background (GdkWindow      *window,
   private->bg_pixmap = NULL;
 }
 
-/**
- * gdk_window_set_back_pixmap:
- * @window: a #GdkWindow
- * @pixmap: a #GdkPixmap, or %NULL
- * @parent_relative: whether the tiling origin is at the origin of @window's parent
- *
- * Sets the background pixmap of @window. May also be used to set a background of
- * "None" on @window, by setting a background pixmap of %NULL.
- * A background pixmap will be tiled, positioning the first tile at the origin of
- * @window, or if @parent_relative is %TRUE, the tiling will be done based on the
- * origin of the parent window (useful to align tiles in a parent with tiles
- * in a child).
- *
- * A background pixmap of %NULL means that the window will have no
- * background.  A window with no background will never have its
- * background filled by the windowing system, instead the window will
- * contain whatever pixels were already in the corresponding area of
- * the display.
- *
- * The windowing system will normally fill a window with its background
- * when the window is obscured then exposed, and when you call
- * gdk_window_clear().
- * 
- **/
-void
-gdk_window_set_back_pixmap (GdkWindow *window,
-			    GdkPixmap *pixmap,
-			    gboolean   parent_relative)
+static void
+gdk_window_x11_set_back_pixmap (GdkWindow *window,
+                                GdkPixmap *pixmap,
+                                gboolean   parent_relative)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   Pixmap xpixmap;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  g_return_if_fail (pixmap == NULL || !parent_relative);
-  g_return_if_fail (pixmap == NULL || gdk_drawable_get_depth (window) == gdk_drawable_get_depth (pixmap));
-
   if (pixmap && !gdk_drawable_get_colormap (pixmap))
     {
       g_warning ("gdk_window_set_back_pixmap(): pixmap must have a colormap");
@@ -3096,30 +2875,15 @@ gdk_window_set_back_pixmap (GdkWindow *window,
 				GDK_WINDOW_XID (window), xpixmap);
 }
 
-/**
- * gdk_window_set_cursor:
- * @window: a #GdkWindow
- * @cursor: a cursor
- *
- * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new() or
- * gdk_cursor_new_from_pixmap() to create the cursor.
- * To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create
- * a cursor with no pixels in it. Passing %NULL for the @cursor argument
- * to gdk_window_set_cursor() means that @window will use the cursor of
- * its parent window. Most windows should use this default.
- * 
- **/
-void
-gdk_window_set_cursor (GdkWindow *window,
-		       GdkCursor *cursor)
+static void
+gdk_window_x11_set_cursor (GdkWindow *window,
+                           GdkCursor *cursor)
 {
   GdkWindowObject *private;
   GdkWindowImplX11 *impl;
   GdkCursorPrivate *cursor_private;
   Cursor xcursor;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-    
   private = (GdkWindowObject *)window;
   impl = GDK_WINDOW_IMPL_X11 (private->impl);
   cursor_private = (GdkCursorPrivate*) cursor;
@@ -3163,45 +2927,13 @@ _gdk_x11_window_get_cursor (GdkWindow *window)
   return impl->cursor;
 }
 
-/**
- * gdk_window_get_geometry:
- * @window: a #GdkWindow
- * @x: return location for X coordinate of window (relative to its parent)
- * @y: return location for Y coordinate of window (relative to its parent)
- * @width: return location for width of window
- * @height: return location for height of window
- * @depth: return location for bit depth of window
- *
- * Any of the return location arguments to this function may be %NULL,
- * if you aren't interested in getting the value of that field.
- *
- * The X and Y coordinates returned are relative to the parent window
- * of @window, which for toplevels usually means relative to the
- * window decorations (titlebar, etc.) rather than relative to the
- * root window (screen-size background window).
- *
- * On the X11 platform, the geometry is obtained from the X server,
- * so reflects the latest position of @window; this may be out-of-sync
- * with the position of @window delivered in the most-recently-processed
- * #GdkEventConfigure. gdk_window_get_position() in contrast gets the
- * position from the most recent configure event.
- * 
- * <note>
- * If @window is not a toplevel, it is <emphasis>much</emphasis> better 
- * to call gdk_window_get_position() and gdk_drawable_get_size() instead, 
- * because it avoids the roundtrip to the X server and because 
- * gdk_drawable_get_size() supports the full 32-bit coordinate space,
- * whereas gdk_window_get_geometry() is restricted to the 16-bit
- * coordinates of X11.
- *</note>
- **/
-void
-gdk_window_get_geometry (GdkWindow *window,
-			 gint      *x,
-			 gint      *y,
-			 gint      *width,
-			 gint      *height,
-			 gint      *depth)
+static void
+gdk_window_x11_get_geometry (GdkWindow *window,
+                             gint      *x,
+                             gint      *y,
+                             gint      *width,
+                             gint      *height,
+                             gint      *depth)
 {
   Window root;
   gint tx;
@@ -3211,15 +2943,6 @@ gdk_window_get_geometry (GdkWindow *window,
   guint tborder_width;
   guint tdepth;
   
-  g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
-  
-  if (!window)
-    {
-      GDK_NOTE (MULTIHEAD,
-		g_message ("gdk_window_get_geometry(): Window needs to be non-NULL to be multi head safe"));
-      window = gdk_screen_get_root_window ((gdk_screen_get_default ()));
-    }
-
   if (!GDK_WINDOW_DESTROYED (window))
     {
       XGetGeometry (GDK_WINDOW_XDISPLAY (window),
@@ -3239,31 +2962,16 @@ gdk_window_get_geometry (GdkWindow *window,
     }
 }
 
-/**
- * gdk_window_get_origin:
- * @window: a #GdkWindow
- * @x: return location for X coordinate
- * @y: return location for Y coordinate
- * 
- * Obtains the position of a window in root window coordinates.
- * (Compare with gdk_window_get_position() and
- * gdk_window_get_geometry() which return the position of a window
- * relative to its parent window.)
- * 
- * Return value: not meaningful, ignore
- **/
-gint
-gdk_window_get_origin (GdkWindow *window,
-		       gint      *x,
-		       gint      *y)
+static gint
+gdk_window_x11_get_origin (GdkWindow *window,
+                           gint      *x,
+                           gint      *y)
 {
   gint return_val;
   Window child;
   gint tx = 0;
   gint ty = 0;
   
-  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
-  
   if (!GDK_WINDOW_DESTROYED (window))
     {
       return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
@@ -3313,7 +3021,7 @@ gdk_window_get_deskrelative_origin (GdkWindow *window,
   gulong number_return, bytes_after_return;
   guchar *data_return;
   
-  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+  g_return_val_if_fail (GDK_IS_ONSCREEN_WINDOW (window), FALSE);
   
   if (!GDK_WINDOW_DESTROYED (window))
     {
@@ -3379,7 +3087,7 @@ gdk_window_get_root_origin (GdkWindow *window,
 {
   GdkRectangle rect;
 
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
   gdk_window_get_frame_extents (window, &rect);
 
@@ -3423,7 +3131,7 @@ gdk_window_get_frame_extents (GdkWindow    *window,
   guint ww, wh, wb, wd;
   gint wx, wy;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   g_return_if_fail (rect != NULL);
   
   private = (GdkWindowObject*) window;
@@ -3433,7 +3141,7 @@ gdk_window_get_frame_extents (GdkWindow    *window,
   rect->width = 1;
   rect->height = 1;
   
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
   
   while (private->parent && ((GdkWindowObject*) private->parent)->parent)
@@ -3585,7 +3293,7 @@ _gdk_windowing_window_get_pointer (GdkDisplay      *display,
 
   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
   
-  _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
+  _gdk_x11_window_get_offsets (window, &xoffset, &yoffset);
 
   return_val = NULL;
   if (!GDK_WINDOW_DESTROYED (window)) 
@@ -3771,21 +3479,11 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display,
   return window;
 }
 
-/**
- * gdk_window_get_events:
- * @window: a #GdkWindow
- * 
- * Gets the event mask for @window. See gdk_window_set_events().
- * 
- * Return value: event mask for @window
- **/
-GdkEventMask  
-gdk_window_get_events (GdkWindow *window)
+static GdkEventMask
+gdk_window_x11_get_events (GdkWindow *window)
 {
   XWindowAttributes attrs;
   GdkEventMask event_mask;
-  
-  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 
   if (GDK_WINDOW_DESTROYED (window))
     return 0;
@@ -3801,27 +3499,13 @@ gdk_window_get_events (GdkWindow *window)
       return event_mask;
     }
 }
-
-/**
- * gdk_window_set_events:
- * @window: a #GdkWindow
- * @event_mask: event mask for @window
- *
- * The event mask for a window determines which events will be reported
- * for that window. For example, an event mask including #GDK_BUTTON_PRESS_MASK
- * means the window should report button press events. The event mask
- * is the bitwise OR of values from the #GdkEventMask enumeration.
- * 
- **/
-void          
-gdk_window_set_events (GdkWindow       *window,
-		       GdkEventMask     event_mask)
+static void
+gdk_window_x11_set_events (GdkWindow    *window,
+                           GdkEventMask  event_mask)
 {
   long xevent_mask;
   int i;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
   if (!GDK_WINDOW_DESTROYED (window))
     {
       GDK_WINDOW_OBJECT (window)->event_mask = event_mask;
@@ -3890,10 +3574,10 @@ gdk_window_add_colormap_windows (GdkWindow *window)
  * If not available, shaped windows will look
  * ugly, but programs still work.    Stefan Wille
  */
-static void
+static inline void
 do_shape_combine_mask (GdkWindow *window,
 		       GdkBitmap *mask,
-		       gint       x, 
+		       gint       x,
 		       gint       y,
 		       gint       shape)
 {
@@ -3901,13 +3585,11 @@ do_shape_combine_mask (GdkWindow *window,
   Pixmap pixmap;
   gint xoffset, yoffset;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
 #ifdef HAVE_SHAPE_EXT
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
-  _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
+  _gdk_x11_window_get_offsets (window, &xoffset, &yoffset);
 
   if (xoffset != 0 || yoffset != 0)
     {
@@ -3944,37 +3626,11 @@ do_shape_combine_mask (GdkWindow *window,
 #endif /* HAVE_SHAPE_EXT */
 }
 
-/**
- * gdk_window_shape_combine_mask:
- * @window: a #GdkWindow
- * @mask: shape mask
- * @x: X position of shape mask with respect to @window
- * @y: Y position of shape mask with respect to @window
- *
- * Applies a shape mask to @window. Pixels in @window corresponding to
- * set bits in the @mask will be visible; pixels in @window
- * corresponding to unset bits in the @mask will be transparent. This
- * gives a non-rectangular window.
- *
- * If @mask is %NULL, the shape mask will be unset, and the @x/@y
- * parameters are not used.
- *
- * On the X11 platform, this uses an X server extension which is
- * widely available on most common platforms, but not available on
- * very old X servers, and occasionally the implementation will be
- * buggy. On servers without the shape extension, this function
- * will do nothing.
- *
- * On the Win32 platform the functionality is always present.
- *
- * This function works on both toplevel and child windows.
- * 
- **/
-void
-gdk_window_shape_combine_mask (GdkWindow *window,
-			       GdkBitmap *mask,
-			       gint       x, 
-			       gint       y)
+static void
+gdk_window_x11_shape_combine_mask (GdkWindow *window,
+                                   GdkBitmap *mask,
+                                   gint       x, 
+                                   gint       y)
 {
   do_shape_combine_mask (window, mask, x, y, ShapeBounding);
 }
@@ -4017,7 +3673,7 @@ gdk_window_input_shape_combine_mask (GdkWindow *window,
 }
 
 
-static void
+static inline void
 do_shape_combine_region (GdkWindow       *window,
 			 const GdkRegion *shape_region,
 			 gint             offset_x,
@@ -4027,13 +3683,11 @@ do_shape_combine_region (GdkWindow       *window,
   GdkWindowObject *private = (GdkWindowObject *)window;
   gint xoffset, yoffset;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
 #ifdef HAVE_SHAPE_EXT
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
-  _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
+  _gdk_x11_window_get_offsets (window, &xoffset, &yoffset);
 
   if (xoffset != 0 || yoffset != 0)
     {
@@ -4073,38 +3727,11 @@ do_shape_combine_region (GdkWindow       *window,
     }
 #endif /* HAVE_SHAPE_EXT */
 }
-
-/**
- * gdk_window_shape_combine_region:
- * @window: a #GdkWindow
- * @shape_region: region of window to be non-transparent
- * @offset_x: X position of @shape_region in @window coordinates
- * @offset_y: Y position of @shape_region in @window coordinates
- *
- * Makes pixels in @window outside @shape_region be transparent,
- * so that the window may be nonrectangular. See also
- * gdk_window_shape_combine_mask() to use a bitmap as the mask.
- *
- * If @shape_region is %NULL, the shape will be unset, so the whole
- * window will be opaque again. @offset_x and @offset_y are ignored
- * if @shape_region is %NULL.
- * 
- * On the X11 platform, this uses an X server extension which is
- * widely available on most common platforms, but not available on
- * very old X servers, and occasionally the implementation will be
- * buggy. On servers without the shape extension, this function
- * will do nothing.
- *
- * On the Win32 platform, this functionality is always present.
- *
- * This function works on both toplevel and child windows.
- * 
- **/
-void
-gdk_window_shape_combine_region (GdkWindow       *window,
-                                 const GdkRegion *shape_region,
-                                 gint             offset_x,
-                                 gint             offset_y)
+static void
+gdk_window_x11_shape_combine_region (GdkWindow       *window,
+                                     const GdkRegion *shape_region,
+                                     gint             offset_x,
+                                     gint             offset_y)
 { 
   do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeBounding);
 }
@@ -4168,7 +3795,7 @@ gdk_window_set_override_redirect (GdkWindow *window,
 {
   XSetWindowAttributes attr;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
   if (!GDK_WINDOW_DESTROYED (window))
     {
@@ -4204,7 +3831,7 @@ gdk_window_set_accept_focus (GdkWindow *window,
 {
   GdkWindowObject *private;
 
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
   private = (GdkWindowObject *)window;  
   
@@ -4241,7 +3868,7 @@ gdk_window_set_focus_on_map (GdkWindow *window,
 {
   GdkWindowObject *private;
 
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
   private = (GdkWindowObject *)window;  
   
@@ -4286,9 +3913,9 @@ gdk_x11_window_set_user_time (GdkWindow *window,
   glong timestamp_long = (glong)timestamp;
   Window xid;
 
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   display = gdk_drawable_get_display (window);
@@ -4356,9 +3983,9 @@ gdk_window_set_icon_list (GdkWindow *window,
   GdkDisplay *display;
   gint n;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   display = gdk_drawable_get_display (window);
@@ -4468,10 +4095,10 @@ gdk_window_set_icon (GdkWindow *window,
 {
   GdkToplevelX11 *toplevel;
 
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
   
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   toplevel = _gdk_x11_window_get_toplevel (window);
@@ -4528,9 +4155,9 @@ gdk_window_set_icon_name (GdkWindow   *window,
 {
   GdkDisplay *display;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   display = gdk_drawable_get_display (window);
@@ -4563,9 +4190,9 @@ gdk_window_set_icon_name (GdkWindow   *window,
 void
 gdk_window_iconify (GdkWindow *window)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   if (GDK_WINDOW_IS_MAPPED (window))
@@ -4597,9 +4224,9 @@ gdk_window_iconify (GdkWindow *window)
 void
 gdk_window_deiconify (GdkWindow *window)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   if (GDK_WINDOW_IS_MAPPED (window))
@@ -4633,9 +4260,9 @@ gdk_window_deiconify (GdkWindow *window)
 void
 gdk_window_stick (GdkWindow *window)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   if (GDK_WINDOW_IS_MAPPED (window))
@@ -4690,9 +4317,9 @@ gdk_window_stick (GdkWindow *window)
 void
 gdk_window_unstick (GdkWindow *window)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   if (GDK_WINDOW_IS_MAPPED (window))
@@ -4734,9 +4361,9 @@ gdk_window_unstick (GdkWindow *window)
 void
 gdk_window_maximize (GdkWindow *window)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   if (GDK_WINDOW_IS_MAPPED (window))
@@ -4769,9 +4396,9 @@ gdk_window_maximize (GdkWindow *window)
 void
 gdk_window_unmaximize (GdkWindow *window)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   if (GDK_WINDOW_IS_MAPPED (window))
@@ -4807,9 +4434,9 @@ gdk_window_unmaximize (GdkWindow *window)
 void
 gdk_window_fullscreen (GdkWindow *window)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   if (GDK_WINDOW_IS_MAPPED (window))
@@ -4843,9 +4470,9 @@ gdk_window_fullscreen (GdkWindow *window)
 void
 gdk_window_unfullscreen (GdkWindow *window)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   if (GDK_WINDOW_IS_MAPPED (window))
@@ -4877,7 +4504,8 @@ gdk_window_unfullscreen (GdkWindow *window)
  * Since: 2.4
  **/
 void
-gdk_window_set_keep_above (GdkWindow *window, gboolean setting)
+gdk_window_set_keep_above (GdkWindow *window,
+                           gboolean   setting)
 {
   g_return_if_fail (GDK_IS_WINDOW (window));
 
@@ -4956,10 +4584,10 @@ gdk_window_get_group (GdkWindow *window)
 {
   GdkToplevelX11 *toplevel;
   
-  g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
+  g_return_val_if_fail (GDK_IS_ONSCREEN_WINDOW (window), NULL);
   g_return_val_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD, NULL);
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return NULL;
   
   toplevel = _gdk_x11_window_get_toplevel (window);
@@ -4989,9 +4617,9 @@ gdk_window_set_group (GdkWindow *window,
 {
   GdkToplevelX11 *toplevel;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
-  g_return_if_fail (leader == NULL || GDK_IS_WINDOW (leader));
+  g_return_if_fail (leader == NULL || GDK_IS_ONSCREEN_WINDOW (leader));
 
   if (GDK_WINDOW_DESTROYED (window) || (leader != NULL && GDK_WINDOW_DESTROYED (leader)))
     return;
@@ -5119,7 +4747,7 @@ gdk_window_set_decorations (GdkWindow      *window,
 {
   MotifWmHints hints;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   
   /* initialize to zero to avoid writing uninitialized data to socket */
   memset(&hints, 0, sizeof(hints));
@@ -5144,7 +4772,7 @@ gdk_window_get_decorations(GdkWindow       *window,
   MotifWmHints *hints;
   gboolean result = FALSE;
 
-  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+  g_return_val_if_fail (GDK_IS_ONSCREEN_WINDOW (window), FALSE);
 
   hints = gdk_window_get_mwm_hints (window);
   
@@ -5516,53 +5144,48 @@ gdk_propagate_shapes (Display *disp,
 
 #endif /* HAVE_SHAPE_EXT */
 
-/**
- * gdk_window_set_child_shapes:
- * @window: a #GdkWindow
- * 
- * Sets the shape mask of @window to the union of shape masks
- * for all children of @window, ignoring the shape mask of @window
- * itself. Contrast with gdk_window_merge_child_shapes() which includes
- * the shape mask of @window in the masks to be merged.
- **/
-void
-gdk_window_set_child_shapes (GdkWindow *window)
+static inline void
+do_child_shapes (GdkWindow *window,
+                 gboolean   merge)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
-  
-#ifdef HAVE_SHAPE_EXT
   if (!GDK_WINDOW_DESTROYED (window) &&
       gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
-    gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
-			  GDK_WINDOW_XID (window), FALSE, ShapeBounding);
-#endif   
+    {
+      gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
+                            GDK_WINDOW_XID (window),
+                            merge,
+                            ShapeBounding);
+    }
 }
 
-/**
- * gdk_window_merge_child_shapes:
- * @window: a #GdkWindow
- * 
- * Merges the shape masks for any child windows into the
- * shape mask for @window. i.e. the union of all masks
- * for @window and its children will become the new mask
- * for @window. See gdk_window_shape_combine_mask().
- *
- * This function is distinct from gdk_window_set_child_shapes()
- * because it includes @window's shape mask in the set of shapes to
- * be merged.
- **/
-void
-gdk_window_merge_child_shapes (GdkWindow *window)
+static void
+gdk_window_x11_set_child_shapes (GdkWindow *window)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  
 #ifdef HAVE_SHAPE_EXT
+  do_child_shapes (window, FALSE);
+#endif
+}
+
+static void
+gdk_window_x11_merge_child_shapes (GdkWindow *window)
+{
+#ifdef HAVE_SHAPE_EXT
+  do_child_shapes (window, TRUE);
+#endif
+}
+
+static inline void
+do_child_input_shapes (GdkWindow *window,
+                       gboolean   merge)
+{
   if (!GDK_WINDOW_DESTROYED (window) &&
       gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
-    gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
-			  GDK_WINDOW_XID (window), TRUE, ShapeBounding);
-#endif   
+    {
+      gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
+                            GDK_WINDOW_XID (window),
+                            merge,
+                            ShapeInput);
+    }
 }
 
 /**
@@ -5583,10 +5206,7 @@ gdk_window_set_child_input_shapes (GdkWindow *window)
   
 #ifdef HAVE_SHAPE_EXT
 #ifdef ShapeInput
-  if (!GDK_WINDOW_DESTROYED (window) &&
-      gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window)))
-    gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
-			  GDK_WINDOW_XID (window), FALSE, ShapeInput);
+  do_child_input_shapes (window, FALSE);
 #endif
 #endif   
 }
@@ -5613,10 +5233,7 @@ gdk_window_merge_child_input_shapes (GdkWindow *window)
   
 #ifdef HAVE_SHAPE_EXT
 #ifdef ShapeInput
-  if (!GDK_WINDOW_DESTROYED (window) &&
-      gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window)))
-    gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
-			  GDK_WINDOW_XID (window), TRUE, ShapeInput);
+  do_child_input_shapes (window, TRUE);
 #endif
 #endif   
 }
@@ -5657,27 +5274,13 @@ gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on)
 			   CWWinGravity,  &xattributes);
 }
 
-/**
- * gdk_window_set_static_gravities:
- * @window: a #GdkWindow
- * @use_static: %TRUE to turn on static gravity
- *
- * Set the bit gravity of the given window to static, and flag it so
- * all children get static subwindow gravity. This is used if you are
- * implementing scary features that involve deep knowledge of the
- * windowing system. Don't worry about it unless you have to.
- * 
- * Return value: %TRUE if the server supports static gravity
- **/
-gboolean 
-gdk_window_set_static_gravities (GdkWindow *window,
-				 gboolean   use_static)
+static gboolean
+gdk_window_x11_set_static_gravities (GdkWindow *window,
+                                     gboolean   use_static)
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   GList *tmp_list;
   
-  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
-
   if (!use_static == !private->guffaw_gravity)
     return TRUE;
 
@@ -5690,7 +5293,8 @@ gdk_window_set_static_gravities (GdkWindow *window,
       tmp_list = private->children;
       while (tmp_list)
 	{
-	  gdk_window_set_static_win_gravity (tmp_list->data, use_static);
+          if (!gdk_window_is_offscreen (tmp_list->data))
+            gdk_window_set_static_win_gravity (tmp_list->data, use_static);
 	  
 	  tmp_list = tmp_list->next;
 	}
@@ -6265,9 +5869,9 @@ gdk_window_begin_resize_drag (GdkWindow     *window,
                               gint           root_y,
                               guint32        timestamp)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
@@ -6300,9 +5904,9 @@ gdk_window_begin_move_drag (GdkWindow *window,
                             gint       root_y,
                             guint32    timestamp)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
     return;
 
   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
@@ -6336,7 +5940,7 @@ gdk_window_enable_synchronized_configure (GdkWindow *window)
   GdkWindowObject *private = (GdkWindowObject *)window;
   GdkWindowImplX11 *impl;
 
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
 
   impl = GDK_WINDOW_IMPL_X11 (private->impl);
 	  
@@ -6367,7 +5971,7 @@ gdk_window_configure_finished (GdkWindow *window)
 {
   GdkWindowImplX11 *impl;
 
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_ONSCREEN_WINDOW (window));
   
   impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl);
   if (!impl->use_synchronized_configure)
@@ -6408,6 +6012,11 @@ gdk_window_beep (GdkWindow *window)
 {
   GdkDisplay *display;
 
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if (GDK_WINDOW_DESTROYED (window) || gdk_window_is_offscreen (window))
+    return;
+
   display = GDK_WINDOW_DISPLAY (window);
 
 #ifdef HAVE_XKB
@@ -6507,6 +6116,35 @@ _gdk_windowing_window_set_composited (GdkWindow *window,
 #endif
 }
 
+static void
+gdk_window_impl_iface_init (GdkWindowImplIface *iface)
+{
+  iface->show = gdk_window_x11_show;
+  iface->hide = gdk_window_x11_hide;
+  iface->withdraw = gdk_window_x11_withdraw;
+  iface->set_events = gdk_window_x11_set_events;
+  iface->get_events = gdk_window_x11_get_events;
+  iface->clear_area = gdk_window_x11_clear_area;
+  iface->raise = gdk_window_x11_raise;
+  iface->lower = gdk_window_x11_lower;
+  iface->move = gdk_window_x11_move;
+  iface->resize = gdk_window_x11_resize;
+  iface->move_resize = gdk_window_x11_move_resize;
+  iface->scroll = _gdk_x11_window_scroll;
+  iface->move_region = _gdk_x11_window_move_region;
+  iface->set_background = gdk_window_x11_set_background;
+  iface->set_back_pixmap = gdk_window_x11_set_back_pixmap;
+  iface->reparent = gdk_window_x11_reparent;
+  iface->set_cursor = gdk_window_x11_set_cursor;
+  iface->get_geometry = gdk_window_x11_get_geometry;
+  iface->get_origin = gdk_window_x11_get_origin;
+  iface->shape_combine_mask = gdk_window_x11_shape_combine_mask;
+  iface->shape_combine_region = gdk_window_x11_shape_combine_region;
+  iface->set_child_shapes = gdk_window_x11_set_child_shapes;
+  iface->merge_child_shapes = gdk_window_x11_merge_child_shapes;
+  iface->set_static_gravities = gdk_window_x11_set_static_gravities;
+  iface->get_offsets = _gdk_x11_window_get_offsets;
+}
 
 #define __GDK_WINDOW_X11_C__
 #include "gdkaliasdef.c"
diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h
index 3ab23d6..2a2799b 100644
--- a/gdk/x11/gdkwindow-x11.h
+++ b/gdk/x11/gdkwindow-x11.h
@@ -169,6 +169,9 @@ void            _gdk_x11_window_tmp_reset_bg  (GdkWindow *window,
 
 
 GdkCursor      *_gdk_x11_window_get_cursor    (GdkWindow *window);
+void            _gdk_x11_window_get_offsets   (GdkWindow *window,
+                                               gint      *x_offset,
+                                               gint      *y_offset);
 
 G_END_DECLS
 
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 6749252..6ffe008 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1531,6 +1531,7 @@ gtk_main_do_event (GdkEvent *event)
     case GDK_VISIBILITY_NOTIFY:
     case GDK_WINDOW_STATE:
     case GDK_GRAB_BROKEN:
+    case GDK_DAMAGE:
       gtk_widget_event (event_widget, event);
       break;
 
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 9d54a01..c137709 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -127,6 +127,7 @@ enum {
   QUERY_TOOLTIP,
   KEYNAV_FAILED,
   DRAG_FAILED,
+  DAMAGE_EVENT,
   LAST_SIGNAL
 };
 
@@ -1994,6 +1995,28 @@ gtk_widget_class_init (GtkWidgetClass *klass)
 		  GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
 
   /**
+   * GtkWidget::damage-event:
+   * @widget: the object which received the signal
+   * @event: the #GdkEventExpose event
+   *
+   * Emitted when a redirected window belonging to @widget gets drawn into.
+   * The region/area members of the event shows what area of the redirected
+   * drawable was drawn into.
+   *
+   * Returns: %TRUE to stop other handlers from being invoked for the event.
+   *   %FALSE to propagate the event further.
+   *
+   * Since: 2.16
+   */
+  widget_signals[DAMAGE_EVENT] =
+    g_signal_new ("damage_event",
+		  G_TYPE_FROM_CLASS (gobject_class),
+		  G_SIGNAL_RUN_LAST, 0,
+		  _gtk_boolean_handled_accumulator, NULL,
+		  _gtk_marshal_BOOLEAN__BOXED,
+		  G_TYPE_BOOLEAN, 1,
+		  GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+/**
    * GtkWidget::grab-broken-event:
    * @widget: the object which received the signal
    * @event: the #GdkEventGrabBroken event
@@ -4667,6 +4690,9 @@ gtk_widget_event_internal (GtkWidget *widget,
 	case GDK_GRAB_BROKEN:
 	  signal_num = GRAB_BROKEN;
 	  break;
+	case GDK_DAMAGE:
+	  signal_num = DAMAGE_EVENT;
+	  break;
 	default:
 	  g_warning ("gtk_widget_event(): unhandled event type: %d", event->type);
 	  signal_num = -1;
@@ -8285,6 +8311,49 @@ gtk_widget_unref (GtkWidget *widget)
   g_object_unref ((GObject*) widget);
 }
 
+/**
+ * gtk_widget_get_snapshot:
+ * @widget: a #GtkWidget
+ *
+ * Creates a #GdkPixmap of the contents of the widget and its
+ * children. Works even if the widget is obscured.
+ *
+ * Return value: #GdkPixmap of the widget
+ * Since: 2.16
+ **/
+GdkPixmap*
+gtk_widget_get_snapshot (GtkWidget *widget)
+{
+  GdkPixmap *pixmap;
+  int x, y;
+
+  if (!GTK_WIDGET_REALIZED (widget))
+    gtk_widget_realize (widget);
+
+  pixmap = gdk_pixmap_new (widget->window,
+			   widget->allocation.width,
+			   widget->allocation.height,
+			   gdk_drawable_get_depth (widget->window));
+  if (GTK_WIDGET_NO_WINDOW (widget))
+    {
+      x = widget->allocation.x;
+      y = widget->allocation.y;
+    }
+  else
+    x = y = 0;
+
+  gdk_window_redirect_to_drawable (widget->window,
+				   pixmap,
+				   x, y,
+				   0, 0,
+				   widget->allocation.width,
+				   widget->allocation.height);
+  gtk_widget_queue_draw (widget);
+  gdk_window_process_updates (widget->window, TRUE);
+  gdk_window_remove_redirection (widget->window);
+
+  return pixmap;
+}
 
 /* style properties
  */
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index d991a71..1f0b8b9 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -416,9 +416,12 @@ struct _GtkWidgetClass
 				       gint        y,
 				       gboolean    keyboard_tooltip,
 				       GtkTooltip *tooltip);
+  /* Signals without a C default handler class slot:
+   * gboolean	(*damage_event)	(GtkWidget      *widget,
+   *                             GdkEventExpose *event);
+   */
 
   /* Padding for future expansion */
-  void (*_gtk_reserved5) (void);
   void (*_gtk_reserved6) (void);
   void (*_gtk_reserved7) (void);
 };
@@ -610,6 +613,7 @@ GdkWindow *   gtk_widget_get_root_window (GtkWidget *widget);
 GtkSettings*  gtk_widget_get_settings    (GtkWidget *widget);
 GtkClipboard *gtk_widget_get_clipboard   (GtkWidget *widget,
 					  GdkAtom    selection);
+GdkPixmap *   gtk_widget_get_snapshot    (GtkWidget *widget);
 
 #ifndef GTK_DISABLE_DEPRECATED
 #define gtk_widget_set_visual(widget,visual)  ((void) 0)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a985187..4c8e555 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -81,6 +81,7 @@ noinst_PROGRAMS =  $(TEST_PROGS)	\
 	testmultiscreen			\
 	testnotebookdnd			\
 	testnouiprint			\
+	testoffscreen			\
 	testprint			\
 	testrgb				\
 	testrecentchooser 		\
@@ -154,6 +155,7 @@ testmultidisplay_DEPENDENCIES = $(TEST_DEPS)
 testmultiscreen_DEPENDENCIES = $(TEST_DEPS)
 testnotebookdnd_DEPENDENCIES = $(TEST_DEPS)
 testnouiprint_DEPENDENCIES = $(TEST_DEPS)
+testoffscreen_DEPENDENCIES = $(TEST_DEPS)
 testprint_DEPENDENCIES = $(TEST_DEPS)
 testrecentchooser_DEPENDENCIES = $(TEST_DEPS)
 testrecentchoosermenu_DEPENDENCIES = $(TEST_DEPS)
@@ -207,6 +209,7 @@ testmultidisplay_LDADD = $(LDADDS)
 testmultiscreen_LDADD = $(LDADDS)
 testnotebookdnd_LDADD = $(LDADDS)
 testnouiprint_LDADD = $(LDADDS)
+testoffscreen_LDADD = $(LDADDS)
 testprint_LDADD = $(LDADDS)
 testrecentchooser_LDADD = $(LDADDS)
 testrecentchoosermenu_LDADD = $(LDADDS)
@@ -327,6 +330,11 @@ testrecentchoosermenu_SOURCES =	\
 testvolumebutton_SOURCES =	\
 	testvolumebutton.c
 
+testoffscreen_SOURCES = 	\
+	gtkoffscreenbox.c	\
+	gtkoffscreenbox.h	\
+	testoffscreen.c
+
 EXTRA_DIST += 			\
 	prop-editor.h		\
 	testgtk.1 		\
diff --git a/tests/gtkoffscreenbox.c b/tests/gtkoffscreenbox.c
new file mode 100644
index 0000000..5986d4d
--- /dev/null
+++ b/tests/gtkoffscreenbox.c
@@ -0,0 +1,692 @@
+#include <config.h>
+#include "gtkoffscreenbox.h"
+#include <x11/gdkx.h>
+#include <cairo-xlib.h>
+#include <math.h>
+
+static void       gtk_offscreen_box_class_init            (GtkOffscreenBoxClass *klass);
+static void       gtk_offscreen_box_init                  (GtkOffscreenBox      *offscreen_box);
+static void       gtk_offscreen_box_realize               (GtkWidget            *widget);
+static void       gtk_offscreen_box_unrealize             (GtkWidget            *widget);
+static void       gtk_offscreen_box_map                   (GtkWidget            *widget);
+static void       gtk_offscreen_box_unmap                 (GtkWidget            *widget);
+static void       gtk_offscreen_box_size_request          (GtkWidget            *widget,
+							   GtkRequisition       *requisition);
+static void       gtk_offscreen_box_size_allocate         (GtkWidget            *widget,
+							   GtkAllocation        *allocation);
+static gint       gtk_offscreen_box_expose                (GtkWidget            *widget,
+							   GdkEventExpose       *offscreen);
+static void       gtk_offscreen_box_add                   (GtkContainer         *container,
+							   GtkWidget            *child);
+static void       gtk_offscreen_box_remove                (GtkContainer         *container,
+							   GtkWidget            *widget);
+static void       gtk_offscreen_box_forall                (GtkContainer         *container,
+							   gboolean              include_internals,
+							   GtkCallback           callback,
+							   gpointer              callback_data);
+static GType      gtk_offscreen_box_child_type            (GtkContainer         *container);
+static gboolean   gtk_offscreen_box_damage_event          (GtkWidget            *widget,
+							   GdkEventExpose       *event);
+static void       window_to_parent_coordinate             (GdkWindow            *window,
+							   double                x,
+							   double                y,
+							   double               *parent_x,
+							   double               *parent_y);
+static void       parent_to_window_coordinate             (GdkWindow            *window,
+							   double                x,
+							   double                y,
+							   double               *win_x,
+							   double               *win_y);
+static GdkWindow *find_offscreen_child                    (GdkWindow            *window,
+							   double                x,
+							   double                y);
+  
+static GtkContainerClass *parent_class = NULL;
+
+static const GdkOffscreenHooks offscreen_hooks = {
+  window_to_parent_coordinate,
+  parent_to_window_coordinate,
+  find_offscreen_child
+};
+
+#define CHILD1_SIZE_SCALE 1.0
+#define CHILD2_SIZE_SCALE 1.0
+
+G_DEFINE_TYPE (GtkOffscreenBox, gtk_offscreen_box, GTK_TYPE_CONTAINER);
+
+static void
+gtk_offscreen_box_class_init (GtkOffscreenBoxClass *class)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+  GtkContainerClass *container_class;
+
+  parent_class = g_type_class_peek_parent (class);
+  container_class = (GtkContainerClass*) class;
+
+  widget_class->realize = gtk_offscreen_box_realize;
+  widget_class->unrealize = gtk_offscreen_box_unrealize;
+  widget_class->map = gtk_offscreen_box_map;
+  widget_class->unmap = gtk_offscreen_box_unmap;
+  widget_class->size_request = gtk_offscreen_box_size_request;
+  widget_class->size_allocate = gtk_offscreen_box_size_allocate;
+  widget_class->expose_event = gtk_offscreen_box_expose;
+
+  container_class->add = gtk_offscreen_box_add;
+  container_class->remove = gtk_offscreen_box_remove;
+  container_class->forall = gtk_offscreen_box_forall;
+  container_class->child_type = gtk_offscreen_box_child_type;
+}
+
+static void
+gtk_offscreen_box_init (GtkOffscreenBox *offscreen_box)
+{
+  GTK_WIDGET_UNSET_FLAGS (offscreen_box, GTK_NO_WINDOW);
+
+  g_signal_connect (offscreen_box, "damage-event",
+                    G_CALLBACK (gtk_offscreen_box_damage_event),
+                    NULL);
+}
+
+GtkWidget*
+gtk_offscreen_box_new (void)
+{
+  return g_object_new (GTK_TYPE_OFFSCREEN_BOX, NULL);
+}
+
+static void
+gtk_offscreen_box_realize (GtkWidget *widget)
+{
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+  gint border_width;
+  GtkOffscreenBox *offscreen_box;
+  GtkRequisition child_requisition;
+  int start_y;
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+  offscreen_box = GTK_OFFSCREEN_BOX (widget);
+  border_width = GTK_CONTAINER (widget)->border_width;
+  
+  attributes.x = widget->allocation.x + border_width;
+  attributes.y = widget->allocation.y + border_width;
+  attributes.width = widget->allocation.width - 2*border_width;
+  attributes.height = widget->allocation.height - 2*border_width;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.event_mask = gtk_widget_get_events (widget)
+			| GDK_EXPOSURE_MASK
+			| GDK_POINTER_MOTION_MASK
+			| GDK_BUTTON_PRESS_MASK
+			| GDK_BUTTON_RELEASE_MASK
+			| GDK_SCROLL_MASK
+			| GDK_ENTER_NOTIFY_MASK
+			| GDK_LEAVE_NOTIFY_MASK;
+
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.wclass = GDK_INPUT_OUTPUT;
+      
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  
+  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
+				   &attributes, attributes_mask);
+  gdk_window_set_user_data (widget->window, widget);
+  gdk_window_set_offscreen_hooks (widget->window, &offscreen_hooks);
+
+  start_y = 0;
+
+  /* Child 1 */
+  child_requisition.width = child_requisition.height = 0;
+  if (offscreen_box->child1 && GTK_WIDGET_VISIBLE (offscreen_box->child1))
+    gtk_widget_get_child_requisition (offscreen_box->child1, &child_requisition);
+
+  attributes.x = child_requisition.width * (CHILD1_SIZE_SCALE - 1.0) / 2;
+  attributes.y = start_y + child_requisition.height * (CHILD1_SIZE_SCALE - 1.0) / 2;
+  attributes.width = child_requisition.width;
+  attributes.height = child_requisition.height;
+
+  start_y += CHILD1_SIZE_SCALE * child_requisition.height;
+  
+  offscreen_box->offscreen_window1 = gdk_window_new_offscreen (widget->window,
+							       &attributes, attributes_mask);
+  gdk_window_set_user_data (offscreen_box->offscreen_window1, widget);
+
+  if (offscreen_box->child1)
+    gtk_widget_set_parent_window (offscreen_box->child1,
+				  offscreen_box->offscreen_window1);
+
+  /* Child 2 */
+  child_requisition.width = child_requisition.height = 0;
+  if (offscreen_box->child2 && GTK_WIDGET_VISIBLE (offscreen_box->child2))
+    gtk_widget_get_child_requisition (offscreen_box->child2, &child_requisition);
+
+  attributes.x = child_requisition.width * (CHILD2_SIZE_SCALE - 1.0) / 2;
+  attributes.y = start_y + child_requisition.height * (CHILD2_SIZE_SCALE - 1.0) / 2;
+  attributes.width = child_requisition.width;
+  attributes.height = child_requisition.height;
+
+  start_y += CHILD2_SIZE_SCALE * child_requisition.height;
+  
+  offscreen_box->offscreen_window2 = gdk_window_new_offscreen (widget->window,
+							       &attributes, attributes_mask);
+  gdk_window_set_user_data (offscreen_box->offscreen_window2, widget);
+
+  if (offscreen_box->child2)
+    gtk_widget_set_parent_window (offscreen_box->child2,
+				  offscreen_box->offscreen_window2);
+
+  
+  widget->style = gtk_style_attach (widget->style, widget->window);
+  
+  gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+  gtk_style_set_background (widget->style, offscreen_box->offscreen_window1, GTK_STATE_NORMAL);
+  gtk_style_set_background (widget->style, offscreen_box->offscreen_window2, GTK_STATE_NORMAL);
+
+  gdk_window_show (offscreen_box->offscreen_window1);
+  gdk_window_show (offscreen_box->offscreen_window2);
+}
+
+static void
+gtk_offscreen_box_unrealize (GtkWidget *widget)
+{
+  GtkOffscreenBox *offscreen_box;
+
+  offscreen_box = GTK_OFFSCREEN_BOX (widget);
+
+  gdk_window_set_user_data (offscreen_box->offscreen_window1, NULL);
+  gdk_window_destroy (offscreen_box->offscreen_window1);
+  offscreen_box->offscreen_window1 = NULL;
+  
+  gdk_window_set_user_data (offscreen_box->offscreen_window2, NULL);
+  gdk_window_destroy (offscreen_box->offscreen_window2);
+  offscreen_box->offscreen_window2 = NULL;
+  
+  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+static GType
+gtk_offscreen_box_child_type (GtkContainer *container)
+{
+  if (!GTK_OFFSCREEN_BOX (container)->child1 || !GTK_OFFSCREEN_BOX (container)->child2)
+    return GTK_TYPE_WIDGET;
+  else
+    return G_TYPE_NONE;
+}
+
+static void
+gtk_offscreen_box_add (GtkContainer *container,
+		       GtkWidget    *widget)
+{
+  GtkOffscreenBox *offscreen_box;
+
+  g_return_if_fail (GTK_IS_OFFSCREEN_BOX (container));
+
+  offscreen_box = GTK_OFFSCREEN_BOX (container);
+
+  if (!offscreen_box->child1)
+    gtk_offscreen_box_add1 (offscreen_box, widget);
+  else if (!offscreen_box->child2)
+    gtk_offscreen_box_add2 (offscreen_box, widget);
+  else
+    g_warning ("GtkOffscreenBox cannot have more than 2 children\n");
+}
+
+void
+gtk_offscreen_box_add1 (GtkOffscreenBox  *offscreen_box,
+			GtkWidget    *child)
+{
+  g_return_if_fail (GTK_IS_WIDGET (child));
+
+  if (offscreen_box->child1 == NULL)
+    {
+      gtk_widget_set_parent_window (child, offscreen_box->offscreen_window1);
+      gtk_widget_set_parent (child, GTK_WIDGET (offscreen_box));
+      offscreen_box->child1 = child;
+    }
+}
+
+void
+gtk_offscreen_box_add2 (GtkOffscreenBox  *offscreen_box,
+			GtkWidget    *child)
+{
+  g_return_if_fail (GTK_IS_WIDGET (child));
+
+  if (offscreen_box->child2 == NULL)
+    {
+      gtk_widget_set_parent_window (child, offscreen_box->offscreen_window2);
+      gtk_widget_set_parent (child, GTK_WIDGET (offscreen_box));
+      offscreen_box->child2 = child;
+    }
+}
+
+static void
+gtk_offscreen_box_remove (GtkContainer *container,
+			  GtkWidget    *widget)
+{
+  GtkOffscreenBox *offscreen_box;
+  gboolean was_visible;
+
+  
+  offscreen_box = GTK_OFFSCREEN_BOX (container);
+  was_visible = GTK_WIDGET_VISIBLE (widget);
+
+  if (offscreen_box->child1 == widget)
+    {
+      gtk_widget_unparent (widget);
+
+      offscreen_box->child1 = NULL;
+
+      if (was_visible && GTK_WIDGET_VISIBLE (container))
+	gtk_widget_queue_resize (GTK_WIDGET (container));
+    }
+  else if (offscreen_box->child2 == widget)
+    {
+      gtk_widget_unparent (widget);
+
+      offscreen_box->child2 = NULL;
+
+      if (was_visible && GTK_WIDGET_VISIBLE (container))
+	gtk_widget_queue_resize (GTK_WIDGET (container));
+    }
+}
+
+static void
+gtk_offscreen_box_forall (GtkContainer *container,
+			  gboolean      include_internals,
+			  GtkCallback   callback,
+			  gpointer      callback_data)
+{
+  GtkOffscreenBox *offscreen_box;
+
+  g_return_if_fail (callback != NULL);
+
+  offscreen_box = GTK_OFFSCREEN_BOX (container);
+
+  if (offscreen_box->child1)
+    (*callback) (offscreen_box->child1, callback_data);
+  if (offscreen_box->child2)
+    (*callback) (offscreen_box->child2, callback_data);
+}
+
+static void
+gtk_offscreen_box_map (GtkWidget *widget)
+{
+  (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
+}
+
+static void
+gtk_offscreen_box_unmap (GtkWidget *widget)
+{
+  (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
+}
+
+void
+gtk_offscreen_box_set_angle (GtkOffscreenBox  *offscreen_box,
+			     double angle)
+{
+  g_return_if_fail (GTK_IS_OFFSCREEN_BOX (offscreen_box));
+  
+  offscreen_box->angle = angle;
+  gtk_widget_queue_draw (GTK_WIDGET (offscreen_box));
+  /* TODO: Really needs to resent pointer events if over the rotated
+     window */
+}
+
+
+static void
+gtk_offscreen_box_size_request (GtkWidget      *widget,
+				GtkRequisition *requisition)
+{
+  GtkOffscreenBox *offscreen_box = GTK_OFFSCREEN_BOX (widget);
+  int w, h;
+
+  w = 0;
+  h = 0;
+  
+  if (offscreen_box->child1 &&
+      GTK_WIDGET_VISIBLE (offscreen_box->child1))
+    {
+      GtkRequisition child_requisition;
+      
+      gtk_widget_size_request (offscreen_box->child1, &child_requisition);
+
+      w = MAX (w, CHILD1_SIZE_SCALE * child_requisition.width);
+      h += CHILD1_SIZE_SCALE * child_requisition.height;
+    }
+
+  if (offscreen_box->child2 &&
+      GTK_WIDGET_VISIBLE (offscreen_box->child2))
+    {
+      GtkRequisition child_requisition;
+      
+      gtk_widget_size_request (offscreen_box->child2, &child_requisition);
+
+      w = MAX (w, CHILD2_SIZE_SCALE * child_requisition.width);
+      h += CHILD2_SIZE_SCALE * child_requisition.height;
+    }
+  
+  requisition->width = GTK_CONTAINER (widget)->border_width * 2 + w;
+  requisition->height = GTK_CONTAINER (widget)->border_width * 2 + h;
+}
+
+static void
+gtk_offscreen_box_size_allocate (GtkWidget     *widget,
+				 GtkAllocation *allocation)
+{
+  GtkOffscreenBox *offscreen_box;
+  GtkAllocation child_allocation;
+  GtkRequisition child_requisition;
+  gint border_width;
+  gint start_y;
+  
+  widget->allocation = *allocation;
+  offscreen_box = GTK_OFFSCREEN_BOX (widget);
+  
+  border_width = GTK_CONTAINER (widget)->border_width;
+  
+  
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      gdk_window_move_resize (widget->window,
+			      allocation->x + border_width,
+			      allocation->y + border_width,
+			      allocation->width - border_width * 2,
+			      allocation->height - border_width * 2);
+      
+    }
+
+  start_y = 0;
+  
+  if (offscreen_box->child1 && GTK_WIDGET_VISIBLE (offscreen_box->child1))
+    {
+      gtk_widget_get_child_requisition (offscreen_box->child1, &child_requisition);
+
+      child_allocation.x = child_requisition.width * (CHILD1_SIZE_SCALE - 1.0) / 2;
+      child_allocation.y = start_y + child_requisition.height * (CHILD1_SIZE_SCALE - 1.0) / 2;
+      child_allocation.width = child_requisition.width;
+      child_allocation.height = child_requisition.height;
+
+      start_y += CHILD1_SIZE_SCALE * child_requisition.height;
+      
+      if (GTK_WIDGET_REALIZED (widget))
+	gdk_window_move_resize (offscreen_box->offscreen_window1,
+				child_allocation.x, child_allocation.y,
+				child_allocation.width, child_allocation.height);
+      child_allocation.x = child_allocation.y = 0;
+      gtk_widget_size_allocate (offscreen_box->child1, &child_allocation);
+    }
+  
+  if (offscreen_box->child2 && GTK_WIDGET_VISIBLE (offscreen_box->child2))
+    {
+      gtk_widget_get_child_requisition (offscreen_box->child2, &child_requisition);
+
+      child_allocation.x = child_requisition.width * (CHILD2_SIZE_SCALE - 1.0) / 2;
+      child_allocation.y = start_y + child_requisition.height * (CHILD2_SIZE_SCALE - 1.0) / 2;
+      child_allocation.width = child_requisition.width;
+      child_allocation.height = child_requisition.height;
+
+      start_y += CHILD2_SIZE_SCALE * child_requisition.height;
+      
+      if (GTK_WIDGET_REALIZED (widget))
+	gdk_window_move_resize (offscreen_box->offscreen_window2,
+				child_allocation.x, child_allocation.y,
+				child_allocation.width, child_allocation.height);
+      child_allocation.x = child_allocation.y = 0;
+      gtk_widget_size_allocate (offscreen_box->child2, &child_allocation);
+    }
+
+}
+
+static gboolean
+gtk_offscreen_box_damage_event (GtkWidget *widget,
+					 GdkEventExpose *event)
+{
+  gdk_window_invalidate_rect (widget->window, NULL, FALSE);
+  return TRUE;
+}
+
+static gint
+gtk_offscreen_box_expose (GtkWidget      *widget,
+			  GdkEventExpose *event)
+{
+  GtkOffscreenBox *offscreen_box = GTK_OFFSCREEN_BOX (widget);
+  GtkRequisition child_requisition;
+
+  
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      if (event->window == widget->window)
+	{
+	  GdkPixmap *pixmap;
+	  GdkGC *gc;
+	  int x, y, width, height, start_y;
+
+	  start_y = 0;
+
+	  if (offscreen_box->child1 && GTK_WIDGET_VISIBLE (offscreen_box->child1))
+	    {
+	      gtk_widget_get_child_requisition (offscreen_box->child1, &child_requisition);
+	  
+	      x = child_requisition.width * (CHILD1_SIZE_SCALE - 1.0) / 2;
+	      y = start_y + child_requisition.height * (CHILD1_SIZE_SCALE - 1.0) / 2;
+	      width = child_requisition.width;
+	      height = child_requisition.height;
+
+	      start_y += CHILD1_SIZE_SCALE * child_requisition.height;
+
+	      pixmap = gdk_window_get_offscreen_pixmap (offscreen_box->offscreen_window1);
+
+	      gc = gdk_gc_new (pixmap);
+
+	      gdk_draw_drawable (widget->window, gc, pixmap,
+				 0, 0,
+				 x, y,
+				 -1, -1);
+	  
+	      g_object_unref (gc);
+	    }
+	  
+	  if (offscreen_box->child2 && GTK_WIDGET_VISIBLE (offscreen_box->child2))
+	    {
+	      cairo_t *cr;
+	      
+	      gtk_widget_get_child_requisition (offscreen_box->child2, &child_requisition);
+	  
+	      x = child_requisition.width * (CHILD2_SIZE_SCALE - 1.0) / 2;
+	      y = start_y + child_requisition.height * (CHILD2_SIZE_SCALE - 1.0) / 2;
+	      width = child_requisition.width;
+	      height = child_requisition.height;
+
+	      start_y += CHILD2_SIZE_SCALE * child_requisition.height;
+
+	      pixmap = gdk_window_get_offscreen_pixmap (offscreen_box->offscreen_window2);
+
+	      cr = gdk_cairo_create (widget->window);
+	      cairo_translate (cr, x, y);
+	      cairo_translate (cr, width/2, height/2);
+	      cairo_rotate (cr, offscreen_box->angle);
+	      cairo_translate (cr, -width/2, -height/2);
+	      gdk_cairo_set_source_pixmap (cr, pixmap, 0, 0);
+	      cairo_paint (cr);
+	    }
+
+
+	}
+      else if (event->window == offscreen_box->offscreen_window1)
+	{
+	  gtk_paint_flat_box (widget->style, event->window, 
+			      GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+			      &event->area, widget, "blah",
+			      0, 0, -1, -1);
+	  if (offscreen_box->child1)
+	    gtk_container_propagate_expose (GTK_CONTAINER (widget),
+					    offscreen_box->child1, event);
+	}
+      else if (event->window == offscreen_box->offscreen_window2)
+	{
+	  gtk_paint_flat_box (widget->style, event->window, 
+			      GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+			      &event->area, widget, "blah",
+			      0, 0, -1, -1);
+	  if (offscreen_box->child2)
+	    gtk_container_propagate_expose (GTK_CONTAINER (widget),
+					    offscreen_box->child2, event);
+	}
+    }
+
+  return FALSE;
+}
+
+static gboolean
+parent_to_child1 (GtkOffscreenBox *offscreen_box,
+		  double x,
+                  double y,
+                  double *child_x,
+                  double *child_y)
+{
+  GtkRequisition child_requisition;
+  
+  gtk_widget_size_request (offscreen_box->child1, &child_requisition);
+  
+  *child_x = x + (child_requisition.width * (CHILD1_SIZE_SCALE - 1.0) / 2);
+  *child_y = y + (child_requisition.height * (CHILD1_SIZE_SCALE - 1.0) / 2);
+
+  return (*child_x >= 0 && *child_x <= child_requisition.width &&
+	  *child_y >= 0 && *child_y <= child_requisition.height);
+}
+
+static void
+parent_to_window_coordinate (GdkWindow *window,
+			     double x,
+                             double y,
+			     double *win_x,
+                             double *win_y)
+{
+  GtkOffscreenBox *offscreen_box = NULL;
+  GtkRequisition child_requisition;
+  double pos_x, pos_y, rot_x, rot_y, start_y;
+  double angle;
+
+  gdk_window_get_user_data (window, (gpointer *) &offscreen_box);
+  if (!offscreen_box)
+    return;
+
+  start_y = 0;
+
+  if (offscreen_box->child1)
+    {
+      gtk_widget_size_request (offscreen_box->child1, &child_requisition);
+      start_y = child_requisition.height * CHILD1_SIZE_SCALE;
+    }
+  
+  gtk_widget_size_request (offscreen_box->child2, &child_requisition);
+  
+  pos_x = x - (child_requisition.width * (CHILD2_SIZE_SCALE - 1.0) / 2);
+  pos_y = y - (start_y + child_requisition.height * (CHILD2_SIZE_SCALE - 1.0) / 2);
+
+  pos_x -= child_requisition.width/2;
+  pos_y -= child_requisition.height/2;
+
+  angle = -offscreen_box->angle;
+  rot_x = pos_x*cos (angle) - pos_y * sin(angle);
+  rot_y = pos_x*sin (angle) + pos_y * cos(angle);
+  
+  *win_x = rot_x + child_requisition.width/2;
+  *win_y = rot_y + child_requisition.height/2;
+}
+
+static void
+window_to_parent_coordinate (GdkWindow *window,
+			     double x,
+                             double y,
+			     double *parent_x,
+                             double *parent_y)
+{
+  GtkOffscreenBox *offscreen_box = NULL;
+  GtkRequisition child_requisition;
+  double pos_x, pos_y, rot_x, rot_y, start_y;
+  double angle;
+
+  gdk_window_get_user_data (window, (gpointer *) &offscreen_box);
+  if (!offscreen_box)
+    return;
+
+  gtk_widget_size_request (offscreen_box->child1, &child_requisition);
+  start_y = child_requisition.height * CHILD1_SIZE_SCALE;
+  
+  gtk_widget_size_request (offscreen_box->child2, &child_requisition);
+
+  pos_x = x + child_requisition.width/2;
+  pos_y = y + child_requisition.height/2;
+
+  angle = offscreen_box->angle;
+  rot_x = pos_x*cos (angle) - pos_y * sin(angle);
+  rot_y = pos_x*sin (angle) + pos_y * cos(angle);
+  
+  rot_x += child_requisition.width/2;
+  rot_y += child_requisition.height/2;
+
+  *parent_x = rot_x + (child_requisition.width * (CHILD2_SIZE_SCALE - 1.0) / 2);
+  *parent_y = rot_y + (start_y + child_requisition.height * (CHILD2_SIZE_SCALE - 1.0) / 2);
+}
+
+static gboolean
+parent_to_child2 (GtkOffscreenBox *offscreen_box,
+		  double x,
+                  double y,
+                  double *child_x,
+                  double *child_y)
+{
+  GtkRequisition child_requisition;
+  double pos_x, pos_y, rot_x, rot_y, start_y;
+  double angle;
+
+  start_y = 0;
+  if (offscreen_box->child1)
+    {
+      gtk_widget_size_request (offscreen_box->child1, &child_requisition);
+      start_y += child_requisition.height * CHILD1_SIZE_SCALE;
+    }
+  
+  gtk_widget_size_request (offscreen_box->child2, &child_requisition);
+  
+  pos_x = x - (child_requisition.width * (CHILD2_SIZE_SCALE - 1.0) / 2);
+  pos_y = y - (start_y + child_requisition.height * (CHILD2_SIZE_SCALE - 1.0) / 2);
+
+  pos_x -= child_requisition.width/2;
+  pos_y -= child_requisition.height/2;
+
+  angle = -offscreen_box->angle;
+  rot_x = pos_x*cos (angle) - pos_y * sin(angle);
+  rot_y = pos_x*sin (angle) + pos_y * cos(angle);
+  
+  *child_x = rot_x + child_requisition.width/2;
+  *child_y = rot_y + child_requisition.height/2;
+
+  return (*child_x >= 0 && *child_x < child_requisition.width &&
+	  *child_y >= 0 && *child_y < child_requisition.height);
+}
+
+static GdkWindow *
+find_offscreen_child (GdkWindow *window,
+                      double x,
+                      double y)
+{
+  GtkOffscreenBox *offscreen_box = NULL;
+  double ox, oy;
+
+  gdk_window_get_user_data (window, (gpointer *) &offscreen_box);
+  g_assert (offscreen_box != NULL);
+
+  /* Child2 is drawn last, pick first */
+  if (offscreen_box->child2 &&
+      parent_to_child2 (offscreen_box, x, y, &ox, &oy))
+    return offscreen_box->offscreen_window2;
+  
+  if (offscreen_box->child1 &&
+      parent_to_child1 (offscreen_box, x, y, &ox, &oy))
+    return offscreen_box->offscreen_window1;
+
+  return NULL;
+}
diff --git a/tests/gtkoffscreenbox.h b/tests/gtkoffscreenbox.h
new file mode 100644
index 0000000..0984fb3
--- /dev/null
+++ b/tests/gtkoffscreenbox.h
@@ -0,0 +1,53 @@
+#ifndef __GTK_OFFSCREEN_BOX_H__
+#define __GTK_OFFSCREEN_BOX_H__
+
+
+#include <gdk/gdk.h>
+#include <gtk/gtkbin.h>
+
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_OFFSCREEN_BOX              (gtk_offscreen_box_get_type ())
+#define GTK_OFFSCREEN_BOX(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_OFFSCREEN_BOX, GtkOffscreenBox))
+#define GTK_OFFSCREEN_BOX_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_OFFSCREEN_BOX, GtkOffscreenBoxClass))
+#define GTK_IS_OFFSCREEN_BOX(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_OFFSCREEN_BOX))
+#define GTK_IS_OFFSCREEN_BOX_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_OFFSCREEN_BOX))
+#define GTK_OFFSCREEN_BOX_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_OFFSCREEN_BOX, GtkOffscreenBoxClass))
+
+typedef struct _GtkOffscreenBox	  GtkOffscreenBox;
+typedef struct _GtkOffscreenBoxClass  GtkOffscreenBoxClass;
+
+struct _GtkOffscreenBox
+{
+  GtkContainer container;
+  
+  GtkWidget *child1;
+  GtkWidget *child2;
+  
+  GdkWindow *offscreen_window1;
+  GdkWindow *offscreen_window2;
+
+  GdkWindow *last_pointer_event_window;
+  gdouble angle;
+};
+
+struct _GtkOffscreenBoxClass
+{
+  GtkBinClass parent_class;
+};
+
+GType	   gtk_offscreen_box_get_type           (void) G_GNUC_CONST;
+GtkWidget* gtk_offscreen_box_new       (void);
+void       gtk_offscreen_box_add1      (GtkOffscreenBox *offscreen,
+					GtkWidget       *child);
+void       gtk_offscreen_box_add2      (GtkOffscreenBox *offscreen,
+					GtkWidget       *child);
+void       gtk_offscreen_box_set_angle (GtkOffscreenBox *offscreen,
+					double           angle);
+
+
+
+G_END_DECLS
+
+#endif /* __GTK_OFFSCREEN_BOX_H__ */
diff --git a/tests/testgtk.c b/tests/testgtk.c
index 1c0dde5..594e3d1 100644
--- a/tests/testgtk.c
+++ b/tests/testgtk.c
@@ -12206,6 +12206,155 @@ create_properties (GtkWidget *widget)
   
 }
 
+struct SnapshotData {
+  GtkWidget *toplevel_button;
+  GtkWidget **window;
+  GdkCursor *cursor;
+  gboolean in_query;
+  gboolean is_toplevel;
+  gint handler;
+};
+
+static void
+destroy_snapshot_data (GtkWidget             *widget,
+		       struct SnapshotData *data)
+{
+  if (*data->window)
+    *data->window = NULL;
+  
+  if (data->cursor)
+    {
+      gdk_cursor_unref (data->cursor);
+      data->cursor = NULL;
+    }
+
+  if (data->handler)
+    {
+      g_signal_handler_disconnect (widget, data->handler);
+      data->handler = 0;
+    }
+
+  g_free (data);
+}
+
+static gint
+snapshot_widget_event (GtkWidget	       *widget,
+		       GdkEvent	       *event,
+		       struct SnapshotData *data)
+{
+  GtkWidget *res_widget = NULL;
+
+  if (!data->in_query)
+    return FALSE;
+  
+  if (event->type == GDK_BUTTON_RELEASE)
+    {
+      gtk_grab_remove (widget);
+      gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
+				  GDK_CURRENT_TIME);
+      
+      res_widget = find_widget_at_pointer (gtk_widget_get_display (widget));
+      if (data->is_toplevel && res_widget)
+	res_widget = gtk_widget_get_toplevel (res_widget);
+      if (res_widget)
+	{
+	  GdkPixmap *pixmap;
+	  GtkWidget *window, *image;
+
+	  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	  pixmap = gtk_widget_get_snapshot (res_widget);
+	  image = gtk_image_new_from_pixmap (pixmap, NULL);
+	  gtk_container_add (GTK_CONTAINER (window), image);
+          g_object_unref (pixmap);
+	  gtk_widget_show_all (window);
+	}
+
+      data->in_query = FALSE;
+    }
+  return FALSE;
+}
+
+
+static void
+snapshot_widget (GtkButton *button,
+		 struct SnapshotData *data)
+{
+  gint failure;
+
+  g_signal_connect (button, "event",
+		    G_CALLBACK (snapshot_widget_event), data);
+
+  data->is_toplevel = GTK_WIDGET (button) == data->toplevel_button;
+  
+  if (!data->cursor)
+    data->cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (button)),
+					       GDK_TARGET);
+  
+  failure = gdk_pointer_grab (GTK_WIDGET (button)->window,
+			      TRUE,
+			      GDK_BUTTON_RELEASE_MASK,
+			      NULL,
+			      data->cursor,
+			      GDK_CURRENT_TIME);
+
+  gtk_grab_add (GTK_WIDGET (button));
+
+  data->in_query = TRUE;
+}
+
+static void
+create_snapshot (GtkWidget *widget)
+{
+  static GtkWidget *window = NULL;
+  GtkWidget *button;
+  GtkWidget *vbox;
+  struct SnapshotData *data;
+
+  data = g_new (struct SnapshotData, 1);
+  data->window = &window;
+  data->in_query = FALSE;
+  data->cursor = NULL;
+  data->handler = 0;
+
+  if (!window)
+    {
+      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+      gtk_window_set_screen (GTK_WINDOW (window),
+			     gtk_widget_get_screen (widget));      
+
+      data->handler = g_signal_connect (window, "destroy",
+					G_CALLBACK (destroy_snapshot_data),
+					data);
+
+      gtk_window_set_title (GTK_WINDOW (window), "test snapshot");
+      gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+      vbox = gtk_vbox_new (FALSE, 1);
+      gtk_container_add (GTK_CONTAINER (window), vbox);
+            
+      button = gtk_button_new_with_label ("Snapshot widget");
+      gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
+      g_signal_connect (button, "clicked",
+			G_CALLBACK (snapshot_widget),
+			data);
+      
+      button = gtk_button_new_with_label ("Snapshot toplevel");
+      data->toplevel_button = button;
+      gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
+      g_signal_connect (button, "clicked",
+			G_CALLBACK (snapshot_widget),
+			data);
+    }
+
+  if (!GTK_WIDGET_VISIBLE (window))
+    gtk_widget_show_all (window);
+  else
+    gtk_widget_destroy (window);
+  
+}
+
+
 
 /*
  * Color Preview
@@ -13489,6 +13638,7 @@ struct {
   { "scrolled windows", create_scrolled_windows },
   { "shapes", create_shapes },
   { "size groups", create_size_groups },
+  { "snapshot", create_snapshot },
   { "spinbutton", create_spins },
   { "statusbar", create_statusbar },
   { "styles", create_styles },
@@ -13524,7 +13674,7 @@ create_main_window (void)
 
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_widget_set_name (window, "main window");
-  gtk_widget_set_uposition (window, 20, 20);
+  gtk_widget_set_uposition (window, 50, 20);
   gtk_window_set_default_size (GTK_WINDOW (window), -1, 400);
 
   geometry.min_width = -1;
diff --git a/tests/testoffscreen.c b/tests/testoffscreen.c
new file mode 100644
index 0000000..c0742b0
--- /dev/null
+++ b/tests/testoffscreen.c
@@ -0,0 +1,291 @@
+#undef GTK_DISABLE_DEPRECATED
+
+#include <math.h>
+#include <gtk/gtk.h>
+#include "gtkoffscreenbox.h"
+
+
+static void
+combo_changed_cb (GtkWidget *combo,
+		  gpointer   data)
+{
+  GtkWidget *label = GTK_WIDGET (data);
+  gint active;
+
+  active = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
+  
+  gtk_label_set_ellipsize (GTK_LABEL (label), (PangoEllipsizeMode)active);
+}
+
+gboolean
+layout_expose_handler (GtkWidget *widget, GdkEventExpose *event)
+{
+  GtkLayout *layout;
+
+  gint i,j;
+  gint imin, imax, jmin, jmax;
+
+  layout = GTK_LAYOUT (widget);
+
+  if (event->window != layout->bin_window)
+    return FALSE;
+  
+  imin = (event->area.x) / 10;
+  imax = (event->area.x + event->area.width + 9) / 10;
+
+  jmin = (event->area.y) / 10;
+  jmax = (event->area.y + event->area.height + 9) / 10;
+
+  for (i=imin; i<imax; i++)
+    for (j=jmin; j<jmax; j++)
+      if ((i+j) % 2)
+	gdk_draw_rectangle (layout->bin_window,
+			    widget->style->black_gc,
+			    TRUE,
+			    10*i, 10*j, 
+			    1+i%10, 1+j%10);
+  
+  return FALSE;
+}
+
+static gboolean
+scroll_layout (gpointer data)
+{
+  GtkWidget *layout = data;
+  GtkAdjustment *adj;
+  
+  adj = gtk_layout_get_hadjustment (GTK_LAYOUT (layout));
+  gtk_adjustment_set_value (adj,
+			    gtk_adjustment_get_value (adj) + 5.0);
+  return TRUE;
+}
+
+static guint layout_timeout;
+
+void create_layout (GtkWidget *vbox)
+{
+  GtkWidget *layout;
+  GtkWidget *scrolledwindow;
+  GtkWidget *button;
+  gchar buf[16];
+  gint i, j;
+      
+
+  scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow),
+				       GTK_SHADOW_IN);
+  gtk_scrolled_window_set_placement (GTK_SCROLLED_WINDOW (scrolledwindow),
+				     GTK_CORNER_TOP_RIGHT);
+  
+  gtk_box_pack_start (GTK_BOX (vbox), scrolledwindow, TRUE, TRUE, 0);
+  
+  layout = gtk_layout_new (NULL, NULL);
+  gtk_container_add (GTK_CONTAINER (scrolledwindow), layout);
+  
+  /* We set step sizes here since GtkLayout does not set
+   * them itself.
+   */
+  GTK_LAYOUT (layout)->hadjustment->step_increment = 10.0;
+  GTK_LAYOUT (layout)->vadjustment->step_increment = 10.0;
+  
+  gtk_widget_set_events (layout, GDK_EXPOSURE_MASK);
+  g_signal_connect (layout, "expose_event",
+		    G_CALLBACK (layout_expose_handler), NULL);
+  
+  gtk_layout_set_size (GTK_LAYOUT (layout), 1600, 128000);
+  
+  for (i=0 ; i < 16 ; i++)
+    for (j=0 ; j < 16 ; j++)
+      {
+	sprintf(buf, "Button %d, %d", i, j);
+	if ((i + j) % 2)
+	  button = gtk_button_new_with_label (buf);
+	else
+	  button = gtk_label_new (buf);
+	
+	gtk_layout_put (GTK_LAYOUT (layout), button,
+			j*100, i*100);
+      }
+  
+  for (i=16; i < 1280; i++)
+    {
+      sprintf(buf, "Button %d, %d", i, 0);
+      if (i % 2)
+	button = gtk_button_new_with_label (buf);
+      else
+	button = gtk_label_new (buf);
+      
+      gtk_layout_put (GTK_LAYOUT (layout), button,
+		      0, i*100);
+    }
+
+  layout_timeout = g_timeout_add (1000, scroll_layout, layout);
+}
+
+GtkWidget *
+create_widgets (void)
+{
+  GtkWidget *vbox, *hbox, *label, *combo, *entry, *button, *cb;
+  GtkWidget *sw, *text_view;
+  GList *cbitems = NULL;
+  
+  vbox = gtk_vbox_new (0, FALSE);
+  
+  hbox = gtk_hbox_new (0, FALSE);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  
+  label = gtk_label_new ("This label may be ellipsized\nto make it fit.");
+  gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+
+  combo = gtk_combo_box_new_text ();
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "NONE");
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "START");
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "MIDDLE");
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "END");
+  gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
+  gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
+  g_signal_connect (combo, "changed", G_CALLBACK (combo_changed_cb), label);
+  
+  entry = gtk_entry_new ();
+  gtk_entry_set_text (GTK_ENTRY (entry), "an entry - lots of text.... lots of text.... lots of text.... lots of text.... ");
+  gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+  
+  label = gtk_label_new ("Label after entry.");
+  gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+  gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
+
+  button = gtk_button_new_with_label ("Button");
+  gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
+
+  button = gtk_check_button_new_with_mnemonic ("_Check button");
+  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+  cb = gtk_combo_new ();
+  cbitems = g_list_append(cbitems, "item0");
+  cbitems = g_list_append(cbitems, "item1 item1");
+  cbitems = g_list_append(cbitems, "item2 item2 item2");
+  gtk_combo_set_popdown_strings (GTK_COMBO (cb), cbitems);
+  gtk_entry_set_text (GTK_ENTRY (GTK_COMBO(cb)->entry), "hello world ♥ foo");
+  gtk_editable_select_region (GTK_EDITABLE (GTK_COMBO(cb)->entry),
+			      0, -1);
+  gtk_box_pack_start (GTK_BOX (vbox), cb, TRUE, TRUE, 0);
+
+  sw = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+				  GTK_POLICY_AUTOMATIC,
+				  GTK_POLICY_AUTOMATIC);
+  text_view = gtk_text_view_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
+  gtk_container_add (GTK_CONTAINER (sw), text_view);
+  
+  create_layout (vbox);
+  
+  return vbox;
+}
+
+
+static void
+scale_changed (GtkRange     *range,
+	       GtkOffscreenBox *offscreen_box)
+{
+  gtk_offscreen_box_set_angle (offscreen_box,
+			       gtk_range_get_value (range));
+
+}
+
+static void
+remove_clicked (GtkButton *button, GtkWidget *widget)
+{
+  static gboolean destroyed = FALSE;
+
+  if (destroyed)
+    return;
+
+  destroyed = TRUE;
+  gtk_widget_destroy (widget);
+  g_source_remove (layout_timeout);
+}
+
+int
+main (int argc, char *argv[])
+{
+  GtkWidget *window, *widget, *scale, *vbox, *button, *widget2, *entry;
+  GtkWidget *offscreen = NULL, *offscreen2;
+  gboolean use_offscreen;
+
+  gtk_init (&argc, &argv);
+
+  use_offscreen = argc == 1;
+  
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_default_size (GTK_WINDOW (window), 300,300);
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  vbox = gtk_vbox_new (0, FALSE);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+
+  scale = gtk_hscale_new_with_range (0, 
+				     M_PI * 2,
+				     0.01);
+  gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
+
+  button = gtk_button_new_with_label ("Remove child 2");
+  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+  
+  if (use_offscreen)
+    {
+      offscreen = gtk_offscreen_box_new ();
+      g_signal_connect (G_OBJECT (scale), "value_changed", G_CALLBACK (scale_changed), offscreen);
+    }
+  else
+    offscreen = gtk_vpaned_new ();
+  
+  gtk_box_pack_start (GTK_BOX (vbox), offscreen, TRUE, TRUE, 0);
+
+  widget = create_widgets ();
+  if (use_offscreen)
+    gtk_offscreen_box_add1 (GTK_OFFSCREEN_BOX (offscreen),
+			    widget);
+  else
+    gtk_paned_add1 (GTK_PANED (offscreen), widget);
+  
+  widget = create_widgets ();
+  if (1)
+    {
+      widget2 = gtk_button_new_with_label ("Offscreen in offscreen");
+      offscreen2 = gtk_offscreen_box_new ();
+      gtk_offscreen_box_add2 (GTK_OFFSCREEN_BOX (offscreen2),
+			      widget2);
+      g_signal_connect (G_OBJECT (scale), "value_changed", G_CALLBACK (scale_changed), offscreen2);
+      gtk_box_pack_start (GTK_BOX (widget), offscreen2, FALSE, FALSE, 0);
+    }
+      
+  if (use_offscreen)
+    gtk_offscreen_box_add2 (GTK_OFFSCREEN_BOX (offscreen),
+			    widget);
+  else
+    gtk_paned_add2 (GTK_PANED (offscreen), widget);
+
+  gtk_widget_show_all (window);
+
+  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (remove_clicked), widget);
+
+  /* redirect */
+  if (0)
+    {
+      GtkWidget *redirect_win;
+      
+      redirect_win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+      gtk_window_set_default_size (GTK_WINDOW (redirect_win), 400,400);
+      gtk_widget_show (redirect_win);
+      gtk_widget_realize (redirect_win);
+      gtk_widget_realize (window);
+      gdk_window_redirect_to_drawable (window->window,
+				       GDK_DRAWABLE (redirect_win->window),
+				       0, 0, 0, 0, -1, -1);
+    }
+  
+  gtk_main ();
+
+  return 0;
+}
