[mutter] Introduce regional stage rendering



commit 566c28bdaf2217e1ae82210af9c11ac250aa12f6
Author: Jonas Ådahl <jadahl gmail com>
Date:   Fri May 27 11:09:24 2016 +0800

    Introduce regional stage rendering
    
    Add support for drawing a stage using multiple framebuffers each making
    up one part of the stage. This works by the stage backend
    (ClutterStageWindow) providing a list of views which will be for
    splitting up the stage in different regions.
    
    A view layout, for now, is a set of rectangles. The stage window (i.e.
    stage "backend" will use this information when drawing a frame, using
    one framebuffer for each view. The scene graph is adapted to explictly
    take a view when painting the stage. It will use this view, its
    assigned framebuffer and layout to offset and clip the drawing
    accordingly.
    
    This effectively removes any notion of "stage framebuffer", since each
    stage now may consist of multiple framebuffers. Therefore, API
    involving this has been deprecated and made no-ops; namely
    clutter_stage_ensure_context(). Callers are now assumed to either
    always use a framebuffer reference explicitly, or push/pop the
    framebuffer of a given view where the code has not yet changed to use
    the explicit-buffer-using cogl API.
    
    Currently only the nested X11 backend supports this mode fully, and the
    per view framebuffers are all offscreen. Upon frame completion, it'll
    blit each view's framebuffer onto the onscreen framebuffer before
    swapping.
    
    Other backends (X11 CM and native/KMS) are adapted to manage a
    full-stage view. The X11 CM backend will continue to use this method,
    while the native/KMS backend will be adopted to use multiple view
    drawing.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=768976

 clutter/clutter/Makefile.am                       |    2 +
 clutter/clutter/clutter-backend-private.h         |    7 +-
 clutter/clutter/clutter-backend.c                 |  103 -----
 clutter/clutter/clutter-macros.h                  |    2 +
 clutter/clutter/clutter-mutter.h                  |    1 +
 clutter/clutter/clutter-private.h                 |    4 +
 clutter/clutter/clutter-stage-private.h           |    6 +-
 clutter/clutter/clutter-stage-view.c              |  188 +++++++++
 clutter/clutter/clutter-stage-view.h              |   55 +++
 clutter/clutter/clutter-stage-window.c            |   38 +--
 clutter/clutter/clutter-stage-window.h            |   14 +-
 clutter/clutter/clutter-stage.c                   |  373 ++++++++++++------
 clutter/clutter/clutter-stage.h                   |    3 -
 clutter/clutter/clutter-util.c                    |   33 ++
 clutter/clutter/cogl/clutter-stage-cogl.c         |  427 +++++++++++++++------
 clutter/clutter/cogl/clutter-stage-cogl.h         |   19 +-
 clutter/clutter/deprecated/clutter-stage.h        |    3 +
 clutter/clutter/x11/clutter-stage-x11.c           |   67 +++-
 clutter/clutter/x11/clutter-stage-x11.h           |    3 +
 src/Makefile.am                                   |    2 +
 src/backends/meta-backend-private.h               |    2 +
 src/backends/meta-renderer-view.c                 |   43 ++
 src/backends/meta-renderer-view.h                 |   29 ++
 src/backends/meta-renderer.c                      |   74 ++++-
 src/backends/meta-renderer.h                      |   12 +
 src/backends/meta-stage.c                         |    3 +
 src/backends/meta-stage.h                         |    3 +
 src/backends/native/meta-backend-native.c         |    7 +
 src/backends/native/meta-clutter-backend-native.c |   25 +-
 src/backends/native/meta-clutter-backend-native.h |    3 +
 src/backends/native/meta-stage-native.c           |  146 ++++++--
 src/backends/native/meta-stage-native.h           |    4 +
 src/backends/x11/meta-backend-x11.c               |    3 +
 src/backends/x11/meta-renderer-x11.c              |   31 ++
 src/backends/x11/meta-stage-x11-nested.c          |  130 ++++++-
 src/core/boxes-private.h                          |    2 +
 src/core/boxes.c                                  |   11 +
 37 files changed, 1434 insertions(+), 444 deletions(-)
---
diff --git a/clutter/clutter/Makefile.am b/clutter/clutter/Makefile.am
index b9bf68d..df157df 100644
--- a/clutter/clutter/Makefile.am
+++ b/clutter/clutter/Makefile.am
@@ -114,6 +114,7 @@ source_h =                                  \
        clutter-snap-constraint.h       \
        clutter-stage.h                 \
        clutter-stage-manager.h \
+       clutter-stage-view.h            \
        clutter-tap-action.h            \
        clutter-test-utils.h            \
        clutter-texture.h               \
@@ -197,6 +198,7 @@ source_c = \
        clutter-snap-constraint.c       \
        clutter-stage.c         \
        clutter-stage-manager.c \
+       clutter-stage-view.c    \
        clutter-stage-window.c  \
        clutter-tap-action.c            \
        clutter-test-utils.c            \
diff --git a/clutter/clutter/clutter-backend-private.h b/clutter/clutter/clutter-backend-private.h
index f485cba..b808d25 100644
--- a/clutter/clutter/clutter-backend-private.h
+++ b/clutter/clutter/clutter-backend-private.h
@@ -86,8 +86,6 @@ struct _ClutterBackendClass
                                                 GError         **error);
   gboolean              (* create_context)     (ClutterBackend  *backend,
                                                 GError         **error);
-  void                  (* ensure_context)     (ClutterBackend  *backend,
-                                                ClutterStage    *stage);
   ClutterDeviceManager *(* get_device_manager) (ClutterBackend  *backend);
 
   void                  (* copy_event_data)    (ClutterBackend     *backend,
@@ -113,10 +111,6 @@ ClutterBackend *        _clutter_create_backend                         (void);
 ClutterStageWindow *    _clutter_backend_create_stage                   (ClutterBackend         *backend,
                                                                          ClutterStage           *wrapper,
                                                                          GError                **error);
-void                    _clutter_backend_ensure_context                 (ClutterBackend         *backend,
-                                                                         ClutterStage           *stage);
-void                    _clutter_backend_ensure_context_internal        (ClutterBackend         *backend,
-                                                                         ClutterStage           *stage);
 gboolean                _clutter_backend_create_context                 (ClutterBackend         *backend,
                                                                          GError                **error);
 
@@ -152,6 +146,7 @@ gint32                  _clutter_backend_get_units_serial               (Clutter
 
 PangoDirection          _clutter_backend_get_keymap_direction           (ClutterBackend         *backend);
 
+CLUTTER_AVAILABLE_IN_MUTTER
 void                    _clutter_backend_reset_cogl_framebuffer         (ClutterBackend         *backend);
 
 void                    clutter_set_allowed_drivers                     (const char             *drivers);
diff --git a/clutter/clutter/clutter-backend.c b/clutter/clutter/clutter-backend.c
index c3b7295..5a1d252 100644
--- a/clutter/clutter/clutter-backend.c
+++ b/clutter/clutter/clutter-backend.c
@@ -413,27 +413,6 @@ clutter_backend_real_create_context (ClutterBackend  *backend,
   return TRUE;
 }
 
-static void
-clutter_backend_real_ensure_context (ClutterBackend *backend,
-                                     ClutterStage   *stage)
-{
-  ClutterStageWindow *stage_impl;
-  CoglFramebuffer *framebuffer;
-
-  if (stage == NULL)
-    return;
-
-  stage_impl = _clutter_stage_get_window (stage);
-  if (stage_impl == NULL)
-    return;
-
-  framebuffer = _clutter_stage_window_get_active_framebuffer (stage_impl);
-  if (framebuffer == NULL)
-    return;
-
-  cogl_set_framebuffer (framebuffer);
-}
-
 static ClutterFeatureFlags
 clutter_backend_real_get_features (ClutterBackend *backend)
 {
@@ -697,7 +676,6 @@ clutter_backend_class_init (ClutterBackendClass *klass)
   klass->get_device_manager = clutter_backend_real_get_device_manager;
   klass->translate_event = clutter_backend_real_translate_event;
   klass->create_context = clutter_backend_real_create_context;
-  klass->ensure_context = clutter_backend_real_ensure_context;
   klass->get_features = clutter_backend_real_get_features;
 }
 
@@ -789,87 +767,6 @@ _clutter_backend_create_context (ClutterBackend  *backend,
   return klass->create_context (backend, error);
 }
 
-void
-_clutter_backend_ensure_context_internal (ClutterBackend  *backend,
-                                          ClutterStage    *stage)
-{
-  ClutterBackendClass *klass = CLUTTER_BACKEND_GET_CLASS (backend);
-  if (G_LIKELY (klass->ensure_context))
-    klass->ensure_context (backend, stage);
-}
-
-void
-_clutter_backend_ensure_context (ClutterBackend *backend,
-                                 ClutterStage   *stage)
-{
-  static ClutterStage *current_context_stage = NULL;
-
-  g_assert (CLUTTER_IS_BACKEND (backend));
-  g_assert (CLUTTER_IS_STAGE (stage));
-
-  if (current_context_stage != stage ||
-      !clutter_actor_is_realized (CLUTTER_ACTOR (stage)))
-    {
-      ClutterStage *new_stage = NULL;
-
-      if (!clutter_actor_is_realized (CLUTTER_ACTOR (stage)))
-        {
-          new_stage = NULL;
-
-          CLUTTER_NOTE (BACKEND,
-                        "Stage [%p] is not realized, unsetting the stage",
-                        stage);
-        }
-      else
-        {
-          new_stage = stage;
-
-          CLUTTER_NOTE (BACKEND,
-                        "Setting the new stage [%p]",
-                        new_stage);
-        }
-
-      /* XXX: Until Cogl becomes fully responsible for backend windows
-       * Clutter need to manually keep it informed of the current window size
-       *
-       * NB: This must be done after we ensure_context above because Cogl
-       * always assumes there is a current GL context.
-       */
-      if (new_stage != NULL)
-        {
-          float width, height;
-
-          _clutter_backend_ensure_context_internal (backend, new_stage);
-
-          clutter_actor_get_size (CLUTTER_ACTOR (stage), &width, &height);
-
-          cogl_onscreen_clutter_backend_set_size (width, height);
-
-          /* Eventually we will have a separate CoglFramebuffer for
-           * each stage and each one will track private projection
-           * matrix and viewport state, but until then we need to make
-           * sure we update the projection and viewport whenever we
-           * switch between stages.
-           *
-           * This dirty mechanism will ensure they are asserted before
-           * the next paint...
-           */
-          _clutter_stage_dirty_viewport (stage);
-          _clutter_stage_dirty_projection (stage);
-        }
-
-      /* FIXME: With a NULL stage and thus no active context it may make more
-       * sense to clean the context but then re call with the default stage 
-       * so at least there is some kind of context in place (as to avoid
-       * potential issue of GL calls with no context).
-       */
-      current_context_stage = new_stage;
-    }
-  else
-    CLUTTER_NOTE (BACKEND, "Stage is the same");
-}
-
-
 ClutterFeatureFlags
 _clutter_backend_get_features (ClutterBackend *backend)
 {
diff --git a/clutter/clutter/clutter-macros.h b/clutter/clutter/clutter-macros.h
index 521ad43..21cb304 100644
--- a/clutter/clutter/clutter-macros.h
+++ b/clutter/clutter/clutter-macros.h
@@ -278,6 +278,8 @@
 # define CLUTTER_DEPRECATED_IN_1_12_FOR(f)      _CLUTTER_EXTERN
 #endif
 
+#define CLUTTER_DEPRECATED_IN_MUTTER            CLUTTER_DEPRECATED
+
 #if CLUTTER_VERSION_MAX_ALLOWED < CLUTTER_VERSION_1_12
 # define CLUTTER_AVAILABLE_IN_1_12              CLUTTER_UNAVAILABLE(1, 12)
 #else
diff --git a/clutter/clutter/clutter-mutter.h b/clutter/clutter/clutter-mutter.h
index ab50742..cdb6e4b 100644
--- a/clutter/clutter/clutter-mutter.h
+++ b/clutter/clutter/clutter-mutter.h
@@ -27,6 +27,7 @@
 
 #include "clutter-backend.h"
 #include "clutter-macros.h"
+#include "clutter-stage-view.h"
 #include "cogl/clutter-stage-cogl.h"
 #include "x11/clutter-stage-x11.h"
 
diff --git a/clutter/clutter/clutter-private.h b/clutter/clutter/clutter-private.h
index ab2cc97..129880d 100644
--- a/clutter/clutter/clutter-private.h
+++ b/clutter/clutter/clutter-private.h
@@ -244,6 +244,10 @@ void _clutter_util_rectangle_union (const cairo_rectangle_int_t *src1,
                                     const cairo_rectangle_int_t *src2,
                                     cairo_rectangle_int_t       *dest);
 
+gboolean _clutter_util_rectangle_intersection (const cairo_rectangle_int_t *src1,
+                                               const cairo_rectangle_int_t *src2,
+                                               cairo_rectangle_int_t       *dest);
+
 
 struct _ClutterVertex4
 {
diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h
index 7529cdf..6e06cf1 100644
--- a/clutter/clutter/clutter-stage-private.h
+++ b/clutter/clutter/clutter-stage-private.h
@@ -36,7 +36,8 @@ typedef struct _ClutterStageQueueRedrawEntry ClutterStageQueueRedrawEntry;
 /* stage */
 ClutterStageWindow *_clutter_stage_get_default_window    (void);
 
-void                _clutter_stage_do_paint              (ClutterStage                *stage,
+void                _clutter_stage_paint_view            (ClutterStage                *stage,
+                                                          ClutterStageView            *view,
                                                           const cairo_rectangle_int_t *clip);
 
 void                _clutter_stage_set_window            (ClutterStage          *stage,
@@ -56,7 +57,8 @@ void                _clutter_stage_get_viewport          (ClutterStage
                                                           float                 *width,
                                                           float                 *height);
 void                _clutter_stage_dirty_viewport        (ClutterStage          *stage);
-void                _clutter_stage_maybe_setup_viewport  (ClutterStage          *stage);
+void                _clutter_stage_maybe_setup_viewport  (ClutterStage          *stage,
+                                                          ClutterStageView      *view);
 void                _clutter_stage_maybe_relayout        (ClutterActor          *stage);
 gboolean            _clutter_stage_needs_update          (ClutterStage          *stage);
 gboolean            _clutter_stage_do_update             (ClutterStage          *stage);
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
new file mode 100644
index 0000000..6a6cf33
--- /dev/null
+++ b/clutter/clutter/clutter-stage-view.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "clutter-build-config.h"
+
+#include "clutter/clutter-stage-view.h"
+
+#include <cairo-gobject.h>
+
+enum
+{
+  PROP_0,
+
+  PROP_LAYOUT,
+  PROP_FRAMEBUFFER,
+
+  PROP_LAST
+};
+
+static GParamSpec *obj_props[PROP_LAST];
+
+typedef struct _ClutterStageViewPrivate
+{
+  cairo_rectangle_int_t layout;
+  CoglFramebuffer *framebuffer;
+  guint dirty_viewport   : 1;
+  guint dirty_projection : 1;
+} ClutterStageViewPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageView, clutter_stage_view, G_TYPE_OBJECT)
+
+void
+clutter_stage_view_get_layout (ClutterStageView      *view,
+                               cairo_rectangle_int_t *rect)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  *rect = priv->layout;
+}
+
+CoglFramebuffer *
+clutter_stage_view_get_framebuffer (ClutterStageView *view)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  return priv->framebuffer;
+}
+
+gboolean
+clutter_stage_view_is_dirty_viewport (ClutterStageView *view)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  return priv->dirty_viewport;
+}
+
+void
+clutter_stage_view_set_dirty_viewport (ClutterStageView *view,
+                                       gboolean          dirty)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  priv->dirty_viewport = dirty;
+}
+
+gboolean
+clutter_stage_view_is_dirty_projection (ClutterStageView *view)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  return priv->dirty_projection;
+}
+
+void
+clutter_stage_view_set_dirty_projection (ClutterStageView *view,
+                                         gboolean          dirty)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  priv->dirty_projection = dirty;
+}
+
+static void
+clutter_stage_view_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  ClutterStageView *view = CLUTTER_STAGE_VIEW (object);
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  switch (prop_id)
+    {
+    case PROP_LAYOUT:
+      g_value_set_boxed (value, &priv->layout);
+      break;
+    case PROP_FRAMEBUFFER:
+      g_value_set_boxed (value, priv->framebuffer);
+      break;
+    }
+}
+
+static void
+clutter_stage_view_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  ClutterStageView *view = CLUTTER_STAGE_VIEW (object);
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+  cairo_rectangle_int_t *layout;
+
+  switch (prop_id)
+    {
+    case PROP_LAYOUT:
+      layout = g_value_get_boxed (value);
+      priv->layout = *layout;
+      break;
+    case PROP_FRAMEBUFFER:
+      priv->framebuffer = g_value_get_boxed (value);
+      break;
+    }
+}
+
+static void
+clutter_stage_view_dispose (GObject *object)
+{
+  ClutterStageView *view = CLUTTER_STAGE_VIEW (object);
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  g_clear_pointer (&priv->framebuffer, cogl_object_unref);
+}
+
+static void
+clutter_stage_view_init (ClutterStageView *view)
+{
+}
+
+static void
+clutter_stage_view_class_init (ClutterStageViewClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->get_property = clutter_stage_view_get_property;
+  object_class->set_property = clutter_stage_view_set_property;
+  object_class->dispose = clutter_stage_view_dispose;
+
+  obj_props[PROP_LAYOUT] =
+    g_param_spec_boxed ("layout",
+                        "View layout",
+                        "The view layout on the screen",
+                        CAIRO_GOBJECT_TYPE_RECTANGLE_INT,
+                        G_PARAM_READWRITE |
+                        G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_FRAMEBUFFER] =
+    g_param_spec_boxed ("framebuffer",
+                        "View framebuffer",
+                        "The framebuffer of the view",
+                        COGL_TYPE_HANDLE,
+                        G_PARAM_READWRITE |
+                        G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, PROP_LAST, obj_props);
+}
diff --git a/clutter/clutter/clutter-stage-view.h b/clutter/clutter/clutter-stage-view.h
new file mode 100644
index 0000000..e9fe3a0
--- /dev/null
+++ b/clutter/clutter/clutter-stage-view.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CLUTTER_STAGE_VIEW_H__
+#define __CLUTTER_STAGE_VIEW_H__
+
+#include <cairo.h>
+#include <glib-object.h>
+#include <cogl/cogl.h>
+
+#include "clutter-macros.h"
+
+#define CLUTTER_TYPE_STAGE_VIEW (clutter_stage_view_get_type ())
+CLUTTER_AVAILABLE_IN_MUTTER
+G_DECLARE_DERIVABLE_TYPE (ClutterStageView, clutter_stage_view,
+                          CLUTTER, STAGE_VIEW,
+                          GObject)
+
+struct _ClutterStageViewClass
+{
+  GObjectClass parent_class;
+};
+
+CLUTTER_AVAILABLE_IN_MUTTER
+void clutter_stage_view_get_layout (ClutterStageView      *view,
+                                    cairo_rectangle_int_t *rect);
+
+CLUTTER_AVAILABLE_IN_MUTTER
+CoglFramebuffer *clutter_stage_view_get_framebuffer (ClutterStageView *view);
+
+gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
+
+void clutter_stage_view_set_dirty_viewport (ClutterStageView *view,
+                                            gboolean          dirty);
+
+gboolean clutter_stage_view_is_dirty_projection (ClutterStageView *view);
+
+void clutter_stage_view_set_dirty_projection (ClutterStageView *view,
+                                              gboolean          dirty);
+
+#endif /* __CLUTTER_STAGE_VIEW_H__ */
diff --git a/clutter/clutter/clutter-stage-window.c b/clutter/clutter/clutter-stage-window.c
index 2efb325..c6e7780 100644
--- a/clutter/clutter/clutter-stage-window.c
+++ b/clutter/clutter/clutter-stage-window.c
@@ -274,6 +274,7 @@ _clutter_stage_window_redraw (ClutterStageWindow *window)
 
 void
 _clutter_stage_window_get_dirty_pixel (ClutterStageWindow *window,
+                                       ClutterStageView   *view,
                                        int *x, int *y)
 {
   ClutterStageWindowIface *iface;
@@ -285,27 +286,7 @@ _clutter_stage_window_get_dirty_pixel (ClutterStageWindow *window,
 
   iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
   if (iface->get_dirty_pixel)
-    iface->get_dirty_pixel (window, x, y);
-}
-
-/* NB: The presumption shouldn't be that a stage can't be comprised of
- * multiple internal framebuffers, so instead of simply naming this
- * function _clutter_stage_window_get_framebuffer(), the "active"
- * infix is intended to clarify that it gets the framebuffer that is
- * currently in use/being painted.
- */
-CoglFramebuffer *
-_clutter_stage_window_get_active_framebuffer (ClutterStageWindow *window)
-{
-  ClutterStageWindowIface *iface;
-
-  g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), NULL);
-
-  iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
-  if (iface->get_active_framebuffer)
-    return iface->get_active_framebuffer (window);
-  else
-    return NULL;
+    iface->get_dirty_pixel (window, view, x, y);
 }
 
 gboolean
@@ -349,12 +330,12 @@ _clutter_stage_window_get_scale_factor (ClutterStageWindow *window)
   return 1;
 }
 
-CoglFramebuffer  *
-_clutter_stage_window_get_legacy_onscreen (ClutterStageWindow *window)
+GList *
+_clutter_stage_window_get_views (ClutterStageWindow *window)
 {
   ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
 
-  return iface->get_legacy_onscreen (window);
+  return iface->get_views (window);
 }
 
 CoglFrameClosure *
@@ -376,6 +357,15 @@ _clutter_stage_window_remove_frame_callback (ClutterStageWindow *window,
   iface->remove_frame_callback (window, closure);
 }
 
+void
+_clutter_stage_window_finish_frame (ClutterStageWindow *window)
+{
+  ClutterStageWindowIface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
+
+  if (iface->finish_frame)
+    iface->finish_frame (window);
+}
+
 int64_t
 _clutter_stage_window_get_frame_counter (ClutterStageWindow *window)
 {
diff --git a/clutter/clutter/clutter-stage-window.h b/clutter/clutter/clutter-stage-window.h
index 863ecfc..947eb87 100644
--- a/clutter/clutter/clutter-stage-window.h
+++ b/clutter/clutter/clutter-stage-window.h
@@ -3,6 +3,7 @@
 
 #include <cogl/cogl.h>
 #include <clutter/clutter-types.h>
+#include "clutter/clutter-stage-view.h"
 
 G_BEGIN_DECLS
 
@@ -77,22 +78,22 @@ struct _ClutterStageWindowIface
   void              (* redraw)                  (ClutterStageWindow *stage_window);
 
   void              (* get_dirty_pixel)         (ClutterStageWindow *stage_window,
+                                                 ClutterStageView   *view,
                                                  int *x, int *y);
 
-  CoglFramebuffer  *(* get_active_framebuffer)  (ClutterStageWindow *stage_window);
-
   gboolean          (* can_clip_redraws)        (ClutterStageWindow *stage_window);
 
   void              (* set_scale_factor)        (ClutterStageWindow *stage_window,
                                                  int                 factor);
   int               (* get_scale_factor)        (ClutterStageWindow *stage_window);
-  CoglFramebuffer  *(* get_legacy_onscreen)     (ClutterStageWindow *stage_window);
+  GList            *(* get_views)               (ClutterStageWindow *stage_window);
   CoglFrameClosure *(* set_frame_callback)      (ClutterStageWindow *stage_window,
                                                  CoglFrameCallback   callback,
                                                  gpointer            user_data);
   void              (* remove_frame_callback)   (ClutterStageWindow *stage_window,
                                                  CoglFrameClosure   *closure);
   int64_t           (* get_frame_counter)       (ClutterStageWindow *stage_window);
+  void              (* finish_frame)            (ClutterStageWindow *stage_window);
 };
 
 CLUTTER_AVAILABLE_IN_MUTTER
@@ -139,17 +140,16 @@ void              _clutter_stage_window_set_accept_focus        (ClutterStageWin
 void              _clutter_stage_window_redraw                  (ClutterStageWindow *window);
 
 void              _clutter_stage_window_get_dirty_pixel         (ClutterStageWindow *window,
+                                                                 ClutterStageView   *view,
                                                                  int *x, int *y);
 
-CoglFramebuffer  *_clutter_stage_window_get_active_framebuffer  (ClutterStageWindow *window);
-
 gboolean          _clutter_stage_window_can_clip_redraws        (ClutterStageWindow *window);
 
 void              _clutter_stage_window_set_scale_factor        (ClutterStageWindow *window,
                                                                  int                 factor);
 int               _clutter_stage_window_get_scale_factor        (ClutterStageWindow *window);
 
-CoglFramebuffer  *_clutter_stage_window_get_legacy_onscreen     (ClutterStageWindow *stage_window);
+GList *           _clutter_stage_window_get_views               (ClutterStageWindow *window);
 
 CoglFrameClosure *_clutter_stage_window_set_frame_callback      (ClutterStageWindow *window,
                                                                  CoglFrameCallback   callback,
@@ -158,6 +158,8 @@ CoglFrameClosure *_clutter_stage_window_set_frame_callback      (ClutterStageWin
 void              _clutter_stage_window_remove_frame_callback   (ClutterStageWindow *stage_winow,
                                                                  CoglFrameClosure   *closure);
 
+void              _clutter_stage_window_finish_frame            (ClutterStageWindow *window);
+
 int64_t           _clutter_stage_window_get_frame_counter       (ClutterStageWindow *window);
 
 G_END_DECLS
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
index ac5a356..6e53435 100644
--- a/clutter/clutter/clutter-stage.c
+++ b/clutter/clutter/clutter-stage.c
@@ -158,8 +158,6 @@ struct _ClutterStagePrivate
   guint throttle_motion_events : 1;
   guint use_alpha              : 1;
   guint min_size_changed       : 1;
-  guint dirty_viewport         : 1;
-  guint dirty_projection       : 1;
   guint accept_focus           : 1;
   guint motion_events_enabled  : 1;
   guint has_custom_perspective : 1;
@@ -602,7 +600,8 @@ _cogl_util_get_eye_planes_for_screen_poly (float *polygon,
 }
 
 static void
-_clutter_stage_update_active_framebuffer (ClutterStage *stage)
+_clutter_stage_update_active_framebuffer (ClutterStage    *stage,
+                                          CoglFramebuffer *framebuffer)
 {
   ClutterStagePrivate *priv = stage->priv;
 
@@ -611,34 +610,27 @@ _clutter_stage_update_active_framebuffer (ClutterStage *stage)
    * offscreen framebuffer.
    */
 
-  priv->active_framebuffer =
-    _clutter_stage_window_get_active_framebuffer (priv->impl);
-
-  if (!priv->active_framebuffer)
-    priv->active_framebuffer = cogl_get_draw_framebuffer ();
+  priv->active_framebuffer = framebuffer;
 }
 
-/* This provides a common point of entry for painting the scenegraph
- * for picking or painting...
- *
- * XXX: Instead of having a toplevel 2D clip region, it might be
+/* XXX: Instead of having a toplevel 2D clip region, it might be
  * better to have a clip volume within the view frustum. This could
  * allow us to avoid projecting actors into window coordinates to
  * be able to cull them.
  */
-void
-_clutter_stage_do_paint (ClutterStage                *stage,
-                         const cairo_rectangle_int_t *clip)
+static void
+clutter_stage_do_paint_view (ClutterStage                *stage,
+                             ClutterStageView            *view,
+                             const cairo_rectangle_int_t *clip)
 {
   ClutterStagePrivate *priv = stage->priv;
+  CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
+  cairo_rectangle_int_t view_layout;
   float clip_poly[8];
   float viewport[4];
   cairo_rectangle_int_t geom;
   int window_scale;
 
-  if (priv->impl == NULL)
-    return;
-
   _clutter_stage_window_get_geometry (priv->impl, &geom);
   window_scale = _clutter_stage_window_get_scale_factor (priv->impl);
 
@@ -647,29 +639,26 @@ _clutter_stage_do_paint (ClutterStage                *stage,
   viewport[2] = priv->viewport[2] * window_scale;
   viewport[3] = priv->viewport[3] * window_scale;
 
-  if (clip)
+  if (!clip)
     {
-      clip_poly[0] = MAX (clip->x * window_scale, 0);
-      clip_poly[1] = MAX (clip->y * window_scale, 0);
-      clip_poly[2] = MIN ((clip->x + clip->width) * window_scale, geom.width * window_scale);
-      clip_poly[3] = clip_poly[1];
-      clip_poly[4] = clip_poly[2];
-      clip_poly[5] = MIN ((clip->y + clip->height) * window_scale, geom.height * window_scale);
-      clip_poly[6] = clip_poly[0];
-      clip_poly[7] = clip_poly[5];
-    }
-  else
-    {
-      clip_poly[0] = 0;
-      clip_poly[1] = 0;
-      clip_poly[2] = geom.width * window_scale;
-      clip_poly[3] = 0;
-      clip_poly[4] = geom.width * window_scale;
-      clip_poly[5] = geom.height * window_scale;
-      clip_poly[6] = 0;
-      clip_poly[7] = geom.height * window_scale;
+      clutter_stage_view_get_layout (view, &view_layout);
+      clip = &view_layout;
     }
 
+  clip_poly[0] = MAX (clip->x * window_scale, 0);
+  clip_poly[1] = MAX (clip->y * window_scale, 0);
+
+  clip_poly[2] = MIN ((clip->x + clip->width) * window_scale,
+                      geom.width * window_scale);
+  clip_poly[3] = clip_poly[1];
+
+  clip_poly[4] = clip_poly[2];
+  clip_poly[5] = MIN ((clip->y + clip->height) * window_scale,
+                      geom.height * window_scale);
+
+  clip_poly[6] = clip_poly[0];
+  clip_poly[7] = clip_poly[5];
+
   CLUTTER_NOTE (CLIPPING, "Setting stage clip too: "
                 "x=%f, y=%f, width=%f, height=%f",
                 clip_poly[0], clip_poly[1],
@@ -684,9 +673,24 @@ _clutter_stage_do_paint (ClutterStage                *stage,
                                              priv->current_clip_planes);
 
   _clutter_stage_paint_volume_stack_free_all (stage);
-  _clutter_stage_update_active_framebuffer (stage);
+  _clutter_stage_update_active_framebuffer (stage, framebuffer);
   clutter_actor_paint (CLUTTER_ACTOR (stage));
+}
 
+/* This provides a common point of entry for painting the scenegraph
+ * for picking or painting...
+ */
+void
+_clutter_stage_paint_view (ClutterStage                *stage,
+                           ClutterStageView            *view,
+                           const cairo_rectangle_int_t *clip)
+{
+  ClutterStagePrivate *priv = stage->priv;
+
+  if (!priv->impl)
+    return;
+
+  clutter_stage_do_paint_view (stage, view, clip);
   g_signal_emit (stage, stage_signals[AFTER_PAINT], 0);
 }
 
@@ -736,31 +740,10 @@ clutter_stage_realize (ClutterActor *self)
   ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
   gboolean is_realized;
 
-  /* Make sure the viewport and projection matrix are valid for the
-   * first paint (which will likely occur before the ConfigureNotify
-   * is received)
-   */
-  priv->dirty_viewport = TRUE;
-  priv->dirty_projection = TRUE;
-
   g_assert (priv->impl != NULL);
   is_realized = _clutter_stage_window_realize (priv->impl);
 
-  /* ensure that the stage is using the context if the
-   * realization sequence was successful
-   */
-  if (is_realized)
-    {
-      ClutterBackend *backend = clutter_get_default_backend ();
-
-      /* We want to select the context without calling
-         clutter_backend_ensure_context so that it doesn't call any
-         Cogl functions. Otherwise it would create the Cogl context
-         before we get a chance to check whether the GL version is
-         valid */
-      _clutter_backend_ensure_context_internal (backend, CLUTTER_STAGE (self));
-    }
-  else
+  if (!is_realized)
     CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
 }
 
@@ -774,8 +757,6 @@ clutter_stage_unrealize (ClutterActor *self)
   _clutter_stage_window_unrealize (priv->impl);
 
   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
-
-  clutter_stage_ensure_current (CLUTTER_STAGE (self));
 }
 
 static void
@@ -1106,7 +1087,6 @@ _clutter_stage_maybe_relayout (ClutterActor *actor)
 static void
 clutter_stage_do_redraw (ClutterStage *stage)
 {
-  ClutterBackend *backend = clutter_get_default_backend ();
   ClutterActor *actor = CLUTTER_ACTOR (stage);
   ClutterStagePrivate *priv = stage->priv;
 
@@ -1120,16 +1100,12 @@ clutter_stage_do_redraw (ClutterStage *stage)
                 _clutter_actor_get_debug_name (actor),
                 stage);
 
-  _clutter_backend_ensure_context (backend, stage);
-
   if (_clutter_context_get_show_fps ())
     {
       if (priv->fps_timer == NULL)
         priv->fps_timer = g_timer_new ();
     }
 
-  _clutter_stage_maybe_setup_viewport (stage);
-
   _clutter_stage_window_redraw (priv->impl);
 
   if (_clutter_context_get_show_fps ())
@@ -1371,67 +1347,82 @@ read_pixels_to_file (char *filename_stem,
   read_count++;
 }
 
-ClutterActor *
-_clutter_stage_do_pick (ClutterStage   *stage,
-                        gint            x,
-                        gint            y,
-                        ClutterPickMode mode)
+static ClutterActor *
+_clutter_stage_do_pick_on_view (ClutterStage     *stage,
+                                gint              x,
+                                gint              y,
+                                ClutterPickMode   mode,
+                                ClutterStageView *view)
 {
   ClutterActor *actor = CLUTTER_ACTOR (stage);
   ClutterStagePrivate *priv = stage->priv;
+  CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
+  cairo_rectangle_int_t view_layout;
   ClutterMainContext *context;
   guchar pixel[4] = { 0xff, 0xff, 0xff, 0xff };
   CoglColor stage_pick_id;
   gboolean dither_enabled_save;
   ClutterActor *retval;
-  CoglFramebuffer *fb;
   gint dirty_x;
   gint dirty_y;
   gint read_x;
   gint read_y;
-  float stage_width, stage_height;
   int window_scale;
+  float fb_width, fb_height;
+  int viewport_offset_x;
+  int viewport_offset_y;
 
   priv = stage->priv;
 
-  if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
-    return actor;
-
-  if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_NOP_PICKING))
-    return actor;
-
-  if (G_UNLIKELY (priv->impl == NULL))
-    return actor;
-
-  clutter_actor_get_size (CLUTTER_ACTOR (stage), &stage_width, &stage_height);
-  if (x < 0 || x >= stage_width || y < 0 || y >= stage_height)
-    return actor;
-
   context = _clutter_context_get_default ();
-  clutter_stage_ensure_current (stage);
   window_scale = _clutter_stage_window_get_scale_factor (priv->impl);
+  clutter_stage_view_get_layout (view, &view_layout);
 
-  fb = cogl_get_draw_framebuffer ();
-
-  _clutter_backend_ensure_context (context->backend, stage);
+  fb_width = view_layout.width;
+  fb_height = view_layout.height;
+  cogl_push_framebuffer (fb);
 
   /* needed for when a context switch happens */
-  _clutter_stage_maybe_setup_viewport (stage);
+  _clutter_stage_maybe_setup_viewport (stage, view);
+
+  /* FIXME: For some reason leaving the cogl clip stack empty causes the
+   * picking to not work at all, so setting it the whole framebuffer content
+   * for now. */
+  cogl_framebuffer_push_scissor_clip (fb, 0, 0,
+                                      view_layout.width,
+                                      view_layout.height);
 
-  _clutter_stage_window_get_dirty_pixel (priv->impl, &dirty_x, &dirty_y);
+  _clutter_stage_window_get_dirty_pixel (priv->impl, view, &dirty_x, &dirty_y);
+  dirty_x -= view_layout.x;
+  dirty_y -= view_layout.y;
 
   if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
-    cogl_framebuffer_push_scissor_clip (fb, dirty_x * window_scale, dirty_y * window_scale, 1, 1);
+    {
+      CLUTTER_NOTE (PICK, "Pushing pick scissor clip x: %d, y: %d, 1x1",
+                    dirty_x * window_scale,
+                    dirty_y * window_scale);
+      cogl_framebuffer_push_scissor_clip (fb, dirty_x * window_scale, dirty_y * window_scale, 1, 1);
+    }
 
-  cogl_set_viewport (priv->viewport[0] * window_scale - x * window_scale + dirty_x * window_scale,
-                     priv->viewport[1] * window_scale - y * window_scale + dirty_y * window_scale,
+  viewport_offset_x = x * window_scale - dirty_x * window_scale;
+  viewport_offset_y = y * window_scale - dirty_y * window_scale;
+  CLUTTER_NOTE (PICK, "Setting viewport to %f, %f, %f, %f",
+                priv->viewport[0] * window_scale - viewport_offset_x,
+                priv->viewport[1] * window_scale - viewport_offset_y,
+                priv->viewport[2] * window_scale,
+                priv->viewport[3] * window_scale);
+  cogl_set_viewport (priv->viewport[0] * window_scale - viewport_offset_x,
+                     priv->viewport[1] * window_scale - viewport_offset_y,
                      priv->viewport[2] * window_scale,
                      priv->viewport[3] * window_scale);
 
   read_x = dirty_x * window_scale;
   read_y = dirty_y * window_scale;
 
-  CLUTTER_NOTE (PICK, "Performing pick at %i,%i", x, y);
+  CLUTTER_NOTE (PICK, "Performing pick at %i,%i on view %dx%d+%d+%d",
+                x, y,
+                view_layout.width, view_layout.height,
+                view_layout.x, view_layout.y);
 
   cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255);
   cogl_clear (&stage_pick_id, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH);
@@ -1444,7 +1435,7 @@ _clutter_stage_do_pick (ClutterStage   *stage,
    * are drawn offscreen (as we never swap buffers)
   */
   context->pick_mode = mode;
-  _clutter_stage_do_paint (stage, NULL);
+  _clutter_stage_paint_view (stage, view, NULL);
   context->pick_mode = CLUTTER_PICK_NONE;
 
   /* Read the color of the screen co-ords pixel. RGBA_8888_PRE is used
@@ -1462,11 +1453,11 @@ _clutter_stage_do_pick (ClutterStage   *stage,
   if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
     {
       char *file_name =
-        g_strconcat ("pick-buffer-",
-                     _clutter_actor_get_debug_name (actor),
-                     NULL);
+        g_strdup_printf ("pick-buffer-%s-view-x-%d",
+                         _clutter_actor_get_debug_name (actor),
+                         view_layout.x);
 
-      read_pixels_to_file (file_name, 0, 0, stage_width, stage_height);
+      read_pixels_to_file (file_name, 0, 0, fb_width, fb_height);
 
       g_free (file_name);
     }
@@ -1477,6 +1468,8 @@ _clutter_stage_do_pick (ClutterStage   *stage,
   if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
     cogl_framebuffer_pop_clip (fb);
 
+  cogl_framebuffer_pop_clip (fb);
+
   _clutter_stage_dirty_viewport (stage);
 
   if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
@@ -1486,11 +1479,74 @@ _clutter_stage_do_pick (ClutterStage   *stage,
       guint32 id_ = _clutter_pixel_to_id (pixel);
 
       retval = _clutter_stage_get_actor_by_pick_id (stage, id_);
+      CLUTTER_NOTE (PICK, "Picking actor %s with id %u (pixel: 0x%x%x%x%x",
+                    G_OBJECT_TYPE_NAME (retval),
+                    id_,
+                    pixel[0], pixel[1], pixel[2], pixel[3]);
     }
 
+  cogl_pop_framebuffer ();
+
   return retval;
 }
 
+static ClutterStageView *
+get_view_at (ClutterStage *stage,
+             int           x,
+             int           y)
+{
+  ClutterStagePrivate *priv = stage->priv;
+  GList *l;
+
+  for (l = _clutter_stage_window_get_views (priv->impl); l; l = l->next)
+    {
+      ClutterStageView *view = l->data;
+      cairo_rectangle_int_t view_layout;
+
+      clutter_stage_view_get_layout (view, &view_layout);
+      if (x >= view_layout.x &&
+          x < view_layout.x + view_layout.width &&
+          y >= view_layout.y &&
+          y < view_layout.y + view_layout.height)
+        return view;
+    }
+
+  return NULL;
+}
+
+ClutterActor *
+_clutter_stage_do_pick (ClutterStage   *stage,
+                        gint            x,
+                        gint            y,
+                        ClutterPickMode mode)
+{
+  ClutterActor *actor = CLUTTER_ACTOR (stage);
+  ClutterStagePrivate *priv = stage->priv;
+  float stage_width, stage_height;
+  ClutterStageView *view = NULL;
+
+  priv = stage->priv;
+
+  if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
+    return actor;
+
+  if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_NOP_PICKING))
+    return actor;
+
+  if (G_UNLIKELY (priv->impl == NULL))
+    return actor;
+
+  clutter_actor_get_size (CLUTTER_ACTOR (stage), &stage_width, &stage_height);
+  if (x < 0 || x >= stage_width || y < 0 || y >= stage_height)
+    return actor;
+
+  view = get_view_at (stage, x, y);
+  if (view)
+    return _clutter_stage_do_pick_on_view (stage, x, y, mode, view);
+
+  return actor;
+}
+
 static gboolean
 clutter_stage_real_delete_event (ClutterStage *stage,
                                  ClutterEvent *event)
@@ -2339,7 +2395,7 @@ clutter_stage_set_perspective_internal (ClutterStage       *stage,
   cogl_matrix_get_inverse (&priv->projection,
                            &priv->inverse_projection);
 
-  priv->dirty_projection = TRUE;
+  _clutter_stage_dirty_projection (stage);
   clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
 }
 
@@ -2419,7 +2475,19 @@ _clutter_stage_get_projection_matrix (ClutterStage *stage,
 void
 _clutter_stage_dirty_projection (ClutterStage *stage)
 {
-  stage->priv->dirty_projection = TRUE;
+  ClutterStagePrivate *priv;
+  GList *l;
+
+  g_return_if_fail (CLUTTER_IS_STAGE (stage));
+
+  priv = stage->priv;
+
+  for (l = _clutter_stage_window_get_views (priv->impl); l; l = l->next)
+    {
+      ClutterStageView *view = l->data;
+
+      clutter_stage_view_set_dirty_projection (view, TRUE);
+    }
 }
 
 /*
@@ -2484,7 +2552,7 @@ _clutter_stage_set_viewport (ClutterStage *stage,
   priv->viewport[2] = width;
   priv->viewport[3] = height;
 
-  priv->dirty_viewport = TRUE;
+  _clutter_stage_dirty_viewport (stage);
 
   queue_full_redraw (stage);
 }
@@ -2496,7 +2564,19 @@ _clutter_stage_set_viewport (ClutterStage *stage,
 void
 _clutter_stage_dirty_viewport (ClutterStage *stage)
 {
-  stage->priv->dirty_viewport = TRUE;
+  ClutterStagePrivate *priv;
+  GList *l;
+
+  g_return_if_fail (CLUTTER_IS_STAGE (stage));
+
+  priv = stage->priv;
+
+  for (l = _clutter_stage_window_get_views (priv->impl); l; l = l->next)
+    {
+      ClutterStageView *view = l->data;
+
+      clutter_stage_view_set_dirty_viewport (view, TRUE);
+    }
 }
 
 /*
@@ -2758,14 +2838,18 @@ clutter_stage_read_pixels (ClutterStage *stage,
                            gint          width,
                            gint          height)
 {
+  ClutterStagePrivate *priv;
   ClutterActorBox box;
-  guchar *pixels;
+  GList *l;
+  ClutterStageView *view;
+  cairo_region_t *clip;
+  cairo_rectangle_int_t clip_rect;
+  CoglFramebuffer *framebuffer;
+  uint8_t *pixels;
 
   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
 
-  /* Force a redraw of the stage before reading back pixels */
-  clutter_stage_ensure_current (stage);
-  clutter_actor_paint (CLUTTER_ACTOR (stage));
+  priv = stage->priv;
 
   clutter_actor_get_allocation_box (CLUTTER_ACTOR (stage), &box);
 
@@ -2775,12 +2859,42 @@ clutter_stage_read_pixels (ClutterStage *stage,
   if (height < 0)
     height = ceilf (box.y2 - box.y1);
 
-  pixels = g_malloc (height * width * 4);
+  l = _clutter_stage_window_get_views (priv->impl);
 
-  cogl_read_pixels (x, y, width, height,
-                    COGL_READ_PIXELS_COLOR_BUFFER,
-                    COGL_PIXEL_FORMAT_RGBA_8888,
-                    pixels);
+  if (!l)
+    return NULL;
+
+  /* XXX: We only read the first view. Needs different API for multi view screen
+   * capture. */
+  view = l->data;
+
+  clutter_stage_view_get_layout (view, &clip_rect);
+  clip = cairo_region_create_rectangle (&clip_rect);
+  cairo_region_intersect_rectangle (clip,
+                                    &(cairo_rectangle_int_t) {
+                                      .x = x,
+                                      .y = y,
+                                      .width = width,
+                                      .height = height,
+                                    });
+  cairo_region_get_extents (clip, &clip_rect);
+  cairo_region_destroy (clip);
+
+  if (clip_rect.width == 0 || clip_rect.height == 0)
+    return NULL;
+
+  framebuffer = clutter_stage_view_get_framebuffer (view);
+  cogl_push_framebuffer (framebuffer);
+  clutter_stage_do_paint_view (stage, view, &clip_rect);
+
+  pixels = g_malloc0 (clip_rect.width * clip_rect.height * 4);
+  cogl_framebuffer_read_pixels (framebuffer,
+                                clip_rect.x, clip_rect.y,
+                                clip_rect.width, clip_rect.height,
+                                COGL_PIXEL_FORMAT_RGBA_8888,
+                                pixels);
+
+  cogl_pop_framebuffer ();
 
   return pixels;
 }
@@ -3241,16 +3355,12 @@ clutter_stage_new (void)
  * be used by applications.
  *
  * Since: 0.8
+ * Deprecated: mutter: This function does not do anything.
  */
 void
 clutter_stage_ensure_current (ClutterStage *stage)
 {
-  ClutterBackend *backend;
-
   g_return_if_fail (CLUTTER_IS_STAGE (stage));
-
-  backend = clutter_get_default_backend ();
-  _clutter_backend_ensure_context (backend, stage);
 }
 
 /**
@@ -3425,14 +3535,18 @@ calculate_z_translation (float z_near)
 }
 
 void
-_clutter_stage_maybe_setup_viewport (ClutterStage *stage)
+_clutter_stage_maybe_setup_viewport (ClutterStage     *stage,
+                                     ClutterStageView *view)
 {
   ClutterStagePrivate *priv = stage->priv;
 
-  if (priv->dirty_viewport)
+  if (clutter_stage_view_is_dirty_viewport (view))
     {
+      cairo_rectangle_int_t view_layout;
       ClutterPerspective perspective;
       int window_scale;
+      int viewport_offset_x;
+      int viewport_offset_y;
       float z_2d;
 
       CLUTTER_NOTE (PAINT,
@@ -3441,9 +3555,12 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage)
                     priv->viewport[3]);
 
       window_scale = _clutter_stage_window_get_scale_factor (priv->impl);
+      clutter_stage_view_get_layout (view, &view_layout);
 
-      cogl_set_viewport (priv->viewport[0] * window_scale,
-                         priv->viewport[1] * window_scale,
+      viewport_offset_x = view_layout.x * window_scale;
+      viewport_offset_y = view_layout.y * window_scale;
+      cogl_set_viewport (priv->viewport[0] * window_scale - viewport_offset_x,
+                         priv->viewport[1] * window_scale - viewport_offset_y,
                          priv->viewport[2] * window_scale,
                          priv->viewport[3] * window_scale);
 
@@ -3481,14 +3598,14 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage)
 
       clutter_stage_apply_scale (stage);
 
-      priv->dirty_viewport = FALSE;
+      clutter_stage_view_set_dirty_viewport (view, FALSE);
     }
 
-  if (priv->dirty_projection)
+  if (clutter_stage_view_is_dirty_projection (view))
     {
       cogl_set_projection_matrix (&priv->projection);
 
-      priv->dirty_projection = FALSE;
+      clutter_stage_view_set_dirty_projection (view, FALSE);
     }
 }
 
diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h
index 8a55efb..47cff93 100644
--- a/clutter/clutter/clutter-stage.h
+++ b/clutter/clutter/clutter-stage.h
@@ -229,9 +229,6 @@ guchar *        clutter_stage_read_pixels                       (ClutterStage
 CLUTTER_AVAILABLE_IN_ALL
 void            clutter_stage_get_redraw_clip_bounds            (ClutterStage          *stage,
                                                                  cairo_rectangle_int_t *clip);
-
-CLUTTER_AVAILABLE_IN_ALL
-void            clutter_stage_ensure_current                    (ClutterStage          *stage);
 CLUTTER_AVAILABLE_IN_ALL
 void            clutter_stage_ensure_viewport                   (ClutterStage          *stage);
 CLUTTER_AVAILABLE_IN_ALL
diff --git a/clutter/clutter/clutter-util.c b/clutter/clutter/clutter-util.c
index 04c2ca1..14ef740 100644
--- a/clutter/clutter/clutter-util.c
+++ b/clutter/clutter/clutter-util.c
@@ -161,6 +161,39 @@ _clutter_util_rectangle_union (const cairo_rectangle_int_t *src1,
   dest->y = dest_y;
 }
 
+gboolean
+_clutter_util_rectangle_intersection (const cairo_rectangle_int_t *src1,
+                                      const cairo_rectangle_int_t *src2,
+                                      cairo_rectangle_int_t       *dest)
+{
+  int x1, y1, x2, y2;
+
+  x1 = MAX (src1->x, src2->x);
+  y1 = MAX (src1->y, src2->y);
+
+  x2 = MIN (src1->x + (int) src1->width,  src2->x + (int) src2->width);
+  y2 = MIN (src1->y + (int) src1->height, src2->y + (int) src2->height);
+
+  if (x1 >= x2 || y1 >= y2)
+    {
+      dest->x = 0;
+      dest->y = 0;
+      dest->width  = 0;
+      dest->height = 0;
+
+      return FALSE;
+    }
+  else
+    {
+      dest->x = x1;
+      dest->y = y1;
+      dest->width  = x2 - x1;
+      dest->height = y2 - y1;
+
+      return TRUE;
+    }
+}
+
 float
 _clutter_util_matrix_determinant (const ClutterMatrix *matrix)
 {
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
index 90bc26f..07e10a2 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
@@ -36,6 +36,8 @@
 
 #include "clutter-stage-cogl.h"
 
+#include <stdlib.h>
+
 #include "clutter-actor-private.h"
 #include "clutter-backend-private.h"
 #include "clutter-debug.h"
@@ -46,6 +48,18 @@
 #include "clutter-private.h"
 #include "clutter-stage-private.h"
 
+typedef struct _ClutterStageViewCoglPrivate
+{
+  /* Stores a list of previous damaged areas in the stage coordinate space */
+#define DAMAGE_HISTORY_MAX 16
+#define DAMAGE_HISTORY(x) ((x) & (DAMAGE_HISTORY_MAX - 1))
+  cairo_rectangle_int_t damage_history[DAMAGE_HISTORY_MAX];
+  unsigned int damage_index;
+} ClutterStageViewCoglPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageViewCogl, clutter_stage_view_cogl,
+                            CLUTTER_TYPE_STAGE_VIEW)
+
 static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
 
 G_DEFINE_TYPE_WITH_CODE (ClutterStageCogl,
@@ -74,8 +88,6 @@ clutter_stage_cogl_unrealize (ClutterStageWindow *stage_window)
                                                    stage_cogl->frame_closure);
       stage_cogl->frame_closure = NULL;
     }
-
-  stage_cogl->pending_swaps = 0;
 }
 
 static void
@@ -340,51 +352,156 @@ clutter_stage_cogl_get_redraw_clip_bounds (ClutterStageWindow    *stage_window,
 }
 
 static inline gboolean
-valid_buffer_age (ClutterStageCogl *stage_cogl, int age)
+valid_buffer_age (ClutterStageViewCogl *view_cogl,
+                  int                   age)
 {
+  ClutterStageViewCoglPrivate *view_priv =
+    clutter_stage_view_cogl_get_instance_private (view_cogl);
+
   if (age <= 0)
     return FALSE;
 
-  return age < MIN (stage_cogl->damage_index, DAMAGE_HISTORY_MAX);
+  return age < MIN (view_priv->damage_index, DAMAGE_HISTORY_MAX);
+}
+
+static gboolean
+swap_framebuffer (ClutterStageWindow    *stage_window,
+                  ClutterStageView      *view,
+                  cairo_rectangle_int_t *swap_region,
+                  gboolean               swap_with_damage)
+{
+  CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
+  int damage[4], ndamage;
+
+  damage[0] = swap_region->x;
+  damage[1] = swap_region->y;
+  damage[2] = swap_region->width;
+  damage[3] = swap_region->height;
+
+  if (swap_region->width != 0)
+    ndamage = 1;
+  else
+    ndamage = 0;
+
+  if (cogl_is_onscreen (framebuffer))
+    {
+      CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+
+      /* push on the screen */
+      if (ndamage == 1 && !swap_with_damage)
+        {
+          CLUTTER_NOTE (BACKEND,
+                        "cogl_onscreen_swap_region (onscreen: %p, "
+                        "x: %d, y: %d, "
+                        "width: %d, height: %d)",
+                        onscreen,
+                        damage[0], damage[1], damage[2], damage[3]);
+
+          cogl_onscreen_swap_region (onscreen,
+                                     damage, ndamage);
+
+          return FALSE;
+        }
+      else
+        {
+          CLUTTER_NOTE (BACKEND, "cogl_onscreen_swap_buffers (onscreen: %p)",
+                        onscreen);
+
+          cogl_onscreen_swap_buffers_with_damage (onscreen,
+                                                  damage, ndamage);
+
+          return TRUE;
+        }
+    }
+  else
+    {
+      CLUTTER_NOTE (BACKEND, "cogl_framebuffer_finish (framebuffer: %p)",
+                    framebuffer);
+      cogl_framebuffer_finish (framebuffer);
+
+      return FALSE;
+    }
 }
 
-/* XXX: This is basically identical to clutter_stage_glx_redraw */
 static void
-clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
+paint_stage (ClutterStageCogl            *stage_cogl,
+             ClutterStageView            *view,
+             const cairo_rectangle_int_t *clip)
+{
+  ClutterStage *stage = stage_cogl->wrapper;
+
+  _clutter_stage_maybe_setup_viewport (stage, view);
+  _clutter_stage_paint_view (stage, view, clip);
+}
+
+static void
+fill_current_damage_history_and_step (ClutterStageView *view)
+{
+  ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
+  ClutterStageViewCoglPrivate *view_priv =
+    clutter_stage_view_cogl_get_instance_private (view_cogl);
+  cairo_rectangle_int_t view_rect;
+  cairo_rectangle_int_t *current_damage;
+
+  current_damage =
+    &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index)];
+  clutter_stage_view_get_layout (view, &view_rect);
+
+  *current_damage = view_rect;
+  view_priv->damage_index++;
+}
+
+static gboolean
+clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
+                                ClutterStageView   *view)
 {
   ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
-  CoglOnscreen *onscreen;
-  cairo_rectangle_int_t geom;
+  ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
+  ClutterStageViewCoglPrivate *view_priv =
+    clutter_stage_view_cogl_get_instance_private (view_cogl);
+  CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
+  cairo_rectangle_int_t view_rect;
   gboolean have_clip;
   gboolean may_use_clipped_redraw;
   gboolean use_clipped_redraw;
   gboolean can_blit_sub_buffer;
   gboolean has_buffer_age;
+  gboolean do_swap_buffer;
+  gboolean swap_with_damage;
   ClutterActor *wrapper;
-  cairo_rectangle_int_t *clip_region;
-  int damage[4], ndamage;
-  gboolean force_swap;
+  cairo_rectangle_int_t redraw_clip;
+  cairo_rectangle_int_t swap_region;
+  cairo_rectangle_int_t clip_region;
+  gboolean clip_region_empty;
   int window_scale;
 
   wrapper = CLUTTER_ACTOR (stage_cogl->wrapper);
 
-  onscreen = _clutter_stage_window_get_legacy_onscreen (stage_window);
-  if (!onscreen)
-    return;
+  clutter_stage_view_get_layout (view, &view_rect);
 
   can_blit_sub_buffer =
+    cogl_is_onscreen (fb) &&
     cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION);
 
-  has_buffer_age = cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
-
-  _clutter_stage_window_get_geometry (stage_window, &geom);
+  has_buffer_age =
+    cogl_is_onscreen (fb) &&
+    cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
 
   /* NB: a zero width redraw clip == full stage redraw */
-  have_clip = (stage_cogl->bounding_redraw_clip.width != 0 &&
-              !(stage_cogl->bounding_redraw_clip.x == 0 &&
-                stage_cogl->bounding_redraw_clip.y == 0 &&
-                stage_cogl->bounding_redraw_clip.width == geom.width &&
-                stage_cogl->bounding_redraw_clip.height == geom.height));
+  if (stage_cogl->bounding_redraw_clip.width == 0)
+    have_clip = FALSE;
+  else
+    {
+      redraw_clip = stage_cogl->bounding_redraw_clip;
+      _clutter_util_rectangle_intersection (&redraw_clip,
+                                            &view_rect,
+                                            &redraw_clip);
+
+      have_clip = !(redraw_clip.x == view_rect.x &&
+                    redraw_clip.y == view_rect.y &&
+                    redraw_clip.width == view_rect.width &&
+                    redraw_clip.height == view_rect.height);
+    }
 
   may_use_clipped_redraw = FALSE;
   if (_clutter_stage_window_can_clip_redraws (stage_window) &&
@@ -392,13 +509,15 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
       have_clip &&
       /* some drivers struggle to get going and produce some junk
        * frames when starting up... */
-      stage_cogl->frame_count > 3)
+      cogl_onscreen_get_frame_counter (COGL_ONSCREEN (fb)) > 3)
     {
       may_use_clipped_redraw = TRUE;
-      clip_region = &stage_cogl->bounding_redraw_clip;
+      clip_region = redraw_clip;
     }
   else
-    clip_region = NULL;
+    {
+      clip_region = (cairo_rectangle_int_t){ 0 };
+    }
 
   if (may_use_clipped_redraw &&
       G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
@@ -406,70 +525,87 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
   else
     use_clipped_redraw = FALSE;
 
-  force_swap = FALSE;
+  clip_region_empty = may_use_clipped_redraw && clip_region.width == 0;
 
   window_scale = _clutter_stage_window_get_scale_factor (stage_window);
 
+  swap_with_damage = FALSE;
   if (has_buffer_age)
     {
-      cairo_rectangle_int_t *current_damage =
-       &stage_cogl->damage_history[DAMAGE_HISTORY (stage_cogl->damage_index++)];
-
-      if (use_clipped_redraw)
-       {
-         int age = cogl_onscreen_get_buffer_age (onscreen), i;
-
-         *current_damage = *clip_region;
-
-         if (valid_buffer_age (stage_cogl, age))
-           {
-             for (i = 1; i <= age; i++)
-               _clutter_util_rectangle_union (clip_region,
-                                              &stage_cogl->damage_history[DAMAGE_HISTORY 
(stage_cogl->damage_index - i - 1)],
-                                              clip_region);
-
-             CLUTTER_NOTE (CLIPPING, "Reusing back buffer(age=%d) - repairing region: x=%d, y=%d, width=%d, 
height=%d\n",
-                           age,
-                           clip_region->x,
-                           clip_region->y,
-                           clip_region->width,
-                           clip_region->height);
-             force_swap = TRUE;
-           }
-         else
-           {
-             CLUTTER_NOTE (CLIPPING, "Invalid back buffer(age=%d): forcing full redraw\n", age);
-             use_clipped_redraw = FALSE;
-           }
-       }
-      else
-       {
-         current_damage->x = 0;
-         current_damage->y = 0;
-         current_damage->width  = geom.width;
-         current_damage->height = geom.height;
-       }
+      if (use_clipped_redraw && !clip_region_empty)
+        {
+          int age, i;
+          cairo_rectangle_int_t *current_damage =
+            &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index++)];
+
+          age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (fb));
+
+          if (valid_buffer_age (view_cogl, age))
+            {
+              *current_damage = clip_region;
+
+              for (i = 1; i <= age; i++)
+                {
+                  cairo_rectangle_int_t *damage =
+                    &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index - i - 1)];
+
+                  _clutter_util_rectangle_union (&clip_region, damage, &clip_region);
+                }
+
+              /* Update the bounding redraw clip state with the extra damage. */
+              _clutter_util_rectangle_union (&stage_cogl->bounding_redraw_clip,
+                                             &clip_region,
+                                             &stage_cogl->bounding_redraw_clip);
+
+              CLUTTER_NOTE (CLIPPING, "Reusing back buffer(age=%d) - repairing region: x=%d, y=%d, width=%d, 
height=%d\n",
+                            age,
+                            clip_region.x,
+                            clip_region.y,
+                            clip_region.width,
+                            clip_region.height);
+
+              swap_with_damage = TRUE;
+            }
+          else
+            {
+              CLUTTER_NOTE (CLIPPING, "Invalid back buffer(age=%d): forcing full redraw\n", age);
+              use_clipped_redraw = FALSE;
+              *current_damage = view_rect;
+            }
+        }
+      else if (!use_clipped_redraw)
+        {
+          fill_current_damage_history_and_step (view);
+        }
     }
 
-  if (use_clipped_redraw)
+  cogl_push_framebuffer (fb);
+  if (use_clipped_redraw && clip_region_empty)
     {
-      CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
+      CLUTTER_NOTE (CLIPPING, "Empty stage output paint\n");
+    }
+  else if (use_clipped_redraw)
+    {
+      int scissor_x;
+      int scissor_y;
 
       CLUTTER_NOTE (CLIPPING,
                     "Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n",
-                    clip_region->x,
-                    clip_region->y,
-                    clip_region->width,
-                    clip_region->height);
+                    clip_region.x,
+                    clip_region.y,
+                    clip_region.width,
+                    clip_region.height);
 
       stage_cogl->using_clipped_redraw = TRUE;
 
+      scissor_x = (clip_region.x - view_rect.x) * window_scale;
+      scissor_y = (clip_region.y - view_rect.y) * window_scale;
       cogl_framebuffer_push_scissor_clip (fb,
-                                          clip_region->x * window_scale,
-                                          clip_region->y * window_scale,
-                                          clip_region->width * window_scale,
-                                          clip_region->height * window_scale);
-      _clutter_stage_do_paint (CLUTTER_STAGE (wrapper), clip_region);
+                                          scissor_x,
+                                          scissor_y,
+                                          clip_region.width * window_scale,
+                                          clip_region.height * window_scale);
+      paint_stage (stage_cogl, view, &clip_region);
       cogl_framebuffer_pop_clip (fb);
 
       stage_cogl->using_clipped_redraw = FALSE;
@@ -481,26 +617,37 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
       /* If we are trying to debug redraw issues then we want to pass
        * the bounding_redraw_clip so it can be visualized */
       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS) &&
-          may_use_clipped_redraw)
+          may_use_clipped_redraw &&
+          !clip_region_empty)
         {
-          _clutter_stage_do_paint (CLUTTER_STAGE (wrapper), clip_region);
+          int scissor_x;
+          int scissor_y;
+
+          scissor_x = (clip_region.x - view_rect.x) * window_scale;;
+          scissor_y = (clip_region.y - view_rect.y) * window_scale;
+          cogl_framebuffer_push_scissor_clip (fb,
+                                              scissor_x,
+                                              scissor_y,
+                                              clip_region.width * window_scale,
+                                              clip_region.height * window_scale);
+          paint_stage (stage_cogl, view, &clip_region);
+          cogl_framebuffer_pop_clip (fb);
         }
       else
-        _clutter_stage_do_paint (CLUTTER_STAGE (wrapper), NULL);
+        paint_stage (stage_cogl, view, &view_rect);
     }
+  cogl_pop_framebuffer ();
 
   if (may_use_clipped_redraw &&
       G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)))
     {
-      CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
       CoglContext *ctx = cogl_framebuffer_get_context (fb);
       static CoglPipeline *outline = NULL;
-      cairo_rectangle_int_t *clip = &stage_cogl->bounding_redraw_clip;
       ClutterActor *actor = CLUTTER_ACTOR (wrapper);
-      float x_1 = clip->x * window_scale;
-      float x_2 = clip->x + clip->width * window_scale;
-      float y_1 = clip->y * window_scale;
-      float y_2 = clip->y + clip->height * window_scale;
+      float x_1 = redraw_clip.x;
+      float x_2 = redraw_clip.x + redraw_clip.width;
+      float y_1 = redraw_clip.y;
+      float y_2 = redraw_clip.y + redraw_clip.height;
       CoglVertexP2 quad[4] = {
         { x_1, y_1 },
         { x_2, y_1 },
@@ -525,9 +672,7 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
       cogl_matrix_init_identity (&modelview);
       _clutter_actor_apply_modelview_transform (actor, &modelview);
       cogl_framebuffer_set_modelview_matrix (fb, &modelview);
-      cogl_framebuffer_draw_primitive (COGL_FRAMEBUFFER (onscreen),
-                                       outline,
-                                       prim);
+      cogl_framebuffer_draw_primitive (fb, outline, prim);
       cogl_framebuffer_pop_matrix (fb);
       cogl_object_unref (prim);
     }
@@ -540,45 +685,77 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
    * the resize anyway so it should only exhibit temporary
    * artefacts.
    */
-  if (use_clipped_redraw || force_swap)
+  if (use_clipped_redraw)
     {
-      damage[0] = clip_region->x * window_scale;
-      damage[1] = clip_region->y * window_scale;
-      damage[2] = clip_region->width * window_scale;
-      damage[3] = clip_region->height * window_scale;
-      ndamage = 1;
+      if (use_clipped_redraw && clip_region_empty)
+        {
+          do_swap_buffer = FALSE;
+        }
+      else if (use_clipped_redraw)
+        {
+          swap_region = (cairo_rectangle_int_t) {
+            .x = (clip_region.x - view_rect.x) * window_scale,
+            .y = (clip_region.y - view_rect.y) * window_scale,
+            .width = clip_region.width * window_scale,
+            .height = clip_region.height * window_scale,
+          };
+          g_assert (swap_region.width > 0);
+          do_swap_buffer = TRUE;
+        }
+      else
+        {
+          swap_region = (cairo_rectangle_int_t) {
+            .x = 0,
+            .y = 0,
+            .width = view_rect.width * window_scale,
+            .height = view_rect.height * window_scale,
+          };
+          do_swap_buffer = TRUE;
+        }
     }
   else
     {
-      ndamage = 0;
+      swap_region = (cairo_rectangle_int_t) { 0 };
+      do_swap_buffer = TRUE;
     }
 
-  /* push on the screen */
-  if (use_clipped_redraw && !force_swap)
+  if (do_swap_buffer)
     {
-      CLUTTER_NOTE (BACKEND,
-                    "cogl_onscreen_swap_region (onscreen: %p, "
-                                                "x: %d, y: %d, "
-                                                "width: %d, height: %d)",
-                    onscreen,
-                    damage[0], damage[1], damage[2], damage[3]);
-
-      cogl_onscreen_swap_region (onscreen,
-                                damage, ndamage);
+      return swap_framebuffer (stage_window,
+                               view,
+                               &swap_region,
+                               swap_with_damage);
     }
   else
     {
-      CLUTTER_NOTE (BACKEND, "cogl_onscreen_swap_buffers (onscreen: %p)",
-                    onscreen);
+      return FALSE;
+    }
+}
 
+static void
+clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
+{
+  ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
+  gboolean swap_event = FALSE;
+  GList *l;
+
+  for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
+    {
+      ClutterStageView *view = l->data;
+
+      swap_event =
+        clutter_stage_cogl_redraw_view (stage_window, view) || swap_event;
+    }
+
+  _clutter_stage_window_finish_frame (stage_window);
+
+  if (swap_event)
+    {
       /* If we have swap buffer events then cogl_onscreen_swap_buffers
        * will return immediately and we need to track that there is a
        * swap in progress... */
       if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
         stage_cogl->pending_swaps++;
-
-      cogl_onscreen_swap_buffers_with_damage (onscreen,
-                                             damage, ndamage);
     }
 
   /* reset the redraw clipping for the next paint... */
@@ -587,22 +764,15 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
   stage_cogl->frame_count++;
 }
 
-static CoglFramebuffer *
-clutter_stage_cogl_get_active_framebuffer (ClutterStageWindow *stage_window)
-{
-  CoglOnscreen *onscreen =
-    _clutter_stage_window_get_legacy_onscreen (stage_window);
-
-  return COGL_FRAMEBUFFER (onscreen);
-}
-
 static void
 clutter_stage_cogl_get_dirty_pixel (ClutterStageWindow *stage_window,
+                                    ClutterStageView   *view,
                                     int                *x,
                                     int                *y)
 {
-  ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
-  gboolean has_buffer_age = cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
+  gboolean has_buffer_age =
+    cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
+  cairo_rectangle_int_t *rect;
 
   if (!has_buffer_age)
     {
@@ -611,9 +781,11 @@ clutter_stage_cogl_get_dirty_pixel (ClutterStageWindow *stage_window,
     }
   else
     {
-      cairo_rectangle_int_t *rect;
+      ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
+      ClutterStageViewCoglPrivate *view_priv =
+        clutter_stage_view_cogl_get_instance_private (view_cogl);
 
-      rect = &stage_cogl->damage_history[DAMAGE_HISTORY (stage_cogl->damage_index-1)];
+      rect = &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index - 1)];
       *x = rect->x;
       *y = rect->y;
     }
@@ -636,7 +808,6 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
   iface->ignoring_redraw_clips = clutter_stage_cogl_ignoring_redraw_clips;
   iface->get_redraw_clip_bounds = clutter_stage_cogl_get_redraw_clip_bounds;
   iface->redraw = clutter_stage_cogl_redraw;
-  iface->get_active_framebuffer = clutter_stage_cogl_get_active_framebuffer;
   iface->get_dirty_pixel = clutter_stage_cogl_get_dirty_pixel;
 }
 
@@ -683,3 +854,13 @@ _clutter_stage_cogl_init (ClutterStageCogl *stage)
 
   stage->update_time = -1;
 }
+
+static void
+clutter_stage_view_cogl_init (ClutterStageViewCogl *view_cogl)
+{
+}
+
+static void
+clutter_stage_view_cogl_class_init (ClutterStageViewCoglClass *klass)
+{
+}
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.h b/clutter/clutter/cogl/clutter-stage-cogl.h
index 690a012..6a4a773 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.h
+++ b/clutter/clutter/cogl/clutter-stage-cogl.h
@@ -11,6 +11,8 @@
 #include <X11/Xutil.h>
 #endif
 
+#include "clutter/clutter-stage-window.h"
+
 G_BEGIN_DECLS
 
 #define CLUTTER_TYPE_STAGE_COGL                  (_clutter_stage_cogl_get_type ())
@@ -25,6 +27,17 @@ typedef struct _ClutterStageCoglClass    ClutterStageCoglClass;
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterStageCogl, g_object_unref)
 
+#define CLUTTER_TYPE_STAGE_VIEW_COGL (clutter_stage_view_cogl_get_type ())
+CLUTTER_AVAILABLE_IN_MUTTER
+G_DECLARE_DERIVABLE_TYPE (ClutterStageViewCogl, clutter_stage_view_cogl,
+                          CLUTTER, STAGE_VIEW_COGL,
+                          ClutterStageView)
+
+struct _ClutterStageViewCoglClass
+{
+  ClutterStageViewClass parent_class;
+};
+
 struct _ClutterStageCogl
 {
   GObject parent_instance;
@@ -50,12 +63,6 @@ struct _ClutterStageCogl
 
   cairo_rectangle_int_t bounding_redraw_clip;
 
-  /* Stores a list of previous damaged areas */
-#define DAMAGE_HISTORY_MAX 16
-#define DAMAGE_HISTORY(x) ((x) & (DAMAGE_HISTORY_MAX - 1))
-  cairo_rectangle_int_t damage_history[DAMAGE_HISTORY_MAX];
-  unsigned int damage_index;
-
   guint initialized_redraw_clip : 1;
 
   /* TRUE if the current paint cycle has a clipped redraw. In that
diff --git a/clutter/clutter/deprecated/clutter-stage.h b/clutter/clutter/deprecated/clutter-stage.h
index e56e299..1a0f288 100644
--- a/clutter/clutter/deprecated/clutter-stage.h
+++ b/clutter/clutter/deprecated/clutter-stage.h
@@ -97,6 +97,9 @@ CLUTTER_DEPRECATED_IN_1_10_FOR(clutter_actor_get_background_color)
 void            clutter_stage_get_color         (ClutterStage       *stage,
                                                  ClutterColor       *color);
 
+CLUTTER_DEPRECATED_IN_MUTTER
+void            clutter_stage_ensure_current    (ClutterStage       *stage);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_STAGE_DEPRECATED_H__ */
diff --git a/clutter/clutter/x11/clutter-stage-x11.c b/clutter/clutter/x11/clutter-stage-x11.c
index cd5c3bc..2838292 100644
--- a/clutter/clutter/x11/clutter-stage-x11.c
+++ b/clutter/clutter/x11/clutter-stage-x11.c
@@ -445,6 +445,8 @@ clutter_stage_x11_unrealize (ClutterStageWindow *stage_window)
 
   clutter_stage_window_parent_iface->unrealize (stage_window);
 
+  g_list_free (stage_x11->legacy_views);
+  g_clear_object (&stage_x11->legacy_view);
   g_clear_pointer (&stage_x11->onscreen, cogl_object_unref);
 }
 
@@ -626,6 +628,11 @@ clutter_stage_x11_realize (ClutterStageWindow *stage_window)
 
   stage_x11->onscreen = cogl_onscreen_new (backend->cogl_context, width, height);
 
+  if (stage_x11->legacy_view)
+    g_object_set (G_OBJECT (stage_x11->legacy_view),
+                  "framebuffer", stage_x11->onscreen,
+                  NULL);
+
   /* We just created a window of the size of the actor. No need to fix
      the size of the stage, just update it. */
   stage_x11->xwin_width = width;
@@ -892,12 +899,34 @@ clutter_stage_x11_get_scale_factor (ClutterStageWindow *stage_window)
   return stage_x11->scale_factor;
 }
 
-static CoglFramebuffer *
-clutter_stage_x11_get_legacy_onscreen (ClutterStageWindow *stage_window)
+static void
+ensure_legacy_view (ClutterStageWindow *stage_window)
+{
+  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
+  cairo_rectangle_int_t view_layout;
+  CoglFramebuffer *framebuffer;
+
+  if (stage_x11->legacy_view)
+    return;
+
+  _clutter_stage_window_get_geometry (stage_window, &view_layout);
+  framebuffer = COGL_FRAMEBUFFER (stage_x11->onscreen);
+  stage_x11->legacy_view = g_object_new (CLUTTER_TYPE_STAGE_VIEW_COGL,
+                                         "layout", &view_layout,
+                                         "framebuffer", framebuffer,
+                                         NULL);
+  stage_x11->legacy_views = g_list_append (stage_x11->legacy_views,
+                                           stage_x11->legacy_view);
+}
+
+static GList *
+clutter_stage_x11_get_views (ClutterStageWindow *stage_window)
 {
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
 
-  return stage_x11->onscreen;
+  ensure_legacy_view (stage_window);
+
+  return stage_x11->legacy_views;
 }
 
 static CoglFrameClosure *
@@ -1007,7 +1036,7 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
   iface->can_clip_redraws = clutter_stage_x11_can_clip_redraws;
   iface->set_scale_factor = clutter_stage_x11_set_scale_factor;
   iface->get_scale_factor = clutter_stage_x11_get_scale_factor;
-  iface->get_legacy_onscreen = clutter_stage_x11_get_legacy_onscreen;
+  iface->get_views = clutter_stage_x11_get_views;
   iface->set_frame_callback = clutter_stage_x11_set_frame_callback;
   iface->remove_frame_callback = clutter_stage_x11_remove_frame_callback;
   iface->get_frame_counter = clutter_stage_x11_get_frame_counter;
@@ -1112,6 +1141,8 @@ clutter_stage_x11_translate_event (ClutterEventTranslator *translator,
       if (!stage_x11->is_foreign_xwin)
         {
           gboolean size_changed = FALSE;
+          int stage_width;
+          int stage_height;
 
           CLUTTER_NOTE (BACKEND, "ConfigureNotify[%x] (%d, %d)",
                         (unsigned int) stage_x11->xwin,
@@ -1131,9 +1162,9 @@ clutter_stage_x11_translate_event (ClutterEventTranslator *translator,
               stage_x11->xwin_height = xevent->xconfigure.height;
             }
 
-          clutter_actor_set_size (CLUTTER_ACTOR (stage),
-                                  xevent->xconfigure.width / stage_x11->scale_factor,
-                                  xevent->xconfigure.height / stage_x11->scale_factor);
+          stage_width = xevent->xconfigure.width / stage_x11->scale_factor;
+          stage_height = xevent->xconfigure.height / stage_x11->scale_factor;
+          clutter_actor_set_size (CLUTTER_ACTOR (stage), stage_width, stage_height);
 
           if (size_changed)
             {
@@ -1194,6 +1225,22 @@ clutter_stage_x11_translate_event (ClutterEventTranslator *translator,
                * to set up the GL viewport with the new size
                */
               clutter_stage_ensure_viewport (stage);
+
+              /* If this was a result of the Xrandr change when running as a
+               * X11 compositing manager, we need to reset the legacy
+               * stage view, now that it has a new size.
+               */
+              if (stage_x11->legacy_view)
+                {
+                  cairo_rectangle_int_t view_layout = {
+                    .width = stage_width,
+                    .height = stage_height
+                  };
+
+                  g_object_set (G_OBJECT (stage_x11->legacy_view),
+                                "layout", &view_layout,
+                                NULL);
+                }
             }
         }
       break;
@@ -1463,12 +1510,6 @@ set_foreign_window_callback (ClutterActor *actor,
   g_hash_table_insert (clutter_stages_by_xid,
                        GINT_TO_POINTER (fwd->stage_x11->xwin),
                        fwd->stage_x11);
-
-  /* calling this with the stage unrealized will unset the stage
-   * from the GL context; once the stage is realized the GL context
-   * will be set again
-   */
-  clutter_stage_ensure_current (CLUTTER_STAGE (actor));
 }
 
 /**
diff --git a/clutter/clutter/x11/clutter-stage-x11.h b/clutter/clutter/x11/clutter-stage-x11.h
index f15ce9b..e1ee033 100644
--- a/clutter/clutter/x11/clutter-stage-x11.h
+++ b/clutter/clutter/x11/clutter-stage-x11.h
@@ -58,6 +58,9 @@ struct _ClutterStageX11
   gint xwin_width;
   gint xwin_height; /* FIXME target_width / height */
 
+  ClutterStageView *legacy_view;
+  GList *legacy_views;
+
   gchar *title;
 
   guint clipped_redraws_cool_off;
diff --git a/src/Makefile.am b/src/Makefile.am
index b378f9f..988227c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -107,6 +107,8 @@ libmutter_la_SOURCES =                              \
        backends/meta-stage.c                   \
        backends/meta-renderer.c                \
        backends/meta-renderer.h                \
+       backends/meta-renderer-view.c           \
+       backends/meta-renderer-view.h           \
        backends/edid-parse.c                   \
        backends/edid.h                         \
        backends/x11/meta-backend-x11.c                 \
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index 109e43f..08b2499 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -106,6 +106,8 @@ struct _MetaBackendClass
 
 void meta_init_backend (MetaBackendType backend_type);
 
+ClutterBackend * meta_backend_get_clutter_backend (MetaBackend *backend);
+
 MetaIdleMonitor * meta_backend_get_idle_monitor (MetaBackend *backend,
                                                  int          device_id);
 MetaMonitorManager * meta_backend_get_monitor_manager (MetaBackend *backend);
diff --git a/src/backends/meta-renderer-view.c b/src/backends/meta-renderer-view.c
new file mode 100644
index 0000000..6c9b2b2
--- /dev/null
+++ b/src/backends/meta-renderer-view.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "backends/meta-renderer-view.h"
+
+#include "backends/meta-renderer.h"
+#include "clutter/clutter-mutter.h"
+
+struct _MetaRendererView
+{
+  ClutterStageView parent;
+
+  MetaMonitorInfo *monitor_info;
+};
+
+G_DEFINE_TYPE (MetaRendererView, meta_renderer_view,
+               CLUTTER_TYPE_STAGE_VIEW_COGL)
+
+static void
+meta_renderer_view_init (MetaRendererView *view)
+{
+}
+
+static void
+meta_renderer_view_class_init (MetaRendererViewClass *klass)
+{
+}
diff --git a/src/backends/meta-renderer-view.h b/src/backends/meta-renderer-view.h
new file mode 100644
index 0000000..0f08760
--- /dev/null
+++ b/src/backends/meta-renderer-view.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef META_RENDERER_VIEW_H
+#define META_RENDERER_VIEW_H
+
+#include "backends/meta-monitor-manager-private.h"
+#include "clutter/clutter-mutter.h"
+
+#define META_TYPE_RENDERER_VIEW (meta_renderer_view_get_type ())
+G_DECLARE_FINAL_TYPE (MetaRendererView, meta_renderer_view,
+                      META, RENDERER_VIEW,
+                      ClutterStageViewCogl)
+
+#endif /* META_RENDERER_VIEW_H */
diff --git a/src/backends/meta-renderer.c b/src/backends/meta-renderer.c
index dd6376d..ff5fd6e 100644
--- a/src/backends/meta-renderer.c
+++ b/src/backends/meta-renderer.c
@@ -26,9 +26,15 @@
 
 #include <glib-object.h>
 
+#include "backends/meta-backend-private.h"
 #include "backends/meta-renderer.h"
 
-G_DEFINE_TYPE (MetaRenderer, meta_renderer, G_TYPE_OBJECT)
+typedef struct _MetaRendererPrivate
+{
+  GList *views;
+} MetaRendererPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (MetaRenderer, meta_renderer, G_TYPE_OBJECT)
 
 CoglRenderer *
 meta_renderer_create_cogl_renderer (MetaRenderer *renderer)
@@ -36,6 +42,69 @@ meta_renderer_create_cogl_renderer (MetaRenderer *renderer)
   return META_RENDERER_GET_CLASS (renderer)->create_cogl_renderer (renderer);
 }
 
+static MetaRendererView *
+meta_renderer_create_view (MetaRenderer    *renderer,
+                           MetaMonitorInfo *monitor_info)
+{
+  return META_RENDERER_GET_CLASS (renderer)->create_view (renderer,
+                                                          monitor_info);
+}
+
+void
+meta_renderer_rebuild_views (MetaRenderer *renderer)
+{
+  MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer);
+  MetaBackend *backend = meta_get_backend ();
+  MetaMonitorManager *monitor_manager =
+    meta_backend_get_monitor_manager (backend);
+  MetaMonitorInfo *monitor_infos;
+  unsigned int num_monitor_infos;
+  unsigned int i;
+
+  g_list_free_full (priv->views, g_object_unref);
+  priv->views = NULL;
+
+  monitor_infos = meta_monitor_manager_get_monitor_infos (monitor_manager,
+                                                          &num_monitor_infos);
+
+  for (i = 0; i < num_monitor_infos; i++)
+    {
+      MetaRendererView *view;
+
+      view = meta_renderer_create_view (renderer, &monitor_infos[i]);
+      priv->views = g_list_append (priv->views, view);
+    }
+}
+
+void
+meta_renderer_set_legacy_view (MetaRenderer     *renderer,
+                               MetaRendererView *legacy_view)
+{
+  MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer);
+
+  g_assert (!priv->views);
+
+  priv->views = g_list_append (priv->views, legacy_view);
+}
+
+GList *
+meta_renderer_get_views (MetaRenderer *renderer)
+{
+  MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer);
+
+  return priv->views;
+}
+
+static void
+meta_renderer_finalize (GObject *object)
+{
+  MetaRenderer *renderer = META_RENDERER (object);
+  MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer);
+
+  g_list_free_full (priv->views, g_object_unref);
+  priv->views = NULL;
+}
+
 static void
 meta_renderer_init (MetaRenderer *renderer)
 {
@@ -44,4 +113,7 @@ meta_renderer_init (MetaRenderer *renderer)
 static void
 meta_renderer_class_init (MetaRendererClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = meta_renderer_finalize;
 }
diff --git a/src/backends/meta-renderer.h b/src/backends/meta-renderer.h
index 3888e60..ca6868b 100644
--- a/src/backends/meta-renderer.h
+++ b/src/backends/meta-renderer.h
@@ -28,6 +28,9 @@
 #include <glib-object.h>
 
 #include "cogl/cogl.h"
+#include "clutter/clutter-mutter.h"
+#include "backends/meta-monitor-manager-private.h"
+#include "backends/meta-renderer-view.h"
 
 #define META_TYPE_RENDERER (meta_renderer_get_type ())
 G_DECLARE_DERIVABLE_TYPE (MetaRenderer, meta_renderer, META, RENDERER, GObject)
@@ -37,8 +40,17 @@ struct _MetaRendererClass
   GObjectClass parent_class;
 
   CoglRenderer * (* create_cogl_renderer) (MetaRenderer *renderer);
+  MetaRendererView * (* create_view) (MetaRenderer    *renderer,
+                                      MetaMonitorInfo *monitor_info);
 };
 
 CoglRenderer * meta_renderer_create_cogl_renderer (MetaRenderer *renderer);
 
+void meta_renderer_rebuild_views (MetaRenderer *renderer);
+
+void meta_renderer_set_legacy_view (MetaRenderer     *renderer,
+                                    MetaRendererView *legacy_view);
+
+GList * meta_renderer_get_views (MetaRenderer *renderer);
+
 #endif /* META_RENDERER_H */
diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c
index 3b992d9..1bb3e1f 100644
--- a/src/backends/meta-stage.c
+++ b/src/backends/meta-stage.c
@@ -25,7 +25,10 @@
 #include "meta-stage.h"
 
 #include <meta/meta-backend.h>
+#include <meta/meta-monitor-manager.h>
 #include <meta/util.h>
+#include "backends/meta-backend-private.h"
+#include "clutter/clutter-mutter.h"
 
 struct _MetaOverlay {
   gboolean enabled;
diff --git a/src/backends/meta-stage.h b/src/backends/meta-stage.h
index 5376c7a..028a347 100644
--- a/src/backends/meta-stage.h
+++ b/src/backends/meta-stage.h
@@ -63,6 +63,9 @@ void              meta_stage_update_cursor_overlay   (MetaStage     *stage,
 
 void meta_stage_set_active (MetaStage *stage,
                             gboolean   is_active);
+
+void meta_stage_update_view_layout (MetaStage *stage);
+
 G_END_DECLS
 
 #endif /* META_STAGE_H */
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index 9ab9c18..5edfd79 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -38,8 +38,10 @@
 #include "meta-launcher.h"
 #include "backends/meta-cursor-tracker-private.h"
 #include "backends/meta-pointer-constraint.h"
+#include "backends/meta-stage.h"
 #include "backends/native/meta-clutter-backend-native.h"
 #include "backends/native/meta-renderer-native.h"
+#include "backends/native/meta-stage-native.h"
 
 #include <stdlib.h>
 
@@ -383,8 +385,13 @@ static void
 meta_backend_native_update_screen_size (MetaBackend *backend,
                                         int width, int height)
 {
+  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+  MetaStageNative *stage_native;
   ClutterActor *stage = meta_backend_get_stage (backend);
 
+  stage_native = meta_clutter_backend_native_get_stage_native (clutter_backend);
+  meta_stage_native_legacy_set_size (stage_native, width, height);
+
   clutter_actor_set_size (stage, width, height);
 }
 
diff --git a/src/backends/native/meta-clutter-backend-native.c 
b/src/backends/native/meta-clutter-backend-native.c
index 675395a..e932753 100644
--- a/src/backends/native/meta-clutter-backend-native.c
+++ b/src/backends/native/meta-clutter-backend-native.c
@@ -36,11 +36,22 @@
 struct _MetaClutterBackendNative
 {
   ClutterBackendEglNative parent;
+
+  MetaStageNative *stage_native;
 };
 
 G_DEFINE_TYPE (MetaClutterBackendNative, meta_clutter_backend_native,
                CLUTTER_TYPE_BACKEND_EGL_NATIVE)
 
+MetaStageNative *
+meta_clutter_backend_native_get_stage_native (ClutterBackend *backend)
+{
+  MetaClutterBackendNative *clutter_backend_native =
+    META_CLUTTER_BACKEND_NATIVE (backend);
+
+  return clutter_backend_native->stage_native;
+}
+
 static CoglRenderer *
 meta_clutter_backend_native_get_renderer (ClutterBackend  *clutter_backend,
                                           GError         **error)
@@ -56,10 +67,16 @@ meta_clutter_backend_native_create_stage (ClutterBackend  *backend,
                                           ClutterStage    *wrapper,
                                           GError         **error)
 {
-  return g_object_new (META_TYPE_STAGE_NATIVE,
-                       "backend", backend,
-                       "wrapper", wrapper,
-                       NULL);
+  MetaClutterBackendNative *clutter_backend_native =
+    META_CLUTTER_BACKEND_NATIVE (backend);
+
+  g_assert (!clutter_backend_native->stage_native);
+
+  clutter_backend_native->stage_native = g_object_new (META_TYPE_STAGE_NATIVE,
+                                                       "backend", backend,
+                                                       "wrapper", wrapper,
+                                                       NULL);
+  return CLUTTER_STAGE_WINDOW (clutter_backend_native->stage_native);
 }
 
 static void
diff --git a/src/backends/native/meta-clutter-backend-native.h 
b/src/backends/native/meta-clutter-backend-native.h
index d9124f2..2b4153e 100644
--- a/src/backends/native/meta-clutter-backend-native.h
+++ b/src/backends/native/meta-clutter-backend-native.h
@@ -29,10 +29,13 @@
 
 #include "clutter/clutter.h"
 #include "clutter/egl/clutter-backend-eglnative.h"
+#include "backends/native/meta-stage-native.h"
 
 #define META_TYPE_CLUTTER_BACKEND_NATIVE (meta_clutter_backend_native_get_type ())
 G_DECLARE_FINAL_TYPE (MetaClutterBackendNative, meta_clutter_backend_native,
                       META, CLUTTER_BACKEND_NATIVE,
                       ClutterBackendEglNative)
 
+MetaStageNative * meta_clutter_backend_native_get_stage_native (ClutterBackend *backend);
+
 #endif /* META_CLUTTER_BACKEND_NATIVE_H */
diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c
index 12061e5..1dd3c50 100644
--- a/src/backends/native/meta-stage-native.c
+++ b/src/backends/native/meta-stage-native.c
@@ -35,7 +35,7 @@ struct _MetaStageNative
 {
   ClutterStageCogl parent;
 
-  CoglOnscreen *onscreen;
+  CoglOnscreen *pending_onscreen;
 };
 
 static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
@@ -47,19 +47,79 @@ G_DEFINE_TYPE_WITH_CODE (MetaStageNative, meta_stage_native,
                          CLUTTER_TYPE_STAGE_COGL,
                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
                                                 clutter_stage_window_iface_init))
+
+static MetaRendererView *
+get_legacy_view (MetaRenderer *renderer)
+{
+  GList *views;
+
+  views = meta_renderer_get_views (renderer);
+  g_assert (g_list_length (views) <= 1);
+
+  if (views)
+    return views->data;
+  else
+    return NULL;
+}
+
+static CoglOnscreen *
+get_legacy_onscreen (MetaStageNative *stage_native)
+{
+  if (stage_native->pending_onscreen)
+    {
+      return stage_native->pending_onscreen;
+    }
+  else
+    {
+      MetaBackend *backend = meta_get_backend ();
+      MetaRenderer *renderer = meta_backend_get_renderer (backend);
+      ClutterStageView *stage_view;
+      CoglFramebuffer *framebuffer;
+
+      stage_view = CLUTTER_STAGE_VIEW (get_legacy_view (renderer));
+      framebuffer = clutter_stage_view_get_framebuffer (stage_view);
+
+      return COGL_ONSCREEN (framebuffer);
+    }
+}
+
+void
+meta_stage_native_legacy_set_size (MetaStageNative *stage_native,
+                                   int              width,
+                                   int              height)
+{
+  MetaBackend *backend = meta_get_backend ();
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
+  MetaRendererView *legacy_view;
+  cairo_rectangle_int_t view_layout;
+
+  legacy_view = get_legacy_view (renderer);
+  if (!legacy_view)
+    return;
+
+  view_layout = (cairo_rectangle_int_t) {
+    .width = width,
+    .height = height
+  };
+  g_object_set (G_OBJECT (legacy_view),
+                "layout", &view_layout,
+                NULL);
+}
+
 static gboolean
 meta_stage_native_realize (ClutterStageWindow *stage_window)
 {
   MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
-  ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
-  ClutterBackend *clutter_backend = CLUTTER_BACKEND (stage_cogl->backend);
+  MetaBackend *backend = meta_get_backend ();
+  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+  CoglFramebuffer *framebuffer;
   GError *error = NULL;
 
-  stage_native->onscreen = cogl_onscreen_new (clutter_backend->cogl_context,
-                                              1, 1);
+  stage_native->pending_onscreen =
+    cogl_onscreen_new (clutter_backend->cogl_context, 1, 1);
 
-  if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (stage_native->onscreen),
-                                  &error))
+  framebuffer = COGL_FRAMEBUFFER (stage_native->pending_onscreen);
+  if (!cogl_framebuffer_allocate (framebuffer, &error))
     meta_fatal ("Failed to allocate onscreen framebuffer: %s\n",
                 error->message);
 
@@ -76,7 +136,7 @@ meta_stage_native_unrealize (ClutterStageWindow *stage_window)
 
   clutter_stage_window_parent_iface->unrealize (stage_window);
 
-  g_clear_pointer (&stage_native->onscreen, cogl_object_unref);
+  g_clear_pointer (&stage_native->pending_onscreen, cogl_object_unref);
 }
 
 static gboolean
@@ -89,15 +149,15 @@ static void
 meta_stage_native_get_geometry (ClutterStageWindow    *stage_window,
                                 cairo_rectangle_int_t *geometry)
 {
-  MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (stage_native->onscreen);
+  MetaBackend *backend = meta_get_backend ();
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
+  MetaRendererView *legacy_view;
 
-  if (framebuffer)
+  legacy_view = get_legacy_view (renderer);
+  if (legacy_view)
     {
-      *geometry = (cairo_rectangle_int_t) {
-        .width = cogl_framebuffer_get_width (framebuffer),
-        .height = cogl_framebuffer_get_height (framebuffer)
-      };
+      clutter_stage_view_get_layout (CLUTTER_STAGE_VIEW (legacy_view),
+                                     geometry);
     }
   else
     {
@@ -108,12 +168,44 @@ meta_stage_native_get_geometry (ClutterStageWindow    *stage_window,
     }
 }
 
-static CoglFramebuffer *
-meta_stage_native_get_legacy_onscreen (ClutterStageWindow *stage_window)
+static void
+ensure_legacy_view (ClutterStageWindow *stage_window)
 {
   MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
+  MetaBackend *backend = meta_get_backend ();
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
+  MetaMonitorManager *monitor_manager =
+    meta_backend_get_monitor_manager (backend);
+  MetaRendererView *legacy_view;
+  cairo_rectangle_int_t view_layout = { 0 };
+  CoglFramebuffer *framebuffer;
+
+  legacy_view = get_legacy_view (renderer);
+  if (legacy_view)
+    return;
+
+  if (!monitor_manager)
+    return;
+
+  meta_monitor_manager_get_screen_size (monitor_manager,
+                                        &view_layout.width,
+                                        &view_layout.height);
+  framebuffer = g_steal_pointer (&stage_native->pending_onscreen);
+  legacy_view = g_object_new (META_TYPE_RENDERER_VIEW,
+                              "layout", &view_layout,
+                              "framebuffer", framebuffer,
+                              NULL);
+  meta_renderer_set_legacy_view (renderer, legacy_view);
+}
 
-  return COGL_FRAMEBUFFER (stage_native->onscreen);
+static GList *
+meta_stage_native_get_views (ClutterStageWindow *stage_window)
+{
+  MetaBackend *backend = meta_get_backend ();
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
+
+  ensure_legacy_view (stage_window);
+  return meta_renderer_get_views (renderer);
 }
 
 static CoglClosure *
@@ -122,11 +214,13 @@ meta_stage_native_set_frame_callback (ClutterStageWindow *stage_window,
                                       gpointer            user_data)
 {
   MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
+  CoglOnscreen *legacy_onscreen;
 
-  cogl_onscreen_set_swap_throttled (stage_native->onscreen,
+  legacy_onscreen = get_legacy_onscreen (stage_native);
+  cogl_onscreen_set_swap_throttled (legacy_onscreen,
                                     _clutter_get_sync_to_vblank ());
 
-  return cogl_onscreen_add_frame_callback (stage_native->onscreen,
+  return cogl_onscreen_add_frame_callback (legacy_onscreen,
                                            callback,
                                            user_data,
                                            NULL);
@@ -137,16 +231,22 @@ meta_stage_native_remove_frame_callback (ClutterStageWindow *stage_window,
                                          CoglFrameClosure   *closure)
 {
   MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
+  CoglOnscreen *legacy_onscreen;
+
+  legacy_onscreen = get_legacy_onscreen (stage_native);
 
-  cogl_onscreen_remove_frame_callback (stage_native->onscreen, closure);
+  cogl_onscreen_remove_frame_callback (legacy_onscreen, closure);
 }
 
 static int64_t
 meta_stage_native_get_frame_counter (ClutterStageWindow *stage_window)
 {
   MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
+  CoglOnscreen *legacy_onscreen;
+
+  legacy_onscreen = get_legacy_onscreen (stage_native);
 
-  return cogl_onscreen_get_frame_counter (stage_native->onscreen);
+  return cogl_onscreen_get_frame_counter (legacy_onscreen);
 }
 
 static void
@@ -168,7 +268,7 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
   iface->unrealize = meta_stage_native_unrealize;
   iface->can_clip_redraws = meta_stage_native_can_clip_redraws;
   iface->get_geometry = meta_stage_native_get_geometry;
-  iface->get_legacy_onscreen = meta_stage_native_get_legacy_onscreen;
+  iface->get_views = meta_stage_native_get_views;
   iface->set_frame_callback = meta_stage_native_set_frame_callback;
   iface->remove_frame_callback = meta_stage_native_remove_frame_callback;
   iface->get_frame_counter = meta_stage_native_get_frame_counter;
diff --git a/src/backends/native/meta-stage-native.h b/src/backends/native/meta-stage-native.h
index 95b8028..d0b87e0 100644
--- a/src/backends/native/meta-stage-native.h
+++ b/src/backends/native/meta-stage-native.h
@@ -31,4 +31,8 @@
 G_DECLARE_FINAL_TYPE (MetaStageNative, meta_stage_native,
                       META, STAGE_NATIVE, ClutterStageCogl)
 
+void meta_stage_native_legacy_set_size (MetaStageNative *stage_native,
+                                        int              width,
+                                        int              height);
+
 #endif /* META_STAGE_NATIVE_H */
diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
index 9c3bc62..24aaca3 100644
--- a/src/backends/x11/meta-backend-x11.c
+++ b/src/backends/x11/meta-backend-x11.c
@@ -41,6 +41,7 @@
 #include "meta-idle-monitor-xsync.h"
 #include "meta-monitor-manager-xrandr.h"
 #include "backends/meta-monitor-manager-dummy.h"
+#include "backends/meta-stage.h"
 #include "backends/x11/nested/meta-cursor-renderer-x11-nested.h"
 #include "backends/x11/meta-clutter-backend-x11.h"
 #include "backends/x11/meta-renderer-x11.h"
@@ -814,7 +815,9 @@ meta_backend_x11_update_screen_size (MetaBackend *backend,
   if (priv->mode == META_BACKEND_X11_MODE_NESTED)
     {
       ClutterActor *stage = meta_backend_get_stage (backend);
+      MetaRenderer *renderer = meta_backend_get_renderer (backend);
 
+      meta_renderer_rebuild_views (renderer);
       clutter_actor_set_size (stage, width, height);
     }
   else
diff --git a/src/backends/x11/meta-renderer-x11.c b/src/backends/x11/meta-renderer-x11.c
index 9dab81d..565a28e 100644
--- a/src/backends/x11/meta-renderer-x11.c
+++ b/src/backends/x11/meta-renderer-x11.c
@@ -31,8 +31,12 @@
 #include "cogl/cogl-xlib.h"
 #include "cogl/winsys/cogl-winsys-glx-private.h"
 #include "cogl/winsys/cogl-winsys-egl-x11-private.h"
+#include "backends/meta-backend-private.h"
 #include "backends/meta-renderer.h"
+#include "backends/meta-renderer-view.h"
 #include "backends/x11/meta-renderer-x11.h"
+#include "core/boxes-private.h"
+#include "meta/meta-backend.h"
 #include "meta/util.h"
 
 struct _MetaRendererX11
@@ -64,6 +68,32 @@ meta_renderer_x11_create_cogl_renderer (MetaRenderer *renderer)
   return cogl_renderer;
 }
 
+static MetaRendererView *
+meta_renderer_x11_create_view (MetaRenderer    *renderer,
+                               MetaMonitorInfo *monitor_info)
+{
+  MetaBackend *backend = meta_get_backend ();
+  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+  CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
+  int width, height;
+  cairo_rectangle_int_t view_layout;
+  CoglTexture2D *texture_2d;
+  CoglOffscreen *offscreen;
+
+  g_assert (meta_is_wayland_compositor ());
+
+  width = monitor_info->rect.width;
+  height = monitor_info->rect.height;
+  texture_2d = cogl_texture_2d_new_with_size (cogl_context, width, height);
+  offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture_2d));
+  view_layout = meta_rectangle_to_cairo_rectangle (&monitor_info->rect);
+
+  return g_object_new (META_TYPE_RENDERER_VIEW,
+                       "layout", &view_layout,
+                       "framebuffer", COGL_FRAMEBUFFER (offscreen),
+                       NULL);
+}
+
 static void
 meta_renderer_x11_init (MetaRendererX11 *renderer_x11)
 {
@@ -75,4 +105,5 @@ meta_renderer_x11_class_init (MetaRendererX11Class *klass)
   MetaRendererClass *renderer_class = META_RENDERER_CLASS (klass);
 
   renderer_class->create_cogl_renderer = meta_renderer_x11_create_cogl_renderer;
+  renderer_class->create_view = meta_renderer_x11_create_view;
 }
diff --git a/src/backends/x11/meta-stage-x11-nested.c b/src/backends/x11/meta-stage-x11-nested.c
index ba0173f..c9dee09 100644
--- a/src/backends/x11/meta-stage-x11-nested.c
+++ b/src/backends/x11/meta-stage-x11-nested.c
@@ -26,13 +26,127 @@
 
 #include "backends/x11/meta-stage-x11-nested.h"
 
+#include "backends/meta-backend-private.h"
+#include "backends/meta-renderer.h"
+#include "clutter/clutter-mutter.h"
+
+static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
+
 struct _MetaStageX11Nested
 {
   ClutterStageX11 parent;
+
+  CoglPipeline *pipeline;
+  GList *views;
 };
 
-G_DEFINE_TYPE (MetaStageX11Nested, meta_stage_x11_nested,
-               CLUTTER_TYPE_STAGE_X11)
+static void
+clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaStageX11Nested, meta_stage_x11_nested,
+                         CLUTTER_TYPE_STAGE_X11,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
+                                                clutter_stage_window_iface_init))
+
+typedef struct _ClutterStageX11View
+{
+  CoglTexture *texture;
+  ClutterStageViewCogl *view;
+} MetaStageX11NestedView;
+
+static gboolean
+meta_stage_x11_nested_can_clip_redraws (ClutterStageWindow *stage_window)
+{
+  return FALSE;
+}
+
+static GList *
+meta_stage_x11_nested_get_views (ClutterStageWindow *stage_window)
+{
+  MetaBackend *backend = meta_get_backend ();
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
+
+  return meta_renderer_get_views (renderer);
+}
+
+static void
+meta_stage_x11_nested_finish_frame (ClutterStageWindow *stage_window)
+{
+  MetaStageX11Nested *stage_nested = META_STAGE_X11_NESTED (stage_window);
+  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
+  MetaBackend *backend = meta_get_backend ();
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
+  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+  CoglFramebuffer *onscreen = COGL_FRAMEBUFFER (stage_x11->onscreen);
+  GList *l;
+
+  if (!stage_nested->pipeline)
+    stage_nested->pipeline = cogl_pipeline_new (clutter_backend->cogl_context);
+
+  cogl_framebuffer_clear4f (onscreen,
+                            COGL_BUFFER_BIT_COLOR,
+                            0.0f, 0.0f, 0.0f, 1.0f);
+
+  for (l = meta_renderer_get_views (renderer); l; l = l->next)
+    {
+      ClutterStageView *view = l->data;
+      cairo_rectangle_int_t view_layout;
+      CoglFramebuffer *framebuffer;
+      CoglTexture *texture;
+
+      clutter_stage_view_get_layout (view, &view_layout);
+
+      framebuffer = clutter_stage_view_get_framebuffer (view);
+      texture = cogl_offscreen_get_texture (COGL_OFFSCREEN (framebuffer));
+      cogl_framebuffer_set_viewport (onscreen,
+                                     view_layout.x,
+                                     view_layout.y,
+                                     view_layout.width,
+                                     view_layout.height);
+      cogl_pipeline_set_layer_texture (stage_nested->pipeline, 0, texture);
+      cogl_framebuffer_draw_rectangle (onscreen,
+                                       stage_nested->pipeline,
+                                       -1, 1, 1, -1);
+    }
+
+  cogl_onscreen_swap_buffers (stage_x11->onscreen);
+}
+
+static void
+meta_stage_x11_nested_unrealize (ClutterStageWindow *stage_window)
+{
+  MetaStageX11Nested *stage_nested = META_STAGE_X11_NESTED (stage_window);
+  ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
+  MetaBackend *backend = meta_get_backend ();
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
+  GList *l;
+
+  /* Clutter still uses part of the deprecated stateful API of Cogl
+   * (in particulart cogl_set_framebuffer). It means Cogl can keep an
+   * internal reference to the onscreen object we rendered to. In the
+   * case of foreign window, we want to avoid this, as we don't know
+   * what's going to happen to that window.
+   *
+   * The following call sets the current Cogl framebuffer to a dummy
+   * 1x1 one if we're unrealizing the current one, so Cogl doesn't
+   * keep any reference to the foreign window.
+   */
+  for (l = meta_renderer_get_views (renderer); l ;l = l->next)
+    {
+      ClutterStageView *view = l->data;
+      CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
+
+      if (cogl_get_draw_framebuffer () == framebuffer)
+        {
+          _clutter_backend_reset_cogl_framebuffer (stage_cogl->backend);
+          break;
+        }
+    }
+
+  g_clear_pointer (&stage_nested->pipeline, cogl_object_unref);
+
+  clutter_stage_window_parent_iface->unrealize (stage_window);
+}
 
 static void
 meta_stage_x11_nested_init (MetaStageX11Nested *stage_x11_nested)
@@ -43,3 +157,15 @@ static void
 meta_stage_x11_nested_class_init (MetaStageX11NestedClass *klass)
 {
 }
+
+static void
+clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
+{
+  clutter_stage_window_parent_iface = g_type_interface_peek_parent (iface);
+
+  iface->can_clip_redraws = meta_stage_x11_nested_can_clip_redraws;
+  iface->unrealize = meta_stage_x11_nested_unrealize;
+  iface->get_views = meta_stage_x11_nested_get_views;
+  iface->finish_frame = meta_stage_x11_nested_finish_frame;
+}
+
diff --git a/src/core/boxes-private.h b/src/core/boxes-private.h
index c2eec0a..315cc26 100644
--- a/src/core/boxes-private.h
+++ b/src/core/boxes-private.h
@@ -215,4 +215,6 @@ GList* meta_rectangle_find_nonintersected_monitor_edges (
                                            const GList         *monitor_rects,
                                            const GSList        *all_struts);
 
+cairo_rectangle_int_t meta_rectangle_to_cairo_rectangle (MetaRectangle *rect);
+
 #endif /* META_BOXES_PRIVATE_H */
diff --git a/src/core/boxes.c b/src/core/boxes.c
index 2a70497..bc9a119 100644
--- a/src/core/boxes.c
+++ b/src/core/boxes.c
@@ -2013,3 +2013,14 @@ meta_rectangle_find_nonintersected_monitor_edges (
 
   return ret;
 }
+
+cairo_rectangle_int_t
+meta_rectangle_to_cairo_rectangle (MetaRectangle *rect)
+{
+  return (cairo_rectangle_int_t) {
+    .x = rect->x,
+    .y = rect->y,
+    .width = rect->width,
+    .height = rect->height
+  };
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]