[mutter/wayland] Revert unintentional merge from wip/surface-content to wayland



commit 20545941fabf15c4f3fb96b5143340c484c6a265
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Wed Jan 22 09:16:56 2014 -0500

    Revert unintentional merge from wip/surface-content to wayland
    
    This reverts a lot of commits.

 doc/reference/meta-sections.txt             |    2 +
 src/Makefile.am                             |    4 -
 src/compositor/compositor-private.h         |    7 +-
 src/compositor/compositor.c                 |  183 +++++--
 src/compositor/meta-surface-actor-wayland.c |  159 ------
 src/compositor/meta-surface-actor-wayland.h |   65 ---
 src/compositor/meta-surface-actor-x11.c     |  551 ------------------
 src/compositor/meta-surface-actor-x11.h     |   69 ---
 src/compositor/meta-surface-actor.c         |  210 +++-----
 src/compositor/meta-surface-actor.h         |   48 +-
 src/compositor/meta-window-actor-private.h  |   11 +-
 src/compositor/meta-window-actor.c          |  819 ++++++++++++++++++++++-----
 src/compositor/meta-window-group.c          |   17 +-
 src/compositor/plugins/default.c            |    2 +-
 src/core/display.c                          |    2 +-
 src/core/frame.c                            |    3 +-
 src/core/frame.h                            |    1 +
 src/core/window.c                           |  240 ++++++---
 src/meta/compositor.h                       |   13 +-
 src/meta/meta-window-actor.h                |    3 +
 src/meta/window.h                           |    2 +
 src/wayland/meta-wayland-surface.c          |   17 +-
 src/wayland/meta-xwayland.c                 |    2 -
 23 files changed, 1129 insertions(+), 1301 deletions(-)
---
diff --git a/doc/reference/meta-sections.txt b/doc/reference/meta-sections.txt
index 22d4350..7aa8931 100644
--- a/doc/reference/meta-sections.txt
+++ b/doc/reference/meta-sections.txt
@@ -96,6 +96,8 @@ meta_compositor_hide_window
 meta_compositor_switch_workspace
 meta_compositor_maximize_window
 meta_compositor_unmaximize_window
+meta_compositor_window_mapped
+meta_compositor_window_unmapped
 meta_compositor_sync_window_geometry
 meta_compositor_set_updates_frozen
 meta_compositor_queue_frame_drawn
diff --git a/src/Makefile.am b/src/Makefile.am
index 991c1ae..b81c6ec 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -83,10 +83,6 @@ libmutter_wayland_la_SOURCES =                       \
        compositor/meta-shaped-texture-private.h        \
        compositor/meta-surface-actor.c         \
        compositor/meta-surface-actor.h         \
-       compositor/meta-surface-actor-x11.c     \
-       compositor/meta-surface-actor-x11.h     \
-       compositor/meta-surface-actor-wayland.c \
-       compositor/meta-surface-actor-wayland.h \
        compositor/meta-texture-rectangle.c     \
        compositor/meta-texture-rectangle.h     \
        compositor/meta-texture-tower.c         \
diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
index 18bcff6..2e8d85f 100644
--- a/src/compositor/compositor-private.h
+++ b/src/compositor/compositor-private.h
@@ -46,8 +46,11 @@ struct _MetaCompScreen
   CoglFrameClosure      *frame_closure;
 
   /* Used for unredirecting fullscreen windows */
-  guint                  disable_unredirect_count;
-  MetaWindow            *unredirected_window;
+  guint                   disable_unredirect_count;
+  MetaWindowActor             *unredirected_window;
+
+  /* Before we create the output window */
+  XserverRegion     pending_input_region;
 
   gint                   switch_workspace_in_progress;
 
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index 0fb8df9..d2598f4 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -42,6 +42,15 @@
  * the call, so it may be necessary to readjust the display based on the
  * old_rect to start the animation.
  *
+ * meta_compositor_window_mapped() and meta_compositor_window_unmapped() are
+ * notifications when the toplevel window (frame or client window) is mapped or
+ * unmapped. That is, when the result of meta_window_toplevel_is_mapped()
+ * changes. The main use of this is to drop resources when a window is unmapped.
+ * A window will always be mapped before meta_compositor_show_window()
+ * is called and will not be unmapped until after meta_compositor_hide_window()
+ * is called. If the live_hidden_windows preference is set, windows will never
+ * be unmapped.
+ *
  * # Containers #
  *
  * There's two containers in the stage that are used to place window actors, here
@@ -274,6 +283,25 @@ meta_get_window_actors (MetaScreen *screen)
   return info->windows;
 }
 
+static void
+do_set_stage_input_region (MetaScreen   *screen,
+                           XserverRegion region)
+{
+  MetaCompScreen *info = meta_screen_get_compositor_data (screen);
+  MetaDisplay *display = meta_screen_get_display (screen);
+  Display        *xdpy = meta_display_get_xdisplay (display);
+  Window        xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
+
+  XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region);
+
+  /* It's generally a good heuristic that when a crossing event is generated because
+   * we reshape the overlay, we don't want it to affect focus-follows-mouse focus -
+   * it's not the user doing something, it's the environment changing under the user.
+   */
+  meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy));
+  XFixesSetWindowShapeRegion (xdpy, info->output, ShapeInput, 0, 0, region);
+}
+
 void
 meta_set_stage_input_region (MetaScreen   *screen,
                              XserverRegion region)
@@ -285,19 +313,29 @@ meta_set_stage_input_region (MetaScreen   *screen,
    */
   if (!meta_is_wayland_compositor ())
     {
-      MetaCompScreen *info    = meta_screen_get_compositor_data (screen);
-      MetaDisplay    *display = meta_screen_get_display (screen);
-      Display        *xdpy    = meta_display_get_xdisplay (display);
-      Window          xstage  = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
-
-      XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region);
+      MetaCompScreen *info = meta_screen_get_compositor_data (screen);
+      MetaDisplay  *display = meta_screen_get_display (screen);
+      Display      *xdpy    = meta_display_get_xdisplay (display);
 
-      /* It's generally a good heuristic that when a crossing event is generated because
-       * we reshape the overlay, we don't want it to affect focus-follows-mouse focus -
-       * it's not the user doing something, it's the environment changing under the user.
-       */
-      meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy));
-      XFixesSetWindowShapeRegion (xdpy, info->output, ShapeInput, 0, 0, region);
+      if (info->stage && info->output)
+        {
+          do_set_stage_input_region (screen, region);
+        }
+      else 
+        {
+          /* Reset info->pending_input_region if one existed before and set the new
+           * one to use it later. */ 
+          if (info->pending_input_region)
+            {
+              XFixesDestroyRegion (xdpy, info->pending_input_region);
+              info->pending_input_region = None;
+            }
+          if (region != None)
+            {
+              info->pending_input_region = XFixesCreateRegion (xdpy, NULL, 0);
+              XFixesCopyRegion (xdpy, info->pending_input_region, region);
+            }
+        } 
     }
 }
 
@@ -639,6 +677,21 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
     return;
 
   info = g_new0 (MetaCompScreen, 1);
+  /*
+   * We use an empty input region for Clutter as a default because that allows
+   * the user to interact with all the windows displayed on the screen.
+   * We have to initialize info->pending_input_region to an empty region explicitly, 
+   * because None value is used to mean that the whole screen is an input region.
+   */
+  if (!meta_is_wayland_compositor ())
+    info->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0);
+  else
+    {
+      /* Stage input region trickery isn't needed when we're running as a
+       * wayland compositor. */
+      info->pending_input_region = None;
+    }
+
   info->screen = screen;
 
   meta_screen_set_compositor_data (screen, info);
@@ -724,8 +777,6 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
       info->output = get_output_window (screen);
       XReparentWindow (xdisplay, xwin, info->output, 0, 0);
 
-      meta_empty_stage_input_region (screen);
-
       /* Make sure there isn't any left-over output shape on the 
        * overlay window by setting the whole screen to be an
        * output region.
@@ -736,6 +787,13 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
        */
       XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
 
+      do_set_stage_input_region (screen, info->pending_input_region);
+      if (info->pending_input_region != None)
+        {
+          XFixesDestroyRegion (xdisplay, info->pending_input_region);
+          info->pending_input_region = None;
+        }
+
       /* Map overlay window before redirecting windows offscreen so we catch their
        * contents until we show the stage.
        */
@@ -805,30 +863,6 @@ meta_shape_cow_for_window (MetaScreen *screen,
     }
 }
 
-static void
-set_unredirected_window (MetaCompScreen *info,
-                         MetaWindow     *window)
-{
-  if (info->unredirected_window == window)
-    return;
-
-  if (info->unredirected_window != NULL)
-    {
-      MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private 
(info->unredirected_window));
-      meta_window_actor_set_unredirected (window_actor, FALSE);
-    }
-
-  info->unredirected_window = window;
-
-  if (info->unredirected_window != NULL)
-    {
-      MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private 
(info->unredirected_window));
-      meta_window_actor_set_unredirected (window_actor, TRUE);
-    }
-
-  meta_shape_cow_for_window (info->screen, info->unredirected_window);
-}
-
 void
 meta_compositor_add_window (MetaCompositor    *compositor,
                             MetaWindow        *window)
@@ -857,11 +891,19 @@ meta_compositor_remove_window (MetaCompositor *compositor,
   if (!window_actor)
     return;
 
-  screen = meta_window_get_screen (window);
-  info = meta_screen_get_compositor_data (screen);
+  if (!meta_is_wayland_compositor ())
+    {
+      screen = meta_window_get_screen (window);
+      info = meta_screen_get_compositor_data (screen);
 
-  if (info->unredirected_window == window)
-    set_unredirected_window (info, NULL);
+      if (window_actor == info->unredirected_window)
+        {
+          meta_window_actor_set_redirected (window_actor, TRUE);
+          meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window 
(info->unredirected_window)),
+                                     NULL);
+          info->unredirected_window = NULL;
+        }
+    }
 
   meta_window_actor_destroy (window_actor);
 }
@@ -1361,6 +1403,30 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
 }
 
 void
+meta_compositor_window_mapped (MetaCompositor *compositor,
+                               MetaWindow     *window)
+{
+  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
+  DEBUG_TRACE ("meta_compositor_window_mapped\n");
+  if (!window_actor)
+    return;
+
+  meta_window_actor_mapped (window_actor);
+}
+
+void
+meta_compositor_window_unmapped (MetaCompositor *compositor,
+                                 MetaWindow     *window)
+{
+  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
+  DEBUG_TRACE ("meta_compositor_window_unmapped\n");
+  if (!window_actor)
+    return;
+
+  meta_window_actor_unmapped (window_actor);
+}
+
+void
 meta_compositor_sync_window_geometry (MetaCompositor *compositor,
                                      MetaWindow *window,
                                       gboolean did_placement)
@@ -1467,6 +1533,7 @@ pre_paint_windows (MetaCompScreen *info)
 {
   GList *l;
   MetaWindowActor *top_window;
+  MetaWindowActor *expected_unredirected_window = NULL;
 
   if (info->onscreen == NULL)
     {
@@ -1480,13 +1547,33 @@ pre_paint_windows (MetaCompScreen *info)
   if (info->windows == NULL)
     return;
 
-  top_window = g_list_last (info->windows)->data;
+  if (!meta_is_wayland_compositor ())
+    {
+      top_window = g_list_last (info->windows)->data;
 
-  if (meta_window_actor_should_unredirect (top_window) &&
-      info->disable_unredirect_count == 0)
-    set_unredirected_window (info, meta_window_actor_get_meta_window (top_window));
-  else
-    set_unredirected_window (info, NULL);
+      if (meta_window_actor_should_unredirect (top_window) &&
+          info->disable_unredirect_count == 0)
+        expected_unredirected_window = top_window;
+
+      if (info->unredirected_window != expected_unredirected_window)
+        {
+          if (info->unredirected_window != NULL)
+            {
+              meta_window_actor_set_redirected (info->unredirected_window, TRUE);
+              meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window 
(info->unredirected_window)),
+                                         NULL);
+            }
+
+          if (expected_unredirected_window != NULL)
+            {
+              meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window 
(top_window)),
+                                         meta_window_actor_get_meta_window (top_window));
+              meta_window_actor_set_redirected (top_window, FALSE);
+            }
+
+          info->unredirected_window = expected_unredirected_window;
+        }
+    }
 
   for (l = info->windows; l; l = l->next)
     meta_window_actor_pre_paint (l->data);
diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c
index 9d21c74..37b87b0 100644
--- a/src/compositor/meta-surface-actor.c
+++ b/src/compositor/meta-surface-actor.c
@@ -10,118 +10,44 @@
  */
 
 #include <config.h>
-
-#include "meta-surface-actor.h"
-
 #include <clutter/clutter.h>
+#include <cogl/cogl-wayland-server.h>
+#include <cogl/cogl-texture-pixmap-x11.h>
 #include <meta/meta-shaped-texture.h>
+#include "meta-surface-actor.h"
 #include "meta-wayland-private.h"
 #include "meta-cullable.h"
+
 #include "meta-shaped-texture-private.h"
 
 struct _MetaSurfaceActorPrivate
 {
   MetaShapedTexture *texture;
-
-  /* The region that is visible, used to optimize out redraws */
-  cairo_region_t   *unobscured_region;
+  MetaWaylandBuffer *buffer;
 };
 
 static void cullable_iface_init (MetaCullableInterface *iface);
 
-G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR,
-                                  G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
-
-static gboolean
-meta_surface_actor_get_paint_volume (ClutterActor       *actor,
-                                     ClutterPaintVolume *volume)
-{
-  MetaSurfaceActor *self = META_SURFACE_ACTOR (actor);
-  MetaSurfaceActorPrivate *priv = self->priv;
-
-  if (!CLUTTER_ACTOR_CLASS (meta_surface_actor_parent_class)->get_paint_volume (actor, volume))
-    return FALSE;
-
-  if (priv->unobscured_region)
-    {
-      ClutterVertex origin;
-      cairo_rectangle_int_t bounds, unobscured_bounds;
-
-      /* I hate ClutterPaintVolume so much... */
-      clutter_paint_volume_get_origin (volume, &origin);
-      bounds.x = origin.x;
-      bounds.y = origin.y;
-      bounds.width = clutter_paint_volume_get_width (volume);
-      bounds.height = clutter_paint_volume_get_height (volume);
-
-      cairo_region_get_extents (priv->unobscured_region, &unobscured_bounds);
-      gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds);
-
-      origin.x = bounds.x;
-      origin.y = bounds.y;
-      clutter_paint_volume_set_origin (volume, &origin);
-      clutter_paint_volume_set_width (volume, bounds.width);
-      clutter_paint_volume_set_height (volume, bounds.height);
-    }
-
-  return TRUE;
-}
-
-static void
-meta_surface_actor_dispose (GObject *object)
-{
-  MetaSurfaceActor *self = META_SURFACE_ACTOR (object);
-  MetaSurfaceActorPrivate *priv = self->priv;
-
-  g_clear_pointer (&priv->unobscured_region, cairo_region_destroy);
-
-  G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object);
-}
+G_DEFINE_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR,
+                         G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
 
 static void
 meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
 {
-  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-  actor_class->get_paint_volume = meta_surface_actor_get_paint_volume;
-  object_class->dispose = meta_surface_actor_dispose;
-
   g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate));
 }
 
 static void
-set_unobscured_region (MetaSurfaceActor *self,
-                       cairo_region_t   *unobscured_region)
-{
-  MetaSurfaceActorPrivate *priv = self->priv;
-
-  if (priv->unobscured_region)
-    cairo_region_destroy (priv->unobscured_region);
-
-  if (unobscured_region)
-    priv->unobscured_region = cairo_region_copy (unobscured_region);
-  else
-    priv->unobscured_region = NULL;
-}
-
-static void
 meta_surface_actor_cull_out (MetaCullable   *cullable,
                              cairo_region_t *unobscured_region,
                              cairo_region_t *clip_region)
 {
-  MetaSurfaceActor *self = META_SURFACE_ACTOR (cullable);
-
-  set_unobscured_region (self, unobscured_region);
   meta_cullable_cull_out_children (cullable, unobscured_region, clip_region);
 }
 
 static void
 meta_surface_actor_reset_culling (MetaCullable *cullable)
 {
-  MetaSurfaceActor *self = META_SURFACE_ACTOR (cullable);
-
-  set_unobscured_region (self, NULL);
   meta_cullable_reset_culling_children (cullable);
 }
 
@@ -158,104 +84,100 @@ meta_surface_actor_get_texture (MetaSurfaceActor *self)
   return self->priv->texture;
 }
 
-static cairo_region_t *
-effective_unobscured_region (MetaSurfaceActor *self)
+static void
+update_area (MetaSurfaceActor *self,
+             int x, int y, int width, int height)
 {
   MetaSurfaceActorPrivate *priv = self->priv;
 
-  return clutter_actor_has_mapped_clones (CLUTTER_ACTOR (self)) ? NULL : priv->unobscured_region;
+  if (meta_is_wayland_compositor ())
+    {
+      struct wl_resource *resource = priv->buffer->resource;
+      struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource);
+
+      if (shm_buffer)
+        {
+          CoglTexture2D *texture = COGL_TEXTURE_2D (priv->buffer->texture);
+          cogl_wayland_texture_set_region_from_shm_buffer (texture, x, y, width, height, shm_buffer, x, y, 
0, NULL);
+        }
+    }
+  else
+    {
+      CoglTexturePixmapX11 *texture = COGL_TEXTURE_PIXMAP_X11 (meta_shaped_texture_get_texture 
(priv->texture));
+      cogl_texture_pixmap_x11_update_area (texture, x, y, width, height);
+    }
 }
 
 gboolean
-meta_surface_actor_redraw_area (MetaSurfaceActor *self,
-                                int x, int y, int width, int height)
+meta_surface_actor_damage_all (MetaSurfaceActor *self,
+                               cairo_region_t   *unobscured_region)
 {
   MetaSurfaceActorPrivate *priv = self->priv;
+  CoglTexture *texture = meta_shaped_texture_get_texture (priv->texture);
 
+  update_area (self, 0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture));
   return meta_shaped_texture_update_area (priv->texture,
-                                          x, y, width, height,
-                                          effective_unobscured_region (self));
+                                          0, 0,
+                                          cogl_texture_get_width (texture),
+                                          cogl_texture_get_height (texture),
+                                          unobscured_region);
 }
 
 gboolean
-meta_surface_actor_is_obscured (MetaSurfaceActor *self)
+meta_surface_actor_damage_area (MetaSurfaceActor *self,
+                                int               x,
+                                int               y,
+                                int               width,
+                                int               height,
+                                cairo_region_t   *unobscured_region)
 {
   MetaSurfaceActorPrivate *priv = self->priv;
 
-  if (priv->unobscured_region)
-    return cairo_region_is_empty (priv->unobscured_region);
-  else
-    return FALSE;
-}
-
-void
-meta_surface_actor_set_input_region (MetaSurfaceActor *self,
-                                     cairo_region_t   *region)
-{
-  MetaSurfaceActorPrivate *priv = self->priv;
-  meta_shaped_texture_set_input_shape_region (priv->texture, region);
+  update_area (self, x, y, width, height);
+  return meta_shaped_texture_update_area (priv->texture,
+                                          x, y, width, height,
+                                          unobscured_region);
 }
 
 void
-meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
-                                      cairo_region_t   *region)
+meta_surface_actor_attach_wayland_buffer (MetaSurfaceActor *self,
+                                          MetaWaylandBuffer *buffer)
 {
   MetaSurfaceActorPrivate *priv = self->priv;
-  meta_shaped_texture_set_opaque_region (priv->texture, region);
-}
+  priv->buffer = buffer;
 
-void
-meta_surface_actor_process_damage (MetaSurfaceActor *actor,
-                                   int x, int y, int width, int height)
-{
-  META_SURFACE_ACTOR_GET_CLASS (actor)->process_damage (actor, x, y, width, height);
+  if (buffer)
+    meta_shaped_texture_set_texture (priv->texture, buffer->texture);
+  else
+    meta_shaped_texture_set_texture (priv->texture, NULL);
 }
 
 void
-meta_surface_actor_pre_paint (MetaSurfaceActor *actor)
-{
-  META_SURFACE_ACTOR_GET_CLASS (actor)->pre_paint (actor);
-}
-
-gboolean
-meta_surface_actor_is_argb32 (MetaSurfaceActor *actor)
+meta_surface_actor_set_texture (MetaSurfaceActor *self,
+                                CoglTexture      *texture)
 {
-  return META_SURFACE_ACTOR_GET_CLASS (actor)->is_argb32 (actor);
-}
-
-gboolean
-meta_surface_actor_is_visible (MetaSurfaceActor *actor)
-{
-  return META_SURFACE_ACTOR_GET_CLASS (actor)->is_visible (actor);
+  MetaSurfaceActorPrivate *priv = self->priv;
+  meta_shaped_texture_set_texture (priv->texture, texture);
 }
 
 void
-meta_surface_actor_freeze (MetaSurfaceActor *actor)
+meta_surface_actor_set_input_region (MetaSurfaceActor *self,
+                                     cairo_region_t   *region)
 {
-  META_SURFACE_ACTOR_GET_CLASS (actor)->freeze (actor);
+  MetaSurfaceActorPrivate *priv = self->priv;
+  meta_shaped_texture_set_input_shape_region (priv->texture, region);
 }
 
 void
-meta_surface_actor_thaw (MetaSurfaceActor *actor)
-{
-  META_SURFACE_ACTOR_GET_CLASS (actor)->thaw (actor);
-}
-
-gboolean
-meta_surface_actor_is_frozen (MetaSurfaceActor *actor)
-{
-  return META_SURFACE_ACTOR_GET_CLASS (actor)->is_frozen (actor);
-}
-
-gboolean
-meta_surface_actor_should_unredirect (MetaSurfaceActor *actor)
+meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
+                                      cairo_region_t   *region)
 {
-  return META_SURFACE_ACTOR_GET_CLASS (actor)->should_unredirect (actor);
+  MetaSurfaceActorPrivate *priv = self->priv;
+  meta_shaped_texture_set_opaque_region (priv->texture, region);
 }
 
-void
-meta_surface_actor_set_unredirected (MetaSurfaceActor *actor,
-                                     gboolean          unredirected)
+MetaSurfaceActor *
+meta_surface_actor_new (void)
 {
-  META_SURFACE_ACTOR_GET_CLASS (actor)->set_unredirected (actor, unredirected);
+  return g_object_new (META_TYPE_SURFACE_ACTOR, NULL);
 }
diff --git a/src/compositor/meta-surface-actor.h b/src/compositor/meta-surface-actor.h
index f9d458c..484877b 100644
--- a/src/compositor/meta-surface-actor.h
+++ b/src/compositor/meta-surface-actor.h
@@ -6,6 +6,7 @@
 #include <config.h>
 
 #include <meta/meta-shaped-texture.h>
+#include "meta-wayland-types.h"
 
 G_BEGIN_DECLS
 
@@ -24,20 +25,6 @@ struct _MetaSurfaceActorClass
 {
   /*< private >*/
   ClutterActorClass parent_class;
-
-  void     (* process_damage)    (MetaSurfaceActor *actor,
-                                  int x, int y, int width, int height);
-  void     (* pre_paint)         (MetaSurfaceActor *actor);
-  gboolean (* is_argb32)         (MetaSurfaceActor *actor);
-  gboolean (* is_visible)        (MetaSurfaceActor *actor);
-
-  void     (* freeze)            (MetaSurfaceActor *actor);
-  void     (* thaw)              (MetaSurfaceActor *actor);
-  gboolean (* is_frozen)         (MetaSurfaceActor *actor);
-
-  gboolean (* should_unredirect) (MetaSurfaceActor *actor);
-  void     (* set_unredirected)  (MetaSurfaceActor *actor,
-                                  gboolean          unredirected);
 };
 
 struct _MetaSurfaceActor
@@ -49,35 +36,32 @@ struct _MetaSurfaceActor
 
 GType meta_surface_actor_get_type (void);
 
+MetaSurfaceActor *meta_surface_actor_new (void);
+
 cairo_surface_t *meta_surface_actor_get_image (MetaSurfaceActor      *self,
                                                cairo_rectangle_int_t *clip);
 
 MetaShapedTexture *meta_surface_actor_get_texture (MetaSurfaceActor *self);
 
-gboolean meta_surface_actor_is_obscured (MetaSurfaceActor *self);
+gboolean meta_surface_actor_damage_all (MetaSurfaceActor *self,
+                                        cairo_region_t   *unobscured_region);
+
+gboolean meta_surface_actor_damage_area (MetaSurfaceActor *self,
+                                         int               x,
+                                         int               y,
+                                         int               width,
+                                         int               height,
+                                         cairo_region_t   *unobscured_region);
 
+void meta_surface_actor_set_texture (MetaSurfaceActor *self,
+                                     CoglTexture      *texture);
+void meta_surface_actor_attach_wayland_buffer (MetaSurfaceActor  *self,
+                                               MetaWaylandBuffer *buffer);
 void meta_surface_actor_set_input_region (MetaSurfaceActor *self,
                                           cairo_region_t   *region);
 void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
                                            cairo_region_t   *region);
 
-gboolean meta_surface_actor_redraw_area (MetaSurfaceActor *actor,
-                                         int x, int y, int width, int height);
-
-void meta_surface_actor_process_damage (MetaSurfaceActor *actor,
-                                        int x, int y, int width, int height);
-void meta_surface_actor_pre_paint (MetaSurfaceActor *actor);
-gboolean meta_surface_actor_is_argb32 (MetaSurfaceActor *actor);
-gboolean meta_surface_actor_is_visible (MetaSurfaceActor *actor);
-
-void meta_surface_actor_freeze (MetaSurfaceActor *actor);
-void meta_surface_actor_thaw (MetaSurfaceActor *actor);
-gboolean meta_surface_actor_is_frozen (MetaSurfaceActor *actor);
-
-gboolean meta_surface_actor_should_unredirect (MetaSurfaceActor *actor);
-void meta_surface_actor_set_unredirected (MetaSurfaceActor *actor,
-                                          gboolean          unredirected);
-
 G_END_DECLS
 
 #endif /* META_SURFACE_ACTOR_PRIVATE_H */
diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
index 9c6a847..82326d2 100644
--- a/src/compositor/meta-window-actor-private.h
+++ b/src/compositor/meta-window-actor-private.h
@@ -39,13 +39,13 @@ void meta_window_actor_frame_complete (MetaWindowActor    *self,
 
 void meta_window_actor_invalidate_shadow (MetaWindowActor *self);
 
+void meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state);
+
+gboolean meta_window_actor_should_unredirect (MetaWindowActor *self);
+
 void meta_window_actor_get_shape_bounds (MetaWindowActor       *self,
                                           cairo_rectangle_int_t *bounds);
 
-gboolean meta_window_actor_should_unredirect   (MetaWindowActor *self);
-void     meta_window_actor_set_unredirected    (MetaWindowActor *self,
-                                                gboolean         unredirected);
-
 gboolean meta_window_actor_effect_in_progress  (MetaWindowActor *self);
 void     meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
                                                 gboolean         did_placement);
@@ -59,6 +59,9 @@ void     meta_window_actor_set_updates_frozen  (MetaWindowActor *self,
 void     meta_window_actor_queue_frame_drawn   (MetaWindowActor *self,
                                                 gboolean         no_delay_frame);
 
+void meta_window_actor_set_unobscured_region      (MetaWindowActor *self,
+                                                   cairo_region_t  *unobscured_region);
+
 void meta_window_actor_effect_completed (MetaWindowActor *actor,
                                          gulong           event);
 
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 4745d96..e7a9220 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -10,6 +10,10 @@
 
 #include <math.h>
 
+#include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/Xrender.h>
+
 #include <clutter/x11/clutter-x11.h>
 #include <cogl/cogl-texture-pixmap-x11.h>
 #include <gdk/gdk.h> /* for gdk_rectangle_union() */
@@ -26,14 +30,21 @@
 #include "meta-shaped-texture-private.h"
 #include "meta-shadow-factory-private.h"
 #include "meta-window-actor-private.h"
+#include "meta-surface-actor.h"
 #include "meta-texture-rectangle.h"
 #include "region-utils.h"
 #include "meta-wayland-private.h"
 #include "monitor-private.h"
 #include "meta-cullable.h"
 
-#include "meta-surface-actor.h"
-#include "meta-surface-actor-x11.h"
+enum {
+  POSITION_CHANGED,
+  SIZE_CHANGED,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
 
 struct _MetaWindowActorPrivate
 {
@@ -61,13 +72,22 @@ struct _MetaWindowActorPrivate
   /* The region we should clip to when painting the shadow */
   cairo_region_t   *shadow_clip;
 
-  /* Extracted size-invariant shape used for shadows */
-  MetaWindowShape  *shadow_shape;
-  char *            shadow_class;
+  /* The region that is visible, used to optimize out redraws */
+  cairo_region_t   *unobscured_region;
 
   guint              send_frame_messages_timer;
   gint64             frame_drawn_time;
 
+  /* Extracted size-invariant shape used for shadows */
+  MetaWindowShape  *shadow_shape;
+
+  gint              last_width;
+  gint              last_height;
+
+  gint              freeze_count;
+
+  char *            shadow_class;
+
   /*
    * These need to be counters rather than flags, since more plugins
    * can implement same effect; the practicality of stacking effects
@@ -82,7 +102,12 @@ struct _MetaWindowActorPrivate
   /* List of FrameData for recent frames */
   GList            *frames;
 
+  Pixmap            back_pixmap; /* Not used in wayland compositor mode */
+  Damage            damage; /* Not used in wayland compositor mode */
+
   guint                    visible                : 1;
+  guint                    mapped                 : 1;
+  guint                    argb32                 : 1;
   guint                    disposed               : 1;
   guint             redecorating           : 1;
 
@@ -99,7 +124,24 @@ struct _MetaWindowActorPrivate
 
   guint             no_shadow              : 1;
 
+
+  /* 
+   * None of these are used in wayland compositor mode...
+   */
+
+  guint                    needs_damage_all       : 1;
+  guint                    received_x11_damage    : 1;
+
+  guint                    needs_pixmap           : 1;
+
+  guint                    x11_size_changed       : 1;
   guint             updates_frozen         : 1;
+
+  guint             unredirected           : 1;
+
+  /* This is used to detect fullscreen windows that need to be unredirected */
+  guint             full_damage_frames_count;
+  guint             does_full_damage  : 1;
 };
 
 typedef struct _FrameData FrameData;
@@ -136,6 +178,7 @@ static gboolean meta_window_actor_get_paint_volume (ClutterActor       *actor,
                                                     ClutterPaintVolume *volume);
 
 
+static void meta_window_actor_detach_x11_pixmap     (MetaWindowActor *self);
 static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
 
 static void meta_window_actor_handle_updates (MetaWindowActor *self);
@@ -206,6 +249,19 @@ meta_window_actor_class_init (MetaWindowActorClass *klass)
   g_object_class_install_property (object_class,
                                    PROP_SHADOW_CLASS,
                                    pspec);
+
+  signals[POSITION_CHANGED] =
+    g_signal_new ("position-changed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL, NULL,
+                  G_TYPE_NONE, 0);
+  signals[SIZE_CHANGED] =
+    g_signal_new ("size-changed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL, NULL,
+                  G_TYPE_NONE, 0);
 }
 
 static void
@@ -226,6 +282,9 @@ window_decorated_notify (MetaWindow *mw,
 {
   MetaWindowActor        *self     = META_WINDOW_ACTOR (data);
   MetaWindowActorPrivate *priv     = self->priv;
+  MetaScreen             *screen   = priv->screen;
+  MetaDisplay            *display  = meta_screen_get_display (screen);
+  Display                *xdisplay = meta_display_get_xdisplay (display);
 
   /*
    * Basically, we have to reconstruct the the internals of this object
@@ -233,6 +292,23 @@ window_decorated_notify (MetaWindow *mw,
    */
   priv->redecorating = TRUE;
 
+  if (!meta_is_wayland_compositor ())
+    {
+      meta_window_actor_detach_x11_pixmap (self);
+
+      /*
+       * First of all, clean up any resources we are currently using and will
+       * be replacing.
+       */
+      if (priv->damage != None)
+        {
+          meta_error_trap_push (display);
+          XDamageDestroy (xdisplay, priv->damage);
+          meta_error_trap_pop (display);
+          priv->damage = None;
+        }
+    }
+
   /*
    * Recreate the contents.
    */
@@ -255,13 +331,8 @@ surface_allocation_changed_notify (ClutterActor           *actor,
 {
   meta_window_actor_sync_actor_geometry (self, FALSE);
   meta_window_actor_update_shape (self);
-}
 
-static gboolean
-is_argb32 (MetaWindowActor *self)
-{
-  MetaWindowActorPrivate *priv = self->priv;
-  return meta_surface_actor_is_argb32 (priv->surface);
+  g_signal_emit (self, signals[SIZE_CHANGED], 0);
 }
 
 static gboolean
@@ -270,96 +341,56 @@ is_non_opaque (MetaWindowActor *self)
   MetaWindowActorPrivate *priv = self->priv;
   MetaWindow *window = priv->window;
 
-  return is_argb32 (self) || (window->opacity != 0xFF);
-}
-
-static gboolean
-is_frozen (MetaWindowActor *self)
-{
-  MetaWindowActorPrivate *priv = self->priv;
-  return meta_surface_actor_is_frozen (priv->surface);
+  return priv->argb32 || (window->opacity != 0xFF);
 }
 
 static void
-meta_window_actor_freeze (MetaWindowActor *self)
-{
-  MetaWindowActorPrivate *priv = self->priv;
-  meta_surface_actor_freeze (priv->surface);
-}
-
-static void
-meta_window_actor_thaw (MetaWindowActor *self)
+meta_window_actor_constructed (GObject *object)
 {
-  MetaWindowActorPrivate *priv = self->priv;
-
-  meta_surface_actor_thaw (priv->surface);
+  MetaWindowActor        *self     = META_WINDOW_ACTOR (object);
+  MetaWindowActorPrivate *priv     = self->priv;
+  MetaWindow             *window   = priv->window;
+  Window                  xwindow  = meta_window_get_toplevel_xwindow (window);
+  MetaScreen             *screen   = meta_window_get_screen (window);
+  MetaDisplay            *display  = meta_screen_get_display (screen);
+  Display                *xdisplay = meta_display_get_xdisplay (display);
 
-  if (meta_surface_actor_is_frozen (priv->surface))
-    return;
+  priv->screen = screen;
 
-  /* We sometimes ignore moves and resizes on frozen windows */
-  meta_window_actor_sync_actor_geometry (self, FALSE);
+  if (!meta_is_wayland_compositor ())
+    priv->damage = XDamageCreate (xdisplay, xwindow,
+                                  XDamageReportBoundingBox);
 
-  /* We do this now since we might be going right back into the
-   * frozen state */
-  meta_window_actor_handle_updates (self);
-}
+  if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
+    {
+      XRenderPictFormat      *format;
 
-static void
-set_surface_actor (MetaWindowActor  *self,
-                   MetaSurfaceActor *surface)
-{
-  MetaWindowActorPrivate *priv = self->priv;
+      format = XRenderFindVisualFormat (xdisplay, window->xvisual);
 
-  if (priv->surface)
+      if (format && format->type == PictTypeDirect && format->direct.alphaMask)
+        priv->argb32 = TRUE;
+    }
+  else
     {
-      g_object_unref (priv->surface);
-      clutter_actor_remove_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
+      /* XXX: parse shm formats to determine argb32 */
+      priv->argb32 = TRUE;
     }
 
-  priv->surface = surface;
-
-  if (priv->surface)
+  if (!priv->surface)
     {
+      if (window->surface)
+        priv->surface = window->surface->surface_actor;
+      else
+        priv->surface = meta_surface_actor_new ();
       g_object_ref_sink (priv->surface);
+
       clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
 
       g_signal_connect_object (priv->surface, "allocation-changed",
                                G_CALLBACK (surface_allocation_changed_notify), self, 0);
+      meta_window_actor_update_shape (self);
     }
 
-  meta_window_actor_update_shape (self);
-}
-
-static void
-meta_window_actor_sync_surface_actor (MetaWindowActor *self)
-{
-  MetaWindowActorPrivate *priv = self->priv;
-  MetaWindow *window = priv->window;
-
-  MetaSurfaceActor *surface = NULL;
-
-  if (window)
-    {
-      if (window->surface)
-        surface = window->surface->surface_actor;
-      else if (!meta_is_wayland_compositor ())
-        surface = meta_surface_actor_x11_new (window);
-    }
-
-  set_surface_actor (self, surface);
-}
-
-static void
-meta_window_actor_constructed (GObject *object)
-{
-  MetaWindowActor        *self     = META_WINDOW_ACTOR (object);
-  MetaWindowActorPrivate *priv     = self->priv;
-  MetaWindow             *window   = priv->window;
-
-  priv->screen = window->screen;
-
-  meta_window_actor_sync_surface_actor (self);
   meta_window_actor_update_opacity (self);
 
   /* Start off with an empty shape region to maintain the invariant
@@ -373,6 +404,8 @@ meta_window_actor_dispose (GObject *object)
   MetaWindowActor        *self = META_WINDOW_ACTOR (object);
   MetaWindowActorPrivate *priv = self->priv;
   MetaScreen             *screen;
+  MetaDisplay            *display;
+  Display                *xdisplay;
   MetaCompScreen         *info;
 
   if (priv->disposed)
@@ -383,12 +416,16 @@ meta_window_actor_dispose (GObject *object)
   screen   = priv->screen;
   info     = meta_screen_get_compositor_data (screen);
 
+  if (!meta_is_wayland_compositor ())
+    meta_window_actor_detach_x11_pixmap (self);
+
   if (priv->send_frame_messages_timer != 0)
     {
       g_source_remove (priv->send_frame_messages_timer);
       priv->send_frame_messages_timer = 0;
     }
 
+  g_clear_pointer (&priv->unobscured_region, cairo_region_destroy);
   g_clear_pointer (&priv->shape_region, cairo_region_destroy);
   g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
 
@@ -397,11 +434,26 @@ meta_window_actor_dispose (GObject *object)
   g_clear_pointer (&priv->unfocused_shadow, meta_shadow_unref);
   g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref);
 
+  if (!meta_is_wayland_compositor () && priv->damage != None)
+    {
+      display  = meta_screen_get_display (screen);
+      xdisplay = meta_display_get_xdisplay (display);
+
+      meta_error_trap_push (display);
+      XDamageDestroy (xdisplay, priv->damage);
+      meta_error_trap_pop (display);
+
+      priv->damage = None;
+    }
+
   info->windows = g_list_remove (info->windows, (gconstpointer) self);
 
   g_clear_object (&priv->window);
 
-  meta_window_actor_sync_surface_actor (self);
+  /*
+   * Release the extra reference we took on the actor.
+   */
+  g_clear_object (&priv->surface);
 
   G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object);
 }
@@ -669,15 +721,12 @@ meta_window_actor_get_paint_volume (ClutterActor       *actor,
       gdk_rectangle_union (&bounds, &shadow_bounds, &bounds);
     }
 
-  {
-    const ClutterPaintVolume *child_volume;
-
-    child_volume = clutter_actor_get_transformed_paint_volume (CLUTTER_ACTOR (priv->surface), actor);
-    if (!child_volume)
-      return FALSE;
-
-    clutter_paint_volume_union (volume, child_volume);
-  }
+  if (priv->unobscured_region)
+    {
+      cairo_rectangle_int_t unobscured_bounds;
+      cairo_region_get_extents (priv->unobscured_region, &unobscured_bounds);
+      gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds);
+    }
 
   origin.x = bounds.x;
   origin.y = bounds.y;
@@ -811,6 +860,66 @@ meta_window_actor_is_destroyed (MetaWindowActor *self)
   return self->priv->disposed;
 }
 
+gboolean
+meta_window_actor_is_override_redirect (MetaWindowActor *self)
+{
+  return meta_window_is_override_redirect (self->priv->window);
+}
+
+/**
+ * meta_window_actor_get_workspace:
+ * @self: #MetaWindowActor
+ *
+ * Returns the index of workspace on which this window is located; if the
+ * window is sticky, or is not currently located on any workspace, returns -1.
+ * This function is deprecated  and should not be used in newly written code;
+ * meta_window_get_workspace() instead.
+ *
+ * Return value: (transfer none): index of workspace on which this window is
+ * located.
+ */
+gint
+meta_window_actor_get_workspace (MetaWindowActor *self)
+{
+  MetaWindowActorPrivate *priv;
+  MetaWorkspace          *workspace;
+
+  if (!self)
+    return -1;
+
+  priv = self->priv;
+
+  if (!priv->window || meta_window_is_on_all_workspaces (priv->window))
+    return -1;
+
+  workspace = meta_window_get_workspace (priv->window);
+
+  if (!workspace)
+    return -1;
+
+  return meta_workspace_index (workspace);
+}
+
+gboolean
+meta_window_actor_showing_on_its_workspace (MetaWindowActor *self)
+{
+  if (!self)
+    return FALSE;
+
+  /* If override redirect: */
+  if (!self->priv->window)
+    return TRUE;
+
+  return meta_window_showing_on_its_workspace (self->priv->window);
+}
+
+static void
+meta_window_actor_freeze (MetaWindowActor *self)
+{
+  if (!meta_is_wayland_compositor ())
+    self->priv->freeze_count++;
+}
+
 static gboolean
 send_frame_messages_timeout (gpointer data)
 {
@@ -865,6 +974,61 @@ queue_send_frame_messages_timeout (MetaWindowActor *self)
   priv->send_frame_messages_timer = g_timeout_add_full (META_PRIORITY_REDRAW, offset, 
send_frame_messages_timeout, self, NULL);
 }
 
+static void
+meta_window_actor_damage_all (MetaWindowActor *self)
+{
+  MetaWindowActorPrivate *priv = self->priv;
+  cairo_region_t *unobscured_region;
+  gboolean redraw_queued;
+
+  if (!priv->needs_damage_all)
+    return;
+
+  if (!priv->mapped || priv->needs_pixmap)
+    return;
+
+  unobscured_region =
+    clutter_actor_has_mapped_clones (CLUTTER_ACTOR (priv->surface))
+    ? NULL : priv->unobscured_region;
+
+  redraw_queued = meta_surface_actor_damage_all (priv->surface, unobscured_region);
+
+  priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued;
+  priv->needs_damage_all = FALSE;
+}
+
+static void
+meta_window_actor_thaw (MetaWindowActor *self)
+{
+  if (!meta_is_wayland_compositor ())
+    {
+      self->priv->freeze_count--;
+
+      if (G_UNLIKELY (self->priv->freeze_count < 0))
+        {
+          g_warning ("Error in freeze/thaw accounting.");
+          self->priv->freeze_count = 0;
+          return;
+        }
+
+      if (self->priv->freeze_count)
+        return;
+
+      /* We sometimes ignore moves and resizes on frozen windows */
+      meta_window_actor_sync_actor_geometry (self, FALSE);
+
+      /* We do this now since we might be going right back into the
+       * frozen state */
+      meta_window_actor_handle_updates (self);
+
+      /* Since we ignore damage events while a window is frozen for certain effects
+       * we may need to issue an update_area() covering the whole pixmap if we
+       * don't know what real damage has happened. */
+      if (self->priv->needs_damage_all)
+        meta_window_actor_damage_all (self);
+    }
+}
+
 void
 meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
                                      gboolean         no_delay_frame)
@@ -886,7 +1050,17 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
 
   if (!priv->repaint_scheduled)
     {
-      gboolean is_obscured = meta_surface_actor_is_obscured (priv->surface);
+      gboolean is_obscured = FALSE;
+
+      /* Find out whether the window is completly obscured */
+      if (priv->unobscured_region)
+        {
+          cairo_region_t *unobscured_window_region;
+          unobscured_window_region = cairo_region_copy (priv->shape_region);
+          cairo_region_intersect (unobscured_window_region, priv->unobscured_region);
+          is_obscured = cairo_region_is_empty (unobscured_window_region);
+          cairo_region_destroy (unobscured_window_region);
+        }
 
       /* A frame was marked by the client without actually doing any
        * damage or any unobscured, or while we had the window frozen
@@ -900,7 +1074,7 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
         {
           queue_send_frame_messages_timeout (self);
         }
-      else
+      else if (priv->mapped && (!meta_is_wayland_compositor () || !priv->needs_pixmap))
         {
           const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
           clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (priv->surface), &clip);
@@ -920,6 +1094,36 @@ meta_window_actor_effect_in_progress (MetaWindowActor *self)
 }
 
 static gboolean
+is_frozen (MetaWindowActor *self)
+{
+  return self->priv->freeze_count ? TRUE : FALSE;
+}
+
+static void
+meta_window_actor_queue_create_x11_pixmap (MetaWindowActor *self)
+{
+  MetaWindowActorPrivate *priv = self->priv;
+
+  priv->needs_pixmap = TRUE;
+
+  if (!priv->mapped)
+    return;
+
+  if (is_frozen (self))
+    return;
+
+  /* This will cause the compositor paint function to be run
+   * if the actor is visible or a clone of the actor is visible.
+   * if the actor isn't visible in any way, then we don't
+   * need to repair the window anyways, and can wait until
+   * the stage is redrawn for some other reason
+   *
+   * The compositor paint function repairs all windows.
+   */
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->surface));
+}
+
+static gboolean
 is_freeze_thaw_effect (gulong event)
 {
   switch (event)
@@ -999,6 +1203,15 @@ meta_window_actor_after_effects (MetaWindowActor *self)
 
   meta_window_actor_sync_visibility (self);
   meta_window_actor_sync_actor_geometry (self, FALSE);
+
+  if (!meta_is_wayland_compositor ())
+    {
+      if (!meta_window_is_mapped (priv->window))
+        meta_window_actor_detach_x11_pixmap (self);
+
+      if (priv->needs_pixmap)
+        clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->surface));
+    }
 }
 
 void
@@ -1073,19 +1286,95 @@ meta_window_actor_effect_completed (MetaWindowActor *self,
     meta_window_actor_after_effects (self);
 }
 
+/* Called to drop our reference to a window backing pixmap that we
+ * previously obtained with XCompositeNameWindowPixmap. We do this
+ * when the window is unmapped or when we want to update to a new
+ * pixmap for a new size.
+ */
+static void
+meta_window_actor_detach_x11_pixmap (MetaWindowActor *self)
+{
+  MetaWindowActorPrivate *priv     = self->priv;
+  MetaScreen            *screen   = priv->screen;
+  MetaDisplay           *display  = meta_screen_get_display (screen);
+  Display               *xdisplay = meta_display_get_xdisplay (display);
+
+  if (!priv->back_pixmap)
+    return;
+
+  /* Get rid of all references to the pixmap before freeing it; it's unclear whether
+   * you are supposed to be able to free a GLXPixmap after freeing the underlying
+   * pixmap, but it certainly doesn't work with current DRI/Mesa
+   */
+  meta_surface_actor_set_texture (priv->surface, NULL);
+  cogl_flush();
+
+  XFreePixmap (xdisplay, priv->back_pixmap);
+  priv->back_pixmap = None;
+
+  meta_window_actor_queue_create_x11_pixmap (self);
+}
+
 gboolean
 meta_window_actor_should_unredirect (MetaWindowActor *self)
 {
+  MetaWindow *metaWindow = meta_window_actor_get_meta_window (self);
   MetaWindowActorPrivate *priv = self->priv;
-  return meta_surface_actor_should_unredirect (priv->surface);
+
+  if (meta_is_wayland_compositor ())
+    return FALSE;
+
+  if (meta_window_requested_dont_bypass_compositor (metaWindow))
+    return FALSE;
+
+  if (metaWindow->opacity != 0xFF)
+    return FALSE;
+
+  if (metaWindow->shape_region != NULL)
+    return FALSE;
+
+  if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow))
+    return FALSE;
+
+  if (!meta_window_is_monitor_sized (metaWindow))
+    return FALSE;
+
+  if (meta_window_requested_bypass_compositor (metaWindow))
+    return TRUE;
+
+  if (meta_window_is_override_redirect (metaWindow))
+    return TRUE;
+
+  if (priv->does_full_damage)
+    return TRUE;
+
+  return FALSE;
 }
 
 void
-meta_window_actor_set_unredirected (MetaWindowActor *self,
-                                    gboolean         unredirected)
+meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state)
 {
-  MetaWindowActorPrivate *priv = self->priv;
-  meta_surface_actor_set_unredirected (priv->surface, unredirected);
+  MetaWindow *metaWindow = meta_window_actor_get_meta_window (self);
+  MetaDisplay *display = meta_window_get_display (metaWindow);
+
+  Display *xdisplay = meta_display_get_xdisplay (display);
+  Window  xwin = meta_window_get_toplevel_xwindow (metaWindow);
+
+  if (state)
+    {
+      meta_error_trap_push (display);
+      XCompositeRedirectWindow (xdisplay, xwin, CompositeRedirectManual);
+      meta_error_trap_pop (display);
+      meta_window_actor_detach_x11_pixmap (self);
+      self->priv->unredirected = FALSE;
+    }
+  else
+    {
+      meta_error_trap_push (display);
+      XCompositeUnredirectWindow (xdisplay, xwin, CompositeRedirectManual);
+      meta_error_trap_pop (display);
+      self->priv->unredirected = TRUE;
+    }
 }
 
 void
@@ -1139,11 +1428,19 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
 
   meta_window_get_input_rect (priv->window, &window_rect);
 
-  /* When running as a Wayland compositor we catch size changes when new
-   * buffers are attached */
-  if (META_IS_SURFACE_ACTOR_X11 (priv->surface))
-    meta_surface_actor_x11_set_size (META_SURFACE_ACTOR_X11 (priv->surface),
-                                     window_rect.width, window_rect.height);
+  /* When running as a display server we catch size changes when new
+     buffers are attached */
+  if (!meta_is_wayland_compositor ())
+    {
+      if (priv->last_width != window_rect.width ||
+          priv->last_height != window_rect.height)
+        {
+          priv->x11_size_changed = TRUE;
+
+          priv->last_width = window_rect.width;
+          priv->last_height = window_rect.height;
+        }
+    }
 
   /* Normally we want freezing a window to also freeze its position; this allows
    * windows to atomically move and resize together, either under app control,
@@ -1155,6 +1452,15 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
   if (is_frozen (self) && !did_placement)
     return;
 
+  if (!meta_is_wayland_compositor ())
+    {
+      if (priv->x11_size_changed)
+        {
+          meta_window_actor_queue_create_x11_pixmap (self);
+          meta_window_actor_update_shape (self);
+        }
+    }
+
   if (meta_window_actor_effect_in_progress (self))
     return;
 
@@ -1162,6 +1468,8 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
                               window_rect.x, window_rect.y);
   clutter_actor_set_size (CLUTTER_ACTOR (self),
                           window_rect.width, window_rect.height);
+
+  g_signal_emit (self, signals[POSITION_CHANGED], 0);
 }
 
 void
@@ -1321,11 +1629,19 @@ meta_window_actor_new (MetaWindow *window)
                        NULL);
 
   priv = self->priv;
+  priv->mapped = meta_window_toplevel_is_mapped (priv->window);
 
-  meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (priv->window));
-
-  if (META_IS_SURFACE_ACTOR_X11 (priv->surface))
+  if (!meta_is_wayland_compositor ())
     {
+      priv->last_width = -1;
+      priv->last_height = -1;
+
+      if (priv->mapped)
+        meta_window_actor_queue_create_x11_pixmap (self);
+
+      meta_window_actor_set_updates_frozen (self,
+                                            meta_window_updates_are_frozen (priv->window));
+
       /* If a window doesn't start off with updates frozen, we should
        * we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn.
        */
@@ -1357,6 +1673,38 @@ meta_window_actor_new (MetaWindow *window)
   return self;
 }
 
+void
+meta_window_actor_mapped (MetaWindowActor *self)
+{
+  MetaWindowActorPrivate *priv = self->priv;
+
+  g_return_if_fail (!priv->mapped);
+
+  priv->mapped = TRUE;
+
+  if (!meta_is_wayland_compositor ())
+    meta_window_actor_queue_create_x11_pixmap (self);
+}
+
+void
+meta_window_actor_unmapped (MetaWindowActor *self)
+{
+  MetaWindowActorPrivate *priv = self->priv;
+
+  g_return_if_fail (priv->mapped);
+
+  priv->mapped = FALSE;
+
+  if (meta_window_actor_effect_in_progress (self))
+    return;
+
+  if (!meta_is_wayland_compositor ())
+    {
+      meta_window_actor_detach_x11_pixmap (self);
+      priv->needs_pixmap = FALSE;
+    }
+}
+
 #if 0
 /* Print out a region; useful for debugging */
 static void
@@ -1399,6 +1747,30 @@ see_region (cairo_region_t *region,
 #endif
 
 /**
+ * meta_window_actor_set_unobscured_region:
+ * @self: a #MetaWindowActor
+ * @unobscured_region: the region of the screen that isn't completely
+ *  obscured.
+ *
+ * Provides a hint as to what areas of the window need to queue
+ * redraws when damaged. Regions not in @unobscured_region are completely obscured.
+ */
+void
+meta_window_actor_set_unobscured_region (MetaWindowActor *self,
+                                         cairo_region_t  *unobscured_region)
+{
+  MetaWindowActorPrivate *priv = self->priv;
+
+  if (priv->unobscured_region)
+    cairo_region_destroy (priv->unobscured_region);
+
+  if (unobscured_region)
+    priv->unobscured_region = cairo_region_copy (unobscured_region);
+  else
+    priv->unobscured_region = NULL;
+}
+
+/**
  * meta_window_actor_set_clip_region_beneath:
  * @self: a #MetaWindowActor
  * @clip_region: the region of the screen that isn't completely
@@ -1437,6 +1809,16 @@ meta_window_actor_cull_out (MetaCullable   *cullable,
 {
   MetaWindowActor *self = META_WINDOW_ACTOR (cullable);
 
+  if (!meta_is_wayland_compositor ())
+    {
+      MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen);
+
+      /* Don't do any culling for the unredirected window */
+      if (self == info->unredirected_window)
+        return;
+    }
+
+  meta_window_actor_set_unobscured_region (self, unobscured_region);
   meta_cullable_cull_out_children (cullable, unobscured_region, clip_region);
   meta_window_actor_set_clip_region_beneath (self, clip_region);
 }
@@ -1459,6 +1841,88 @@ cullable_iface_init (MetaCullableInterface *iface)
   iface->reset_culling = meta_window_actor_reset_culling;
 }
 
+/* When running as a wayland compositor we don't make requests for
+ * replacement pixmaps when resizing windows, we will instead be
+ * asked to attach replacement buffers by the clients. */
+static void
+check_needs_x11_pixmap (MetaWindowActor *self)
+{
+  MetaWindowActorPrivate *priv     = self->priv;
+  MetaScreen          *screen   = priv->screen;
+  MetaDisplay         *display  = meta_screen_get_display (screen);
+  Display             *xdisplay = meta_display_get_xdisplay (display);
+  MetaCompScreen      *info     = meta_screen_get_compositor_data (screen);
+  Window               xwindow  = meta_window_get_toplevel_xwindow (priv->window);
+
+  if (!priv->needs_pixmap)
+    return;
+
+  if (!priv->mapped)
+    return;
+
+  if (xwindow == meta_screen_get_xroot (screen) ||
+      xwindow == clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)))
+    return;
+
+  if (priv->x11_size_changed)
+    {
+      meta_window_actor_detach_x11_pixmap (self);
+      priv->x11_size_changed = FALSE;
+    }
+
+  meta_error_trap_push (display);
+
+  if (priv->back_pixmap == None)
+    {
+      CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
+      CoglTexture *texture;
+
+      meta_error_trap_push (display);
+
+      priv->back_pixmap = XCompositeNameWindowPixmap (xdisplay, xwindow);
+
+      if (meta_error_trap_pop_with_return (display) != Success)
+        {
+          /* Probably a BadMatch if the window isn't viewable; we could
+           * GrabServer/GetWindowAttributes/NameWindowPixmap/UngrabServer/Sync
+           * to avoid this, but there's no reason to take two round trips
+           * when one will do. (We need that Sync if we want to handle failures
+           * for any reason other than !viewable. That's unlikely, but maybe
+           * we'll BadAlloc or something.)
+           */
+          priv->back_pixmap = None;
+        }
+
+      if (priv->back_pixmap == None)
+        {
+          meta_verbose ("Unable to get named pixmap for %p\n", self);
+          goto out;
+        }
+
+      texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->back_pixmap, FALSE, NULL));
+      if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture))))
+        g_warning ("NOTE: Not using GLX TFP!\n");
+
+      meta_surface_actor_set_texture (META_SURFACE_ACTOR (priv->surface), texture);
+
+      /* ::size-changed is supposed to refer to meta_window_get_frame_rect().
+       * Emitting it here works pretty much OK because a new value of the
+       * *input* rect (which is the outer rect with the addition of invisible
+       * borders) forces a new pixmap and we get here. In the rare case where
+       * a change to the window size was exactly balanced by a change to the
+       * invisible borders, we would miss emitting the signal. We would also
+       * emit spurious signals when we get a new pixmap without a new size,
+       * but that should be mostly harmless.
+       */
+      g_signal_emit (self, signals[SIZE_CHANGED], 0);
+    }
+
+  priv->needs_pixmap = FALSE;
+
+ out:
+  meta_error_trap_pop (display);
+}
+
 static void
 check_needs_shadow (MetaWindowActor *self)
 {
@@ -1469,6 +1933,9 @@ check_needs_shadow (MetaWindowActor *self)
   gboolean should_have_shadow;
   gboolean appears_focused;
 
+  if (!priv->mapped)
+    return;
+
   /* Calling meta_window_actor_has_shadow() here at every pre-paint is cheap
    * and avoids the need to explicitly handle window type changes, which
    * we would do if tried to keep track of when we might be adding or removing
@@ -1526,14 +1993,68 @@ meta_window_actor_process_x11_damage (MetaWindowActor    *self,
                                       XDamageNotifyEvent *event)
 {
   MetaWindowActorPrivate *priv = self->priv;
+  MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
+  gboolean redraw_queued;
+  cairo_region_t *unobscured_region;
+
+  priv->received_x11_damage = TRUE;
+
+  if (meta_window_is_fullscreen (priv->window) && g_list_last (info->windows)->data == self && 
!priv->unredirected)
+    {
+      MetaRectangle window_rect;
+      meta_window_get_frame_rect (priv->window, &window_rect);
+
+      if (window_rect.x == event->area.x &&
+          window_rect.y == event->area.y &&
+          window_rect.width == event->area.width &&
+          window_rect.height == event->area.height)
+        priv->full_damage_frames_count++;
+      else
+        priv->full_damage_frames_count = 0;
 
-  g_assert (!meta_is_wayland_compositor ());
+      if (priv->full_damage_frames_count >= 100)
+        priv->does_full_damage = TRUE;
+    }
+
+  /* Drop damage event for unredirected windows */
+  if (priv->unredirected)
+    return;
+
+  if (is_frozen (self))
+    {
+      /* The window is frozen due to an effect in progress: we ignore damage
+       * here on the off chance that this will stop the corresponding
+       * texture_from_pixmap from being update.
+       *
+       * needs_damage_all tracks that some unknown damage happened while the
+       * window was frozen so that when the window becomes unfrozen we can
+       * issue a full window update to cover any lost damage.
+       *
+       * It should be noted that this is an unreliable mechanism since it's
+       * quite likely that drivers will aim to provide a zero-copy
+       * implementation of the texture_from_pixmap extension and in those cases
+       * any drawing done to the window is always immediately reflected in the
+       * texture regardless of damage event handling.
+       */
+      priv->needs_damage_all = TRUE;
+      return;
+    }
+
+  if (!priv->mapped || priv->needs_pixmap)
+    return;
+
+  unobscured_region =
+    clutter_actor_has_mapped_clones (CLUTTER_ACTOR (priv->surface))
+    ? NULL : priv->unobscured_region;
+  redraw_queued = meta_surface_actor_damage_area (priv->surface,
+                                                  event->area.x,
+                                                  event->area.y,
+                                                  event->area.width,
+                                                  event->area.height,
+                                                  unobscured_region);
+
+  priv->repaint_scheduled = priv->repaint_scheduled  || redraw_queued;
 
-  meta_surface_actor_process_damage (priv->surface,
-                                     event->area.x,
-                                     event->area.y,
-                                     event->area.width,
-                                     event->area.height);
 }
 
 void
@@ -1761,9 +2282,8 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self)
 {
   MetaWindowActorPrivate *priv = self->priv;
   cairo_region_t *opaque_region;
-  gboolean argb32 = is_argb32 (self);
 
-  if (argb32 && priv->window->opaque_region != NULL)
+  if (priv->argb32 && priv->window->opaque_region != NULL)
     {
       MetaFrameBorders borders;
 
@@ -1783,7 +2303,7 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self)
       cairo_region_translate (opaque_region, borders.total.left, borders.total.top);
       cairo_region_intersect (opaque_region, priv->shape_region);
     }
-  else if (argb32)
+  else if (priv->argb32)
     opaque_region = NULL;
   else
     opaque_region = cairo_region_reference (priv->shape_region);
@@ -1799,6 +2319,9 @@ check_needs_reshape (MetaWindowActor *self)
   MetaFrameBorders borders;
   cairo_rectangle_int_t client_area;
 
+  if (!priv->mapped)
+    return;
+
   if (!priv->needs_reshape)
     return;
 
@@ -1840,6 +2363,9 @@ static void
 meta_window_actor_handle_updates (MetaWindowActor *self)
 {
   MetaWindowActorPrivate *priv = self->priv;
+  MetaScreen          *screen   = priv->screen;
+  MetaDisplay         *display  = meta_screen_get_display (screen);
+  Display             *xdisplay = meta_display_get_xdisplay (display);
 
   if (is_frozen (self))
     {
@@ -1848,10 +2374,45 @@ meta_window_actor_handle_updates (MetaWindowActor *self)
       return;
     }
 
-  meta_surface_actor_pre_paint (priv->surface);
+  if (!meta_is_wayland_compositor ())
+    {
+      if (priv->unredirected)
+        {
+          /* Nothing to do here until/if the window gets redirected again */
+          return;
+        }
 
-  if (!meta_surface_actor_is_visible (priv->surface))
-    return;
+      if (priv->received_x11_damage)
+        {
+          meta_error_trap_push (display);
+          XDamageSubtract (xdisplay, priv->damage, None, None);
+          meta_error_trap_pop (display);
+
+          /* We need to make sure that any X drawing that happens before the
+           * XDamageSubtract() above is visible to subsequent GL rendering;
+           * the only standardized way to do this is EXT_x11_sync_object,
+           * which isn't yet widely available. For now, we count on details
+           * of Xorg and the open source drivers, and hope for the best
+           * otherwise.
+           *
+           * Xorg and open source driver specifics:
+           *
+           * The X server makes sure to flush drawing to the kernel before
+           * sending out damage events, but since we use DamageReportBoundingBox
+           * there may be drawing between the last damage event and the
+           * XDamageSubtract() that needs to be flushed as well.
+           *
+           * Xorg always makes sure that drawing is flushed to the kernel
+           * before writing events or responses to the client, so any round trip
+           * request at this point is sufficient to flush the GLX buffers.
+           */
+          XSync (xdisplay, False);
+
+          priv->received_x11_damage = FALSE;
+        }
+
+      check_needs_x11_pixmap (self);
+    }
 
   check_needs_reshape (self);
   check_needs_shadow (self);
@@ -2040,16 +2601,20 @@ void
 meta_window_actor_set_updates_frozen (MetaWindowActor *self,
                                       gboolean         updates_frozen)
 {
-  MetaWindowActorPrivate *priv = self->priv;
+  /* On wayland we shouldn't need to ever freeze updates... */
+  if (!meta_is_wayland_compositor ())
+    {
+      MetaWindowActorPrivate *priv = self->priv;
 
-  updates_frozen = updates_frozen != FALSE;
+      updates_frozen = updates_frozen != FALSE;
 
-  if (priv->updates_frozen != updates_frozen)
-    {
-      priv->updates_frozen = updates_frozen;
-      if (updates_frozen)
-        meta_window_actor_freeze (self);
-      else
-        meta_window_actor_thaw (self);
+      if (priv->updates_frozen != updates_frozen)
+        {
+          priv->updates_frozen = updates_frozen;
+          if (updates_frozen)
+            meta_window_actor_freeze (self);
+          else
+            meta_window_actor_thaw (self);
+        }
     }
 }
diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c
index 5420605..9554571 100644
--- a/src/compositor/meta-window-group.c
+++ b/src/compositor/meta-window-group.c
@@ -115,6 +115,8 @@ meta_window_group_paint (ClutterActor *actor)
 {
   cairo_region_t *clip_region;
   cairo_region_t *unobscured_region;
+  ClutterActorIter iter;
+  ClutterActor *child;
   cairo_rectangle_int_t visible_rect, clip_rect;
   int paint_x_offset, paint_y_offset;
   int paint_x_origin, paint_y_origin;
@@ -123,6 +125,18 @@ meta_window_group_paint (ClutterActor *actor)
   MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
   ClutterActor *stage = clutter_actor_get_stage (actor);
 
+  /* Start off by treating all windows as completely unobscured, so damage anywhere
+   * in a window queues redraws, but confine it more below. */
+  clutter_actor_iter_init (&iter, actor);
+  while (clutter_actor_iter_next (&iter, &child))
+    {
+      if (META_IS_WINDOW_ACTOR (child))
+        {
+          MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
+          meta_window_actor_set_unobscured_region (window_actor, NULL);
+        }
+    }
+
   /* Normally we expect an actor to be drawn at it's position on the screen.
    * However, if we're inside the paint of a ClutterClone, that won't be the
    * case and we need to compensate. We look at the position of the window
@@ -170,8 +184,9 @@ meta_window_group_paint (ClutterActor *actor)
       if (info->unredirected_window != NULL)
         {
           cairo_rectangle_int_t unredirected_rect;
+          MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);
 
-          meta_window_get_frame_rect (info->unredirected_window, (MetaRectangle *)&unredirected_rect);
+          meta_window_get_frame_rect (window, (MetaRectangle *)&unredirected_rect);
           cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect);
           cairo_region_subtract_rectangle (clip_region, &unredirected_rect);
         }
diff --git a/src/compositor/plugins/default.c b/src/compositor/plugins/default.c
index 892854b..91b30c0 100644
--- a/src/compositor/plugins/default.c
+++ b/src/compositor/plugins/default.c
@@ -409,7 +409,7 @@ switch_workspace (MetaPlugin *plugin,
       ClutterActor    *actor       = CLUTTER_ACTOR (window_actor);
       gint             win_workspace;
 
-      win_workspace = meta_window_get_workspace (meta_window_actor_get_meta_window (window_actor));
+      win_workspace = meta_window_actor_get_workspace (window_actor);
 
       if (win_workspace == to || win_workspace == from)
         {
diff --git a/src/core/display.c b/src/core/display.c
index a11836c..8a98cf5 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -2777,7 +2777,7 @@ handle_other_xevent (MetaDisplay *display,
 
           if (display->grab_op != META_GRAB_OP_NONE &&
               display->grab_window == window &&
-              window->frame == NULL)
+              ((window->frame == NULL) || !window->frame->mapped))
             meta_display_end_grab_op (display, timestamp);
 
           if (!frame_was_receiver)
diff --git a/src/core/frame.c b/src/core/frame.c
index e54e862..5fa7bee 100644
--- a/src/core/frame.c
+++ b/src/core/frame.c
@@ -62,6 +62,7 @@ meta_window_ensure_frame (MetaWindow *window)
   frame->right_width = 0;
   frame->current_cursor = 0;
 
+  frame->mapped = FALSE;
   frame->is_flashing = FALSE;
   frame->borders_cached = FALSE;
   
@@ -156,8 +157,6 @@ meta_window_ensure_frame (MetaWindow *window)
 
   /* Move keybindings to frame instead of window */
   meta_window_grab_keys (window);
-
-  meta_ui_map_frame (frame->window->screen->ui, frame->xwindow);
 }
 
 void
diff --git a/src/core/frame.h b/src/core/frame.h
index 8ac1c26..0f1ebea 100644
--- a/src/core/frame.h
+++ b/src/core/frame.h
@@ -47,6 +47,7 @@ struct _MetaFrame
   int right_width;
   int bottom_height;
 
+  guint mapped : 1;
   guint need_reapply_frame_shape : 1;
   guint is_flashing : 1; /* used by the visual bell flash */
   guint borders_cached : 1;
diff --git a/src/core/window.c b/src/core/window.c
index 13d8e2a..b4a845d 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -215,8 +215,6 @@ enum
   FOCUS,
   RAISED,
   UNMANAGED,
-  SIZE_CHANGED,
-  POSITION_CHANGED,
 
   LAST_SIGNAL
 };
@@ -613,22 +611,6 @@ meta_window_class_init (MetaWindowClass *klass)
                   G_STRUCT_OFFSET (MetaWindowClass, unmanaged),
                   NULL, NULL, NULL,
                   G_TYPE_NONE, 0);
-
-  window_signals[POSITION_CHANGED] =
-    g_signal_new ("position-changed",
-                  G_TYPE_FROM_CLASS (object_class),
-                  G_SIGNAL_RUN_LAST,
-                  0,
-                  NULL, NULL, NULL,
-                  G_TYPE_NONE, 0);
-
-  window_signals[SIZE_CHANGED] =
-    g_signal_new ("size-changed",
-                  G_TYPE_FROM_CLASS (object_class),
-                  G_SIGNAL_RUN_LAST,
-                  0,
-                  NULL, NULL, NULL,
-                  G_TYPE_NONE, 0);
 }
 
 static void
@@ -810,35 +792,6 @@ meta_window_should_attach_to_parent (MetaWindow *window)
     }
 }
 
-static gboolean
-client_window_should_be_mapped (MetaWindow *window)
-{
-  return !window->shaded;
-}
-
-static void
-sync_client_window_mapped (MetaWindow *window)
-{
-  gboolean should_be_mapped = client_window_should_be_mapped (window);
-
-  if (window->mapped == should_be_mapped)
-    return;
-
-  window->mapped = should_be_mapped;
-
-  meta_error_trap_push (window->display);
-  if (should_be_mapped)
-    {
-      XMapWindow (window->display->xdisplay, window->xwindow);
-    }
-  else
-    {
-      XUnmapWindow (window->display->xdisplay, window->xwindow);
-      window->unmaps_pending ++;
-    }
-  meta_error_trap_pop (window->display);
-}
-
 static MetaWindow*
 meta_window_new_shared (MetaDisplay         *display,
                         MetaScreen          *screen,
@@ -1334,6 +1287,9 @@ meta_window_new_shared (MetaDisplay         *display,
       set_net_wm_state (window);
     }
 
+  if (screen->display->compositor)
+    meta_compositor_add_window (screen->display->compositor, window);
+
   /* Sync stack changes */
   meta_stack_thaw (window->screen->stack);
 
@@ -1347,8 +1303,6 @@ meta_window_new_shared (MetaDisplay         *display,
   /* disable show desktop mode unless we're a desktop component */
   maybe_leave_show_desktop_mode (window);
 
-  sync_client_window_mapped (window);
-
   meta_window_queue (window, META_QUEUE_CALC_SHOWING);
   /* See bug 303284; a transient of the given window can already exist, in which
    * case we think it should probably be shown.
@@ -1613,8 +1567,7 @@ meta_window_new (MetaDisplay       *display,
                                    META_WINDOW_CLIENT_TYPE_X11,
                                    NULL,
                                    xwindow,
-                                   /* XXX */
-                                   !meta_is_wayland_compositor (),
+                                   TRUE,
                                    existing_wm_state,
                                    effect,
                                    &attrs);
@@ -1807,13 +1760,10 @@ meta_window_unmanage (MetaWindow  *window,
   if (window->display->compositor)
     {
       if (window->visible_to_compositor)
-        {
-          meta_compositor_hide_window (window->display->compositor, window,
-                                       META_COMP_EFFECT_DESTROY);
+        meta_compositor_hide_window (window->display->compositor, window,
+                                     META_COMP_EFFECT_DESTROY);
 
-          /* XXX - support destroy effects better */
-          meta_compositor_remove_window (window->display->compositor, window);
-        }
+      meta_compositor_remove_window (window->display->compositor, window);
     }
 
   if (window->display->window_with_menu == window)
@@ -2396,8 +2346,6 @@ implement_showing (MetaWindow *window,
   meta_verbose ("Implement showing = %d for window %s\n",
                 showing, window->desc);
 
-  sync_client_window_mapped (window);
-
   if (!showing)
     {
       /* When we manage a new window, we normally delay placing it
@@ -2986,6 +2934,94 @@ window_would_be_covered (const MetaWindow *newbie)
   return FALSE; /* none found */
 }
 
+static gboolean
+map_frame (MetaWindow *window)
+{
+  if (window->frame && !window->frame->mapped)
+    {
+      meta_topic (META_DEBUG_WINDOW_STATE,
+                  "Frame actually needs map\n");
+      window->frame->mapped = TRUE;
+      meta_ui_map_frame (window->screen->ui, window->frame->xwindow);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gboolean
+map_client_window (MetaWindow *window)
+{
+  if (!window->mapped)
+    {
+      meta_topic (META_DEBUG_WINDOW_STATE,
+                  "%s actually needs map\n", window->desc);
+      window->mapped = TRUE;
+      meta_error_trap_push (window->display);
+      XMapWindow (window->display->xdisplay, window->xwindow);
+      meta_error_trap_pop (window->display);
+
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gboolean
+unmap_client_window (MetaWindow *window,
+                     const char *reason)
+{
+  if (window->mapped)
+    {
+      meta_topic (META_DEBUG_WINDOW_STATE,
+                  "%s actually needs unmap%s\n",
+                  window->desc, reason);
+      meta_topic (META_DEBUG_WINDOW_STATE,
+                  "Incrementing unmaps_pending on %s%s\n",
+                  window->desc, reason);
+      window->mapped = FALSE;
+      window->unmaps_pending += 1;
+      meta_error_trap_push (window->display);
+      XUnmapWindow (window->display->xdisplay, window->xwindow);
+      meta_error_trap_pop (window->display);
+
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+/**
+ * meta_window_is_mapped:
+ * @window: a #MetaWindow
+ *
+ * Determines whether the X window for the MetaWindow is mapped.
+ */
+gboolean
+meta_window_is_mapped (MetaWindow  *window)
+{
+  return window->mapped;
+}
+
+/**
+ * meta_window_toplevel_is_mapped:
+ * @window: a #MetaWindow
+ *
+ * Determines whether the toplevel X window for the MetaWindow is
+ * mapped. (The frame window is mapped even without the client window
+ * when a window is shaded.)
+ *
+ * Return Value: %TRUE if the toplevel is mapped.
+ */
+gboolean
+meta_window_toplevel_is_mapped (MetaWindow *window)
+{
+  /* The frame is mapped but not the client window when the window
+   * is shaded.
+   */
+  return window->mapped || (window->frame && window->frame->mapped);
+}
+
 static void
 meta_window_force_placement (MetaWindow *window)
 {
@@ -3024,12 +3060,16 @@ meta_window_show (MetaWindow *window)
   gboolean place_on_top_on_map;
   gboolean needs_stacking_adjustment;
   MetaWindow *focus_window;
+  gboolean toplevel_was_mapped;
+  gboolean toplevel_now_mapped;
   gboolean notify_demands_attention = FALSE;
 
   meta_topic (META_DEBUG_WINDOW_STATE,
               "Showing window %s, shaded: %d iconic: %d placed: %d\n",
               window->desc, window->shaded, window->iconic, window->placed);
 
+  toplevel_was_mapped = meta_window_toplevel_is_mapped (window);
+
   focus_window = window->display->focus_window;  /* May be NULL! */
   did_show = FALSE;
   window_state_on_map (window, &takes_focus_on_map, &place_on_top_on_map);
@@ -3156,18 +3196,46 @@ meta_window_show (MetaWindow *window)
         }
     }
 
-  if (window->hidden)
+  /* Shaded means the frame is mapped but the window is not */
+
+  if (map_frame (window))
+    did_show = TRUE;
+
+  if (window->shaded)
     {
-      meta_stack_freeze (window->screen->stack);
-      window->hidden = FALSE;
-      meta_stack_thaw (window->screen->stack);
-      did_show = TRUE;
+      unmap_client_window (window, " (shading)");
+
+      if (!window->iconic)
+        {
+          window->iconic = TRUE;
+          set_wm_state (window, IconicState);
+        }
     }
+  else
+    {
+      if (map_client_window (window))
+        did_show = TRUE;
 
-  if (window->iconic)
+      if (window->hidden)
+        {
+          meta_stack_freeze (window->screen->stack);
+          window->hidden = FALSE;
+          meta_stack_thaw (window->screen->stack);
+          did_show = TRUE;
+        }
+
+      if (window->iconic)
+        {
+          window->iconic = FALSE;
+          set_wm_state (window, NormalState);
+        }
+    }
+
+  toplevel_now_mapped = meta_window_toplevel_is_mapped (window);
+  if (toplevel_now_mapped != toplevel_was_mapped)
     {
-      window->iconic = FALSE;
-      set_wm_state (window, NormalState);
+      if (window->display->compositor)
+        meta_compositor_window_mapped (window->display->compositor, window);
     }
 
   if (!window->visible_to_compositor)
@@ -3190,8 +3258,8 @@ meta_window_show (MetaWindow *window)
               break;
             }
 
-          meta_compositor_add_window (window->display->compositor, window);
-          meta_compositor_show_window (window->display->compositor, window, effect);
+          meta_compositor_show_window (window->display->compositor,
+                                       window, effect);
         }
     }
 
@@ -3259,10 +3327,14 @@ static void
 meta_window_hide (MetaWindow *window)
 {
   gboolean did_hide;
+  gboolean toplevel_was_mapped;
+  gboolean toplevel_now_mapped;
 
   meta_topic (META_DEBUG_WINDOW_STATE,
               "Hiding window %s\n", window->desc);
 
+  toplevel_was_mapped = meta_window_toplevel_is_mapped (window);
+
   if (window->visible_to_compositor)
     {
       window->visible_to_compositor = FALSE;
@@ -3283,12 +3355,19 @@ meta_window_hide (MetaWindow *window)
               break;
             }
 
-          meta_compositor_hide_window (window->display->compositor, window, effect);
+          meta_compositor_hide_window (window->display->compositor,
+                                       window, effect);
         }
     }
 
   did_hide = FALSE;
 
+  /* If this is the first time that we've calculating the showing
+   * state of the window, the frame and client window might not
+   * yet be mapped, so we need to map them now */
+  map_frame (window);
+  map_client_window (window);
+
   if (!window->hidden)
     {
       meta_stack_freeze (window->screen->stack);
@@ -3304,6 +3383,19 @@ meta_window_hide (MetaWindow *window)
       set_wm_state (window, IconicState);
     }
 
+  toplevel_now_mapped = meta_window_toplevel_is_mapped (window);
+  if (toplevel_now_mapped != toplevel_was_mapped)
+    {
+      if (window->display->compositor)
+        {
+          /* As above, we may be *mapping* live hidden windows */
+          if (toplevel_now_mapped)
+            meta_compositor_window_mapped (window->display->compositor, window);
+          else
+            meta_compositor_window_unmapped (window->display->compositor, window);
+        }
+    }
+
   set_net_wm_state (window);
 
   if (did_hide && window->struts)
@@ -5396,12 +5488,6 @@ meta_window_move_resize_internal (MetaWindow          *window,
   else if (is_user_action)
     save_user_window_placement (window);
 
-  if (need_move_frame)
-    g_signal_emit (window, window_signals[POSITION_CHANGED], 0);
-
-  if (need_resize_client)
-    g_signal_emit (window, window_signals[SIZE_CHANGED], 0);
-
   if (need_move_frame || need_resize_frame ||
       need_move_client || need_resize_client ||
       did_placement || is_wayland_resize)
@@ -8131,7 +8217,7 @@ redraw_icon (MetaWindow *window)
   /* We could probably be smart and just redraw the icon here,
    * instead of the whole frame.
    */
-  if (window->frame)
+  if (window->frame && (window->mapped || window->frame->mapped))
     meta_ui_queue_frame_draw (window->screen->ui, window->frame->xwindow);
 }
 
diff --git a/src/meta/compositor.h b/src/meta/compositor.h
index 45c8b09..42ff0dd 100644
--- a/src/meta/compositor.h
+++ b/src/meta/compositor.h
@@ -75,10 +75,11 @@ gboolean meta_compositor_filter_keybinding (MetaCompositor *compositor,
                                             MetaScreen     *screen,
                                             MetaKeyBinding *binding);
 
-void meta_compositor_add_window        (MetaCompositor      *compositor,
-                                        MetaWindow          *window);
-void meta_compositor_remove_window     (MetaCompositor      *compositor,
-                                        MetaWindow          *window);
+void meta_compositor_add_window    (MetaCompositor *compositor,
+                                    MetaWindow     *window);
+void meta_compositor_remove_window (MetaCompositor *compositor,
+                                    MetaWindow     *window);
+
 void meta_compositor_show_window       (MetaCompositor      *compositor,
                                         MetaWindow          *window,
                                         MetaCompEffect       effect);
@@ -100,6 +101,10 @@ void meta_compositor_unmaximize_window (MetaCompositor      *compositor,
                                         MetaRectangle       *old_rect,
                                         MetaRectangle       *new_rect);
 
+void meta_compositor_window_mapped        (MetaCompositor *compositor,
+                                           MetaWindow     *window);
+void meta_compositor_window_unmapped      (MetaCompositor *compositor,
+                                           MetaWindow     *window);
 void meta_compositor_sync_window_geometry (MetaCompositor *compositor,
                                            MetaWindow     *window,
                                            gboolean        did_placement);
diff --git a/src/meta/meta-window-actor.h b/src/meta/meta-window-actor.h
index 2055ca8..9f808a9 100644
--- a/src/meta/meta-window-actor.h
+++ b/src/meta/meta-window-actor.h
@@ -58,8 +58,11 @@ struct _MetaWindowActor
 GType meta_window_actor_get_type (void);
 
 Window             meta_window_actor_get_x_window         (MetaWindowActor *self);
+gint               meta_window_actor_get_workspace        (MetaWindowActor *self);
 MetaWindow *       meta_window_actor_get_meta_window      (MetaWindowActor *self);
 ClutterActor *     meta_window_actor_get_texture          (MetaWindowActor *self);
+gboolean           meta_window_actor_is_override_redirect (MetaWindowActor *self);
+gboolean       meta_window_actor_showing_on_its_workspace (MetaWindowActor *self);
 gboolean       meta_window_actor_is_destroyed (MetaWindowActor *self);
 
 #endif /* META_WINDOW_ACTOR_H */
diff --git a/src/meta/window.h b/src/meta/window.h
index 430dc6b..ff2d037 100644
--- a/src/meta/window.h
+++ b/src/meta/window.h
@@ -189,6 +189,8 @@ gboolean          meta_window_requested_bypass_compositor (MetaWindow *window);
 gboolean          meta_window_requested_dont_bypass_compositor (MetaWindow *window);
 gint             *meta_window_get_all_monitors (MetaWindow *window, gsize *length);
 
+gboolean meta_window_is_mapped (MetaWindow  *window);
+gboolean meta_window_toplevel_is_mapped (MetaWindow  *window);
 gboolean meta_window_get_icon_geometry (MetaWindow    *window,
                                         MetaRectangle *rect);
 void meta_window_set_icon_geometry (MetaWindow    *window,
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 43ed925..1ca38e5 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -44,11 +44,11 @@
 #include "meta-wayland-private.h"
 #include "meta-xwayland-private.h"
 #include "meta-wayland-stage.h"
+#include "meta-surface-actor.h"
 #include "meta-wayland-seat.h"
 #include "meta-wayland-keyboard.h"
 #include "meta-wayland-pointer.h"
 #include "meta-wayland-data-device.h"
-
 #include "meta-cursor-tracker-private.h"
 #include "display-private.h"
 #include "window-private.h"
@@ -58,9 +58,6 @@
 #include "meta-idle-monitor-private.h"
 #include "monitor-private.h"
 
-#include "meta-surface-actor.h"
-#include "meta-surface-actor-wayland.h"
-
 static void
 surface_process_damage (MetaWaylandSurface *surface,
                         cairo_region_t *region)
@@ -71,8 +68,12 @@ surface_process_damage (MetaWaylandSurface *surface,
     {
       cairo_rectangle_int_t rect;
       cairo_region_get_rectangle (region, i, &rect);
-      meta_surface_actor_process_damage (surface->surface_actor,
-                                         rect.x, rect.y, rect.width, rect.height);
+      meta_surface_actor_damage_area (surface->surface_actor,
+                                      rect.x,
+                                      rect.y,
+                                      rect.width,
+                                      rect.height,
+                                      NULL);
     }
 }
 
@@ -263,7 +264,7 @@ actor_surface_commit (MetaWaylandSurface *surface)
     {
       ensure_buffer_texture (buffer);
       meta_wayland_buffer_reference (&surface->buffer_ref, buffer);
-      meta_surface_actor_wayland_set_buffer (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), buffer);
+      meta_surface_actor_attach_wayland_buffer (surface_actor, buffer);
       changed = TRUE;
     }
 
@@ -504,7 +505,7 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
     surface_handle_pending_buffer_destroy;
   wl_list_init (&surface->pending.frame_callback_list);
 
-  surface->surface_actor = g_object_ref_sink (meta_surface_actor_wayland_new (surface));
+  surface->surface_actor = g_object_ref_sink (meta_surface_actor_new ());
   return surface;
 }
 
diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
index c9be272..02c5b7b 100644
--- a/src/wayland/meta-xwayland.c
+++ b/src/wayland/meta-xwayland.c
@@ -48,8 +48,6 @@ xserver_set_window_id (struct wl_client *client,
     {
       surface->window = window;
       window->surface = surface;
-
-      meta_window_set_surface_mapped (window, TRUE);
     }
 }
 



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