]> Pileus Git - ~andy/gtk/blobdiff - gdk/gdkwindow.c
GdkWindow: remove reference to a long-removed example
[~andy/gtk] / gdk / gdkwindow.c
index e53fdd07fa408bbb4b0a7b7147e43294054b853c..ae77620888496d11bdfcb217cc867b6563356f7b 100644 (file)
@@ -13,9 +13,7 @@
  * 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.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 /*
  * @Short_description: Onscreen display areas in the target window system
  * @Title: Windows
  *
- * A #GdkWindow is a rectangular region on the screen. It's a low-level object,
- * used to implement high-level objects such as #GtkWidget and #GtkWindow on the
- * GTK+ level. A #GtkWindow is a toplevel window, the thing a user might think
- * of as a "window" with a titlebar and so on; a #GtkWindow may contain many
- * #GdkWindow<!-- -->s. For example, each #GtkButton has a #GdkWindow associated
- * with it.
+ * A #GdkWindow is a (usually) rectangular region on the screen.
+ * It's a low-level object, used to implement high-level objects such as
+ * #GtkWidget and #GtkWindow on the GTK+ level. A #GtkWindow is a toplevel
+ * window, the thing a user might think of as a "window" with a titlebar and
+ * so on; a #GtkWindow may contain many #GdkWindows. For example, each
+ * #GtkButton has a #GdkWindow associated with it.
  *
  * <refsect2 id="COMPOSITED-WINDOWS">
  * <title>Composited Windows</title>
  * <firstterm>composited</firstterm> window it is the responsibility of the
  * application to render the window contents at the right spot.
  * </para>
- * <example id="composited-window-example">
- * <title>Composited windows</title>
- * <programlisting>
- * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/gdk/composited-window-example.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include>
- * </programlisting></example>
- * <para>
- * In the example <xref linkend="composited-window-example"/>, a button is
- * placed inside of an event box inside of a window. The event box is set as
- * composited and therefore is no longer automatically drawn to the screen.
- *
- * When the contents of the event box change, an expose event is generated on
- * it's parent window (which, in this case, belongs to the toplevel #GtkWindow).
- * The expose handler for this widget is responsible for merging the changes
- * back on the screen in the way that it wishes.
- *
- * In our case, we merge the contents with a 50% transparency. We also set the
- * background colour of the window to red. The effect is that the background
- * shows through the button.
- * </para>
  * </refsect2>
  * <refsect2 id="OFFSCREEN-WINDOWS">
  * <title>Offscreen Windows</title>
  * be it a toplevel window or a child window. In this setup the
  * GdkWindow (and other GdkDrawables) were platform independent classes,
  * and the actual platform specific implementation was in a delegate
- * object availible as "impl" in the window object.
+ * object available as "impl" in the window object.
  *
  * With the addition of client side windows and offscreen windows this
  * changes a bit. The application-visible GdkWindow object behaves as
@@ -203,9 +182,8 @@ struct _GdkWindowPaint
 {
   cairo_region_t *region;
   cairo_surface_t *surface;
+  cairo_region_t *flushed;
   guint uses_implicit : 1;
-  guint flushed : 1;
-  guint32 region_tag;
 };
 
 typedef struct {
@@ -256,6 +234,8 @@ static void gdk_window_invalidate_rect_full (GdkWindow          *window,
                                             const GdkRectangle *rect,
                                             gboolean            invalidate_children,
                                             ClearBg             clear_bg);
+static void _gdk_window_propagate_has_alpha_background (GdkWindow *window);
+static cairo_surface_t *gdk_window_ref_impl_surface (GdkWindow *window);
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
@@ -263,15 +243,43 @@ static gpointer parent_class = NULL;
 
 static const cairo_user_data_key_t gdk_window_cairo_key;
 
-static guint32
-new_region_tag (void)
+G_DEFINE_ABSTRACT_TYPE (GdkWindow, gdk_window, G_TYPE_OBJECT)
+
+#ifdef DEBUG_WINDOW_PRINTING
+char *
+print_region (cairo_region_t *region)
 {
-  static guint32 tag = 0;
+  GString *s = g_string_new ("{");
+  if (cairo_region_is_empty (region))
+    {
+      g_string_append (s, "empty");
+    }
+  else
+    {
+      int num = cairo_region_num_rectangles (region);
+      cairo_rectangle_int_t r;
 
-  return ++tag;
+      if (num == 1)
+       {
+         cairo_region_get_rectangle (region, 0, &r);
+         g_string_append_printf (s, "%dx%d @%d,%d", r.width, r.height, r.x, r.y);
+       }
+      else
+       {
+         cairo_region_get_extents (region, &r);
+         g_string_append_printf (s, "extent: %dx%d @%d,%d, details: ", r.width, r.height, r.x, r.y);
+         for (int i = 0; i < num; i++)
+           {
+             g_string_append_printf (s, "[%dx%d @%d,%d]", r.width, r.height, r.x, r.y);
+             if (i != num -1)
+               g_string_append (s, ", ");
+           }
+       }
+    }
+  g_string_append (s, "}");
+  return g_string_free (s, FALSE);
 }
-
-G_DEFINE_ABSTRACT_TYPE (GdkWindow, gdk_window, G_TYPE_OBJECT)
+#endif
 
 GType
 _gdk_paintable_get_type (void)
@@ -313,6 +321,9 @@ gdk_window_init (GdkWindow *window)
   window->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
   /* Default to unobscured since some backends don't send visibility events */
   window->native_visibility = GDK_VISIBILITY_UNOBSCURED;
+
+  window->device_cursor = g_hash_table_new_full (NULL, NULL,
+                                                 NULL, g_object_unref);
 }
 
 /* Stop and return on the first non-NULL parent */
@@ -404,11 +415,11 @@ gdk_window_class_init (GdkWindowClass *klass)
   /**
    * GdkWindow::to-embedder:
    * @window: the offscreen window on which the signal is emitted
-   * @offscreen-x: x coordinate in the offscreen window
-   * @offscreen-y: y coordinate in the offscreen window
-   * @embedder-x: (out) (type double): return location for the x
+   * @offscreen_x: x coordinate in the offscreen window
+   * @offscreen_y: y coordinate in the offscreen window
+   * @embedder_x: (out) (type double): return location for the x
    *     coordinate in the embedder window
-   * @embedder-y: (out) (type double): return location for the y
+   * @embedder_y: (out) (type double): return location for the y
    *     coordinate in the embedder window
    *
    * The ::to-embedder signal is emitted to translate coordinates
@@ -435,11 +446,11 @@ gdk_window_class_init (GdkWindowClass *klass)
   /**
    * GdkWindow::from-embedder:
    * @window: the offscreen window on which the signal is emitted
-   * @embedder-x: x coordinate in the embedder window
-   * @embedder-y: y coordinate in the embedder window
-   * @offscreen-x: (out) (type double): return location for the x
+   * @embedder_x: x coordinate in the embedder window
+   * @embedder_y: y coordinate in the embedder window
+   * @offscreen_x: (out) (type double): return location for the x
    *     coordinate in the offscreen window
-   * @offscreen-y: (out) (type double): return location for the y
+   * @offscreen_y: (out) (type double): return location for the y
    *     coordinate in the offscreen window
    *
    * The ::from-embedder signal is emitted to translate coordinates
@@ -567,6 +578,9 @@ gdk_window_finalize (GObject *object)
   if (window->devices_inside)
     g_list_free (window->devices_inside);
 
+  if (window->layered_region)
+      cairo_region_destroy (window->layered_region);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -655,10 +669,64 @@ gdk_window_has_no_impl (GdkWindow *window)
 }
 
 static void
-remove_child_area (GdkWindow *private,
+remove_layered_child_area (GdkWindow *window,
+                          cairo_region_t *region)
+{
+  GdkWindow *child;
+  cairo_region_t *child_region;
+  GdkRectangle r;
+  GList *l;
+
+  for (l = window->children; l; l = l->next)
+    {
+      child = l->data;
+
+      /* If region is empty already, no need to do
+        anything potentially costly */
+      if (cairo_region_is_empty (region))
+       break;
+
+      if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
+       continue;
+
+      /* Ignore offscreen children, as they don't draw in their parent and
+       * don't take part in the clipping */
+      if (gdk_window_is_offscreen (child))
+       continue;
+
+      /* Only non-impl children with alpha add to the layered region */
+      if (!child->has_alpha_background && gdk_window_has_impl (child))
+       continue;
+
+      r.x = child->x;
+      r.y = child->y;
+      r.width = child->width;
+      r.height = child->height;
+
+      /* Bail early if child totally outside region */
+      if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
+       continue;
+
+      child_region = cairo_region_create_rectangle (&r);
+      if (child->shape)
+       {
+         /* Adjust shape region to parent window coords */
+         cairo_region_translate (child->shape, child->x, child->y);
+         cairo_region_intersect (child_region, child->shape);
+         cairo_region_translate (child->shape, -child->x, -child->y);
+       }
+
+      cairo_region_subtract (region, child_region);
+      cairo_region_destroy (child_region);
+    }
+}
+
+static void
+remove_child_area (GdkWindow *window,
                   GdkWindow *until,
                   gboolean for_input,
-                  cairo_region_t *region)
+                  cairo_region_t *region,
+                  cairo_region_t *layered_region)
 {
   GdkWindow *child;
   cairo_region_t *child_region;
@@ -666,7 +734,7 @@ remove_child_area (GdkWindow *private,
   GList *l;
   cairo_region_t *shape;
 
-  for (l = private->children; l; l = l->next)
+  for (l = window->children; l; l = l->next)
     {
       child = l->data;
 
@@ -704,7 +772,7 @@ remove_child_area (GdkWindow *private,
          cairo_region_intersect (child_region, child->shape);
          cairo_region_translate (child->shape, -child->x, -child->y);
        }
-      else if (private->window_type == GDK_WINDOW_FOREIGN)
+      else if (window->window_type == GDK_WINDOW_FOREIGN)
        {
          shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_shape (child);
          if (shape)
@@ -718,7 +786,7 @@ remove_child_area (GdkWindow *private,
        {
          if (child->input_shape)
            cairo_region_intersect (child_region, child->input_shape);
-         else if (private->window_type == GDK_WINDOW_FOREIGN)
+         else if (window->window_type == GDK_WINDOW_FOREIGN)
            {
              shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_input_shape (child);
              if (shape)
@@ -729,9 +797,14 @@ remove_child_area (GdkWindow *private,
            }
        }
 
-      cairo_region_subtract (region, child_region);
+      if (child->has_alpha_background)
+       {
+         if (layered_region != NULL)
+           cairo_region_union (layered_region, child_region);
+       }
+      else
+       cairo_region_subtract (region, child_region);
       cairo_region_destroy (child_region);
-
     }
 }
 
@@ -767,7 +840,7 @@ gdk_window_update_visibility (GdkWindow *window)
       window->effective_visibility = new_visibility;
 
       if (new_visibility != GDK_VISIBILITY_NOT_VIEWABLE &&
-         window->event_mask & GDK_VISIBILITY_NOTIFY)
+         window->event_mask & GDK_VISIBILITY_NOTIFY_MASK)
        {
          event = _gdk_make_event (window, GDK_VISIBILITY_NOTIFY,
                                   NULL, FALSE);
@@ -874,7 +947,7 @@ recompute_visible_regions_internal (GdkWindow *private,
   GdkRectangle r;
   GList *l;
   GdkWindow *child;
-  cairo_region_t *new_clip, *old_clip_region_with_children;
+  cairo_region_t *new_clip, *new_layered;
   gboolean clip_region_changed;
   gboolean abs_pos_changed;
   int old_abs_x, old_abs_y;
@@ -907,6 +980,7 @@ recompute_visible_regions_internal (GdkWindow *private,
   clip_region_changed = FALSE;
   if (recalculate_clip)
     {
+      new_layered = cairo_region_create ();
       if (private->viewable)
        {
          /* Calculate visible region (sans children) in parent window coords */
@@ -919,45 +993,45 @@ recompute_visible_regions_internal (GdkWindow *private,
          if (!gdk_window_is_toplevel (private))
            {
              cairo_region_intersect (new_clip, private->parent->clip_region);
+             cairo_region_union (new_layered, private->parent->layered_region);
 
-             /* Remove all overlapping children from parent.
-              * Unless we're all native, because then we don't need to take
-              * siblings into account since X does that clipping for us.
-              * This makes things like SWT that modify the raw X stacking
-              * order without GDKs knowledge work.
-              */
-             if (!_gdk_native_windows)
-               remove_child_area (private->parent, private, FALSE, new_clip);
+             /* Remove all overlapping children from parent. */
+             remove_child_area (private->parent, private, FALSE, new_clip, new_layered);
            }
 
          /* Convert from parent coords to window coords */
          cairo_region_translate (new_clip, -private->x, -private->y);
+         cairo_region_translate (new_layered, -private->x, -private->y);
 
          if (private->shape)
            cairo_region_intersect (new_clip, private->shape);
        }
       else
-       new_clip = cairo_region_create ();
+         new_clip = cairo_region_create ();
 
+      cairo_region_intersect (new_layered, new_clip);
+      
       if (private->clip_region == NULL ||
          !cairo_region_equal (private->clip_region, new_clip))
        clip_region_changed = TRUE;
 
+      if (private->layered_region == NULL ||
+         !cairo_region_equal (private->layered_region, new_layered))
+       clip_region_changed = TRUE;
+      
       if (private->clip_region)
        cairo_region_destroy (private->clip_region);
       private->clip_region = new_clip;
 
-      old_clip_region_with_children = private->clip_region_with_children;
+      if (private->layered_region != NULL)
+       cairo_region_destroy (private->layered_region);
+      private->layered_region = new_layered;
+
+      if (private->clip_region_with_children)
+       cairo_region_destroy (private->clip_region_with_children);
       private->clip_region_with_children = cairo_region_copy (private->clip_region);
       if (private->window_type != GDK_WINDOW_ROOT)
-       remove_child_area (private, NULL, FALSE, private->clip_region_with_children);
-
-      if (clip_region_changed ||
-         !cairo_region_equal (private->clip_region_with_children, old_clip_region_with_children))
-         private->clip_tag = new_region_tag ();
-
-      if (old_clip_region_with_children)
-       cairo_region_destroy (old_clip_region_with_children);
+       remove_child_area (private, NULL, FALSE, private->clip_region_with_children, NULL);
     }
 
   if (clip_region_changed)
@@ -1146,8 +1220,7 @@ get_native_device_event_mask (GdkWindow *private,
   else
     event_mask = private->event_mask;
 
-  if (_gdk_native_windows ||
-      private->window_type == GDK_WINDOW_ROOT ||
+  if (private->window_type == GDK_WINDOW_ROOT ||
       private->window_type == GDK_WINDOW_FOREIGN)
     return event_mask;
   else
@@ -1188,11 +1261,12 @@ get_native_device_event_mask (GdkWindow *private,
        * lists due to some non-native child window.
        */
       if (gdk_window_is_toplevel (private) ||
-         mask & GDK_BUTTON_PRESS_MASK)
-       mask |=
-         GDK_POINTER_MOTION_MASK |
-         GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
-         GDK_SCROLL_MASK;
+          mask & GDK_BUTTON_PRESS_MASK)
+        mask |=
+          GDK_TOUCH_MASK |
+          GDK_POINTER_MOTION_MASK |
+          GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+          GDK_SCROLL_MASK;
 
       return mask;
     }
@@ -1244,7 +1318,8 @@ sync_native_window_stack_position (GdkWindow *window)
  * @parent: (allow-none): 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
+ * @attributes_mask: (type GdkWindowAttributesType): mask indicating which
+ *   fields in @attributes are valid
  *
  * Creates a new #GdkWindow using the attributes from
  * @attributes. See #GdkWindowAttr and #GdkWindowAttributesType for
@@ -1288,13 +1363,6 @@ gdk_window_new (GdkWindow     *parent,
       return NULL;
     }
 
-  if (attributes->window_type == GDK_WINDOW_OFFSCREEN &&
-      _gdk_native_windows)
-    {
-      g_warning ("Offscreen windows not supported with native-windows gdk");
-      return NULL;
-    }
-
   display = gdk_screen_get_display (screen);
 
   window = _gdk_display_create_window (display);
@@ -1370,7 +1438,8 @@ gdk_window_new (GdkWindow     *parent,
       window->depth = window->visual->depth;
 
       /* XXX: Cache this somehow? */
-      window->background = cairo_pattern_create_rgb (0, 0, 0);
+      window->background = cairo_pattern_create_rgba (0, 0, 0, 0);
+      window->has_alpha_background = TRUE;
     }
   else
     {
@@ -1381,10 +1450,7 @@ gdk_window_new (GdkWindow     *parent,
   if (window->parent)
     window->parent->children = g_list_prepend (window->parent->children, window);
 
-  window->device_cursor = g_hash_table_new_full (NULL, NULL,
-                                                 NULL, g_object_unref);
-
-  native = _gdk_native_windows; /* Default */
+  native = FALSE;
   if (window->parent->window_type == GDK_WINDOW_ROOT)
     native = TRUE; /* Always use native windows for toplevels */
   else if (!window->input_only &&
@@ -1646,10 +1712,22 @@ gdk_window_reparent (GdkWindow *window,
 
   _gdk_window_update_viewable (window);
 
+  if (window->background == NULL)
+    {
+      /* parent relative background, update has_alpha_background */
+      if (window->parent == NULL ||
+         window->parent->window_type == GDK_WINDOW_ROOT)
+       window->has_alpha_background = FALSE;
+      else
+       window->has_alpha_background = window->parent->has_alpha_background;
+    }
+
   recompute_visible_regions (window, TRUE, FALSE);
   if (old_parent && GDK_WINDOW_TYPE (old_parent) != GDK_WINDOW_ROOT)
     recompute_visible_regions (old_parent, FALSE, TRUE);
 
+  _gdk_window_propagate_has_alpha_background (window);
+
   /* We used to apply the clip as the shape, but no more.
      Reset this to the real shape */
   if (gdk_window_has_impl (window) &&
@@ -1772,7 +1850,7 @@ gdk_window_ensure_native (GdkWindow *window)
 
 /**
  * _gdk_event_filter_unref:
- * @window: A #GdkWindow, or %NULL to be the global window
+ * @window: (allow-none): A #GdkWindow, or %NULL to be the global window
  * @filter: A window filter
  *
  * Release a reference to @filter.  Note this function may
@@ -2006,12 +2084,8 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
              window->clip_region_with_children = NULL;
            }
 
-         if (window->outstanding_moves)
-           {
-             g_list_foreach (window->outstanding_moves, (GFunc)gdk_window_region_move_free, NULL);
-             g_list_free (window->outstanding_moves);
-             window->outstanding_moves = NULL;
-           }
+         g_list_free_full (window->outstanding_moves, (GDestroyNotify) gdk_window_region_move_free);
+         window->outstanding_moves = NULL;
        }
       break;
     }
@@ -2057,7 +2131,7 @@ gdk_window_destroy (GdkWindow *window)
 /**
  * gdk_window_set_user_data:
  * @window: a #GdkWindow
- * @user_data: user data
+ * @user_data: (allow-none) (type GObject.Object): user data
  *
  * For most purposes this function is deprecated in favor of
  * g_object_set_data(). However, for historical reasons GTK+ stores
@@ -2412,7 +2486,7 @@ gdk_window_peek_children (GdkWindow *window)
 
 /**
  * gdk_window_add_filter: (skip)
- * @window: a #GdkWindow
+ * @window: (allow-none): a #GdkWindow
  * @function: filter callback
  * @data: data to pass to filter callback
  *
@@ -2422,8 +2496,9 @@ gdk_window_peek_children (GdkWindow *window)
  * doing. Pass %NULL for @window to get all events for all windows,
  * instead of events for a specific window.
  *
- * See gdk_display_add_client_message_filter() if you are interested
- * in X ClientMessage events.
+ * If you are interested in X GenericEvents, bear in mind that
+ * XGetEventData() has been already called on the event, and
+ * XFreeEventData() must not be called within @function.
  **/
 void
 gdk_window_add_filter (GdkWindow     *window,
@@ -2614,7 +2689,7 @@ gdk_window_get_content (GdkWindow *window)
 
   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 
-  surface = _gdk_window_ref_cairo_surface (window);
+  surface = gdk_window_ref_impl_surface (window);
   content = cairo_surface_get_content (surface);
   cairo_surface_destroy (surface);
 
@@ -2639,9 +2714,6 @@ gdk_window_begin_implicit_paint (GdkWindow *window, GdkRectangle *rect)
 
   g_assert (gdk_window_has_impl (window));
 
-  if (_gdk_native_windows)
-    return FALSE; /* No need for implicit paints since we can't merge draws anyway */
-
   if (GDK_IS_PAINTABLE (window->impl))
     return FALSE; /* Implementation does double buffering */
 
@@ -2660,7 +2732,7 @@ gdk_window_begin_implicit_paint (GdkWindow *window, GdkRectangle *rect)
   paint = g_new (GdkWindowPaint, 1);
   paint->region = cairo_region_create (); /* Empty */
   paint->uses_implicit = FALSE;
-  paint->flushed = FALSE;
+  paint->flushed = NULL;
   paint->surface = gdk_window_create_similar_surface (window,
                                                       gdk_window_get_content (window),
                                                      MAX (rect->width, 1),
@@ -2692,55 +2764,55 @@ gdk_cairo_create_for_impl (GdkWindow *window)
   return cr;
 }
 
-/* Ensure that all content related to this (sub)window is pushed to the
-   native region. If there is an active paint then that area is not
-   pushed, in order to not show partially finished double buffers. */
+/* This is called whenever something is drawing directly to the
+ * window, bypassing the double buffering. When this happens we
+ * need to mark any the currently drawn data in the double buffer
+ * as invalid to avoid later drawing it back over the directly
+ * rendered pixels. We also need to mark this region as "flushed"
+ * so that if we later try to paint on it double-buffered we need
+ * to read back the on-window pixels rather than relying on what
+ * is in the current double-buffer pixmap.
+ *
+ * Note that this doesn't correctly handle the case where the
+ * non-double buffered drawing uses transparency and relies on
+ * what the windows below it draws. A fix for that would require
+ * drawing the existing double-buffered background to the window,
+ * but that causes ugly flashes. Non-double buffered drawing is
+ * typically only used in old code or when the drawed widget
+ * already has a double-buffering layer, and in these cases the
+ * pixels are opaque anyway. If you need transparency, don't
+ * disable double buffering.
+ */
 static void
 gdk_window_flush_implicit_paint (GdkWindow *window)
 {
   GdkWindow *impl_window;
   GdkWindowPaint *paint;
   cairo_region_t *region;
-  GSList *list;
 
   impl_window = gdk_window_get_impl_window (window);
   if (impl_window->implicit_paint == NULL)
     return;
 
   paint = impl_window->implicit_paint;
-  paint->flushed = TRUE;
-  region = cairo_region_copy (window->clip_region_with_children);
-
-  /* Don't flush active double buffers, as that may show partially done
-   * rendering */
-  for (list = window->paint_stack; list != NULL; list = list->next)
-    {
-      GdkWindowPaint *tmp_paint = list->data;
 
-      cairo_region_subtract (region, tmp_paint->region);
-    }
+  region = cairo_region_copy (window->clip_region_with_children);
+  cairo_region_translate (region, window->abs_x, window->abs_y);
 
-  cairo_region_translate (region, -window->abs_x, -window->abs_y);
-  cairo_region_intersect (region, paint->region);
+  /* Anything in the whole flushed window that was drawn is now
+     considered unpainted, so that we don't push it back at the
+     end of the implicit paint overwriting the directly rendered
+     pixels. */
+  cairo_region_subtract (paint->region, region);
 
-  if (!GDK_WINDOW_DESTROYED (window) && !cairo_region_is_empty (region))
+  /* Save flushed area so we can read it back if we draw over it later */
+  if (paint->flushed == NULL)
+    paint->flushed = region;
+  else
     {
-      cairo_t *cr;
-
-      /* Remove flushed region from the implicit paint */
-      cairo_region_subtract (paint->region, region);
-
-      /* Some regions are valid, push these to window now */
-      cr = gdk_cairo_create_for_impl (window);
-      gdk_cairo_region (cr, region);
-      cairo_clip (cr);
-      cairo_set_source_surface (cr, paint->surface, 0, 0);
-      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-      cairo_paint (cr);
-      cairo_destroy (cr);
+      cairo_region_union (paint->flushed, region);
+      cairo_region_destroy (region);
     }
-  
-  cairo_region_destroy (region);
 }
 
 /* Ends an implicit paint, paired with gdk_window_begin_implicit_paint returning TRUE */
@@ -2772,7 +2844,8 @@ gdk_window_end_implicit_paint (GdkWindow *window)
     }
   
   cairo_region_destroy (paint->region);
-
+  if (paint->flushed)
+    cairo_region_destroy (paint->flushed);
   cairo_surface_destroy (paint->surface);
   g_free (paint);
 }
@@ -2875,7 +2948,6 @@ gdk_window_begin_paint_region (GdkWindow       *window,
 
   paint = g_new (GdkWindowPaint, 1);
   paint->region = cairo_region_copy (region);
-  paint->region_tag = new_region_tag ();
 
   cairo_region_intersect (paint->region, window->clip_region_with_children);
   cairo_region_get_extents (paint->region, &clip_box);
@@ -2907,6 +2979,45 @@ gdk_window_begin_paint_region (GdkWindow       *window,
                                                          MAX (clip_box.width, 1),
                                                           MAX (clip_box.height, 1));
     }
+
+  /* Normally alpha backgrounded client side windows are composited on the implicit paint
+     by being drawn in back to front order. However, if implicit paints are not used, for
+     instance if it was flushed due to a non-double-buffered paint in the middle of the
+     expose we need to copy in the existing data here. */
+  if (!gdk_window_has_impl (window) &&
+      window->has_alpha_background &&
+      (!implicit_paint ||
+       (implicit_paint && implicit_paint->flushed != NULL && !cairo_region_is_empty (implicit_paint->flushed))))
+    {
+      cairo_t *cr = cairo_create (paint->surface);
+      /* We can't use gdk_cairo_set_source_window here, as that might
+        flush the implicit paint at an unfortunate time, since this
+        would be detected as a draw during non-expose time */
+      cairo_surface_t *source_surface  = gdk_window_ref_impl_surface (impl_window);
+      cairo_set_source_surface (cr, source_surface,
+                               - (window->abs_x + clip_box.x),
+                               - (window->abs_y + clip_box.y));
+      cairo_surface_destroy (source_surface);
+
+      /* Only read back the flushed area if any */
+      if (implicit_paint)
+       {
+         cairo_region_t *flushed = cairo_region_copy (implicit_paint->flushed);
+         /* Convert from impl coords */
+         cairo_region_translate (flushed, -window->abs_x, -window->abs_y);
+         cairo_region_intersect (flushed, paint->region);
+         gdk_cairo_region (cr, flushed);
+         cairo_clip (cr);
+
+         /* Convert to impl coords */
+         cairo_region_translate (flushed, window->abs_x, window->abs_y);
+         cairo_region_subtract (implicit_paint->flushed, flushed);
+         cairo_region_destroy (flushed);
+       }
+      cairo_paint (cr);
+      cairo_destroy (cr);
+    }
+
   cairo_surface_set_device_offset (paint->surface, -clip_box.x, -clip_box.y);
 
   for (list = window->paint_stack; list != NULL; list = list->next)
@@ -2986,6 +3097,7 @@ gdk_window_end_paint (GdkWindow *window)
       cairo_region_intersect (full_clip, paint->region);
 
       cr = gdk_cairo_create (window);
+      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
       cairo_set_source_surface (cr, paint->surface, 0, 0);
       gdk_cairo_region (cr, full_clip);
       cairo_fill (cr);
@@ -3313,28 +3425,6 @@ gdk_window_flush (GdkWindow *window)
   gdk_window_flush_implicit_paint (window);
 }
 
-/* If we're about to move/resize or otherwise change the
- * hierarchy of a client side window in an impl and we're
- * called from an expose event handler then we need to
- * flush any already painted parts of the implicit paint
- * that are not part of the current paint, as these may
- * be used when scrolling or may overdraw the changes
- * caused by the hierarchy change.
- */
-static void
-gdk_window_flush_if_exposing (GdkWindow *window)
-{
-  GdkWindow *impl_window;
-
-  impl_window = gdk_window_get_impl_window (window);
-
-  /* If we're in an implicit paint (i.e. in an expose handler, flush
-     all the already finished exposes to get things to an uptodate state. */
-  if (impl_window->implicit_paint)
-    gdk_window_flush (window);
-}
-
-
 static void
 gdk_window_flush_recursive_helper (GdkWindow *window,
                                   GdkWindowImpl *impl)
@@ -3425,7 +3515,7 @@ gdk_window_get_visible_region (GdkWindow *window)
 }
 
 static cairo_t *
-setup_backing_rect (GdkWindow *window, GdkWindowPaint *paint, int x_offset_cairo, int y_offset_cairo)
+setup_backing_rect (GdkWindow *window, GdkWindowPaint *paint)
 {
   GdkWindow *bg_window;
   cairo_pattern_t *pattern = NULL;
@@ -3462,45 +3552,15 @@ gdk_window_clear_backing_region (GdkWindow *window,
 {
   GdkWindowPaint *paint = window->paint_stack->data;
   cairo_region_t *clip;
-  GdkRectangle clipbox;
   cairo_t *cr;
 
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
-  cr = setup_backing_rect (window, paint, 0, 0);
+  cr = setup_backing_rect (window, paint);
 
   clip = cairo_region_copy (paint->region);
   cairo_region_intersect (clip, region);
-  cairo_region_get_extents (clip, &clipbox);
-
-  gdk_cairo_region (cr, clip);
-  cairo_fill (cr);
-
-  cairo_destroy (cr);
-
-  cairo_region_destroy (clip);
-}
-
-static void
-gdk_window_clear_backing_region_direct (GdkWindow *window,
-                                       cairo_region_t *region)
-{
-  GdkWindowPaint paint;
-  cairo_region_t *clip;
-  GdkRectangle clipbox;
-  cairo_t *cr;
-
-  if (GDK_WINDOW_DESTROYED (window))
-    return;
-
-  paint.surface = _gdk_window_ref_cairo_surface (window);
-
-  cr = setup_backing_rect (window, &paint, 0, 0);
-
-  clip = cairo_region_copy (window->clip_region_with_children);
-  cairo_region_intersect (clip, region);
-  cairo_region_get_extents (clip, &clipbox);
 
   gdk_cairo_region (cr, clip);
   cairo_fill (cr);
@@ -3508,18 +3568,6 @@ gdk_window_clear_backing_region_direct (GdkWindow *window,
   cairo_destroy (cr);
 
   cairo_region_destroy (clip);
-  cairo_surface_destroy (paint.surface);
-}
-
-
-static void
-gdk_window_clear_region_internal (GdkWindow *window,
-                                 cairo_region_t *region)
-{
-  if (window->paint_stack)
-    gdk_window_clear_backing_region (window, region);
-  else
-    gdk_window_clear_backing_region_direct (window, region);
 }
 
 static void
@@ -3794,68 +3842,23 @@ _gdk_window_process_updates_recurse (GdkWindow *window,
                                     cairo_region_t *expose_region)
 {
   GdkWindow *child;
-  cairo_region_t *child_region;
-  GdkRectangle r;
+  cairo_region_t *clipped_expose_region;
   GList *l, *children;
 
   if (cairo_region_is_empty (expose_region))
     return;
 
   if (gdk_window_is_offscreen (window->impl_window) &&
-      window == window->impl_window)
+      gdk_window_has_impl (window))
     _gdk_window_add_damage ((GdkWindow *) window->impl_window, expose_region);
 
-  /* Make this reentrancy safe for expose handlers freeing windows */
-  children = g_list_copy (window->children);
-  g_list_foreach (children, (GFunc)g_object_ref, NULL);
-
-  /* Iterate over children, starting at topmost */
-  for (l = children; l != NULL; l = l->next)
-    {
-      child = l->data;
-
-      if (child->destroyed || !GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
-       continue;
-
-      /* Ignore offscreen children, as they don't draw in their parent and
-       * don't take part in the clipping */
-      if (gdk_window_is_offscreen (child))
-       continue;
-
-      r.x = child->x;
-      r.y = child->y;
-      r.width = child->width;
-      r.height = child->height;
-
-      child_region = cairo_region_create_rectangle (&r);
-      if (child->shape)
-       {
-         /* Adjust shape region to parent window coords */
-         cairo_region_translate (child->shape, child->x, child->y);
-         cairo_region_intersect (child_region, child->shape);
-         cairo_region_translate (child->shape, -child->x, -child->y);
-       }
-
-      if (child->impl == window->impl)
-       {
-         /* Client side child, expose */
-         cairo_region_intersect (child_region, expose_region);
-         cairo_region_subtract (expose_region, child_region);
-         cairo_region_translate (child_region, -child->x, -child->y);
-         _gdk_window_process_updates_recurse ((GdkWindow *)child, child_region);
-       }
-      else
-       {
-         /* Native child, just remove area from expose region */
-         cairo_region_subtract (expose_region, child_region);
-       }
-      cairo_region_destroy (child_region);
-    }
 
-  g_list_foreach (children, (GFunc)g_object_unref, NULL);
-  g_list_free (children);
+  /* Paint the window before the children, clipped to the window region
+     with visible child windows removed */
+  clipped_expose_region = cairo_region_copy (expose_region);
+  cairo_region_intersect (clipped_expose_region, window->clip_region_with_children);
 
-  if (!cairo_region_is_empty (expose_region) &&
+  if (!cairo_region_is_empty (clipped_expose_region) &&
       !window->destroyed)
     {
       if (window->event_mask & GDK_EXPOSURE_MASK)
@@ -3866,8 +3869,8 @@ _gdk_window_process_updates_recurse (GdkWindow *window,
          event.expose.window = g_object_ref (window);
          event.expose.send_event = FALSE;
          event.expose.count = 0;
-         event.expose.region = expose_region;
-         cairo_region_get_extents (expose_region, &event.expose.area);
+         event.expose.region = clipped_expose_region;
+         cairo_region_get_extents (clipped_expose_region, &event.expose.area);
 
           _gdk_event_emit (&event);
 
@@ -3886,11 +3889,41 @@ _gdk_window_process_updates_recurse (GdkWindow *window,
           * We use begin/end_paint around the clear so that we can
           * piggyback on the implicit paint */
 
-         gdk_window_begin_paint_region (window, expose_region);
-         gdk_window_clear_region_internal (window, expose_region);
+         gdk_window_begin_paint_region (window, clipped_expose_region);
+         /* The actual clear happens in begin_paint_region */
          gdk_window_end_paint (window);
        }
     }
+  cairo_region_destroy (clipped_expose_region);
+
+  /* Make this reentrancy safe for expose handlers freeing windows */
+  children = g_list_copy (window->children);
+  g_list_foreach (children, (GFunc)g_object_ref, NULL);
+
+  /* Iterate over children, starting at bottommost */
+  for (l = g_list_last (children); l != NULL; l = l->prev)
+    {
+      child = l->data;
+
+      if (child->destroyed || !GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
+       continue;
+
+      /* Ignore offscreen children, as they don't draw in their parent and
+       * don't take part in the clipping */
+      if (gdk_window_is_offscreen (child))
+       continue;
+
+      /* Client side child, expose */
+      if (child->impl == window->impl)
+       {
+         cairo_region_translate (expose_region, -child->x, -child->y);
+         _gdk_window_process_updates_recurse ((GdkWindow *)child, expose_region);
+         cairo_region_translate (expose_region, child->x, child->y);
+       }
+    }
+
+  g_list_free_full (children, g_object_unref);
+
 }
 
 /* Process and remove any invalid area on the native window by creating
@@ -4434,8 +4467,8 @@ gdk_window_invalidate_maybe_recurse_full (GdkWindow            *window,
  * gdk_window_invalidate_maybe_recurse:
  * @window: a #GdkWindow
  * @region: a #cairo_region_t
- * @child_func: (scope call): function to use to decide if to recurse
- *     to a child, %NULL means never recurse.
+ * @child_func: (scope call) (allow-none): function to use to decide if to
+ *     recurse to a child, %NULL means never recurse.
  * @user_data: data passed to @child_func
  *
  * Adds @region to the update area for @window. The update area is the
@@ -4596,7 +4629,7 @@ cairo_region_t *
 gdk_window_get_update_area (GdkWindow *window)
 {
   GdkWindow *impl_window;
-  cairo_region_t *tmp_region;
+  cairo_region_t *tmp_region, *to_remove;
 
   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 
@@ -4616,7 +4649,21 @@ gdk_window_get_update_area (GdkWindow *window)
        }
       else
        {
-         cairo_region_subtract (impl_window->update_area, tmp_region);
+         /* Convert from impl coords */
+         cairo_region_translate (tmp_region, -window->abs_x, -window->abs_y);
+
+         /* Don't remove any update area that is overlapped by non-opaque windows
+            (children or siblings) with alpha, as these really need to be repainted
+            independently of this window. */
+         to_remove = cairo_region_copy (tmp_region);
+         cairo_region_subtract (to_remove, window->parent->layered_region);
+         remove_layered_child_area (window, to_remove);
+
+         /* Remove from update_area */
+         cairo_region_translate (to_remove, window->abs_x, window->abs_y);
+         cairo_region_subtract (impl_window->update_area, to_remove);
+
+         cairo_region_destroy (to_remove);
 
          if (cairo_region_is_empty (impl_window->update_area) &&
              impl_window->outstanding_moves == NULL)
@@ -4627,10 +4674,7 @@ gdk_window_get_update_area (GdkWindow *window)
              gdk_window_remove_update_window ((GdkWindow *)impl_window);
            }
 
-         /* Convert from impl coords */
-         cairo_region_translate (tmp_region, -window->abs_x, -window->abs_y);
          return tmp_region;
-
        }
     }
   else
@@ -4996,40 +5040,15 @@ gdk_window_get_device_position (GdkWindow       *window,
 }
 
 /**
- * gdk_window_at_pointer:
- * @win_x: (out) (allow-none): return location for origin of the window under the pointer
- * @win_y: (out) (allow-none): return location for origin of the window under the pointer
- *
- * Obtains the window underneath the mouse pointer, returning the
- * location of that window in @win_x, @win_y. Returns %NULL if the
- * window under the mouse pointer is not known to GDK (if the window
- * belongs to another application and a #GdkWindow hasn't been created
- * for it with gdk_window_foreign_new())
- *
- * NOTE: For multihead-aware widgets or applications use
- * gdk_display_get_window_at_pointer() instead.
+ * gdk_get_default_root_window:
  *
- * Return value: (transfer none): window under the mouse pointer
+ * Obtains the root window (parent all other windows are inside)
+ * for the default display and screen.
  *
- * Deprecated: 3.0: Use gdk_device_get_window_at_position() instead.
+ * Return value: (transfer none): the default root window
  **/
-GdkWindow*
-gdk_window_at_pointer (gint *win_x,
-                      gint *win_y)
-{
-  return gdk_display_get_window_at_pointer (gdk_display_get_default (), win_x, win_y);
-}
-
-/**
- * gdk_get_default_root_window:
- *
- * Obtains the root window (parent all other windows are inside)
- * for the default display and screen.
- *
- * Return value: (transfer none): the default root window
- **/
-GdkWindow *
-gdk_get_default_root_window (void)
+GdkWindow *
+gdk_get_default_root_window (void)
 {
   return gdk_screen_get_root_window (gdk_screen_get_default ());
 }
@@ -5143,8 +5162,7 @@ set_viewable (GdkWindow *w,
        set_viewable (child, val);
     }
 
-  if (!_gdk_native_windows &&
-      gdk_window_has_impl (w)  &&
+  if (gdk_window_has_impl (w)  &&
       w->window_type != GDK_WINDOW_FOREIGN &&
       !gdk_window_is_toplevel (w))
     {
@@ -5169,9 +5187,6 @@ set_viewable (GdkWindow *w,
        * do the show ourselves. We can't really tell this case from the normal
        * toplevel show as such toplevels are seen by gdk as parents of the
        * root window, so we make an exception for all toplevels.
-       *
-       * Also, when in GDK_NATIVE_WINDOW mode we never need to play games
-       * like this, so we just always show/hide directly.
        */
 
       impl_class = GDK_WINDOW_IMPL_GET_CLASS (w->impl);
@@ -5228,7 +5243,7 @@ gdk_window_show_internal (GdkWindow *window, gboolean raise)
       if (!was_mapped)
        gdk_synthesize_window_state (window,
                                     GDK_WINDOW_STATE_WITHDRAWN,
-                                    0);
+                                    GDK_WINDOW_STATE_FOCUSED);
     }
   else
     {
@@ -5305,35 +5320,19 @@ gdk_window_show_unraised (GdkWindow *window)
 void
 gdk_window_raise (GdkWindow *window)
 {
-  cairo_region_t *old_region, *new_region;
-
   g_return_if_fail (GDK_IS_WINDOW (window));
 
   if (window->destroyed)
     return;
 
-  gdk_window_flush_if_exposing (window);
-
-  old_region = NULL;
-  if (gdk_window_is_viewable (window) &&
-      !window->input_only)
-    old_region = cairo_region_copy (window->clip_region);
-
   /* Keep children in (reverse) stacking order */
   gdk_window_raise_internal (window);
 
   recompute_visible_regions (window, TRUE, FALSE);
 
-  if (old_region)
-    {
-      new_region = cairo_region_copy (window->clip_region);
-
-      cairo_region_subtract (new_region, old_region);
-      gdk_window_invalidate_region_full (window, new_region, TRUE, CLEAR_BG_ALL);
-
-      cairo_region_destroy (old_region);
-      cairo_region_destroy (new_region);
-    }
+  if (gdk_window_is_viewable (window) &&
+      !window->input_only)
+    gdk_window_invalidate_region_full (window, window->clip_region, TRUE, CLEAR_BG_ALL);
 }
 
 static void
@@ -5446,8 +5445,6 @@ gdk_window_lower (GdkWindow *window)
   if (window->destroyed)
     return;
 
-  gdk_window_flush_if_exposing (window);
-
   /* Keep children in (reverse) stacking order */
   gdk_window_lower_internal (window);
 
@@ -5503,8 +5500,6 @@ gdk_window_restack (GdkWindow     *window,
       return;
     }
 
-  gdk_window_flush_if_exposing (window);
-
   if (gdk_window_is_toplevel (window))
     {
       g_return_if_fail (gdk_window_is_toplevel (sibling));
@@ -5843,10 +5838,7 @@ gdk_window_set_device_events (GdkWindow    *window,
     g_hash_table_insert (window->device_events, device,
                          GINT_TO_POINTER (event_mask));
 
-  if (_gdk_native_windows)
-    native = window;
-  else
-    native = gdk_window_get_toplevel (window);
+  native = gdk_window_get_toplevel (window);
 
   while (gdk_window_is_offscreen (native))
     {
@@ -6036,7 +6028,7 @@ gdk_window_move_resize_internal (GdkWindow *window,
                                 gint       width,
                                 gint       height)
 {
-  cairo_region_t *old_region, *new_region, *copy_area;
+  cairo_region_t *old_region, *old_layered, *new_region, *copy_area;
   cairo_region_t *old_native_child_region, *new_native_child_region;
   GdkWindow *impl_window;
   GdkWindowImplClass *impl_class;
@@ -6063,12 +6055,11 @@ gdk_window_move_resize_internal (GdkWindow *window,
        window->y == y)))
     return;
 
-  gdk_window_flush_if_exposing (window);
-
   /* Handle child windows */
 
   expose = FALSE;
   old_region = NULL;
+  old_layered = NULL;
 
   impl_window = gdk_window_get_impl_window (window);
 
@@ -6082,8 +6073,10 @@ gdk_window_move_resize_internal (GdkWindow *window,
       expose = TRUE;
 
       old_region = cairo_region_copy (window->clip_region);
-      /* Adjust region to parent window coords */
+      old_layered = cairo_region_copy (window->layered_region);
+      /* Adjust regions to parent window coords */
       cairo_region_translate (old_region, window->x, window->y);
+      cairo_region_translate (old_layered, window->x, window->y);
 
       old_native_child_region = collect_native_child_region (window, TRUE);
       if (old_native_child_region)
@@ -6163,7 +6156,19 @@ gdk_window_move_resize_internal (GdkWindow *window,
        * Everything in the old and new regions that is not copied must be
        * invalidated (including children) as this is newly exposed
        */
-      copy_area = cairo_region_copy (new_region);
+      if (window->has_alpha_background)
+       copy_area = cairo_region_create (); /* Copy nothing for alpha windows */
+      else
+       copy_area = cairo_region_copy (new_region);
+
+      /* Don't copy from a previously layered region */
+      cairo_region_translate (old_layered, dx, dy);
+      cairo_region_subtract (copy_area, old_layered);
+
+      /* Don't copy into a layered region */
+      cairo_region_translate (copy_area, -window->x, -window->y);
+      cairo_region_subtract (copy_area, window->layered_region);
+      cairo_region_translate (copy_area, window->x, window->y);
 
       cairo_region_union (new_region, old_region);
 
@@ -6212,6 +6217,7 @@ gdk_window_move_resize_internal (GdkWindow *window,
       gdk_window_invalidate_region_full (window->parent, new_region, TRUE, CLEAR_BG_ALL);
 
       cairo_region_destroy (old_region);
+      cairo_region_destroy (old_layered);
       cairo_region_destroy (new_region);
     }
 
@@ -6321,7 +6327,7 @@ gdk_window_scroll (GdkWindow *window,
                   gint       dy)
 {
   GdkWindow *impl_window;
-  cairo_region_t *copy_area, *noncopy_area;
+  cairo_region_t *copy_area, *noncopy_area, *old_layered_area;
   cairo_region_t *old_native_child_region, *new_native_child_region;
   GList *tmp_list;
 
@@ -6333,8 +6339,7 @@ gdk_window_scroll (GdkWindow *window,
   if (window->destroyed)
     return;
 
-  gdk_window_flush_if_exposing (window);
-
+  old_layered_area = cairo_region_copy (window->layered_region);
   old_native_child_region = collect_native_child_region (window, FALSE);
   if (old_native_child_region)
     {
@@ -6375,7 +6380,11 @@ gdk_window_scroll (GdkWindow *window,
   impl_window = gdk_window_get_impl_window (window);
 
   /* Calculate the area that can be gotten by copying the old area */
-  copy_area = cairo_region_copy (window->clip_region);
+  if (window->has_alpha_background)
+    copy_area = cairo_region_create (); /* Copy nothing for alpha windows */
+  else
+    copy_area = cairo_region_copy (window->clip_region);
+  cairo_region_subtract (copy_area, old_layered_area);
   if (old_native_child_region)
     {
       /* Don't copy from inside native children, as this is copied by
@@ -6389,6 +6398,7 @@ gdk_window_scroll (GdkWindow *window,
     }
   cairo_region_translate (copy_area, dx, dy);
   cairo_region_intersect (copy_area, window->clip_region);
+  cairo_region_subtract (copy_area, window->layered_region);
 
   /* And the rest need to be invalidated */
   noncopy_area = cairo_region_copy (window->clip_region);
@@ -6410,6 +6420,7 @@ gdk_window_scroll (GdkWindow *window,
   gdk_window_invalidate_region_full (window, noncopy_area, TRUE, CLEAR_BG_ALL);
 
   cairo_region_destroy (noncopy_area);
+  cairo_region_destroy (old_layered_area);
 
   if (old_native_child_region)
     {
@@ -6457,12 +6468,19 @@ gdk_window_move_region (GdkWindow       *window,
   impl_window = gdk_window_get_impl_window (window);
 
   /* compute source regions */
-  copy_area = cairo_region_copy (region);
+  if (window->has_alpha_background)
+    copy_area = cairo_region_create (); /* Copy nothing for alpha windows */
+  else
+    copy_area = cairo_region_copy (region);
   cairo_region_intersect (copy_area, window->clip_region_with_children);
+  cairo_region_subtract (copy_area, window->layered_region);
+  remove_layered_child_area (window, copy_area);
 
   /* compute destination regions */
   cairo_region_translate (copy_area, dx, dy);
   cairo_region_intersect (copy_area, window->clip_region_with_children);
+  cairo_region_subtract (copy_area, window->layered_region);
+  remove_layered_child_area (window, copy_area);
 
   /* Invalidate parts of the region (source and dest) not covered
      by the copy */
@@ -6490,6 +6508,8 @@ gdk_window_move_region (GdkWindow       *window,
  * implementing a custom widget.)
  *
  * See also gdk_window_set_background_pattern().
+ *
+ * Deprecated: 3.4: Use gdk_window_set_background_rgba() instead.
  */
 void
 gdk_window_set_background (GdkWindow      *window,
@@ -6534,6 +6554,29 @@ gdk_window_set_background_rgba (GdkWindow *window,
   cairo_pattern_destroy (pattern);
 }
 
+
+/* Updates has_alpha_background recursively for all child windows
+   that have parent-relative alpha */
+static void
+_gdk_window_propagate_has_alpha_background (GdkWindow *window)
+{
+  GdkWindow *child;
+  GList *l;
+
+  for (l = window->children; l; l = l->next)
+    {
+      child = l->data;
+
+      if (child->background == NULL &&
+         child->has_alpha_background != window->has_alpha_background)
+       {
+         child->has_alpha_background = window->has_alpha_background;
+         recompute_visible_regions (child, TRUE, FALSE);
+         _gdk_window_propagate_has_alpha_background (child);
+       }
+    }
+}
+
 /**
  * gdk_window_set_background_pattern:
  * @window: a #GdkWindow
@@ -6551,20 +6594,90 @@ void
 gdk_window_set_background_pattern (GdkWindow *window,
                                    cairo_pattern_t *pattern)
 {
+  gboolean has_alpha;
+  cairo_pattern_type_t type;
+  
   g_return_if_fail (GDK_IS_WINDOW (window));
 
+  if (window->input_only)
+    return;
+
   if (pattern)
     cairo_pattern_reference (pattern);
   if (window->background)
     cairo_pattern_destroy (window->background);
   window->background = pattern;
 
-  if (gdk_window_has_impl (window) &&
-      !window->input_only)
+  has_alpha = TRUE;
+
+  if (pattern == NULL)
+    {
+      /* parent-relative, copy has_alpha from parent */
+      if (window->parent == NULL ||
+         window->parent->window_type == GDK_WINDOW_ROOT)
+       has_alpha = FALSE;
+      else
+       has_alpha = window->parent->has_alpha_background;
+    }
+  else
+    {
+      type = cairo_pattern_get_type (pattern);
+
+      if (type == CAIRO_PATTERN_TYPE_SOLID)
+       {
+         double alpha;
+         cairo_pattern_get_rgba (pattern, NULL, NULL, NULL, &alpha);
+         if (alpha == 1.0)
+           has_alpha = FALSE;
+       }
+      else if (type == CAIRO_PATTERN_TYPE_LINEAR ||
+              type == CAIRO_PATTERN_TYPE_RADIAL)
+       {
+         int i, n;
+         double alpha;
+
+         n = 0;
+         cairo_pattern_get_color_stop_count (pattern, &n);
+         has_alpha = FALSE;
+         for (i = 0; i < n; i++)
+           {
+             cairo_pattern_get_color_stop_rgba (pattern, i, NULL,
+                                                NULL, NULL, NULL, &alpha);
+             if (alpha != 1.0)
+               {
+                 has_alpha = TRUE;
+                 break;
+               }
+           }
+       }
+      else if (type == CAIRO_PATTERN_TYPE_SURFACE)
+       {
+         cairo_surface_t *surface;
+         cairo_content_t content;
+
+         cairo_pattern_get_surface (pattern, &surface);
+         content = cairo_surface_get_content (surface);
+         has_alpha =
+           (content == CAIRO_CONTENT_ALPHA) ||
+           (content == CAIRO_CONTENT_COLOR_ALPHA);
+       }
+    }
+
+  if (has_alpha != window->has_alpha_background)
+    {
+      window->has_alpha_background = has_alpha;  
+      recompute_visible_regions (window, TRUE, FALSE);
+
+      _gdk_window_propagate_has_alpha_background (window);
+    }
+
+  if (gdk_window_has_impl (window))
     {
       GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
       impl_class->set_background (window, pattern);
     }
+  else
+    gdk_window_invalidate_rect_full (window, NULL, TRUE, CLEAR_BG_ALL);
 }
 
 /**
@@ -6589,19 +6702,27 @@ gdk_window_get_background_pattern (GdkWindow *window)
 }
 
 static void
-update_cursor_foreach (GdkDisplay           *display,
-                       GdkDevice            *device,
-                       GdkPointerWindowInfo *pointer_info,
-                       gpointer              user_data)
+gdk_window_set_cursor_internal (GdkWindow *window,
+                                GdkDevice *device,
+                                GdkCursor *cursor)
 {
-  GdkWindow *window = user_data;
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
 
-  if (_gdk_native_windows ||
-      window->window_type == GDK_WINDOW_ROOT ||
+  if (window->window_type == GDK_WINDOW_ROOT ||
       window->window_type == GDK_WINDOW_FOREIGN)
-    GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_device_cursor (window, device, window->cursor);
-  else if (_gdk_window_event_parent_of (window, pointer_info->window_under_pointer))
-    update_cursor (display, device);
+    GDK_WINDOW_IMPL_GET_CLASS (window->impl)->set_device_cursor (window, device, cursor);
+  else
+    {
+      GdkPointerWindowInfo *pointer_info;
+      GdkDisplay *display;
+
+      display = gdk_window_get_display (window);
+      pointer_info = _gdk_display_get_pointer_info (display, device);
+
+      if (_gdk_window_event_parent_of (window, pointer_info->window_under_pointer))
+        update_cursor (display, device);
+    }
 }
 
 /**
@@ -6657,13 +6778,28 @@ gdk_window_set_cursor (GdkWindow *window,
 
   if (!GDK_WINDOW_DESTROYED (window))
     {
+      GdkDeviceManager *device_manager;
+      GList *devices, *d;
+
       if (cursor)
        window->cursor = g_object_ref (cursor);
 
-      _gdk_display_pointer_info_foreach (display,
-                                         update_cursor_foreach,
-                                         window);
+      device_manager = gdk_display_get_device_manager (display);
+      devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+      for (d = devices; d; d = d->next)
+        {
+          GdkDevice *device;
+
+          device = d->data;
+
+          if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
+            continue;
+
+          gdk_window_set_cursor_internal (window, device, window->cursor);
+        }
 
+      g_list_free (devices);
       g_object_notify (G_OBJECT (window), "cursor");
     }
 }
@@ -6717,29 +6853,17 @@ gdk_window_set_device_cursor (GdkWindow *window,
                               GdkDevice *device,
                               GdkCursor *cursor)
 {
-  GdkDisplay *display;
-
   g_return_if_fail (GDK_IS_WINDOW (window));
   g_return_if_fail (GDK_IS_DEVICE (device));
   g_return_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD);
   g_return_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER);
 
-  display = gdk_window_get_display (window);
-
   if (!cursor)
     g_hash_table_remove (window->device_cursor, device);
   else
     g_hash_table_replace (window->device_cursor, device, g_object_ref (cursor));
 
-  if (!GDK_WINDOW_DESTROYED (window))
-    {
-      GdkPointerWindowInfo *pointer_info;
-
-      pointer_info = _gdk_display_get_pointer_info (display, device);
-
-      if (_gdk_window_event_parent_of (window, pointer_info->window_under_pointer))
-        update_cursor (display, device);
-    }
+  gdk_window_set_cursor_internal (window, device, cursor);
 }
 
 /**
@@ -6937,10 +7061,8 @@ gdk_window_get_root_coords (GdkWindow *window,
 
   if (GDK_WINDOW_DESTROYED (window))
     {
-      if (x)
-       *root_x = x;
-      if (y)
-       *root_y = y;
+      *root_x = 0;
+      *root_y = 0;
       return;
     }
   
@@ -7072,7 +7194,7 @@ gdk_window_coords_from_parent (GdkWindow *window,
 /**
  * gdk_window_shape_combine_region:
  * @window: a #GdkWindow
- * @shape_region: region of window to be non-transparent
+ * @shape_region: (allow-none): 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
  *
@@ -7174,7 +7296,7 @@ do_child_shapes (GdkWindow *window,
   r.height = window->height;
 
   region = cairo_region_create_rectangle (&r);
-  remove_child_area (window, NULL, FALSE, region);
+  remove_child_area (window, NULL, FALSE, region, NULL);
 
   if (merge && window->shape)
     cairo_region_subtract (region, window->shape);
@@ -7293,7 +7415,7 @@ do_child_input_shapes (GdkWindow *window,
   r.height = window->height;
 
   region = cairo_region_create_rectangle (&r);
-  remove_child_area (window, NULL, TRUE, region);
+  remove_child_area (window, NULL, TRUE, region, NULL);
 
   if (merge && window->shape)
     cairo_region_subtract (region, window->shape);
@@ -7559,114 +7681,6 @@ gdk_window_is_shaped (GdkWindow *window)
   return window->shaped;
 }
 
-static void
-window_get_size_rectangle (GdkWindow    *window,
-                          GdkRectangle *rect)
-{
-  rect->x = rect->y = 0;
-  rect->width = window->width;
-  rect->height = window->height;
-}
-
-/* Calculates the real clipping region for a window, in window coordinates,
- * taking into account other windows, gc clip region and gc clip mask.
- */
-cairo_region_t *
-_gdk_window_calculate_full_clip_region (GdkWindow *window,
-                                       GdkWindow *base_window,
-                                       gboolean   do_children,
-                                       gint      *base_x_offset,
-                                       gint      *base_y_offset)
-{
-  GdkRectangle visible_rect;
-  cairo_region_t *real_clip_region;
-  gint x_offset, y_offset;
-  GdkWindow *parentwin, *lastwin;
-
-  if (base_x_offset)
-    *base_x_offset = 0;
-  if (base_y_offset)
-    *base_y_offset = 0;
-
-  if (!window->viewable || window->input_only)
-    return cairo_region_create ();
-
-  window_get_size_rectangle (window, &visible_rect);
-
-  /* real_clip_region is in window coordinates */
-  real_clip_region = cairo_region_create_rectangle (&visible_rect);
-
-  x_offset = y_offset = 0;
-
-  lastwin = window;
-  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 == window || lastwin != base_window);
-       lastwin = parentwin, parentwin = lastwin->parent)
-    {
-      GList *cur;
-      GdkRectangle real_clip_rect;
-
-      if (parentwin != window)
-       {
-         x_offset += lastwin->x;
-         y_offset += lastwin->y;
-       }
-
-      /* children is ordered in reverse stack order */
-      for (cur = parentwin->children;
-          cur && cur->data != lastwin;
-          cur = cur->next)
-       {
-         GdkWindow *child = cur->data;
-
-         if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only)
-           continue;
-
-         /* Ignore offscreen children, as they don't draw in their parent and
-          * don't take part in the clipping */
-         if (gdk_window_is_offscreen (child))
-           continue;
-
-         window_get_size_rectangle (child, &visible_rect);
-
-         /* Convert rect to "window" coords */
-         visible_rect.x += child->x - x_offset;
-         visible_rect.y += child->y - y_offset;
-
-         /* This shortcut is really necessary for performance when there are a lot of windows */
-         cairo_region_get_extents (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;
-
-         cairo_region_subtract_rectangle (real_clip_region, &visible_rect);
-       }
-
-      /* Clip to the parent */
-      window_get_size_rectangle ((GdkWindow *)parentwin, &visible_rect);
-      /* Convert rect to "window" coords */
-      visible_rect.x += - x_offset;
-      visible_rect.y += - y_offset;
-
-      cairo_region_intersect_rectangle (real_clip_region, &visible_rect);
-    }
-
-  if (base_x_offset)
-    *base_x_offset = x_offset;
-  if (base_y_offset)
-    *base_y_offset = y_offset;
-
-  return real_clip_region;
-}
-
 void
 _gdk_window_add_damage (GdkWindow *toplevel,
                        cairo_region_t *damaged_region)
@@ -7993,7 +8007,7 @@ gdk_window_beep (GdkWindow *window)
 
   if (toplevel)
     {
-      if (GDK_WINDOW_IMPL_GET_CLASS (toplevel->impl)->beep (window))
+      if (GDK_WINDOW_IMPL_GET_CLASS (toplevel->impl)->beep (toplevel))
         return;
     }
   
@@ -8084,12 +8098,16 @@ static const guint type_masks[] = {
   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_BUTTON_PRESS_MASK,/* GDK_SCROLL= 31 */
+  GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK,/* GDK_SCROLL= 31 */
   0, /* GDK_WINDOW_STATE = 32 */
   0, /* GDK_SETTING = 33 */
   0, /* GDK_OWNER_CHANGE = 34 */
   0, /* GDK_GRAB_BROKEN = 35 */
   0, /* GDK_DAMAGE = 36 */
+  GDK_TOUCH_MASK, /* GDK_TOUCH_BEGIN = 37 */
+  GDK_TOUCH_MASK, /* GDK_TOUCH_UPDATE = 38 */
+  GDK_TOUCH_MASK, /* GDK_TOUCH_END = 39 */
+  GDK_TOUCH_MASK /* GDK_TOUCH_CANCEL = 40 */
 };
 G_STATIC_ASSERT (G_N_ELEMENTS (type_masks) == GDK_EVENT_LAST);
 
@@ -8121,6 +8139,8 @@ is_button_type (GdkEventType type)
         type == GDK_2BUTTON_PRESS ||
         type == GDK_3BUTTON_PRESS ||
         type == GDK_BUTTON_RELEASE ||
+         type == GDK_TOUCH_BEGIN ||
+         type == GDK_TOUCH_END ||
         type == GDK_SCROLL;
 }
 
@@ -8128,10 +8148,20 @@ static gboolean
 is_motion_type (GdkEventType type)
 {
   return type == GDK_MOTION_NOTIFY ||
+         type == GDK_TOUCH_UPDATE ||
         type == GDK_ENTER_NOTIFY ||
         type == GDK_LEAVE_NOTIFY;
 }
 
+static gboolean
+is_touch_type (GdkEventType type)
+{
+  return type == GDK_TOUCH_BEGIN ||
+         type == GDK_TOUCH_UPDATE ||
+         type == GDK_TOUCH_END ||
+         type == GDK_TOUCH_CANCEL;
+}
+
 static GdkWindow *
 find_common_ancestor (GdkWindow *win1,
                      GdkWindow *win2)
@@ -8204,6 +8234,15 @@ _gdk_make_event (GdkWindow    *window,
       event->button.state = the_state;
       break;
 
+    case GDK_TOUCH_BEGIN:
+    case GDK_TOUCH_UPDATE:
+    case GDK_TOUCH_END:
+    case GDK_TOUCH_CANCEL:
+      event->touch.time = the_time;
+      event->touch.axes = NULL;
+      event->touch.state = the_state;
+      break;
+
     case GDK_SCROLL:
       event->scroll.time = the_time;
       event->scroll.state = the_state;
@@ -8292,12 +8331,27 @@ send_crossing_event (GdkDisplay                 *display,
   GdkEvent *event;
   guint32 window_event_mask, type_event_mask;
   GdkDeviceGrabInfo *grab;
+  GdkTouchGrabInfo *touch_grab = NULL;
+  GdkPointerWindowInfo *pointer_info;
   gboolean block_event = FALSE;
+  GdkEventSequence *sequence;
 
   grab = _gdk_display_has_device_grab (display, device, serial);
+  pointer_info = _gdk_display_get_pointer_info (display, device);
 
-  if (grab != NULL &&
-      !grab->owner_events)
+  sequence = gdk_event_get_event_sequence (event_in_queue);
+  if (sequence)
+    touch_grab = _gdk_display_has_touch_grab (display, device, sequence, serial);
+
+  if (touch_grab)
+    {
+      if (window != touch_grab->window)
+        return;
+
+      window_event_mask = touch_grab->event_mask;
+    }
+  else if (grab != NULL &&
+           !grab->owner_events)
     {
       /* !owner_event => only report events wrt grab window, ignore rest */
       if ((GdkWindow *)window != grab->window)
@@ -8307,7 +8361,14 @@ send_crossing_event (GdkDisplay                 *display,
   else
     window_event_mask = window->event_mask;
 
-  if (type == GDK_LEAVE_NOTIFY)
+  if (type == GDK_ENTER_NOTIFY &&
+      pointer_info->need_touch_press_enter &&
+      mode != GDK_CROSSING_TOUCH_BEGIN &&
+      mode != GDK_CROSSING_TOUCH_END)
+    {
+      block_event = TRUE;
+    }
+  else if (type == GDK_LEAVE_NOTIFY)
     {
       type_event_mask = GDK_LEAVE_NOTIFY_MASK;
       window->devices_inside = g_list_remove (window->devices_inside, device);
@@ -8569,11 +8630,6 @@ _gdk_display_set_window_under_pointer (GdkDisplay *display,
 {
   GdkPointerWindowInfo *device_info;
 
-  /* We don't track this if all native, and it can cause issues
-     with the update_cursor call below */
-  if (_gdk_native_windows)
-    return;
-
   device_info = _gdk_display_get_pointer_info (display, device);
 
   if (device_info->window_under_pointer)
@@ -8600,11 +8656,11 @@ _gdk_display_set_window_under_pointer (GdkDisplay *display,
  * @event_mask: specifies the event mask, which is used in accordance with
  *              @owner_events. Note that only pointer events (i.e. button and motion events)
  *              may be selected.
- * @confine_to: If non-%NULL, the pointer will be confined to this
+ * @confine_to: (allow-none): If non-%NULL, the pointer will be confined to this
  *              window during the grab. If the pointer is outside @confine_to, it will
  *              automatically be moved to the closest edge of @confine_to and enter
  *              and leave events will be generated as necessary.
- * @cursor: the cursor to display while the grab is active. If this is %NULL then
+ * @cursor: (allow-none): the cursor to display while the grab is active. If this is %NULL then
  *          the normal cursors are used for @window and its descendants, and the cursor
  *          for @window is used for all other windows.
  * @time_: the timestamp of the event which led to this pointer grab. This usually
@@ -8672,10 +8728,7 @@ gdk_pointer_grab (GdkWindow *      window,
       !gdk_window_is_viewable (window))
     return GDK_GRAB_NOT_VIEWABLE;
 
-  if (_gdk_native_windows)
-    native = window;
-  else
-    native = gdk_window_get_toplevel (window);
+  native = gdk_window_get_toplevel (window);
   while (gdk_window_is_offscreen (native))
     {
       native = gdk_offscreen_window_get_embedder (native);
@@ -8775,10 +8828,7 @@ gdk_keyboard_grab (GdkWindow *window,
       !gdk_window_is_viewable (window))
     return GDK_GRAB_NOT_VIEWABLE;
 
-  if (_gdk_native_windows)
-    native = window;
-  else
-    native = gdk_window_get_toplevel (window);
+  native = gdk_window_get_toplevel (window);
 
   while (gdk_window_is_offscreen (native))
     {
@@ -8938,6 +8988,8 @@ gdk_window_set_source_events (GdkWindow      *window,
         gdk_window_set_device_events (window, device, event_mask);
     }
 
+  g_list_free (devices);
+
   /* Update accounting */
   if (G_UNLIKELY (!window->source_event_masks))
     window->source_event_masks = g_hash_table_new (NULL, NULL);
@@ -9025,7 +9077,7 @@ do_synthesize_crossing_event (gpointer data)
               _gdk_synthesize_crossing_events (display,
                                                pointer_info->window_under_pointer,
                                                new_window_under_pointer,
-                                               device, NULL,
+                                               device, pointer_info->last_slave,
                                                GDK_CROSSING_NORMAL,
                                                pointer_info->toplevel_x,
                                                pointer_info->toplevel_y,
@@ -9047,9 +9099,6 @@ _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
 {
   GdkWindow *toplevel;
 
-  if (_gdk_native_windows)
-    return; /* We use the native crossing events if all native */
-
   toplevel = get_event_toplevel (changed_window);
 
   if (!toplevel->synthesize_crossing_event_queued)
@@ -9067,17 +9116,54 @@ _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
 static GdkWindow *
 get_event_window (GdkDisplay                 *display,
                   GdkDevice                  *device,
-                 GdkWindow                  *pointer_window,
-                 GdkEventType                type,
-                 GdkModifierType             mask,
-                 guint                      *evmask_out,
-                 gulong                      serial)
-{
-  guint evmask;
+                  GdkEventSequence           *sequence,
+                  GdkWindow                  *pointer_window,
+                  GdkEventType                type,
+                  GdkModifierType             mask,
+                  guint                      *evmask_out,
+                  gboolean                    pointer_emulated,
+                  gulong                      serial)
+{
+  guint evmask, emulated_mask = 0;
   GdkWindow *grab_window;
   GdkDeviceGrabInfo *grab;
+  GdkTouchGrabInfo *touch_grab;
 
-  grab = _gdk_display_has_device_grab (display, device, serial);
+  touch_grab = _gdk_display_has_touch_grab (display, device, sequence, serial);
+  grab = _gdk_display_get_last_device_grab (display, device);
+
+  if (is_touch_type (type) && pointer_emulated)
+    {
+      switch (type)
+        {
+        case GDK_TOUCH_BEGIN:
+          emulated_mask |= GDK_BUTTON_PRESS_MASK;
+          break;
+        case GDK_TOUCH_UPDATE:
+          emulated_mask |= GDK_POINTER_MOTION_MASK;
+          break;
+        case GDK_TOUCH_END:
+          emulated_mask |= GDK_BUTTON_RELEASE_MASK;
+        default:
+          break;
+        }
+    }
+
+  if (touch_grab != NULL &&
+      (!grab || grab->implicit || touch_grab->serial >= grab->serial_start))
+    {
+      evmask = touch_grab->event_mask;
+      evmask = update_evmask_for_button_motion (evmask, mask);
+
+      if (evmask & (type_masks[type] | emulated_mask))
+        {
+          if (evmask_out)
+            *evmask_out = evmask;
+          return touch_grab->window;
+        }
+      else
+        return NULL;
+    }
 
   if (grab != NULL && !grab->owner_events)
     {
@@ -9086,7 +9172,7 @@ get_event_window (GdkDisplay                 *display,
 
       grab_window = grab->window;
 
-      if (evmask & type_masks[type])
+      if (evmask & (type_masks[type] | emulated_mask))
        {
          if (evmask_out)
            *evmask_out = evmask;
@@ -9101,7 +9187,7 @@ get_event_window (GdkDisplay                 *display,
       evmask = pointer_window->event_mask;
       evmask = update_evmask_for_button_motion (evmask, mask);
 
-      if (evmask & type_masks[type])
+      if (evmask & (type_masks[type] | emulated_mask))
        {
          if (evmask_out)
            *evmask_out = evmask;
@@ -9117,7 +9203,7 @@ get_event_window (GdkDisplay                 *display,
       evmask = grab->event_mask;
       evmask = update_evmask_for_button_motion (evmask, mask);
 
-      if (evmask & type_masks[type])
+      if (evmask & (type_masks[type] | emulated_mask))
        {
          if (evmask_out)
            *evmask_out = evmask;
@@ -9143,8 +9229,10 @@ proxy_pointer_event (GdkDisplay                 *display,
   guint state;
   gdouble toplevel_x, toplevel_y;
   guint32 time_;
-  gboolean non_linear;
+  gboolean non_linear, need_synthetic_enter = FALSE;
+  gint event_type;
 
+  event_type = source_event->type;
   event_window = source_event->any.window;
   gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
   gdk_event_get_state (source_event, &state);
@@ -9163,6 +9251,15 @@ proxy_pointer_event (GdkDisplay                 *display,
        source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))
     non_linear = TRUE;
 
+  if (pointer_info->need_touch_press_enter &&
+      gdk_device_get_source (pointer_info->last_slave) != GDK_SOURCE_TOUCHSCREEN &&
+      (source_event->type != GDK_TOUCH_UPDATE ||
+       _gdk_event_get_pointer_emulated (source_event)))
+    {
+      pointer_info->need_touch_press_enter = FALSE;
+      need_synthetic_enter = TRUE;
+    }
+
   /* If we get crossing events with subwindow unexpectedly being NULL
      that means there is a native subwindow that gdk doesn't know about.
      We track these and forward them, with the correct virtual window
@@ -9250,7 +9347,9 @@ proxy_pointer_event (GdkDisplay                 *display,
       return TRUE;
     }
 
-  if (pointer_info->window_under_pointer != pointer_window)
+  if ((source_event->type != GDK_TOUCH_UPDATE ||
+       _gdk_event_get_pointer_emulated (source_event)) &&
+      pointer_info->window_under_pointer != pointer_window)
     {
       /* Either a toplevel crossing notify that ended up inside a child window,
         or a motion notify that got into another child window  */
@@ -9267,28 +9366,71 @@ proxy_pointer_event (GdkDisplay                 *display,
                                       serial, non_linear);
       _gdk_display_set_window_under_pointer (display, device, pointer_window);
     }
-  else if (source_event->type == GDK_MOTION_NOTIFY)
+  else if (source_event->type == GDK_MOTION_NOTIFY ||
+           source_event->type == GDK_TOUCH_UPDATE)
     {
       GdkWindow *event_win;
       guint evmask;
       gboolean is_hint;
+      GdkEventSequence *sequence;
+
+      sequence = gdk_event_get_event_sequence (source_event);
 
       event_win = get_event_window (display,
                                     device,
+                                    sequence,
                                     pointer_window,
                                     source_event->type,
                                     state,
                                     &evmask,
+                                    _gdk_event_get_pointer_emulated (source_event),
                                     serial);
 
+      if (event_type == GDK_TOUCH_UPDATE)
+        {
+          if (_gdk_event_get_pointer_emulated (source_event))
+            {
+              /* Touch events emulating pointer events are transformed back
+               * to pointer events if:
+               * 1 - The event window doesn't select for touch events
+               * 2 - There's no touch grab for this sequence, which means
+               *     it was started as a pointer sequence, but a device
+               *     grab added touch events afterwards, the sequence must
+               *     not mutate in this case.
+               */
+              if ((evmask & GDK_TOUCH_MASK) == 0 ||
+                  !_gdk_display_has_touch_grab (display, device, sequence, serial))
+                event_type = GDK_MOTION_NOTIFY;
+            }
+          else if ((evmask & GDK_TOUCH_MASK) == 0)
+            return TRUE;
+        }
+
+      if (is_touch_type (source_event->type) && !is_touch_type (event_type))
+        state |= GDK_BUTTON1_MASK;
+
       if (event_win &&
           gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER &&
           gdk_window_get_device_events (event_win, device) == 0)
         return TRUE;
 
+      /* The last device to interact with the window was a touch device,
+       * which synthesized a leave notify event, so synthesize another enter
+       * notify to tell the pointer is on the window.
+       */
+      if (need_synthetic_enter)
+        _gdk_synthesize_crossing_events (display,
+                                         NULL, pointer_window,
+                                         device, source_device,
+                                         GDK_CROSSING_DEVICE_SWITCH,
+                                         toplevel_x, toplevel_y,
+                                         state, time_, NULL,
+                                         serial, FALSE);
+
       is_hint = FALSE;
 
       if (event_win &&
+          event_type == GDK_MOTION_NOTIFY &&
          (evmask & GDK_POINTER_MOTION_HINT_MASK))
        {
           gulong *device_serial;
@@ -9306,22 +9448,56 @@ proxy_pointer_event (GdkDisplay                 *display,
            }
        }
 
-      if (event_win && !display->ignore_core_events)
+      if (!event_win)
+        return TRUE;
+
+      event = gdk_event_new (event_type);
+      event->any.window = g_object_ref (event_win);
+      event->any.send_event = source_event->any.send_event;
+
+      gdk_event_set_device (event, gdk_event_get_device (source_event));
+      gdk_event_set_source_device (event, source_device);
+
+      if (event_type == GDK_TOUCH_UPDATE)
        {
-         event = _gdk_make_event (event_win, GDK_MOTION_NOTIFY, source_event, FALSE);
-         event->motion.time = time_;
+         event->touch.time = time_;
+         event->touch.state = state | GDK_BUTTON1_MASK;
+         event->touch.sequence = source_event->touch.sequence;
+         event->touch.emulating_pointer = source_event->touch.emulating_pointer;
          convert_toplevel_coords_to_window (event_win,
                                             toplevel_x, toplevel_y,
-                                            &event->motion.x, &event->motion.y);
-         event->motion.x_root = source_event->motion.x_root;
-         event->motion.y_root = source_event->motion.y_root;
+                                            &event->touch.x, &event->touch.y);
+         gdk_event_get_root_coords (source_event,
+                                    &event->touch.x_root,
+                                    &event->touch.y_root);
+
+         event->touch.axes = g_memdup (source_event->touch.axes,
+                                       sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
+       }
+      else
+       {
+         event->motion.time = time_;
          event->motion.state = state;
          event->motion.is_hint = is_hint;
-         event->motion.device = source_event->motion.device;
-          event->motion.axes = g_memdup (source_event->motion.axes,
-                                         sizeof (gdouble) * gdk_device_get_n_axes (source_event->motion.device));
-          gdk_event_set_source_device (event, source_device);
+
+         convert_toplevel_coords_to_window (event_win,
+                                            toplevel_x, toplevel_y,
+                                            &event->motion.x, &event->motion.y);
+         gdk_event_get_root_coords (source_event,
+                                    &event->motion.x_root,
+                                    &event->motion.y_root);
+
+         if (is_touch_type (source_event->type))
+           event->motion.axes = g_memdup (source_event->touch.axes,
+                                          sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
+         else
+           event->motion.axes = g_memdup (source_event->motion.axes,
+                                          sizeof (gdouble) * gdk_device_get_n_axes (source_event->motion.device));
        }
+
+      /* Just insert the event */
+      _gdk_event_queue_insert_after (gdk_window_get_display (event_win),
+                                    source_event, event);
     }
 
   /* unlink all move events from queue.
@@ -9344,6 +9520,8 @@ proxy_button_event (GdkEvent *source_event,
   GdkWindow *pointer_window;
   GdkWindow *parent;
   GdkEvent *event;
+  GdkPointerWindowInfo *pointer_info;
+  GdkDeviceGrabInfo *pointer_grab;
   guint state;
   guint32 time_;
   GdkEventType type;
@@ -9351,6 +9529,8 @@ proxy_button_event (GdkEvent *source_event,
   GdkDisplay *display;
   GdkWindow *w;
   GdkDevice *device, *source_device;
+  GdkEventMask evmask;
+  GdkEventSequence *sequence;
 
   type = source_event->any.type;
   event_window = source_event->any.window;
@@ -9364,9 +9544,17 @@ proxy_button_event (GdkEvent *source_event,
                                                       toplevel_x, toplevel_y,
                                                       &toplevel_x, &toplevel_y);
 
-  if (type == GDK_BUTTON_PRESS &&
+  sequence = gdk_event_get_event_sequence (source_event);
+
+  pointer_info = _gdk_display_get_pointer_info (display, device);
+  pointer_grab = _gdk_display_has_device_grab (display, device, serial);
+
+  if ((type == GDK_BUTTON_PRESS ||
+       type == GDK_TOUCH_BEGIN) &&
       !source_event->any.send_event &&
-      _gdk_display_has_device_grab (display, device, serial) == NULL)
+      (!pointer_grab ||
+       (type == GDK_TOUCH_BEGIN && pointer_grab->implicit &&
+        !_gdk_event_get_pointer_emulated (source_event))))
     {
       pointer_window =
        _gdk_window_find_descendant_at (toplevel_window,
@@ -9379,23 +9567,46 @@ proxy_button_event (GdkEvent *source_event,
             (parent = get_event_parent (w)) != NULL &&
             parent->window_type != GDK_WINDOW_ROOT)
        {
-         if (w->event_mask & GDK_BUTTON_PRESS_MASK)
+         if (w->event_mask & GDK_BUTTON_PRESS_MASK &&
+              (type == GDK_BUTTON_PRESS ||
+               _gdk_event_get_pointer_emulated (source_event)))
            break;
+
+          if (type == GDK_TOUCH_BEGIN &&
+              w->event_mask & GDK_TOUCH_MASK)
+            break;
+
          w = parent;
        }
-      pointer_window = (GdkWindow *)w;
-
-      _gdk_display_add_device_grab  (display,
-                                     device,
-                                     pointer_window,
-                                     toplevel_window,
-                                     GDK_OWNERSHIP_NONE,
-                                     FALSE,
-                                     gdk_window_get_events (pointer_window),
-                                     serial,
-                                     time_,
-                                     TRUE);
-      _gdk_display_device_grab_update (display, device, source_device, serial);
+      pointer_window = w;
+
+      if (pointer_window)
+        {
+          if (type == GDK_TOUCH_BEGIN &&
+              pointer_window->event_mask & GDK_TOUCH_MASK)
+            {
+              _gdk_display_add_touch_grab (display, device, sequence,
+                                           pointer_window, event_window,
+                                           gdk_window_get_events (pointer_window),
+                                           serial, time_);
+            }
+          else if (type == GDK_BUTTON_PRESS ||
+                   _gdk_event_get_pointer_emulated (source_event))
+            {
+              _gdk_display_add_device_grab  (display,
+                                             device,
+                                             pointer_window,
+                                             event_window,
+                                             GDK_OWNERSHIP_NONE,
+                                             FALSE,
+                                             gdk_window_get_events (pointer_window),
+                                             serial,
+                                             time_,
+                                             TRUE);
+              _gdk_display_device_grab_update (display, device,
+                                               source_device, serial);
+            }
+        }
     }
 
   pointer_window = get_pointer_window (display, toplevel_window, device,
@@ -9404,17 +9615,73 @@ proxy_button_event (GdkEvent *source_event,
 
   event_win = get_event_window (display,
                                 device,
-                               pointer_window,
-                               type, state,
-                               NULL, serial);
+                                sequence,
+                                pointer_window,
+                                type, state,
+                                &evmask,
+                                _gdk_event_get_pointer_emulated (source_event),
+                                serial);
+
+  if (type == GDK_TOUCH_BEGIN || type == GDK_TOUCH_END)
+    {
+      if (_gdk_event_get_pointer_emulated (source_event))
+        {
+          if ((evmask & GDK_TOUCH_MASK) == 0 ||
+              !_gdk_display_has_touch_grab (display, device, sequence, serial))
+            {
+              if (type == GDK_TOUCH_BEGIN)
+                type = GDK_BUTTON_PRESS;
+              else if (type == GDK_TOUCH_END)
+                type = GDK_BUTTON_RELEASE;
+            }
+        }
+      else if ((evmask & GDK_TOUCH_MASK) == 0)
+        return TRUE;
+    }
+
+  if (source_event->type == GDK_TOUCH_END && !is_touch_type (type))
+    state |= GDK_BUTTON1_MASK;
 
-  if (event_win == NULL || display->ignore_core_events)
+  if (event_win == NULL)
     return TRUE;
 
   if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER &&
       gdk_window_get_device_events (event_win, device) == 0)
     return TRUE;
 
+  if ((type == GDK_BUTTON_PRESS ||
+       (type == GDK_TOUCH_BEGIN &&
+        _gdk_event_get_pointer_emulated (source_event))) &&
+      pointer_info->need_touch_press_enter)
+    {
+      GdkCrossingMode mode;
+
+      /* The last device to interact with the window was a touch device,
+       * which synthesized a leave notify event, so synthesize another enter
+       * notify to tell the pointer is on the window.
+       */
+      if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
+        mode = GDK_CROSSING_TOUCH_BEGIN;
+      else
+        mode = GDK_CROSSING_DEVICE_SWITCH;
+
+      pointer_info->need_touch_press_enter = FALSE;
+      _gdk_synthesize_crossing_events (display,
+                                       NULL,
+                                       pointer_info->window_under_pointer,
+                                       device, source_device, mode,
+                                       toplevel_x, toplevel_y,
+                                       state, time_, source_event,
+                                       serial, FALSE);
+    }
+  else if (type == GDK_SCROLL &&
+           (((evmask & GDK_SMOOTH_SCROLL_MASK) == 0 &&
+             source_event->scroll.direction == GDK_SCROLL_SMOOTH) ||
+            ((evmask & GDK_SMOOTH_SCROLL_MASK) != 0 &&
+             source_event->scroll.direction != GDK_SCROLL_SMOOTH &&
+             _gdk_event_get_pointer_emulated (source_event))))
+    return FALSE;
+
   event = _gdk_make_event (event_win, type, source_event, FALSE);
 
   switch (type)
@@ -9425,17 +9692,83 @@ proxy_button_event (GdkEvent *source_event,
       convert_toplevel_coords_to_window (event_win,
                                         toplevel_x, toplevel_y,
                                         &event->button.x, &event->button.y);
-      event->button.x_root = source_event->button.x_root;
-      event->button.y_root = source_event->button.y_root;
-      event->button.state = state;
-      event->button.device = source_event->button.device;
-      event->button.axes = g_memdup (source_event->button.axes,
-                                     sizeof (gdouble) * gdk_device_get_n_axes (source_event->button.device));
-
+      gdk_event_get_root_coords (source_event,
+                                &event->button.x_root,
+                                &event->button.y_root);
+      gdk_event_set_device (event, gdk_event_get_device (source_event));
       gdk_event_set_source_device (event, source_device);
 
+      if (is_touch_type (source_event->type))
+        {
+          if (type == GDK_BUTTON_RELEASE)
+            event->button.state |= GDK_BUTTON1_MASK;
+         event->button.button = 1;
+         event->button.axes = g_memdup (source_event->touch.axes,
+                                        sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
+       }
+      else
+       {
+         event->button.button = source_event->button.button;
+         event->button.axes = g_memdup (source_event->button.axes,
+                                        sizeof (gdouble) * gdk_device_get_n_axes (source_event->button.device));
+       }
+
       if (type == GDK_BUTTON_PRESS)
-       _gdk_event_button_generate (display, event);
+        _gdk_event_button_generate (display, event);
+      else if ((type == GDK_BUTTON_RELEASE ||
+                (type == GDK_TOUCH_END &&
+                 _gdk_event_get_pointer_emulated (source_event))) &&
+               pointer_window == pointer_info->window_under_pointer &&
+               gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
+        {
+          /* Synthesize a leave notify event
+           * whenever a touch device is released
+           */
+          pointer_info->need_touch_press_enter = TRUE;
+          _gdk_synthesize_crossing_events (display,
+                                           pointer_window, NULL,
+                                           device, source_device,
+                                           GDK_CROSSING_TOUCH_END,
+                                           toplevel_x, toplevel_y,
+                                           state, time_, NULL,
+                                           serial, FALSE);
+        }
+      return TRUE;
+
+    case GDK_TOUCH_BEGIN:
+    case GDK_TOUCH_END:
+      convert_toplevel_coords_to_window (event_win,
+                                         toplevel_x, toplevel_y,
+                                         &event->button.x, &event->button.y);
+      gdk_event_get_root_coords (source_event,
+                                &event->touch.x_root,
+                                &event->touch.y_root);
+      event->touch.state = state;
+      event->touch.device = source_event->touch.device;
+      event->touch.axes = g_memdup (source_event->touch.axes,
+                                     sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
+      event->touch.sequence = source_event->touch.sequence;
+      event->touch.emulating_pointer = source_event->touch.emulating_pointer;
+
+      gdk_event_set_source_device (event, source_device);
+
+      if ((type == GDK_TOUCH_END &&
+           _gdk_event_get_pointer_emulated (source_event)) &&
+           pointer_window == pointer_info->window_under_pointer &&
+           gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
+        {
+          /* Synthesize a leave notify event
+           * whenever a touch device is released
+           */
+          pointer_info->need_touch_press_enter = TRUE;
+          _gdk_synthesize_crossing_events (display,
+                                           pointer_window, NULL,
+                                           device, source_device,
+                                           GDK_CROSSING_TOUCH_END,
+                                           toplevel_x, toplevel_y,
+                                           state, time_, NULL,
+                                           serial, FALSE);
+        }
       return TRUE;
 
     case GDK_SCROLL:
@@ -9447,6 +9780,8 @@ proxy_button_event (GdkEvent *source_event,
       event->scroll.y_root = source_event->scroll.y_root;
       event->scroll.state = state;
       event->scroll.device = source_event->scroll.device;
+      event->scroll.delta_x = source_event->scroll.delta_x;
+      event->scroll.delta_y = source_event->scroll.delta_y;
       gdk_event_set_source_device (event, source_device);
       return TRUE;
 
@@ -9458,11 +9793,16 @@ proxy_button_event (GdkEvent *source_event,
 }
 
 #ifdef DEBUG_WINDOW_PRINTING
+
+#ifdef GDK_WINDOWING_X11
+#include "x11/gdkx.h"
+#endif
+
 static void
 gdk_window_print (GdkWindow *window,
                  int indent)
 {
-  GdkRectangle r;
+  char *s;
   const char *window_types[] = {
     "root",
     "toplevel",
@@ -9501,11 +9841,8 @@ gdk_window_print (GdkWindow *window,
   g_print (" abs[%d,%d]",
           window->abs_x, window->abs_y);
 
-  cairo_region_get_extents (window->clip_region, &r);
-  if (cairo_region_is_empty (window->clip_region))
-    g_print (" clipbox[empty]");
-  else
-    g_print (" clipbox[%d,%d %dx%d]", r.x, r.y, r.width, r.height);
+  s = print_region (window->clip_region);
+  g_print (" clipbox[%s]", s);
 
   g_print ("\n");
 }
@@ -9531,16 +9868,15 @@ gdk_window_print_tree (GdkWindow *window,
 
 void
 _gdk_windowing_got_event (GdkDisplay *display,
-                         GList      *event_link,
-                         GdkEvent   *event,
-                         gulong      serial)
+                          GList      *event_link,
+                          GdkEvent   *event,
+                          gulong      serial)
 {
   GdkWindow *event_window;
   gdouble x, y;
   gboolean unlink_event;
-  guint old_state, old_button;
   GdkDeviceGrabInfo *button_release_grab;
-  GdkPointerWindowInfo *pointer_info;
+  GdkPointerWindowInfo *pointer_info = NULL;
   GdkDevice *device, *source_device;
   gboolean is_toplevel;
 
@@ -9554,6 +9890,17 @@ _gdk_windowing_got_event (GdkDisplay *display,
     {
       GdkInputMode mode;
 
+      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
+        {
+          pointer_info = _gdk_display_get_pointer_info (display, device);
+
+          if (source_device != pointer_info->last_slave &&
+              gdk_device_get_device_type (source_device) == GDK_DEVICE_TYPE_SLAVE)
+            pointer_info->last_slave = source_device;
+          else
+            source_device = pointer_info->last_slave;
+        }
+
       g_object_get (device, "input-mode", &mode, NULL);
       _gdk_display_device_grab_update (display, device, source_device, serial);
 
@@ -9572,67 +9919,24 @@ _gdk_windowing_got_event (GdkDisplay *display,
   if (!event_window)
     return;
 
-  pointer_info = _gdk_display_get_pointer_info (display, device);
-
 #ifdef DEBUG_WINDOW_PRINTING
   if (event->type == GDK_KEY_PRESS &&
       (event->key.keyval == 0xa7 ||
        event->key.keyval == 0xbd))
     {
-      gdk_window_print_tree (event_window, 0,
-                            event->key.keyval == 0xbd);
+      gdk_window_print_tree (event_window, 0, event->key.keyval == 0xbd);
     }
 #endif
 
-  if (_gdk_native_windows)
-    {
-      if (event->type == GDK_BUTTON_PRESS &&
-         !event->any.send_event &&
-         _gdk_display_has_device_grab (display, device, serial) == NULL)
-       {
-         _gdk_display_add_device_grab  (display,
-                                         device,
-                                         event_window,
-                                         event_window,
-                                         GDK_OWNERSHIP_NONE,
-                                         FALSE,
-                                         gdk_window_get_events (event_window),
-                                         serial,
-                                         gdk_event_get_time (event),
-                                         TRUE);
-         _gdk_display_device_grab_update (display, device, source_device, serial);
-       }
-      if (event->type == GDK_BUTTON_RELEASE &&
-         !event->any.send_event)
-       {
-         button_release_grab =
-            _gdk_display_has_device_grab (display, device, serial);
-         if (button_release_grab &&
-             button_release_grab->implicit &&
-             (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
-           {
-             button_release_grab->serial_end = serial;
-             button_release_grab->implicit_ungrab = FALSE;
-             _gdk_display_device_grab_update (display, device, source_device, serial);
-           }
-       }
-
-      if (event->type == GDK_BUTTON_PRESS)
-       _gdk_event_button_generate (display, event);
-
-      return;
-    }
-
   if (event->type == GDK_VISIBILITY_NOTIFY)
     {
       event_window->native_visibility = event->visibility.state;
-      gdk_window_update_visibility_recursively (event_window,
-                                               event_window);
+      gdk_window_update_visibility_recursively (event_window, event_window);
       return;
     }
 
   if (!(is_button_type (event->type) ||
-       is_motion_type (event->type)) ||
+        is_motion_type (event->type)) ||
       event_window->window_type == GDK_WINDOW_ROOT)
     return;
 
@@ -9663,15 +9967,16 @@ _gdk_windowing_got_event (GdkDisplay *display,
        */
 
       /* We ended up in this window after some (perhaps other clients)
-        grab, so update the toplevel_under_window state */
+       * grab, so update the toplevel_under_window state
+       */
       if (is_toplevel &&
-         event->type == GDK_ENTER_NOTIFY &&
-         event->crossing.mode == GDK_CROSSING_UNGRAB)
-       {
-         if (pointer_info->toplevel_under_pointer)
-           g_object_unref (pointer_info->toplevel_under_pointer);
-         pointer_info->toplevel_under_pointer = g_object_ref (event_window);
-       }
+          event->type == GDK_ENTER_NOTIFY &&
+          event->crossing.mode == GDK_CROSSING_UNGRAB)
+        {
+          if (pointer_info->toplevel_under_pointer)
+            g_object_unref (pointer_info->toplevel_under_pointer);
+          pointer_info->toplevel_under_pointer = g_object_ref (event_window);
+        }
 
       unlink_event = TRUE;
       goto out;
@@ -9681,62 +9986,84 @@ _gdk_windowing_got_event (GdkDisplay *display,
   if (is_toplevel)
     {
       if (event->type == GDK_ENTER_NOTIFY &&
-         event->crossing.detail != GDK_NOTIFY_INFERIOR)
-       {
-         if (pointer_info->toplevel_under_pointer)
-           g_object_unref (pointer_info->toplevel_under_pointer);
-         pointer_info->toplevel_under_pointer = g_object_ref (event_window);
-       }
+          event->crossing.detail != GDK_NOTIFY_INFERIOR)
+        {
+          if (pointer_info->toplevel_under_pointer)
+            g_object_unref (pointer_info->toplevel_under_pointer);
+          pointer_info->toplevel_under_pointer = g_object_ref (event_window);
+        }
       else if (event->type == GDK_LEAVE_NOTIFY &&
-              event->crossing.detail != GDK_NOTIFY_INFERIOR &&
-              pointer_info->toplevel_under_pointer == event_window)
-       {
-         if (pointer_info->toplevel_under_pointer)
-           g_object_unref (pointer_info->toplevel_under_pointer);
-         pointer_info->toplevel_under_pointer = NULL;
-       }
+               event->crossing.detail != GDK_NOTIFY_INFERIOR &&
+               pointer_info->toplevel_under_pointer == event_window)
+        {
+          if (pointer_info->toplevel_under_pointer)
+            g_object_unref (pointer_info->toplevel_under_pointer);
+          pointer_info->toplevel_under_pointer = NULL;
+        }
     }
 
-  /* Store last pointer window and position/state */
-  old_state = pointer_info->state;
-  old_button = pointer_info->button;
+  if (pointer_info &&
+      (!is_touch_type (event->type) ||
+       _gdk_event_get_pointer_emulated (event)))
+    {
+      guint old_state, old_button;
 
-  gdk_event_get_coords (event, &x, &y);
-  convert_native_coords_to_toplevel (event_window, x, y,  &x, &y);
-  pointer_info->toplevel_x = x;
-  pointer_info->toplevel_y = y;
-  gdk_event_get_state (event, &pointer_info->state);
-  if (event->type == GDK_BUTTON_PRESS ||
-      event->type == GDK_BUTTON_RELEASE)
-    pointer_info->button = event->button.button;
+      /* Store last pointer window and position/state */
+      old_state = pointer_info->state;
+      old_button = pointer_info->button;
 
-  if (device &&
-      (pointer_info->state != old_state ||
-       pointer_info->button != old_button))
-    _gdk_display_enable_motion_hints (display, device);
+      gdk_event_get_coords (event, &x, &y);
+      convert_native_coords_to_toplevel (event_window, x, y,  &x, &y);
+      pointer_info->toplevel_x = x;
+      pointer_info->toplevel_y = y;
+      gdk_event_get_state (event, &pointer_info->state);
+
+      if (event->type == GDK_BUTTON_PRESS ||
+          event->type == GDK_BUTTON_RELEASE)
+        pointer_info->button = event->button.button;
+      else if (event->type == GDK_TOUCH_BEGIN ||
+               event->type == GDK_TOUCH_END)
+        pointer_info->button = 1;
+
+      if (device &&
+          (pointer_info->state != old_state ||
+           pointer_info->button != old_button))
+        _gdk_display_enable_motion_hints (display, device);
+    }
 
   unlink_event = FALSE;
   if (is_motion_type (event->type))
-    unlink_event = proxy_pointer_event (display,
-                                       event,
-                                       serial);
+    unlink_event = proxy_pointer_event (display, event, serial);
   else if (is_button_type (event->type))
-    unlink_event = proxy_button_event (event,
-                                      serial);
+    unlink_event = proxy_button_event (event, serial);
 
-  if (event->type == GDK_BUTTON_RELEASE &&
+  if ((event->type == GDK_BUTTON_RELEASE ||
+       event->type == GDK_TOUCH_END) &&
       !event->any.send_event)
     {
-      button_release_grab =
-       _gdk_display_has_device_grab (display, device, serial);
-      if (button_release_grab &&
-         button_release_grab->implicit &&
-         (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
-       {
-         button_release_grab->serial_end = serial;
-         button_release_grab->implicit_ungrab = FALSE;
-         _gdk_display_device_grab_update (display, device, source_device, serial);
-       }
+      GdkEventSequence *sequence;
+
+      sequence = gdk_event_get_event_sequence (event);
+      if (event->type == GDK_TOUCH_END && sequence)
+        {
+          _gdk_display_end_touch_grab (display, device, sequence);
+        }
+
+      if (event->type == GDK_BUTTON_RELEASE ||
+          _gdk_event_get_pointer_emulated (event))
+        {
+          button_release_grab =
+            _gdk_display_has_device_grab (display, device, serial);
+
+          if (button_release_grab &&
+              button_release_grab->implicit &&
+              (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
+            {
+              button_release_grab->serial_end = serial;
+              button_release_grab->implicit_ungrab = FALSE;
+              _gdk_display_device_grab_update (display, device, source_device, serial);
+            }
+        }
     }
 
  out:
@@ -9785,11 +10112,28 @@ gdk_window_create_similar_surface (GdkWindow *     window,
 
   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
   
-  window_surface = _gdk_window_ref_cairo_surface (window);
+  window_surface = gdk_window_ref_impl_surface (window);
 
-  surface = cairo_surface_create_similar (window_surface,
-                                          content,
-                                          width, height);
+  switch (_gdk_rendering_mode)
+  {
+    case GDK_RENDERING_MODE_RECORDING:
+      {
+        cairo_rectangle_t rect = { 0, 0, width, height };
+        surface = cairo_recording_surface_create (content, &rect);
+      }
+      break;
+    case GDK_RENDERING_MODE_IMAGE:
+      surface = cairo_image_surface_create (content == CAIRO_CONTENT_COLOR ? CAIRO_FORMAT_RGB24 :
+                                            content == CAIRO_CONTENT_ALPHA ? CAIRO_FORMAT_A8 : CAIRO_FORMAT_ARGB32,
+                                            width, height);
+      break;
+    case GDK_RENDERING_MODE_SIMILAR:
+    default:
+      surface = cairo_surface_create_similar (window_surface,
+                                              content,
+                                              width, height);
+      break;
+  }
 
   cairo_surface_destroy (window_surface);
 
@@ -10068,7 +10412,7 @@ gdk_window_get_root_origin (GdkWindow *window,
 /**
  * gdk_window_get_frame_extents:
  * @window: a toplevel #GdkWindow
- * @rect: rectangle to fill with bounding box of the window frame
+ * @rect: (out): rectangle to fill with bounding box of the window frame
  *
  * Obtains the bounding box of the window, including window manager
  * titlebar/borders if any. The frame position is given in root window
@@ -10173,7 +10517,7 @@ gdk_window_set_icon_list (GdkWindow *window,
 /**
  * gdk_window_set_icon_name:
  * @window: a toplevel #GdkWindow
- * @name: name of window while iconified (minimized)
+ * @name: (allow-none): name of window while iconified (minimized)
  *
  * Windows may have a name used while minimized, distinct from the
  * name they display in their titlebar. Most of the time this is a bad
@@ -10423,7 +10767,7 @@ gdk_window_get_group (GdkWindow *window)
 /**
  * gdk_window_set_group:
  * @window: a toplevel #GdkWindow
- * @leader: group leader window, or %NULL to restore the default group leader window
+ * @leader: (allow-none): group leader window, or %NULL to restore the default group leader window
  *
  * Sets the group leader window for @window. By default,
  * GDK sets the group leader for all toplevel windows
@@ -10516,9 +10860,10 @@ gdk_window_set_functions (GdkWindow    *window,
 }
 
 /**
- * gdk_window_begin_resize_drag:
+ * gdk_window_begin_resize_drag_for_device:
  * @window: a toplevel #GdkWindow
  * @edge: the edge or corner from which the drag is started
+ * @device: the device used for the operation
  * @button: the button being used to drag
  * @root_x: root window X coordinate of mouse click that began the drag
  * @root_y: root window Y coordinate of mouse click that began the drag
@@ -10530,7 +10875,35 @@ gdk_window_set_functions (GdkWindow    *window,
  * with window managers that support the <ulink url="http://www.freedesktop.org/Standards/wm-spec">Extended Window Manager Hints</ulink>, but has a
  * fallback implementation for other window managers.
  *
- **/
+ * Since: 3.4
+ */
+void
+gdk_window_begin_resize_drag_for_device (GdkWindow     *window,
+                                         GdkWindowEdge  edge,
+                                         GdkDevice     *device,
+                                         gint           button,
+                                         gint           root_x,
+                                         gint           root_y,
+                                         guint32        timestamp)
+{
+  GDK_WINDOW_IMPL_GET_CLASS (window->impl)->begin_resize_drag (window, edge, device, button, root_x, root_y, timestamp);
+}
+
+/**
+ * gdk_window_begin_resize_drag:
+ * @window: a toplevel #GdkWindow
+ * @edge: the edge or corner from which the drag is started
+ * @button: the button being used to drag
+ * @root_x: root window X coordinate of mouse click that began the drag
+ * @root_y: root window Y coordinate of mouse click that began the drag
+ * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
+ *
+ * Begins a window resize operation (for a toplevel window).
+ *
+ * This function assumes that the drag is controlled by the
+ * client pointer device, use gdk_window_begin_resize_drag_for_device()
+ * to begin a drag with a different device.
+ */
 void
 gdk_window_begin_resize_drag (GdkWindow     *window,
                               GdkWindowEdge  edge,
@@ -10539,25 +10912,59 @@ gdk_window_begin_resize_drag (GdkWindow     *window,
                               gint           root_y,
                               guint32        timestamp)
 {
-  GDK_WINDOW_IMPL_GET_CLASS (window->impl)->begin_resize_drag (window, edge, button, root_x, root_y, timestamp);
+  GdkDeviceManager *device_manager;
+  GdkDevice *device;
+
+  device_manager = gdk_display_get_device_manager (gdk_window_get_display (window));
+  device = gdk_device_manager_get_client_pointer (device_manager);
+  gdk_window_begin_resize_drag_for_device (window, edge,
+                                           device, button, root_x, root_y, timestamp);
 }
 
 /**
- * gdk_window_begin_move_drag:
+ * gdk_window_begin_move_drag_for_device:
  * @window: a toplevel #GdkWindow
+ * @device: the device used for the operation
  * @button: the button being used to drag
  * @root_x: root window X coordinate of mouse click that began the drag
  * @root_y: root window Y coordinate of mouse click that began the drag
  * @timestamp: timestamp of mouse click that began the drag
  *
- * Begins a window move operation (for a toplevel window).  You might
- * use this function to implement a "window move grip," for
+ * Begins a window move operation (for a toplevel window).
+ * You might use this function to implement a "window move grip," for
  * example. The function works best with window managers that support
  * the <ulink url="http://www.freedesktop.org/Standards/wm-spec">Extended
  * Window Manager Hints</ulink>, but has a fallback implementation for
  * other window managers.
  *
- **/
+ * Since: 3.4
+ */
+void
+gdk_window_begin_move_drag_for_device (GdkWindow *window,
+                                       GdkDevice *device,
+                                       gint       button,
+                                       gint       root_x,
+                                       gint       root_y,
+                                       guint32    timestamp)
+{
+  GDK_WINDOW_IMPL_GET_CLASS (window->impl)->begin_move_drag (window,
+                                                             device, button, root_x, root_y, timestamp);
+}
+
+/**
+ * gdk_window_begin_move_drag:
+ * @window: a toplevel #GdkWindow
+ * @button: the button being used to drag
+ * @root_x: root window X coordinate of mouse click that began the drag
+ * @root_y: root window Y coordinate of mouse click that began the drag
+ * @timestamp: timestamp of mouse click that began the drag
+ *
+ * Begins a window move operation (for a toplevel window).
+ *
+ * This function assumes that the drag is controlled by the
+ * client pointer device, use gdk_window_begin_move_drag_for_device()
+ * to begin a drag with a different device.
+ */
 void
 gdk_window_begin_move_drag (GdkWindow *window,
                             gint       button,
@@ -10565,7 +10972,12 @@ gdk_window_begin_move_drag (GdkWindow *window,
                             gint       root_y,
                             guint32    timestamp)
 {
-  GDK_WINDOW_IMPL_GET_CLASS (window->impl)->begin_move_drag (window, button, root_x, root_y, timestamp);
+  GdkDeviceManager *device_manager;
+  GdkDevice *device;
+
+  device_manager = gdk_display_get_device_manager (gdk_window_get_display (window));
+  device = gdk_device_manager_get_client_pointer (device_manager);
+  gdk_window_begin_move_drag_for_device (window, device, button, root_x, root_y, timestamp);
 }
 
 /**
@@ -10743,7 +11155,7 @@ gdk_drag_begin_for_device (GdkWindow     *window,
 void
 gdk_test_render_sync (GdkWindow *window)
 {
-  return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->sync_rendering (window);
+  GDK_WINDOW_IMPL_GET_CLASS (window->impl)->sync_rendering (window);
 }
 
 /**
@@ -10868,7 +11280,6 @@ gdk_test_simulate_button (GdkWindow      *window,
  * <para>
  * The XGetWindowProperty() function that gdk_property_get()
  * uses has a very confusing and complicated set of semantics.
- * uses has a very confusing and complicated set of semantics.
  * Unfortunately, gdk_property_get() makes the situation
  * worse instead of better (the semantics should be considered
  * undefined), and also prints warnings to stderr in cases where it