[mutter/wip/wayland-stacking: 3/13] wayland: Adds basic hybrid X + Wayland support



commit 8e0517535ff6519b5bc7334d615ed1da677c33f9
Author: Robert Bragg <robert linux intel com>
Date:   Sat Jan 7 22:21:32 2012 +0000

    wayland: Adds basic hybrid X + Wayland support
    
    This adds support for running mutter as a hybrid X and Wayland
    compositor. It runs a headless XWayland server for X applications
    that presents wayland surfaces back to mutter which mutter can then
    composite.
    
    At this point no input is supported
    
    The following specific dependencies are required to run this:
    
    repo: git://anongit.freedesktop.org/wayland/wayland
    branch: 0.85.0
    (Don't try wayland master since there have been interface changes
     we need to update for)
    
    repo: git://anongit.freedesktop.org/~krh/xserver
    branch: wayland-1.10
    
    Note: Additional authors for this patch include Neil Roberts
    <neil linux intel com> and Rico Tzschichholz.

 configure.in                               |    2 +-
 src/Makefile.am                            |   23 +
 src/compositor/compositor-private.h        |    2 +
 src/compositor/compositor.c                |   76 ++
 src/compositor/meta-plugin-manager.c       |    2 +
 src/compositor/meta-shaped-texture.c       |  204 ++++--
 src/compositor/meta-window-actor-private.h |   12 +
 src/compositor/meta-window-actor.c         |  134 +++-
 src/compositor/meta-window-group.c         |   15 +-
 src/core/display.c                         |   27 +-
 src/core/main.c                            |  102 ++-
 src/core/screen-private.h                  |    2 +
 src/core/screen.c                          |   26 +-
 src/core/window-private.h                  |   24 +
 src/core/window.c                          |  149 +++-
 src/meta/meta-shaped-texture.h             |   30 +-
 src/wayland/meta-wayland-private.h         |  136 +++
 src/wayland/meta-wayland.c                 | 1250 ++++++++++++++++++++++++++++
 18 files changed, 2094 insertions(+), 122 deletions(-)
---
diff --git a/configure.in b/configure.in
index d9555a7..22c3b6f 100644
--- a/configure.in
+++ b/configure.in
@@ -15,7 +15,7 @@ AC_INIT([mutter], [mutter_version],
 AC_CONFIG_SRCDIR(src/core/display.c)
 AC_CONFIG_HEADERS(config.h)
 
-AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar])
+AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz tar-ustar])
 m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
 AM_MAINTAINER_MODE([enable])
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 96fa47f..11b08e3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,6 +11,7 @@ INCLUDES=								\
 	-I$(srcdir)/core						\
 	-I$(srcdir)/ui							\
 	-I$(srcdir)/compositor						\
+	-I$(srcdir)/wayland						\
 	-DMUTTER_LIBEXECDIR=\"$(libexecdir)\"				\
 	-DHOST_ALIAS=\"@HOST_ALIAS \"					\
 	-DMUTTER_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\"		\
@@ -36,6 +37,13 @@ mutter_built_sources = \
 	mutter-enum-types.h \
 	mutter-enum-types.c
 
+if HAVE_WAYLAND
+mutter_built_sources += \
+	wayland/xserver-protocol.c		\
+	wayland/xserver-server-protocol.h	\
+	wayland/xserver-client-protocol.h
+endif
+
 libmutter_la_SOURCES =				\
 	core/async-getprop.c			\
 	core/async-getprop.h			\
@@ -157,6 +165,12 @@ libmutter_la_SOURCES =				\
 	ui/preview-widget.c			\
 	$(mutter_built_sources)
 
+if HAVE_WAYLAND
+libmutter_la_SOURCES +=				\
+	wayland/meta-wayland.c			\
+	wayland/meta-wayland-private.h
+endif
+
 libmutter_la_LDFLAGS = -no-undefined
 libmutter_la_LIBADD  = $(MUTTER_LIBS)
 
@@ -333,3 +347,12 @@ mutter-enum-types.c: stamp-mutter-enum-types.h mutter-enum-types.c.in
 	  $(libmutterinclude_base_headers) ) >> xgen-tetc && \
 	cp xgen-tetc mutter-enum-types.c && \
 	rm -f xgen-tetc
+
+if HAVE_WAYLAND
+wayland/%-protocol.c : @WAYLAND_EXTENSION_PROTOCOLS_DIR@/%.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
+wayland/%-server-protocol.h : @WAYLAND_EXTENSION_PROTOCOLS_DIR@/%.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@
+wayland/%-client-protocol.h : @WAYLAND_EXTENSION_PROTOCOLS_DIR@/%.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
+endif
diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
index e7eadf8..55590bf 100644
--- a/src/compositor/compositor-private.h
+++ b/src/compositor/compositor-private.h
@@ -44,7 +44,9 @@ struct _MetaCompScreen
 
   /* Used for unredirecting fullscreen windows */
   guint                   disable_unredirect_count;
+#ifndef HAVE_WAYLAND
   MetaWindowActor             *unredirected_window;
+#endif
 
   /* Before we create the output window */
   XserverRegion     pending_input_region;
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index f54a22b..dd2da65 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -18,6 +18,9 @@
 #include "meta-background-actor-private.h"
 #include "window-private.h" /* to check window->hidden */
 #include "display-private.h" /* for meta_display_lookup_x_window() */
+#ifdef HAVE_WAYLAND
+#include "meta-wayland-private.h"
+#endif
 #include <X11/extensions/shape.h>
 #include <X11/extensions/Xcomposite.h>
 
@@ -92,6 +95,7 @@ add_win (MetaWindow *window)
   sync_actor_stacking (info);
 }
 
+#ifndef HAVE_WAYLAND
 static void
 process_damage (MetaCompositor     *compositor,
                 XDamageNotifyEvent *event,
@@ -108,6 +112,7 @@ process_damage (MetaCompositor     *compositor,
 
   meta_window_actor_process_damage (window_actor, event);
 }
+#endif
 
 static void
 process_property_notify (MetaCompositor	*compositor,
@@ -149,6 +154,7 @@ process_property_notify (MetaCompositor	*compositor,
   DEBUG_TRACE ("process_property_notify: unknown\n");
 }
 
+#ifndef HAVE_WAYLAND
 static Window
 get_output_window (MetaScreen *screen)
 {
@@ -179,6 +185,7 @@ get_output_window (MetaScreen *screen)
 
   return output;
 }
+#endif /* HAVE_WAYLAND */
 
 /**
  * meta_get_stage_for_screen:
@@ -269,6 +276,7 @@ meta_get_window_actors (MetaScreen *screen)
   return info->windows;
 }
 
+#ifndef HAVE_WAYLAND
 static void
 do_set_stage_input_region (MetaScreen   *screen,
                            XserverRegion region)
@@ -287,11 +295,18 @@ do_set_stage_input_region (MetaScreen   *screen,
   meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy));
   XFixesSetWindowShapeRegion (xdpy, info->output, ShapeInput, 0, 0, region);
 }
+#endif
 
 void
 meta_set_stage_input_region (MetaScreen   *screen,
                              XserverRegion region)
 {
+  /* As a wayland compositor we can simply ignore all this trickery
+   * for setting an input region on the stage for capturing events in
+   * clutter since all input comes to us first and we get to choose
+   * who else see it.
+   */
+#ifndef HAVE_WAYLAND
   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
   MetaDisplay  *display = meta_screen_get_display (screen);
   Display      *xdpy    = meta_display_get_xdisplay (display);
@@ -315,6 +330,7 @@ meta_set_stage_input_region (MetaScreen   *screen,
           XFixesCopyRegion (xdpy, info->pending_input_region, region);
         }
     } 
+#endif
 }
 
 void
@@ -450,6 +466,7 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
                                MetaScreen     *screen)
 {
   MetaCompScreen *info;
+#ifndef HAVE_WAYLAND
   MetaDisplay    *display       = meta_screen_get_display (screen);
   Display        *xdisplay      = meta_display_get_xdisplay (display);
   int             screen_number = meta_screen_get_screen_number (screen);
@@ -460,11 +477,20 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
   long            event_mask;
   guint           n_retries;
   guint           max_retries;
+#else
+  MetaWaylandCompositor *wayland_compositor;
+#endif
 
   /* Check if the screen is already managed */
   if (meta_screen_get_compositor_data (screen))
     return;
 
+  /* If we're running with wayland, connected to a headless xwayland
+   * server then all the windows are implicitly redirected offscreen
+   * already and it would generate an error to try and explicitly
+   * redirect them via XCompositeRedirectSubwindows() */
+#ifndef HAVE_WAYLAND
+
   if (meta_get_replace_current_wm ())
     max_retries = 5;
   else
@@ -496,6 +522,7 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
       n_retries++;
       g_usleep (G_USEC_PER_SEC);
     }
+#endif
 
   info = g_new0 (MetaCompScreen, 1);
   /*
@@ -504,7 +531,13 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
    * 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.
    */
+#ifndef HAVE_WAYLAND
   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;
+#endif
 
   info->screen = screen;
 
@@ -515,6 +548,12 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
 
   meta_screen_set_cm_selection (screen);
 
+  /* We will have already created a stage if running as a wayland
+   * compositor... */
+#ifdef HAVE_WAYLAND
+  wayland_compositor = meta_wayland_compositor_get_default ();
+  info->stage = wayland_compositor->stage;
+#else
   info->stage = clutter_stage_new ();
 
   meta_screen_get_size (screen, &width, &height);
@@ -540,6 +579,8 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
 
   XSelectInput (xdisplay, xwin, event_mask);
 
+#endif /* HAVE_WAYLAND */
+
   info->window_group = meta_window_group_new (screen);
   info->background_actor = meta_background_actor_new_for_screen (screen);
   info->overlay_group = clutter_group_new ();
@@ -561,6 +602,8 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
     meta_plugin_manager_get (screen);
   meta_plugin_manager_initialize (info->plugin_mgr);
 
+#ifndef HAVE_WAYLAND
+
   /*
    * Delay the creation of the overlay window as long as we can, to avoid
    * blanking out the screen. This means that during the plugin loading, the
@@ -588,6 +631,15 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
       info->pending_input_region = None;
     }
 
+#else /* HAVE_WAYLAND */
+
+  /* NB: When running as a wayland compositor we don't need an X composite
+   * overlay window, and we don't need to play any input region tricks
+   * to redirect events into clutter. */
+  info->output = None;
+
+#endif /* HAVE_WAYLAND */
+
   clutter_actor_show (info->overlay_group);
   clutter_actor_show (info->stage);
 }
@@ -596,6 +648,7 @@ void
 meta_compositor_unmanage_screen (MetaCompositor *compositor,
                                  MetaScreen     *screen)
 {
+#ifndef HAVE_WAYLAND
   MetaDisplay    *display       = meta_screen_get_display (screen);
   Display        *xdisplay      = meta_display_get_xdisplay (display);
   Window          xroot         = meta_screen_get_xroot (screen);
@@ -604,8 +657,10 @@ meta_compositor_unmanage_screen (MetaCompositor *compositor,
    * before giving up the window manager selection or the next
    * window manager won't be able to redirect subwindows */
   XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
+#endif
 }
 
+#ifndef HAVE_WAYLAND
 /*
  * Shapes the cow so that the given window is exposed,
  * when metaWindow is NULL it clears the shape again
@@ -646,6 +701,7 @@ meta_shape_cow_for_window (MetaScreen *screen,
       XFixesDestroyRegion (xdisplay, output_region);
     }
 }
+#endif
 
 void
 meta_compositor_add_window (MetaCompositor    *compositor,
@@ -667,14 +723,17 @@ meta_compositor_remove_window (MetaCompositor *compositor,
                                MetaWindow     *window)
 {
   MetaWindowActor         *window_actor     = NULL;
+#ifndef HAVE_WAYLAND
   MetaScreen *screen;
   MetaCompScreen *info;
+#endif
 
   DEBUG_TRACE ("meta_compositor_remove_window\n");
   window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
   if (!window_actor)
     return;
 
+#ifndef HAVE_WAYLAND
   screen = meta_window_get_screen (window);
   info = meta_screen_get_compositor_data (screen);
 
@@ -685,6 +744,7 @@ meta_compositor_remove_window (MetaCompositor *compositor,
                                  NULL);
       info->unredirected_window = NULL;
     }
+#endif
 
   meta_window_actor_destroy (window_actor);
 }
@@ -788,6 +848,7 @@ meta_compositor_process_event (MetaCompositor *compositor,
       break;
 
     default:
+#ifndef HAVE_WAYLAND
       if (event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
         {
           /* Core code doesn't handle damage events, so we need to extract the MetaWindow
@@ -802,13 +863,16 @@ meta_compositor_process_event (MetaCompositor *compositor,
 	  DEBUG_TRACE ("meta_compositor_process_event (process_damage)\n");
           process_damage (compositor, (XDamageNotifyEvent *) event, window);
         }
+#endif
       break;
     }
 
+#ifndef HAVE_WAYLAND
   /* Clutter needs to know about MapNotify events otherwise it will
      think the stage is invisible */
   if (event->type == MapNotify)
     clutter_x11_handle_event (event);
+#endif
 
   /* The above handling is basically just "observing" the events, so we return
    * FALSE to indicate that the event should not be filtered out; if we have
@@ -1118,6 +1182,7 @@ meta_compositor_sync_screen_size (MetaCompositor  *compositor,
 				  guint		   width,
 				  guint		   height)
 {
+#ifndef HAVE_WAYLAND
   MetaDisplay    *display = meta_screen_get_display (screen);
   MetaCompScreen *info    = meta_screen_get_compositor_data (screen);
   Display        *xdisplay;
@@ -1136,18 +1201,28 @@ meta_compositor_sync_screen_size (MetaCompositor  *compositor,
   meta_verbose ("Changed size for stage on screen %d to %dx%d\n",
 		meta_screen_get_screen_number (screen),
 		width, height);
+#else
+  /* It's not clear at the moment how we will be dealing with screen
+   * resizing as a Wayland compositor so for now just abort if we
+   * hit this code. */
+  g_critical ("Unexpected call to meta_compositor_sync_screen_size() "
+              "when running as a wayland compositor");
+#endif
 }
 
 static void
 pre_paint_windows (MetaCompScreen *info)
 {
   GList *l;
+#ifndef HAVE_WAYLAND
   MetaWindowActor *top_window;
   MetaWindowActor *expected_unredirected_window = NULL;
+#endif
 
   if (info->windows == NULL)
     return;
 
+#ifndef HAVE_WAYLAND
   top_window = g_list_last (info->windows)->data;
 
   if (meta_window_actor_should_unredirect (top_window) &&
@@ -1172,6 +1247,7 @@ pre_paint_windows (MetaCompScreen *info)
 
       info->unredirected_window = expected_unredirected_window;
     }
+#endif
 
   for (l = info->windows; l; l = l->next)
     meta_window_actor_pre_paint (l->data);
diff --git a/src/compositor/meta-plugin-manager.c b/src/compositor/meta-plugin-manager.c
index bc4b9c7..9c3effb 100644
--- a/src/compositor/meta-plugin-manager.c
+++ b/src/compositor/meta-plugin-manager.c
@@ -477,8 +477,10 @@ meta_plugin_manager_xevent_filter (MetaPluginManager *plugin_mgr,
       l = l->next;
     }
 
+#ifndef HAVE_WAYLAND
   if (!have_plugin_xevent_func)
     return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
+#endif
 
   return FALSE;
 }
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
index ae21945..627a4e9 100644
--- a/src/compositor/meta-shaped-texture.c
+++ b/src/compositor/meta-shaped-texture.c
@@ -31,14 +31,22 @@
 #include <meta/meta-shaped-texture.h>
 #include "meta-texture-tower.h"
 #include "meta-texture-rectangle.h"
+#include "meta-wayland-private.h"
 
 #include <clutter/clutter.h>
+#ifdef HAVE_WAYLAND
+#include <clutter/wayland/clutter-wayland-surface.h>
+#endif
 #include <cogl/cogl.h>
 #include <cogl/cogl-texture-pixmap-x11.h>
 #include <gdk/gdk.h> /* for gdk_rectangle_intersect() */
 #include <string.h>
 
 static void meta_shaped_texture_dispose  (GObject    *object);
+#ifdef HAVE_WAYLAND
+static void meta_shaped_texture_notify   (GObject    *object,
+					  GParamSpec *pspec);
+#endif
 
 static void meta_shaped_texture_paint (ClutterActor       *actor);
 static void meta_shaped_texture_pick  (ClutterActor       *actor,
@@ -53,13 +61,24 @@ static void meta_shaped_texture_get_preferred_height (ClutterActor *self,
                                                       gfloat        for_width,
                                                       gfloat       *min_height_p,
                                                       gfloat       *natural_height_p);
+#ifdef HAVE_WAYLAND
+static void meta_shaped_texture_queue_damage_redraw (ClutterWaylandSurface *surface,
+                                                     int                    x,
+                                                     int                    y,
+                                                     int                    width,
+                                                     int                    height);
+#endif
 
 static void meta_shaped_texture_dirty_mask (MetaShapedTexture *stex);
 
 static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume);
 
 G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
+#ifdef HAVE_WAYLAND
+               CLUTTER_WAYLAND_TYPE_SURFACE);
+#else
                CLUTTER_TYPE_ACTOR);
+#endif
 
 #define META_SHAPED_TEXTURE_GET_PRIVATE(obj) \
   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_SHAPED_TEXTURE, \
@@ -91,8 +110,14 @@ meta_shaped_texture_class_init (MetaShapedTextureClass *klass)
 {
   GObjectClass *gobject_class = (GObjectClass *) klass;
   ClutterActorClass *actor_class = (ClutterActorClass *) klass;
+#ifdef HAVE_WAYLAND
+  ClutterWaylandSurfaceClass *wayland_surface_class = (ClutterWaylandSurfaceClass *) klass;
+#endif
 
   gobject_class->dispose = meta_shaped_texture_dispose;
+#ifdef HAVE_WAYLAND
+  gobject_class->notify = meta_shaped_texture_notify;
+#endif
 
   actor_class->get_preferred_width = meta_shaped_texture_get_preferred_width;
   actor_class->get_preferred_height = meta_shaped_texture_get_preferred_height;
@@ -100,6 +125,10 @@ meta_shaped_texture_class_init (MetaShapedTextureClass *klass)
   actor_class->pick = meta_shaped_texture_pick;
   actor_class->get_paint_volume = meta_shaped_texture_get_paint_volume;
 
+#ifdef HAVE_WAYLAND
+  wayland_surface_class->queue_damage_redraw = meta_shaped_texture_queue_damage_redraw;
+#endif
+
   g_type_class_add_private (klass, sizeof (MetaShapedTexturePrivate));
 }
 
@@ -155,6 +184,74 @@ meta_shaped_texture_dispose (GObject *object)
 }
 
 static void
+set_cogl_texture (MetaShapedTexture *stex,
+                  CoglHandle         cogl_tex)
+{
+  MetaShapedTexturePrivate *priv;
+  guint width, height;
+
+  g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
+
+  priv = stex->priv;
+
+  if (priv->texture != COGL_INVALID_HANDLE)
+    cogl_handle_unref (priv->texture);
+
+  priv->texture = cogl_tex;
+
+  if (priv->material != COGL_INVALID_HANDLE)
+    cogl_material_set_layer (priv->material, 0, cogl_tex);
+
+  if (priv->material_unshaped != COGL_INVALID_HANDLE)
+    cogl_material_set_layer (priv->material_unshaped, 0, cogl_tex);
+
+  if (cogl_tex != COGL_INVALID_HANDLE)
+    {
+      width = cogl_texture_get_width (cogl_tex);
+      height = cogl_texture_get_height (cogl_tex);
+
+      if (width != priv->tex_width ||
+          height != priv->tex_height)
+        {
+          priv->tex_width = width;
+          priv->tex_height = height;
+
+          clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
+        }
+    }
+  else
+    {
+      /* size changed to 0 going to an invalid handle */
+      priv->tex_width = 0;
+      priv->tex_height = 0;
+      clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
+    }
+
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
+}
+
+#ifdef HAVE_WAYLAND
+static void
+meta_shaped_texture_notify (GObject    *object,
+			    GParamSpec *pspec)
+{
+  if (G_OBJECT_CLASS (meta_shaped_texture_parent_class)->notify)
+    G_OBJECT_CLASS (meta_shaped_texture_parent_class)->notify (object, pspec);
+
+  if (strcmp (pspec->name, "cogl-texture") == 0)
+    {
+      MetaShapedTexture *stex = (MetaShapedTexture *) object;
+      MetaShapedTexturePrivate *priv = stex->priv;
+      CoglHandle texture =
+        clutter_wayland_surface_get_cogl_texture (CLUTTER_WAYLAND_SURFACE (stex));
+      set_cogl_texture (stex, cogl_handle_ref (texture));
+      if (priv->create_mipmaps)
+        meta_texture_tower_set_base_texture (priv->paint_tower, texture);
+    }
+}
+#endif
+
+static void
 meta_shaped_texture_dirty_mask (MetaShapedTexture *stex)
 {
   MetaShapedTexturePrivate *priv = stex->priv;
@@ -556,14 +653,70 @@ meta_shaped_texture_get_paint_volume (ClutterActor *self,
   return clutter_paint_volume_set_from_allocation (volume, self);
 }
 
+#ifdef HAVE_WAYLAND
+void
+meta_shaped_texture_queue_damage_redraw (ClutterWaylandSurface *surface,
+                                         int                    x,
+                                         int                    y,
+                                         int                    width,
+                                         int                    height)
+{
+  MetaShapedTexture *stex = (MetaShapedTexture *) surface;
+  MetaShapedTexturePrivate *priv = stex->priv;
+
+  CLUTTER_WAYLAND_SURFACE_CLASS (meta_shaped_texture_parent_class)->queue_damage_redraw (surface,
+                                                                                         x, y, width, height);
+
+  meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
+}
+
 ClutterActor *
-meta_shaped_texture_new (void)
+meta_shaped_texture_new_with_surface (MetaWaylandSurface *surface)
 {
-  ClutterActor *self = g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
+  if (surface)
+    {
+      ClutterActor *actor =
+        g_object_new (META_TYPE_SHAPED_TEXTURE,
+                      "surface", &surface->wayland_surface, NULL);
+
+      /* XXX: This is a bit messy but meta-wayland.c wants a reference
+       * to the corresponding surface actor so that it can pass on
+       * damage events.
+       *
+       * TODO: find a neater way.
+       */
+      surface->actor = actor;
+
+      if (surface->buffer)
+        {
+          clutter_wayland_surface_attach_buffer (CLUTTER_WAYLAND_SURFACE (surface->actor),
+                                                 surface->buffer->wayland_buffer,
+                                                 NULL);
+        }
+      return actor;
+    }
+  else
+    return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
+}
+
+ClutterActor *
+meta_shaped_texture_new_with_xwindow (Window xwindow)
+{
+  MetaWaylandSurface *surface = meta_wayland_lookup_surface_for_xid (xwindow);
+  return meta_shaped_texture_new_with_surface (surface);
+}
+
+#else /* HAVE_WAYLAND */
 
+ClutterActor *
+meta_shaped_texture_new_with_xwindow (Window xwindow)
+{
+  ClutterActor *self = g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
   return self;
 }
 
+#endif /* HAVE_WAYLAND */
+
 void
 meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
 					gboolean           create_mipmaps)
@@ -634,53 +787,6 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
   clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
 }
 
-static void
-set_cogl_texture (MetaShapedTexture *stex,
-                  CoglHandle         cogl_tex)
-{
-  MetaShapedTexturePrivate *priv;
-  guint width, height;
-
-  g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
-
-  priv = stex->priv;
-
-  if (priv->texture != COGL_INVALID_HANDLE)
-    cogl_handle_unref (priv->texture);
-
-  priv->texture = cogl_tex;
-
-  if (priv->material != COGL_INVALID_HANDLE)
-    cogl_material_set_layer (priv->material, 0, cogl_tex);
-
-  if (priv->material_unshaped != COGL_INVALID_HANDLE)
-    cogl_material_set_layer (priv->material_unshaped, 0, cogl_tex);
-
-  if (cogl_tex != COGL_INVALID_HANDLE)
-    {
-      width = cogl_texture_get_width (cogl_tex);
-      height = cogl_texture_get_height (cogl_tex);
-
-      if (width != priv->tex_width ||
-          height != priv->tex_height)
-        {
-          priv->tex_width = width;
-          priv->tex_height = height;
-
-          clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
-        }
-    }
-  else
-    {
-      /* size changed to 0 going to an invalid handle */
-      priv->tex_width = 0;
-      priv->tex_height = 0;
-      clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
-    }
-
-  clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
-}
-
 /**
  * meta_shaped_texture_set_pixmap:
  * @stex: The #MetaShapedTexture
diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
index 97e3140..9343722 100644
--- a/src/compositor/meta-window-actor-private.h
+++ b/src/compositor/meta-window-actor-private.h
@@ -8,6 +8,10 @@
 #include <X11/extensions/Xdamage.h>
 #include <meta/compositor-mutter.h>
 
+#ifdef HAVE_WAYLAND
+#include <wayland-server.h>
+#endif
+
 MetaWindowActor *meta_window_actor_new (MetaWindow *window);
 
 void meta_window_actor_destroy   (MetaWindowActor *self);
@@ -24,14 +28,18 @@ void meta_window_actor_unmaximize (MetaWindowActor *self,
                                    MetaRectangle   *old_rect,
                                    MetaRectangle   *new_rect);
 
+#ifndef HAVE_WAYLAND
 void meta_window_actor_process_damage (MetaWindowActor    *self,
                                        XDamageNotifyEvent *event);
+#endif
 
 void meta_window_actor_pre_paint      (MetaWindowActor    *self);
 
 void meta_window_actor_invalidate_shadow (MetaWindowActor *self);
 
+#ifndef HAVE_WAYLAND
 void meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state);
+#endif
 
 gboolean meta_window_actor_should_unredirect (MetaWindowActor *self);
 
@@ -57,4 +65,8 @@ void meta_window_actor_reset_visible_regions      (MetaWindowActor *self);
 void meta_window_actor_effect_completed (MetaWindowActor *actor,
                                          gulong           event);
 
+#ifdef HAVE_WAYLAND
+ClutterActor *meta_window_actor_get_shaped_texture (MetaWindowActor *self);
+#endif
+
 #endif /* META_WINDOW_ACTOR_PRIVATE_H */
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 3751d34..bf67867 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -24,6 +24,10 @@
 #include "compositor-private.h"
 #include "meta-shadow-factory-private.h"
 #include "meta-window-actor-private.h"
+#ifdef HAVE_WAYLAND
+#include "meta-wayland-private.h"
+#include <clutter/wayland/clutter-wayland-surface.h>
+#endif
 
 enum {
   POSITION_CHANGED,
@@ -56,9 +60,11 @@ struct _MetaWindowActorPrivate
   MetaShadow       *focused_shadow;
   MetaShadow       *unfocused_shadow;
 
+#ifndef HAVE_WAYLAND
   Pixmap            back_pixmap;
 
   Damage            damage;
+#endif
 
   guint8            opacity;
   guint8            shadow_opacity;
@@ -75,8 +81,10 @@ struct _MetaWindowActorPrivate
   /* Extracted size-invariant shape used for shadows */
   MetaWindowShape  *shadow_shape;
 
+#ifndef HAVE_WAYLAND
   gint              last_width;
   gint              last_height;
+#endif
   MetaFrameBorders  last_borders;
 
   gint              freeze_count;
@@ -100,22 +108,27 @@ struct _MetaWindowActorPrivate
   guint		    disposed               : 1;
   guint             redecorating           : 1;
 
+#ifndef HAVE_WAYLAND
   guint		    needs_damage_all       : 1;
   guint		    received_damage        : 1;
 
   guint		    needs_pixmap           : 1;
+#endif
   guint             needs_reshape          : 1;
   guint             recompute_focused_shadow   : 1;
   guint             recompute_unfocused_shadow : 1;
+#ifndef HAVE_WAYLAND
   guint		    size_changed           : 1;
+#endif
 
   guint		    needs_destroy	   : 1;
 
   guint             no_shadow              : 1;
 
   guint             no_more_x_calls        : 1;
-
+#ifndef HAVE_WAYLAND
   guint             unredirected           : 1;
+#endif
 };
 
 enum
@@ -145,13 +158,19 @@ static gboolean meta_window_actor_get_paint_volume (ClutterActor       *actor,
                                                     ClutterPaintVolume *volume);
 
 
+#ifndef HAVE_WAYLAND
 static void     meta_window_actor_detach     (MetaWindowActor *self);
+#endif
 static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
 
 static void meta_window_actor_clear_shape_region    (MetaWindowActor *self);
 static void meta_window_actor_clear_bounding_region (MetaWindowActor *self);
 static void meta_window_actor_clear_shadow_clip     (MetaWindowActor *self);
 
+static void meta_window_actor_update_bounding_region_and_borders (MetaWindowActor *self,
+                                                                  int              width,
+                                                                  int              height);
+
 G_DEFINE_TYPE (MetaWindowActor, meta_window_actor, CLUTTER_TYPE_GROUP);
 
 static void
@@ -257,9 +276,11 @@ window_decorated_notify (MetaWindow *mw,
   MetaWindowActor        *self     = META_WINDOW_ACTOR (data);
   MetaWindowActorPrivate *priv     = self->priv;
   MetaFrame              *frame    = meta_window_get_frame (mw);
+#ifndef HAVE_WAYLAND
   MetaScreen             *screen   = priv->screen;
   MetaDisplay            *display  = meta_screen_get_display (screen);
   Display                *xdisplay = meta_display_get_xdisplay (display);
+#endif
   Window                  new_xwindow;
 
   /*
@@ -273,6 +294,7 @@ window_decorated_notify (MetaWindow *mw,
   else
     new_xwindow = meta_window_get_xwindow (mw);
 
+#ifndef HAVE_WAYLAND
   meta_window_actor_detach (self);
 
   /*
@@ -286,6 +308,7 @@ window_decorated_notify (MetaWindow *mw,
       meta_error_trap_pop (display);
       priv->damage = None;
     }
+#endif
 
   g_free (priv->desc);
   priv->desc = NULL;
@@ -306,6 +329,21 @@ window_appears_focused_notify (MetaWindow *mw,
   clutter_actor_queue_redraw (CLUTTER_ACTOR (data));
 }
 
+#ifdef HAVE_WAYLAND
+static void
+cogl_texture_notify (ClutterWaylandSurface *surface,
+                     GParamSpec             *arg1,
+                     MetaWindowActor        *self)
+{
+  CoglHandle tex = clutter_wayland_surface_get_cogl_texture (surface);
+  int width = cogl_texture_get_width (tex);
+  int height = cogl_texture_get_height (tex);
+  meta_window_actor_update_bounding_region_and_borders (self,
+                                                        width,
+                                                        height);
+}
+#endif
+
 static void
 meta_window_actor_constructed (GObject *object)
 {
@@ -318,8 +356,10 @@ meta_window_actor_constructed (GObject *object)
   Display                *xdisplay = meta_display_get_xdisplay (display);
   XRenderPictFormat      *format;
 
+#ifndef HAVE_WAYLAND
   priv->damage = XDamageCreate (xdisplay, xwindow,
                                 XDamageReportBoundingBox);
+#endif
 
   format = XRenderFindVisualFormat (xdisplay, window->xvisual);
 
@@ -328,7 +368,12 @@ meta_window_actor_constructed (GObject *object)
 
   if (!priv->actor)
     {
-      priv->actor = meta_shaped_texture_new ();
+      if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
+        priv->actor = meta_shaped_texture_new_with_xwindow (xwindow);
+#ifdef HAVE_WAYLAND
+      else
+        priv->actor = meta_shaped_texture_new_with_surface (window->surface);
+#endif
 
       clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->actor);
 
@@ -345,6 +390,10 @@ meta_window_actor_constructed (GObject *object)
                         G_CALLBACK (window_decorated_notify), self);
       g_signal_connect (window, "notify::appears-focused",
                         G_CALLBACK (window_appears_focused_notify), self);
+#ifdef HAVE_WAYLAND
+      g_signal_connect (priv->actor, "notify::cogl-texture",
+                        G_CALLBACK (cogl_texture_notify), self);
+#endif
     }
   else
     {
@@ -365,8 +414,10 @@ meta_window_actor_dispose (GObject *object)
   MetaWindowActor        *self = META_WINDOW_ACTOR (object);
   MetaWindowActorPrivate *priv = self->priv;
   MetaScreen             *screen;
+#ifndef HAVE_WAYLAND
   MetaDisplay            *display;
   Display                *xdisplay;
+#endif
   MetaCompScreen         *info;
 
   if (priv->disposed)
@@ -375,11 +426,13 @@ meta_window_actor_dispose (GObject *object)
   priv->disposed = TRUE;
 
   screen   = priv->screen;
+  info     = meta_screen_get_compositor_data (screen);
+#ifndef HAVE_WAYLAND
   display  = meta_screen_get_display (screen);
   xdisplay = meta_display_get_xdisplay (display);
-  info     = meta_screen_get_compositor_data (screen);
 
   meta_window_actor_detach (self);
+#endif
 
   meta_window_actor_clear_shape_region (self);
   meta_window_actor_clear_bounding_region (self);
@@ -409,6 +462,7 @@ meta_window_actor_dispose (GObject *object)
       priv->shadow_shape = NULL;
     }
 
+#ifndef HAVE_WAYLAND
   if (priv->damage != None)
     {
       meta_error_trap_push (display);
@@ -417,6 +471,7 @@ meta_window_actor_dispose (GObject *object)
 
       priv->damage = None;
     }
+#endif
 
   info->windows = g_list_remove (info->windows, (gconstpointer) self);
 
@@ -913,6 +968,7 @@ meta_window_actor_freeze (MetaWindowActor *self)
   self->priv->freeze_count++;
 }
 
+#ifndef HAVE_WAYLAND
 static void
 meta_window_actor_damage_all (MetaWindowActor *self)
 {
@@ -934,6 +990,7 @@ meta_window_actor_damage_all (MetaWindowActor *self)
 
   priv->needs_damage_all = FALSE;
 }
+#endif
 
 static void
 meta_window_actor_thaw (MetaWindowActor *self)
@@ -950,12 +1007,14 @@ meta_window_actor_thaw (MetaWindowActor *self)
   if (self->priv->freeze_count)
     return;
 
+#ifndef HAVE_WAYLAND
   /* 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);
+#endif
 }
 
 gboolean
@@ -968,6 +1027,7 @@ meta_window_actor_effect_in_progress (MetaWindowActor *self)
 	  self->priv->destroy_in_progress);
 }
 
+#ifndef HAVE_WAYLAND
 static void
 meta_window_actor_queue_create_pixmap (MetaWindowActor *self)
 {
@@ -988,6 +1048,7 @@ meta_window_actor_queue_create_pixmap (MetaWindowActor *self)
    */
   clutter_actor_queue_redraw (priv->actor);
 }
+#endif
 
 static gboolean
 is_freeze_thaw_effect (gulong event)
@@ -1070,11 +1131,13 @@ meta_window_actor_after_effects (MetaWindowActor *self)
   meta_window_actor_sync_visibility (self);
   meta_window_actor_sync_actor_position (self);
 
+#ifndef HAVE_WAYLAND
   if (!meta_window_is_mapped (priv->window))
     meta_window_actor_detach (self);
 
   if (priv->needs_pixmap)
     clutter_actor_queue_redraw (priv->actor);
+#endif
 }
 
 void
@@ -1149,6 +1212,7 @@ meta_window_actor_effect_completed (MetaWindowActor *self,
     meta_window_actor_after_effects (self);
 }
 
+#ifndef HAVE_WAYLAND
 /* 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
@@ -1178,6 +1242,7 @@ meta_window_actor_detach (MetaWindowActor *self)
 
   meta_window_actor_queue_create_pixmap (self);
 }
+#endif /* HAVE_WAYLAND */
 
 gboolean
 meta_window_actor_should_unredirect (MetaWindowActor *self)
@@ -1215,6 +1280,7 @@ meta_window_actor_should_unredirect (MetaWindowActor *self)
   return FALSE;
 }
 
+#ifndef HAVE_WAYLAND
 void
 meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state)
 {
@@ -1240,6 +1306,7 @@ meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state)
       self->priv->unredirected = TRUE;
     }
 }
+#endif
 
 void
 meta_window_actor_destroy (MetaWindowActor *self)
@@ -1299,6 +1366,7 @@ meta_window_actor_sync_actor_position (MetaWindowActor *self)
 
   meta_window_get_input_rect (priv->window, &window_rect);
 
+#ifndef HAVE_WAYLAND
   if (priv->last_width != window_rect.width ||
       priv->last_height != window_rect.height)
     {
@@ -1308,6 +1376,7 @@ meta_window_actor_sync_actor_position (MetaWindowActor *self)
       priv->last_width = window_rect.width;
       priv->last_height = window_rect.height;
     }
+#endif
 
   if (meta_window_actor_effect_in_progress (self))
     return;
@@ -1468,17 +1537,30 @@ meta_window_actor_new (MetaWindow *window)
   MetaScreen	 	 *screen = meta_window_get_screen (window);
   MetaCompScreen         *info = meta_screen_get_compositor_data (screen);
   MetaWindowActor        *self;
+#ifndef HAVE_WAYLAND
   MetaWindowActorPrivate *priv;
+#endif
   MetaFrame		 *frame;
-  Window		  top_window;
+  Window		  top_window = None;
 
-  frame = meta_window_get_frame (window);
-  if (frame)
-    top_window = meta_frame_get_xwindow (frame);
-  else
-    top_window = meta_window_get_xwindow (window);
+  if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
+    {
+      frame = meta_window_get_frame (window);
+      if (frame)
+        top_window = meta_frame_get_xwindow (frame);
+      else
+        top_window = meta_window_get_xwindow (window);
 
-  meta_verbose ("add window: Meta %p, xwin 0x%x\n", window, (guint)top_window);
+      meta_verbose ("add window: Meta %p, xwin 0x%x\n", window, (guint)top_window);
+    }
+#ifdef HAVE_WAYLAND
+  else
+    {
+      meta_verbose ("add window: Meta %p, wayland surface %p\n",
+                    window, window->surface);
+      top_window = None;
+    }
+#endif
 
   self = g_object_new (META_TYPE_WINDOW_ACTOR,
                        "meta-window",         window,
@@ -1486,6 +1568,7 @@ meta_window_actor_new (MetaWindow *window)
                        "meta-screen",         screen,
                        NULL);
 
+#ifndef HAVE_WAYLAND
   priv = self->priv;
 
   priv->last_width = -1;
@@ -1494,6 +1577,7 @@ meta_window_actor_new (MetaWindow *window)
   priv->mapped = meta_window_toplevel_is_mapped (priv->window);
   if (priv->mapped)
     meta_window_actor_queue_create_pixmap (self);
+#endif
 
   meta_window_actor_sync_actor_position (self);
 
@@ -1521,7 +1605,9 @@ meta_window_actor_mapped (MetaWindowActor *self)
 
   priv->mapped = TRUE;
 
+#ifndef HAVE_WAYLAND
   meta_window_actor_queue_create_pixmap (self);
+#endif
 }
 
 void
@@ -1536,8 +1622,10 @@ meta_window_actor_unmapped (MetaWindowActor *self)
   if (meta_window_actor_effect_in_progress (self))
     return;
 
+#ifndef HAVE_WAYLAND
   meta_window_actor_detach (self);
   priv->needs_pixmap = FALSE;
+#endif
 }
 
 static void
@@ -1667,7 +1755,12 @@ meta_window_actor_get_obscured_region (MetaWindowActor *self)
 {
   MetaWindowActorPrivate *priv = self->priv;
 
-  if (!priv->argb32 && priv->opacity == 0xff && priv->back_pixmap)
+  if (!priv->argb32 && priv->opacity == 0xff
+#ifndef HAVE_WAYLAND
+      && priv->back_pixmap)
+#else
+      )
+#endif
     {
       if (priv->shape_region)
         return priv->shape_region;
@@ -1768,6 +1861,10 @@ meta_window_actor_reset_visible_regions (MetaWindowActor *self)
   meta_window_actor_clear_shadow_clip (self);
 }
 
+/* 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. */
+#ifndef HAVE_WAYLAND
 static void
 check_needs_pixmap (MetaWindowActor *self)
 {
@@ -1853,6 +1950,7 @@ check_needs_pixmap (MetaWindowActor *self)
  out:
   meta_error_trap_pop (display);
 }
+#endif
 
 static void
 check_needs_shadow (MetaWindowActor *self)
@@ -1933,6 +2031,7 @@ is_frozen (MetaWindowActor *self)
   return self->priv->freeze_count ? TRUE : FALSE;
 }
 
+#ifndef HAVE_WAYLAND
 void
 meta_window_actor_process_damage (MetaWindowActor    *self,
                                   XDamageNotifyEvent *event)
@@ -1974,6 +2073,7 @@ meta_window_actor_process_damage (MetaWindowActor    *self,
                                    event->area.width,
                                    event->area.height);
 }
+#endif
 
 void
 meta_window_actor_sync_visibility (MetaWindowActor *self)
@@ -2217,10 +2317,12 @@ meta_window_actor_update_shape (MetaWindowActor *self)
 void
 meta_window_actor_pre_paint (MetaWindowActor *self)
 {
+#ifndef HAVE_WAYLAND
   MetaWindowActorPrivate *priv = self->priv;
   MetaScreen          *screen   = priv->screen;
   MetaDisplay         *display  = meta_screen_get_display (screen);
   Display             *xdisplay = meta_display_get_xdisplay (display);
+#endif
 
   if (is_frozen (self))
     {
@@ -2229,6 +2331,7 @@ meta_window_actor_pre_paint (MetaWindowActor *self)
       return;
     }
 
+#ifndef HAVE_WAYLAND
   if (priv->unredirected)
     {
       /* Nothing to do here until/if the window gets redirected again */
@@ -2265,6 +2368,7 @@ meta_window_actor_pre_paint (MetaWindowActor *self)
     }
 
   check_needs_pixmap (self);
+#endif
   check_needs_reshape (self);
   check_needs_shadow (self);
 }
@@ -2301,3 +2405,11 @@ meta_window_actor_update_opacity (MetaWindowActor *self)
   self->priv->opacity = opacity;
   clutter_actor_set_opacity (self->priv->actor, opacity);
 }
+
+#ifdef HAVE_WAYLAND
+ClutterActor *
+meta_window_actor_get_shaped_texture (MetaWindowActor *self)
+{
+  return self->priv->actor;
+}
+#endif
diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c
index 4ec71f3..876c935 100644
--- a/src/compositor/meta-window-group.c
+++ b/src/compositor/meta-window-group.c
@@ -11,6 +11,7 @@
 #include "meta-window-actor-private.h"
 #include "meta-window-group.h"
 #include "meta-background-actor-private.h"
+#include "window-private.h"
 
 struct _MetaWindowGroupClass
 {
@@ -107,8 +108,10 @@ meta_window_group_paint (ClutterActor *actor)
   cairo_region_t *visible_region;
   cairo_region_t *unredirected_window_region = NULL;
   ClutterActor *stage;
-  cairo_rectangle_int_t visible_rect, unredirected_rect;
+  cairo_rectangle_int_t visible_rect;
   GList *children, *l;
+#ifndef HAVE_WAYLAND
+  cairo_rectangle_int_t unredirected_rect;
 
   MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
   MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
@@ -117,6 +120,7 @@ meta_window_group_paint (ClutterActor *actor)
       meta_window_actor_get_shape_bounds (META_WINDOW_ACTOR (info->unredirected_window), &unredirected_rect);
       unredirected_window_region = cairo_region_create_rectangle (&unredirected_rect);
     }
+#endif
 
   /* We walk the list from top to bottom (opposite of painting order),
    * and subtract the opaque area of each window out of the visible
@@ -166,6 +170,7 @@ meta_window_group_paint (ClutterActor *actor)
 
       if (META_IS_WINDOW_ACTOR (l->data))
         {
+          MetaWindow *meta_window;
           MetaWindowActor *window_actor = l->data;
           int x, y;
 
@@ -177,7 +182,13 @@ meta_window_group_paint (ClutterActor *actor)
 
           meta_window_actor_set_visible_region (window_actor, visible_region);
 
-          if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
+          /* Currently wayland clients have no way to report opaque
+           * window regions so for now we assume that all wayland
+           * clients are transparent... */
+          meta_window = meta_window_actor_get_meta_window (window_actor);
+
+          if (meta_window->client_type != META_WINDOW_CLIENT_TYPE_WAYLAND &&
+              clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
             {
               cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
               if (obscured_region)
diff --git a/src/core/display.c b/src/core/display.c
index 6ef744e..4f3a67f 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -397,8 +397,14 @@ enable_compositor (MetaDisplay *display,
       meta_compositor_manage_screen (screen->display->compositor,
 				     screen);
 
+      /* Instead of explicitly enumerating all windows during
+       * initialization, when we run as a wayland compositor we can
+       * rely on xwayland notifying us of all top level windows so
+       * we start compositing them when we get those notifications. */
+#ifndef HAVE_WAYLAND
       if (composite_windows)
         meta_screen_composite_all_windows (screen);
+#endif
     }
 }
 
@@ -841,14 +847,29 @@ meta_display_open (void)
   enable_compositor (the_display, FALSE);
    
   meta_display_grab (the_display);
-  
+
   /* Now manage all existing windows */
   tmp = the_display->screens;
   while (tmp != NULL)
     {
       MetaScreen *screen = tmp->data;
-	
+
+#ifndef HAVE_WAYLAND
       meta_screen_manage_all_windows (screen);
+#else
+      /* Instead of explicitly enumerating all windows during
+       * initialization, when we run as a wayland compositor we can rely on
+       * xwayland notifying us of all top level windows so we create
+       * MetaWindows when we get those notifications.
+       *
+       * We still want a guard window so we can avoid
+       * unmapping/withdrawing minimized windows for live
+       * thumbnails...
+       */
+      if (screen->guard_window == None)
+        screen->guard_window =
+          meta_screen_create_guard_window (screen->display->xdisplay, screen);
+#endif
 
       tmp = tmp->next;
     }
@@ -2369,9 +2390,11 @@ event_callback (XEvent   *event,
 	      screen->xscreen->height  = event->xconfigure.height;
 #endif
 	      
+#ifndef HAVE_WAYLAND
 	      meta_screen_resize (screen, 
 				  event->xconfigure.width,
 				  event->xconfigure.height);
+#endif
 	    }
 	}
       break;
diff --git a/src/core/main.c b/src/core/main.c
index 8718319..76a8234 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -54,6 +54,7 @@
 #include "session.h"
 #include <meta/prefs.h>
 #include <meta/compositor.h>
+#include "meta-wayland-private.h"
 
 #include <glib-object.h>
 #include <gdk/gdkx.h>
@@ -255,6 +256,8 @@ meta_get_option_context (void)
   return ctx;
 }
 
+#ifndef HAVE_WAYLAND
+
 /* Mutter is responsible for pulling events off the X queue, so Clutter
  * doesn't need (and shouldn't) run its normal event source which polls
  * the X fd, but we do have to deal with dispatching events that accumulate
@@ -337,6 +340,7 @@ meta_select_display (gchar *display_name)
   /* DO NOT FREE envVar, putenv() sucks */
   putenv (envVar);
 }
+#endif
 
 static void
 meta_finalize (void)
@@ -346,28 +350,73 @@ meta_finalize (void)
   if (display)
     meta_display_close (display,
                         CurrentTime); /* I doubt correct timestamps matter here */
+
+#ifdef HAVE_WAYLAND
+  meta_wayland_finalize ();
+#endif
 }
 
-static int sigterm_pipe_fds[2] = { -1, -1 };
+static int signal_pipe_fds[2] = { -1, -1 };
 
 static void
-sigterm_handler (int signum)
+signal_handler (int signum)
 {
-  if (sigterm_pipe_fds[1] >= 0)
+  if (signal_pipe_fds[1] >= 0)
     {
-      int G_GNUC_UNUSED dummy;
-
-      dummy = write (sigterm_pipe_fds[1], "", 1);
-      close (sigterm_pipe_fds[1]);
-      sigterm_pipe_fds[1] = -1;
+      switch (signum)
+        {
+        case SIGTERM:
+          write (signal_pipe_fds[1], "T", 1);
+          break;
+        case SIGCHLD:
+          write (signal_pipe_fds[1], "C", 1);
+          break;
+        default:
+          break;
+        }
     }
 }
 
 static gboolean
-on_sigterm (void)
+on_signal (GIOChannel *source,
+           GIOCondition condition,
+           void *data)
 {
-  meta_quit (META_EXIT_SUCCESS);
-  return FALSE;
+  char signal;
+  int count;
+
+  for (;;)
+    {
+      count = read (signal_pipe_fds[0], &signal, 1);
+      if (count == EINTR)
+        continue;
+      if (count < 0)
+        {
+          const char *msg = strerror (errno);
+          g_warning ("Error handling signal: %s", msg);
+        }
+      if (count != 1)
+        {
+          g_warning ("Unexpectedly failed to read byte from signal pipe\n");
+          return TRUE;
+        }
+      break;
+    }
+  switch (signal)
+    {
+    case 'T': /* SIGTERM */
+      meta_quit (META_EXIT_SUCCESS);
+      break;
+#ifdef HAVE_WAYLAND
+    case 'C': /* SIGCHLD */
+          meta_wayland_handle_sig_child ();
+      break;
+#endif
+    default:
+      g_warning ("Spurious character '%c' read from signal pipe", signal);
+    }
+
+  return TRUE;
 }
 
 /**
@@ -398,20 +447,25 @@ meta_init (void)
                 g_strerror (errno));
 #endif
 
-  if (pipe (sigterm_pipe_fds) != 0)
-    g_printerr ("Failed to create SIGTERM pipe: %s\n",
+  if (pipe (signal_pipe_fds) != 0)
+    g_printerr ("Failed to create signal pipe: %s\n",
                 g_strerror (errno));
 
-  channel = g_io_channel_unix_new (sigterm_pipe_fds[0]);
+  channel = g_io_channel_unix_new (signal_pipe_fds[0]);
   g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
-  g_io_add_watch (channel, G_IO_IN, (GIOFunc) on_sigterm, NULL);
+  g_io_add_watch (channel, G_IO_IN, (GIOFunc) on_signal, NULL);
   g_io_channel_set_close_on_unref (channel, TRUE);
   g_io_channel_unref (channel);
 
-  act.sa_handler = &sigterm_handler;
+  act.sa_handler = &signal_handler;
   if (sigaction (SIGTERM, &act, NULL) < 0)
     g_printerr ("Failed to register SIGTERM handler: %s\n",
 		g_strerror (errno));
+#ifdef HAVE_WAYLAND
+  if (sigaction (SIGCHLD, &act, NULL) < 0)
+    g_printerr ("Failed to register SIGCHLD handler: %s\n",
+		g_strerror (errno));
+#endif
 
   if (g_getenv ("MUTTER_VERBOSE"))
     meta_set_verbose (TRUE);
@@ -429,9 +483,15 @@ meta_init (void)
   g_irepository_prepend_search_path (MUTTER_PKGLIBDIR);
 #endif
 
-  meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL));
-
+#ifdef HAVE_WAYLAND
+  /* NB: When running as a hybrid wayland compositor we run our own headless X
+   * server so the user can't control the X display to connect too. */
+  meta_wayland_init ();
+#else
   meta_select_display (opt_display_name);
+#endif
+
+  meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL));
   
   if (opt_replace_wm)
     meta_set_replace_current_wm (TRUE);
@@ -443,10 +503,16 @@ meta_init (void)
   
   meta_ui_init ();
 
+  /* If we are running with wayland then we don't wait until we have
+   * an X connection before initializing clutter we instead initialize
+   * it earlier since we need to initialize the GL driver so the driver
+   * can register any needed wayland extensions. */
+#ifndef HAVE_WAYLAND
   /*
    * Clutter can only be initialized after the UI.
    */
   meta_clutter_init ();
+#endif
 }
 
 /**
diff --git a/src/core/screen-private.h b/src/core/screen-private.h
index 866f5fb..0f0c484 100644
--- a/src/core/screen-private.h
+++ b/src/core/screen-private.h
@@ -254,4 +254,6 @@ void     meta_screen_workspace_switched (MetaScreen         *screen,
 
 void meta_screen_set_active_workspace_hint (MetaScreen *screen);
 
+Window   meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen);
+
 #endif
diff --git a/src/core/screen.c b/src/core/screen.c
index 536fd19..e776846 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -40,6 +40,9 @@
 #include "xprops.h"
 #include <meta/compositor.h>
 #include "mutter-enum-types.h"
+#ifdef HAVE_WAYLAND
+#include "meta-wayland-private.h"
+#endif
 
 #include <X11/extensions/Xinerama.h>
 
@@ -574,8 +577,8 @@ reload_monitor_infos (MetaScreen *screen)
  * that compositor code may provide live previews of them.
  * Instead of being unmapped/withdrawn, they get pushed underneath
  * the guard window. */
-static Window
-create_guard_window (Display *xdisplay, MetaScreen *screen)
+Window
+meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen)
 {
   XSetWindowAttributes attributes;
   Window guard_window;
@@ -629,6 +632,9 @@ meta_screen_new (MetaDisplay *display,
   char buf[128];
   guint32 manager_timestamp;
   gulong current_workspace;
+#ifdef HAVE_WAYLAND
+  MetaWaylandCompositor *compositor;
+#endif
   
   replace_current_wm = meta_get_replace_current_wm ();
   
@@ -764,8 +770,14 @@ meta_screen_new (MetaDisplay *display,
   screen->xscreen = ScreenOfDisplay (xdisplay, number);
   screen->xroot = xroot;
   screen->rect.x = screen->rect.y = 0;
+#ifdef HAVE_WAYLAND
+  compositor = meta_wayland_compositor_get_default ();
+  screen->rect.width = clutter_actor_get_width (compositor->stage);
+  screen->rect.height = clutter_actor_get_height (compositor->stage);
+#else
   screen->rect.width = WidthOfScreen (screen->xscreen);
   screen->rect.height = HeightOfScreen (screen->xscreen);
+#endif
   screen->current_cursor = -1; /* invalid/unset */
   screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
   screen->default_depth = DefaultDepthOfScreen (screen->xscreen);
@@ -1008,6 +1020,11 @@ list_windows (MetaScreen *screen)
   return g_list_reverse (result);
 }
 
+/* Instead of explicitly enumerating all windows during
+ * initialization, when we run as a wayland compositor we can rely on
+ * xwayland notifying us of all top level windows so we create
+ * MetaWindows when we get those notifications. */
+#ifndef HAVE_WAYLAND
 void
 meta_screen_manage_all_windows (MetaScreen *screen)
 {
@@ -1017,8 +1034,8 @@ meta_screen_manage_all_windows (MetaScreen *screen)
   meta_display_grab (screen->display);
 
   if (screen->guard_window == None)
-    screen->guard_window = create_guard_window (screen->display->xdisplay,
-                                                screen);
+    screen->guard_window =
+      meta_screen_create_guard_window (screen->display->xdisplay, screen);
 
   windows = list_windows (screen);
 
@@ -1066,6 +1083,7 @@ meta_screen_composite_all_windows (MetaScreen *screen)
   /* initialize the compositor's view of the stacking order */
   meta_stack_tracker_sync_stack (screen->stack_tracker);
 }
+#endif /* HAVE_WAYLAND */
 
 /**
  * meta_screen_for_x_screen:
diff --git a/src/core/window-private.h b/src/core/window-private.h
index d89924c..76370d9 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -44,6 +44,17 @@
 #include <X11/Xutil.h>
 #include <cairo.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
+#ifdef HAVE_WAYLAND
+#include "meta-wayland-private.h"
+#endif
+
+/* XXX: We should find a nicer approach to deal with the
+ * circular dependency we have with the current headers
+ * (meta-wayland-private.h which typedefs MetaWaylandSurface
+ *  also includes window-private.h) */
+#ifndef HAVE_META_WAYLAND_SURFACE_TYPE
+typedef struct _MetaWaylandSurface MetaWaylandSurface;
+#endif
 
 typedef struct _MetaWindowQueue MetaWindowQueue;
 
@@ -62,6 +73,11 @@ typedef enum {
 
 #define NUMBER_OF_QUEUES 3
 
+typedef enum {
+  META_WINDOW_CLIENT_TYPE_WAYLAND,
+  META_WINDOW_CLIENT_TYPE_X11
+} MetaWindowClientType;
+
 struct _MetaWindow
 {
   GObject parent_instance;
@@ -70,6 +86,10 @@ struct _MetaWindow
   MetaScreen *screen;
   const MetaMonitorInfo *monitor;
   MetaWorkspace *workspace;
+  MetaWindowClientType client_type;
+#ifdef HAVE_WAYLAND
+  MetaWaylandSurface *surface;
+#endif
   Window xwindow;
   /* may be NULL! not all windows get decorated */
   MetaFrame *frame;
@@ -458,6 +478,10 @@ MetaWindow* meta_window_new_with_attrs     (MetaDisplay       *display,
                                             gboolean           must_be_viewable,
                                             MetaCompEffect     effect,
                                             XWindowAttributes *attrs);
+MetaWindow *meta_window_new_for_wayland    (MetaDisplay        *display,
+                                            int                 width,
+                                            int                 height,
+                                            MetaWaylandSurface *surface);
 void        meta_window_unmanage           (MetaWindow  *window,
                                             guint32      timestamp);
 void        meta_window_calc_showing       (MetaWindow  *window);
diff --git a/src/core/window.c b/src/core/window.c
index d76c9fb..3ddf98f 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -793,12 +793,14 @@ meta_window_should_attach_to_parent (MetaWindow *window)
     }
 }
 
-MetaWindow*
-meta_window_new_with_attrs (MetaDisplay       *display,
-                            Window             xwindow,
-                            gboolean           must_be_viewable,
-                            MetaCompEffect     effect,
-                            XWindowAttributes *attrs)
+static MetaWindow*
+meta_window_new_full (MetaDisplay         *display,
+                      MetaWindowClientType client_type,
+                      MetaWaylandSurface  *surface,
+                      Window               xwindow,
+                      gboolean             must_be_viewable,
+                      MetaCompEffect       effect,
+                      XWindowAttributes   *attrs)
 {
   MetaWindow *window;
   GSList *tmp;
@@ -813,7 +815,8 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 
   meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
 
-  if (meta_display_xwindow_is_a_no_focus_window (display, xwindow))
+  if (client_type == META_WINDOW_CLIENT_TYPE_X11 &&
+      meta_display_xwindow_is_a_no_focus_window (display, xwindow))
     {
       meta_verbose ("Not managing no_focus_window 0x%lx\n",
                     xwindow);
@@ -904,33 +907,39 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 
   meta_error_trap_push_with_return (display);
 
-  /*
-   * XAddToSaveSet can only be called on windows created by a different client.
-   * with Mutter we want to be able to create manageable windows from within
-   * the process (such as a dummy desktop window), so we do not want this
-   * call failing to prevent the window from being managed -- wrap it in its
-   * own error trap (we use the _with_return() version here to ensure that
-   * XSync() is done on the pop, otherwise the error will not get caught).
-   */
-  meta_error_trap_push_with_return (display);
-  XAddToSaveSet (display->xdisplay, xwindow);
-  meta_error_trap_pop_with_return (display);
-
-  event_mask =
-    PropertyChangeMask | EnterWindowMask | LeaveWindowMask |
-    FocusChangeMask | ColormapChangeMask;
-  if (attrs->override_redirect)
-    event_mask |= StructureNotifyMask;
-
-  /* If the window is from this client (a menu, say) we need to augment
-   * the event mask, not replace it. For windows from other clients,
-   * attrs->your_event_mask will be empty at this point.
-   */
-  XSelectInput (display->xdisplay, xwindow, attrs->your_event_mask | event_mask);
+  if (client_type == META_WINDOW_CLIENT_TYPE_X11)
+    {
+      /*
+       * XAddToSaveSet can only be called on windows created by a different
+       * client.  with Mutter we want to be able to create manageable windows
+       * from within the process (such as a dummy desktop window), so we do not
+       * want this call failing to prevent the window from being managed --
+       * wrap it in its own error trap (we use the _with_return() version here
+       * to ensure that XSync() is done on the pop, otherwise the error will
+       * not get caught).
+       */
+      meta_error_trap_push_with_return (display);
+      XAddToSaveSet (display->xdisplay, xwindow);
+      meta_error_trap_pop_with_return (display);
+
+      event_mask =
+        PropertyChangeMask | EnterWindowMask | LeaveWindowMask |
+        FocusChangeMask | ColormapChangeMask;
+      if (attrs->override_redirect)
+        event_mask |= StructureNotifyMask;
+
+      /* If the window is from this client (a menu, say) we need to augment the
+       * event mask, not replace it. For windows from other clients,
+       * attrs->your_event_mask will be empty at this point.
+       */
+      XSelectInput (display->xdisplay, xwindow,
+                    attrs->your_event_mask | event_mask);
+    }
 
   has_shape = FALSE;
 #ifdef HAVE_SHAPE
-  if (META_DISPLAY_HAS_SHAPE (display))
+  if (META_DISPLAY_HAS_SHAPE (display) &&
+      client_type == META_WINDOW_CLIENT_TYPE_X11)
     {
       int x_bounding, y_bounding, x_clip, y_clip;
       unsigned w_bounding, h_bounding, w_clip, h_clip;
@@ -986,6 +995,10 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 
   window->dialog_pid = -1;
 
+  window->client_type = client_type;
+#ifdef HAVE_WAYLAND
+  window->surface = surface;
+#endif
   window->xwindow = xwindow;
 
   /* this is in window->screen->display, but that's too annoying to
@@ -1111,7 +1124,11 @@ meta_window_new_with_attrs (MetaDisplay       *display,
   window->mwm_has_move_func = TRUE;
   window->mwm_has_resize_func = TRUE;
 
-  window->decorated = TRUE;
+  if (client_type == META_WINDOW_CLIENT_TYPE_X11)
+    window->decorated = TRUE;
+  else
+    window->decorated = FALSE;
+
   window->has_close_func = TRUE;
   window->has_minimize_func = TRUE;
   window->has_maximize_func = TRUE;
@@ -1179,7 +1196,8 @@ meta_window_new_with_attrs (MetaDisplay       *display,
       window->has_resize_func = FALSE;
     }
 
-  meta_display_register_x_window (display, &window->xwindow, window);
+  if (client_type == META_WINDOW_CLIENT_TYPE_X11)
+    meta_display_register_x_window (display, &window->xwindow, window);
 
   /* Assign this #MetaWindow a sequence number which can be used
    * for sorting.
@@ -1194,7 +1212,8 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 
   meta_window_load_initial_properties (window);
 
-  if (!window->override_redirect)
+  if (!window->override_redirect &&
+      client_type == META_WINDOW_CLIENT_TYPE_X11)
     {
       update_sm_hints (window); /* must come after transient_for */
 
@@ -1481,6 +1500,68 @@ meta_window_new_with_attrs (MetaDisplay       *display,
   return window;
 }
 
+#ifdef HAVE_WAYLAND
+MetaWindow *
+meta_window_new_for_wayland (MetaDisplay        *display,
+                             int                 width,
+                             int                 height,
+                             MetaWaylandSurface *surface)
+{
+  XWindowAttributes attrs;
+  MetaScreen *scr = display->screens->data;
+  MetaWindow *window;
+
+  attrs.x = 0;
+  attrs.y = 0;
+  attrs.width = width;
+  attrs.height = height;
+  attrs.border_width = 0;
+  attrs.depth = 24;
+  attrs.visual = NULL;
+  attrs.root = scr->xroot;
+  attrs.class = InputOutput;
+  attrs.bit_gravity = NorthWestGravity;
+  attrs.win_gravity = NorthWestGravity;
+  attrs.backing_store = 0;
+  attrs.backing_planes = ~0;
+  attrs.backing_pixel = 0;
+  attrs.save_under = 0;
+  attrs.colormap = 0;
+  attrs.map_installed = 1;
+  attrs.map_state = IsViewable;
+  attrs.all_event_masks = ~0;
+  attrs.your_event_mask = 0;
+  attrs.do_not_propagate_mask = 0;
+  attrs.override_redirect = 0;
+  attrs.screen = scr->xscreen;
+
+  window = meta_window_new_full (display,
+                                 META_WINDOW_CLIENT_TYPE_WAYLAND,
+                                 surface,
+                                 None,
+                                 TRUE,
+                                 META_COMP_EFFECT_NONE,
+                                 &attrs);
+  return window;
+}
+#endif
+
+MetaWindow*
+meta_window_new_with_attrs (MetaDisplay       *display,
+                            Window             xwindow,
+                            gboolean           must_be_viewable,
+                            MetaCompEffect     effect,
+                            XWindowAttributes *attrs)
+{
+  return meta_window_new_full (display,
+                               META_WINDOW_CLIENT_TYPE_X11,
+                               NULL,
+                               xwindow,
+                               must_be_viewable,
+                               effect,
+                               attrs);
+}
+
 /* This function should only be called from the end of meta_window_new_with_attrs () */
 static void
 meta_window_apply_session_info (MetaWindow *window,
diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h
index b8932a6..7849aa4 100644
--- a/src/meta/meta-shaped-texture.h
+++ b/src/meta/meta-shaped-texture.h
@@ -29,6 +29,12 @@
 #include <clutter/clutter.h>
 #include <X11/Xlib.h>
 
+#ifdef HAVE_WAYLAND
+#include <wayland-server.h>
+#include "meta-wayland-private.h"
+#include <clutter/wayland/clutter-wayland-surface.h>
+#endif
+
 G_BEGIN_DECLS
 
 #define META_TYPE_SHAPED_TEXTURE            (meta_shaped_texture_get_type())
@@ -44,19 +50,30 @@ typedef struct _MetaShapedTexturePrivate MetaShapedTexturePrivate;
 
 struct _MetaShapedTextureClass
 {
+#ifdef HAVE_WAYLAND
+  ClutterWaylandSurfaceClass parent_class;
+#else
   ClutterActorClass parent_class;
+#endif
 };
 
 struct _MetaShapedTexture
 {
+#ifdef HAVE_WAYLAND
+  ClutterWaylandSurface parent;
+#else
   ClutterActor parent;
+#endif
 
   MetaShapedTexturePrivate *priv;
 };
 
 GType meta_shaped_texture_get_type (void) G_GNUC_CONST;
 
-ClutterActor *meta_shaped_texture_new (void);
+ClutterActor *meta_shaped_texture_new_with_xwindow (Window xwindow);
+#ifdef HAVE_WAYLAND
+ClutterActor *meta_shaped_texture_new_with_surface (MetaWaylandSurface *surface);
+#endif
 
 void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
 					     gboolean           create_mipmaps);
@@ -86,6 +103,17 @@ void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
 cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture     *stex,
                                                  cairo_rectangle_int_t *clip);
 
+#ifdef HAVE_WAYLAND
+void meta_shaped_texture_set_wayland_surface   (MetaShapedTexture *stex,
+                                                struct wl_surface *surface);
+void meta_shaped_texture_damage_wayland_buffer (MetaShapedTexture *self,
+                                                struct wl_buffer  *buffer,
+                                                gint32             x,
+                                                gint32             y,
+                                                gint32             width,
+                                                gint32             height);
+#endif
+
 G_END_DECLS
 
 #endif /* __META_SHAPED_TEXTURE_H__ */
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
new file mode 100644
index 0000000..d0c5412
--- /dev/null
+++ b/src/wayland/meta-wayland-private.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef META_WAYLAND_PRIVATE_H
+#define META_WAYLAND_PRIVATE_H
+
+#include <wayland-server.h>
+
+#include <clutter/clutter.h>
+
+#include <glib.h>
+
+#include "window-private.h"
+
+typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
+
+typedef struct
+{
+  struct wl_buffer *wayland_buffer;
+  GList *surfaces_attached_to;
+  struct wl_listener buffer_destroy_listener;
+} MetaWaylandBuffer;
+
+struct _MetaWaylandSurface
+{
+  struct wl_surface wayland_surface;
+  MetaWaylandCompositor *compositor;
+  guint32 xid;
+  int x;
+  int y;
+  MetaWaylandBuffer *buffer;
+  MetaWindow *window;
+  ClutterActor *actor;
+  gboolean has_shell_surface;
+  struct wl_listener surface_destroy_listener;
+};
+
+#ifndef HAVE_META_WAYLAND_SURFACE_TYPE
+typedef struct _MetaWaylandSurface MetaWaylandSurface;
+#endif
+
+typedef struct
+{
+  MetaWaylandSurface *surface;
+  struct wl_resource resource;
+  struct wl_listener surface_destroy_listener;
+} MetaWaylandShellSurface;
+
+typedef struct
+{
+  guint32 flags;
+  int width;
+  int height;
+  int refresh;
+} MetaWaylandMode;
+
+typedef struct
+{
+  struct wl_object wayland_output;
+  int x;
+  int y;
+  int width_mm;
+  int height_mm;
+  /* XXX: with sliced stages we'd reference a CoglFramebuffer here. */
+
+  GList *modes;
+} MetaWaylandOutput;
+
+typedef struct
+{
+  GSource source;
+  GPollFD pfd;
+  struct wl_event_loop *loop;
+} WaylandEventSource;
+
+typedef struct
+{
+  /* GList node used as an embedded list */
+  GList node;
+
+  /* Pointer back to the compositor */
+  MetaWaylandCompositor *compositor;
+
+  struct wl_resource resource;
+} MetaWaylandFrameCallback;
+
+struct _MetaWaylandCompositor
+{
+  struct wl_display *wayland_display;
+  struct wl_shm *wayland_shm;
+  struct wl_event_loop *wayland_loop;
+  GMainLoop *init_loop;
+  ClutterActor *stage;
+  GList *outputs;
+  GSource *wayland_event_source;
+  GList *surfaces;
+  GQueue frame_callbacks;
+
+  int xwayland_display_index;
+  char *xwayland_lockfile;
+  int xwayland_abstract_fd;
+  int xwayland_unix_fd;
+  pid_t xwayland_pid;
+  struct wl_client *xwayland_client;
+  struct wl_resource *xserver_resource;
+  GHashTable *window_surfaces;
+};
+
+void                    meta_wayland_init                   (void);
+void                    meta_wayland_finalize               (void);
+
+/* We maintain a singleton MetaWaylandCompositor which can be got at via this
+ * API after meta_wayland_init() has been called. */
+MetaWaylandCompositor  *meta_wayland_compositor_get_default (void);
+
+void                    meta_wayland_handle_sig_child       (void);
+
+MetaWaylandSurface     *meta_wayland_lookup_surface_for_xid (guint32 xid);
+
+#endif /* META_WAYLAND_PRIVATE_H */
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
new file mode 100644
index 0000000..b9e28ba
--- /dev/null
+++ b/src/wayland/meta-wayland.c
@@ -0,0 +1,1250 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#define COGL_ENABLE_EXPERIMENTAL_2_0_API
+#include <clutter/clutter.h>
+#include <clutter/wayland/clutter-wayland-compositor.h>
+#include <clutter/wayland/clutter-wayland-surface.h>
+
+#include <glib.h>
+#include <sys/time.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+
+#include <wayland-server.h>
+
+#include "xserver-server-protocol.h"
+
+#include "meta-wayland-private.h"
+#include "meta-window-actor-private.h"
+#include "display-private.h"
+#include "window-private.h"
+#include <meta/types.h>
+#include <meta/main.h>
+#include "frame.h"
+
+static MetaWaylandCompositor _meta_wayland_compositor;
+
+MetaWaylandCompositor *
+meta_wayland_compositor_get_default (void)
+{
+  return &_meta_wayland_compositor;
+}
+
+static guint32
+get_time (void)
+{
+  struct timeval tv;
+  gettimeofday (&tv, NULL);
+  return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
+static gboolean
+wayland_event_source_prepare (GSource *base, int *timeout)
+{
+  *timeout = -1;
+  return FALSE;
+}
+
+static gboolean
+wayland_event_source_check (GSource *base)
+{
+  WaylandEventSource *source = (WaylandEventSource *)base;
+  return source->pfd.revents;
+}
+
+static gboolean
+wayland_event_source_dispatch (GSource *base,
+                               GSourceFunc callback,
+                               void *data)
+{
+  WaylandEventSource *source = (WaylandEventSource *)base;
+  wl_event_loop_dispatch (source->loop, 0);
+  return TRUE;
+}
+
+static GSourceFuncs wayland_event_source_funcs =
+{
+  wayland_event_source_prepare,
+  wayland_event_source_check,
+  wayland_event_source_dispatch,
+  NULL
+};
+
+static GSource *
+wayland_event_source_new (struct wl_event_loop *loop)
+{
+  WaylandEventSource *source;
+
+  source = (WaylandEventSource *) g_source_new (&wayland_event_source_funcs,
+                                                sizeof (WaylandEventSource));
+  source->loop = loop;
+  source->pfd.fd = wl_event_loop_get_fd (loop);
+  source->pfd.events = G_IO_IN | G_IO_ERR;
+  g_source_add_poll (&source->source, &source->pfd);
+
+  return &source->source;
+}
+
+static void
+buffer_destroy_callback (struct wl_listener *listener,
+                         struct wl_resource *resource,
+                         guint32 time)
+{
+  MetaWaylandBuffer *buffer =
+    container_of (listener, MetaWaylandBuffer,
+                  buffer_destroy_listener);
+  GList *l;
+
+  buffer->wayland_buffer = NULL;
+
+  for (l = buffer->surfaces_attached_to; l; l = l->next)
+    {
+      MetaWaylandSurface *surface = l->data;
+      surface->buffer = NULL;
+    }
+
+  g_list_free (buffer->surfaces_attached_to);
+}
+
+static MetaWaylandBuffer *
+meta_wayland_buffer_new (struct wl_buffer *wayland_buffer)
+{
+  MetaWaylandBuffer *buffer = g_slice_new0 (MetaWaylandBuffer);
+
+  buffer->wayland_buffer = wayland_buffer;
+  buffer->surfaces_attached_to = NULL;
+
+  buffer->buffer_destroy_listener.func = buffer_destroy_callback;
+  wl_list_insert (wayland_buffer->resource.destroy_listener_list.prev,
+                  &buffer->buffer_destroy_listener.link);
+
+  return buffer;
+}
+
+static void
+meta_wayland_buffer_free (MetaWaylandBuffer *buffer)
+{
+  GList *l;
+
+  if (buffer->wayland_buffer)
+    {
+      buffer->wayland_buffer->user_data = NULL;
+
+      wl_list_remove (&buffer->buffer_destroy_listener.link);
+    }
+
+  for (l = buffer->surfaces_attached_to; l; l = l->next)
+    {
+      MetaWaylandSurface *surface = l->data;
+      surface->buffer = NULL;
+    }
+
+  g_list_free (buffer->surfaces_attached_to);
+  g_slice_free (MetaWaylandBuffer, buffer);
+}
+
+static void
+shm_buffer_created (struct wl_buffer *wayland_buffer)
+{
+  /* We ignore the buffer until it is attached to a surface */
+  wayland_buffer->user_data = NULL;
+}
+
+static void
+shm_buffer_damaged (struct wl_buffer *wayland_buffer,
+		    gint32 x,
+                    gint32 y,
+                    gint32 width,
+                    gint32 height)
+{
+  MetaWaylandBuffer *buffer = wayland_buffer->user_data;
+  GList *l;
+
+  /* We only have an associated MetaWaylandBuffer once the wayland buffer has
+   * been attached to a surface. */
+  if (!buffer)
+    return;
+
+  for (l = buffer->surfaces_attached_to; l; l = l->next)
+    {
+      MetaWaylandSurface *surface = l->data;
+      ClutterWaylandSurface *surface_actor =
+        CLUTTER_WAYLAND_SURFACE (surface->actor);
+      clutter_wayland_surface_damage_buffer (surface_actor,
+                                             wayland_buffer,
+                                             x, y, width, height);
+    }
+}
+
+static void
+shm_buffer_destroyed (struct wl_buffer *wayland_buffer)
+{
+  /* We only have an associated MetaWaylandBuffer once the wayland buffer has
+   * been attached to a surface. */
+  if (wayland_buffer->user_data)
+    meta_wayland_buffer_free ((MetaWaylandBuffer *)wayland_buffer->user_data);
+}
+
+const static struct wl_shm_callbacks shm_callbacks = {
+  shm_buffer_created,
+  shm_buffer_damaged,
+  shm_buffer_destroyed
+};
+
+static void
+meta_wayland_surface_destroy (struct wl_client *wayland_client,
+                     struct wl_resource *wayland_resource)
+{
+  wl_resource_destroy (wayland_resource, get_time ());
+}
+
+static void
+meta_wayland_surface_detach_buffer (MetaWaylandSurface *surface)
+{
+  MetaWaylandBuffer *buffer = surface->buffer;
+
+  if (buffer)
+    {
+      wl_resource_queue_event(&buffer->wayland_buffer->resource,
+                              WL_BUFFER_RELEASE);
+
+      buffer->surfaces_attached_to =
+        g_list_remove (buffer->surfaces_attached_to, surface);
+      if (buffer->surfaces_attached_to == NULL)
+        meta_wayland_buffer_free (buffer);
+      surface->buffer = NULL;
+    }
+}
+
+static void
+meta_wayland_surface_attach_buffer (struct wl_client *wayland_client,
+                                    struct wl_resource *wayland_surface_resource,
+                                    struct wl_resource *wayland_buffer_resource,
+                                    gint32 dx, gint32 dy)
+{
+  struct wl_buffer *wayland_buffer = wayland_buffer_resource->data;
+  MetaWaylandBuffer *buffer = wayland_buffer->user_data;
+  MetaWaylandSurface *surface = wayland_surface_resource->data;
+  ClutterWaylandSurface *surface_actor;
+
+  /* XXX: in the case where we are reattaching the same buffer we can
+   * simply bail out. Note this is important because if we don't bail
+   * out then the _detach_buffer will actually end up destroying the
+   * buffer we're trying to attach. */
+  if (buffer && surface->buffer == buffer)
+    return;
+
+  meta_wayland_surface_detach_buffer (surface);
+
+  if (!buffer)
+    {
+      buffer = meta_wayland_buffer_new (wayland_buffer);
+      wayland_buffer->user_data = buffer;
+    }
+
+  g_return_if_fail (g_list_find (buffer->surfaces_attached_to, surface) == NULL);
+
+  buffer->surfaces_attached_to = g_list_prepend (buffer->surfaces_attached_to,
+                                                 surface);
+
+  /* XXX: Its a bit messy but even though xwayland surfaces are
+   * handled separately we still set surface->actor to the
+   * MetaShapedTexture actor thats created for a MetaWindowActor.
+   * This means we can consistently deal with damage and attaching
+   * buffers to surfaces.
+   */
+  if (surface->actor)
+    {
+      surface_actor = CLUTTER_WAYLAND_SURFACE (surface->actor);
+      if (!clutter_wayland_surface_attach_buffer (surface_actor, wayland_buffer,
+                                                  NULL))
+        g_warning ("Failed to attach buffer to ClutterWaylandSurface");
+    }
+
+  surface->buffer = buffer;
+}
+
+static void
+meta_wayland_surface_damage (struct wl_client *client,
+                             struct wl_resource *surface_resource,
+                             gint32 x,
+                             gint32 y,
+                             gint32 width,
+                             gint32 height)
+{
+  MetaWaylandSurface *surface = surface_resource->data;
+  if (surface->buffer && surface->actor)
+    {
+      clutter_wayland_surface_damage_buffer (CLUTTER_WAYLAND_SURFACE (surface->actor),
+                                             surface->buffer->wayland_buffer,
+                                             x, y, width, height);
+    }
+}
+
+static void
+destroy_frame_callback (struct wl_resource *callback_resource)
+{
+  MetaWaylandFrameCallback *callback = callback_resource->data;
+
+  g_queue_unlink (&callback->compositor->frame_callbacks,
+                  &callback->node);
+
+  g_slice_free (MetaWaylandFrameCallback, callback);
+}
+
+static void
+meta_wayland_surface_frame (struct wl_client *client,
+                            struct wl_resource *surface_resource,
+                            guint32 callback_id)
+{
+  MetaWaylandFrameCallback *callback;
+  MetaWaylandSurface *surface = surface_resource->data;
+
+  callback = g_slice_new0 (MetaWaylandFrameCallback);
+  callback->compositor = surface->compositor;
+  callback->node.data = callback;
+  callback->resource.object.interface = &wl_callback_interface;
+  callback->resource.object.id = callback_id;
+  callback->resource.destroy = destroy_frame_callback;
+  callback->resource.data = callback;
+
+  wl_client_add_resource (client, &callback->resource);
+
+  g_queue_push_tail_link (&surface->compositor->frame_callbacks,
+                          &callback->node);
+}
+
+const struct wl_surface_interface meta_wayland_surface_interface = {
+  meta_wayland_surface_destroy,
+  meta_wayland_surface_attach_buffer,
+  meta_wayland_surface_damage,
+  meta_wayland_surface_frame
+};
+
+static void
+surface_actor_destroyed_cb (void *user_data,
+                            GObject *old_object)
+{
+  MetaWaylandSurface *surface = user_data;
+
+  surface->actor = NULL;
+  surface->window = NULL;
+}
+
+static void
+meta_wayland_surface_free (MetaWaylandSurface *surface)
+{
+  MetaWaylandCompositor *compositor = surface->compositor;
+  compositor->surfaces = g_list_remove (compositor->surfaces, surface);
+  meta_wayland_surface_detach_buffer (surface);
+
+  if (surface->actor)
+    g_object_weak_unref (G_OBJECT (surface->actor),
+                         surface_actor_destroyed_cb,
+                         surface);
+
+  /* NB: If the surface corresponds to an X window then we will be
+   * sure to free the MetaWindow according to some X event. */
+  if (surface->window &&
+      surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
+    {
+      MetaDisplay *display = meta_get_display ();
+      guint32 timestamp = meta_display_get_current_time_roundtrip (display);
+      meta_window_unmanage (surface->window, timestamp);
+    }
+
+  g_slice_free (MetaWaylandSurface, surface);
+}
+
+static void
+meta_wayland_surface_resource_destroy_cb (struct wl_resource *wayland_surface_resource)
+{
+  MetaWaylandSurface *surface = wayland_surface_resource->data;
+  meta_wayland_surface_free (surface);
+}
+
+static void
+surface_destroy_callback (struct wl_listener *listener,
+                          struct wl_resource *resource,
+                          guint32 time)
+{
+  g_warning ("Surface destroy callback");
+}
+
+static void
+meta_wayland_compositor_create_surface (struct wl_client *wayland_client,
+                                        struct wl_resource *wayland_compositor_resource,
+                                        guint32 id)
+{
+  MetaWaylandCompositor *compositor = wayland_compositor_resource->data;
+  MetaWaylandSurface *surface = g_slice_new0 (MetaWaylandSurface);
+
+  surface->compositor = compositor;
+
+  surface->wayland_surface.resource.destroy =
+    meta_wayland_surface_resource_destroy_cb;
+  surface->wayland_surface.resource.object.id = id;
+  surface->wayland_surface.resource.object.interface = &wl_surface_interface;
+  surface->wayland_surface.resource.object.implementation =
+          (void (**)(void)) &meta_wayland_surface_interface;
+  surface->wayland_surface.resource.data = surface;
+
+  wl_client_add_resource (wayland_client, &surface->wayland_surface.resource);
+
+  surface->surface_destroy_listener.func = surface_destroy_callback;
+  wl_list_insert (surface->wayland_surface.resource.destroy_listener_list.prev,
+                  &surface->surface_destroy_listener.link);
+
+  compositor->surfaces = g_list_prepend (compositor->surfaces, surface);
+}
+
+static void
+bind_output (struct wl_client *client,
+             void *data,
+             guint32 version,
+             guint32 id)
+{
+  MetaWaylandOutput *output = data;
+  struct wl_resource *resource =
+    wl_client_add_object (client, &wl_output_interface, NULL, id, data);
+  GList *l;
+
+  wl_resource_post_event (resource,
+                          WL_OUTPUT_GEOMETRY,
+                          output->x, output->y,
+                          output->width_mm,
+                          output->height_mm,
+                          0, /* subpixel: unknown */
+                          "unknown", /* make */
+                          "unknown"); /* model */
+
+  for (l = output->modes; l; l = l->next)
+    {
+      MetaWaylandMode *mode = l->data;
+      wl_resource_post_event (resource,
+                              WL_OUTPUT_MODE,
+                              mode->flags,
+                              mode->width,
+                              mode->height,
+                              mode->refresh);
+    }
+}
+
+static void
+meta_wayland_compositor_create_output (MetaWaylandCompositor *compositor,
+                                       int x,
+                                       int y,
+                                       int width,
+                                       int height,
+                                       int width_mm,
+                                       int height_mm)
+{
+  MetaWaylandOutput *output = g_slice_new0 (MetaWaylandOutput);
+  MetaWaylandMode *mode;
+  float final_width, final_height;
+
+  /* XXX: eventually we will support sliced stages and an output should
+   * correspond to a slice/CoglFramebuffer, but for now we only support
+   * one output so we make sure it always matches the size of the stage
+   */
+  clutter_actor_set_size (compositor->stage, width, height);
+
+  /* Read back the actual size we were given.
+   * XXX: This really needs re-thinking later though so we know the
+   * correct output geometry to use. */
+  clutter_actor_get_size (compositor->stage, &final_width, &final_height);
+  width = final_width;
+  height = final_height;
+
+  output->wayland_output.interface = &wl_output_interface;
+
+  output->x = x;
+  output->y = y;
+  output->width_mm = width_mm;
+  output->height_mm = height_mm;
+
+  wl_display_add_global (compositor->wayland_display,
+                         &wl_output_interface,
+                         output,
+                         bind_output);
+
+  mode = g_slice_new0 (MetaWaylandMode);
+  mode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+  mode->width = width;
+  mode->height = height;
+  mode->refresh = 60;
+
+  output->modes = g_list_prepend (output->modes, mode);
+
+  compositor->outputs = g_list_prepend (compositor->outputs, output);
+}
+
+const static struct wl_compositor_interface meta_wayland_compositor_interface = {
+  meta_wayland_compositor_create_surface,
+};
+
+static void
+paint_finished_cb (ClutterActor *self, void *user_data)
+{
+  MetaWaylandCompositor *compositor = user_data;
+
+  while (!g_queue_is_empty (&compositor->frame_callbacks))
+    {
+      MetaWaylandFrameCallback *callback =
+        g_queue_peek_head (&compositor->frame_callbacks);
+
+      wl_resource_post_event (&callback->resource,
+                              WL_CALLBACK_DONE, get_time ());
+      wl_resource_destroy (&callback->resource, 0);
+    }
+}
+
+static void
+compositor_bind (struct wl_client *client,
+		 void *data,
+                 guint32 version,
+                 guint32 id)
+{
+  MetaWaylandCompositor *compositor = data;
+
+  wl_client_add_object (client, &wl_compositor_interface,
+                        &meta_wayland_compositor_interface, id, compositor);
+}
+
+static void
+shell_surface_move(struct wl_client *client,
+                   struct wl_resource *resource,
+                   struct wl_resource *input_resource,
+                   guint32 time)
+{
+}
+
+static void
+shell_surface_resize (struct wl_client *client,
+                      struct wl_resource *resource,
+                      struct wl_resource *input_resource,
+                      guint32 time,
+                      guint32 edges)
+{
+}
+
+static void
+ensure_surface_window (MetaWaylandSurface *surface)
+{
+  MetaDisplay *display = meta_get_display ();
+
+  if (!surface->window)
+    {
+      ClutterActor *window_actor;
+      int width, height;
+
+      if (surface->buffer && surface->buffer->wayland_buffer)
+        {
+          struct wl_buffer *buffer = surface->buffer->wayland_buffer;
+          width = buffer->width;
+          height = buffer->width;
+        }
+      else
+        {
+          width = 0;
+          height = 0;
+        }
+
+      surface->window =
+        meta_window_new_for_wayland (display, width, height, surface);
+
+      /* The new MetaWindow should always result in us creating a corresponding
+       * MetaWindowActor which will be immediately associated with the given
+       * surface... */
+      g_assert (surface->actor);
+
+      window_actor =
+        CLUTTER_ACTOR (meta_window_get_compositor_private (surface->window));
+      meta_window_actor_show (META_WINDOW_ACTOR (window_actor),
+                              META_COMP_EFFECT_CREATE);
+
+      /* If the MetaWindow becomes unmanaged (surface->actor will be freed in
+       * this case) we need to make sure to clear our ->actor and ->window
+       * pointers. */
+      g_object_weak_ref (G_OBJECT (surface->actor),
+                         surface_actor_destroyed_cb,
+                         surface);
+    }
+}
+
+static void
+shell_surface_set_toplevel (struct wl_client *client,
+                            struct wl_resource *resource)
+{
+  MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
+  MetaWaylandShellSurface *shell_surface = resource->data;
+  MetaWaylandSurface *surface = shell_surface->surface;
+
+  /* NB: Surfaces from xwayland become managed based on X events. */
+  if (client == compositor->xwayland_client)
+    return;
+
+  ensure_surface_window (surface);
+
+  meta_window_unmake_fullscreen (surface->window);
+}
+
+static void
+shell_surface_set_transient (struct wl_client *client,
+                             struct wl_resource *resource,
+                             struct wl_resource *parent_resource,
+                             int x,
+                             int y,
+                             guint32 flags)
+{
+  MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
+  MetaWaylandShellSurface *shell_surface = resource->data;
+  MetaWaylandSurface *surface = shell_surface->surface;
+
+  /* NB: Surfaces from xwayland become managed based on X events. */
+  if (client == compositor->xwayland_client)
+    return;
+
+  ensure_surface_window (surface);
+}
+
+static void
+shell_surface_set_fullscreen (struct wl_client *client,
+                              struct wl_resource *resource)
+{
+  MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
+  MetaWaylandShellSurface *shell_surface = resource->data;
+  MetaWaylandSurface *surface = shell_surface->surface;
+
+  /* NB: Surfaces from xwayland become managed based on X events. */
+  if (client == compositor->xwayland_client)
+    return;
+
+  ensure_surface_window (surface);
+
+  meta_window_make_fullscreen (surface->window);
+}
+
+static const struct wl_shell_surface_interface meta_wayland_shell_surface_interface =
+{
+  shell_surface_move,
+  shell_surface_resize,
+  shell_surface_set_toplevel,
+  shell_surface_set_transient,
+  shell_surface_set_fullscreen
+};
+
+static void
+shell_handle_surface_destroy (struct wl_listener *listener,
+                              struct wl_resource *resource,
+                              guint32 time)
+{
+  MetaWaylandShellSurface *shell_surface = container_of (listener,
+                                                         MetaWaylandShellSurface,
+                                                         surface_destroy_listener);
+
+  shell_surface->surface->has_shell_surface = FALSE;
+  shell_surface->surface = NULL;
+  wl_resource_destroy (&shell_surface->resource, time);
+}
+
+static void
+destroy_shell_surface (struct wl_resource *resource)
+{
+  MetaWaylandShellSurface *shell_surface = resource->data;
+
+  /* In case cleaning up a dead client destroys shell_surface first */
+  if (shell_surface->surface)
+    {
+      wl_list_remove (&shell_surface->surface_destroy_listener.link);
+      shell_surface->surface->has_shell_surface = FALSE;
+    }
+
+  g_free (shell_surface);
+}
+
+static void
+get_shell_surface (struct wl_client *client,
+                   struct wl_resource *resource,
+                   guint32 id,
+                   struct wl_resource *surface_resource)
+{
+  MetaWaylandSurface *surface = surface_resource->data;
+  MetaWaylandShellSurface *shell_surface;
+
+  if (surface->has_shell_surface)
+    {
+      wl_resource_post_error (surface_resource,
+                              WL_DISPLAY_ERROR_INVALID_OBJECT,
+                              "wl_shell::get_shell_surface already requested");
+      return;
+    }
+
+  shell_surface = g_new0 (MetaWaylandShellSurface, 1);
+  shell_surface->resource.destroy = destroy_shell_surface;
+  shell_surface->resource.object.id = id;
+  shell_surface->resource.object.interface = &wl_shell_surface_interface;
+  shell_surface->resource.object.implementation =
+    (void (**) (void)) &meta_wayland_shell_surface_interface;
+  shell_surface->resource.data = shell_surface;
+
+  shell_surface->surface = surface;
+  shell_surface->surface_destroy_listener.func = shell_handle_surface_destroy;
+  wl_list_insert (surface->wayland_surface.resource.destroy_listener_list.prev,
+                  &shell_surface->surface_destroy_listener.link);
+
+  surface->has_shell_surface = TRUE;
+
+  wl_client_add_resource (client, &shell_surface->resource);
+}
+
+static const struct wl_shell_interface meta_wayland_shell_interface =
+{
+  get_shell_surface
+};
+
+static void
+bind_shell (struct wl_client *client,
+            void *data,
+            guint32 version,
+            guint32 id)
+{
+  wl_client_add_object (client, &wl_shell_interface,
+                        &meta_wayland_shell_interface, id, data);
+}
+
+static char *
+create_lockfile (int display, int *display_out)
+{
+  char *filename;
+  int size;
+  char pid[11];
+  int fd;
+
+  do
+    {
+      char *end;
+      pid_t other;
+
+      filename = g_strdup_printf ("/tmp/.X%d-lock", display);
+      fd = open (filename, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444);
+
+      if (fd < 0 && errno == EEXIST)
+        {
+          fd = open (filename, O_CLOEXEC, O_RDONLY);
+          if (fd < 0 || read (fd, pid, 11) != 11)
+            {
+              const char *msg = strerror (errno);
+              g_warning ("can't read lock file %s: %s", filename, msg);
+              g_free (filename);
+
+              /* ignore error and try the next display number */
+              display++;
+              continue;
+          }
+          close (fd);
+
+          other = strtol (pid, &end, 0);
+          if (end != pid + 10)
+            {
+              g_warning ("can't parse lock file %s", filename);
+              g_free (filename);
+
+              /* ignore error and try the next display number */
+              display++;
+              continue;
+          }
+
+          if (kill (other, 0) < 0 && errno == ESRCH)
+            {
+              g_warning ("unlinking stale lock file %s", filename);
+              if (unlink (filename) < 0)
+                {
+                  const char *msg = strerror (errno);
+                  g_warning ("failed to unlink stale lock file: %s", msg);
+                  display++;
+                }
+              g_free (filename);
+              continue;
+          }
+
+          g_free (filename);
+          display++;
+          continue;
+        }
+      else if (fd < 0)
+        {
+          const char *msg = strerror (errno);
+          g_warning ("failed to create lock file %s: %s", filename , msg);
+          g_free (filename);
+          return NULL;
+        }
+
+      break;
+    }
+  while (1);
+
+  /* Subtle detail: we use the pid of the wayland compositor, not the xserver
+   * in the lock file. */
+  size = snprintf (pid, 11, "%10d\n", getpid ());
+  if (size != 11 || write (fd, pid, 11) != 11)
+    {
+      unlink (filename);
+      close (fd);
+      g_warning ("failed to write pid to lock file %s", filename);
+      g_free (filename);
+      return NULL;
+    }
+
+  close (fd);
+
+  *display_out = display;
+  return filename;
+}
+
+static int
+bind_to_abstract_socket (int display)
+{
+  struct sockaddr_un addr;
+  socklen_t size, name_size;
+  int fd;
+
+  fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+  if (fd < 0)
+    return -1;
+
+  addr.sun_family = AF_LOCAL;
+  name_size = snprintf (addr.sun_path, sizeof addr.sun_path,
+                        "%c/tmp/.X11-unix/X%d", 0, display);
+  size = offsetof (struct sockaddr_un, sun_path) + name_size;
+  if (bind (fd, (struct sockaddr *) &addr, size) < 0)
+    {
+      g_warning ("failed to bind to @%s: %s\n",
+                 addr.sun_path + 1, strerror (errno));
+      close (fd);
+      return -1;
+    }
+
+  if (listen (fd, 1) < 0)
+    {
+      close (fd);
+      return -1;
+    }
+
+  return fd;
+}
+
+static int
+bind_to_unix_socket (int display)
+{
+  struct sockaddr_un addr;
+  socklen_t size, name_size;
+  int fd;
+
+  fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+  if (fd < 0)
+    return -1;
+
+  addr.sun_family = AF_LOCAL;
+  name_size = snprintf (addr.sun_path, sizeof addr.sun_path,
+                        "/tmp/.X11-unix/X%d", display) + 1;
+  size = offsetof (struct sockaddr_un, sun_path) + name_size;
+  unlink (addr.sun_path);
+  if (bind (fd, (struct sockaddr *) &addr, size) < 0)
+    {
+      char *msg = strerror (errno);
+      g_warning ("failed to bind to %s (%s)\n", addr.sun_path, msg);
+      close (fd);
+      return -1;
+    }
+
+  if (listen (fd, 1) < 0) {
+      unlink (addr.sun_path);
+      close (fd);
+      return -1;
+  }
+
+  return fd;
+}
+
+static gboolean
+start_xwayland (MetaWaylandCompositor *compositor)
+{
+  int display = 0;
+  char *lockfile = NULL;
+  int sp[2];
+  pid_t pid;
+
+  do
+    {
+      lockfile = create_lockfile (display, &display);
+      if (!lockfile)
+        {
+         g_warning ("Failed to create an X lock file");
+         return FALSE;
+        }
+
+      compositor->xwayland_abstract_fd = bind_to_abstract_socket (display);
+      if (compositor->xwayland_abstract_fd < 0 ||
+          compositor->xwayland_abstract_fd == EADDRINUSE)
+        {
+          unlink (lockfile);
+          display++;
+          continue;
+        }
+      compositor->xwayland_unix_fd = bind_to_unix_socket (display);
+      if (compositor->xwayland_abstract_fd < 0)
+        {
+          unlink (lockfile);
+          return FALSE;
+        }
+
+      break;
+    }
+  while (1);
+
+  compositor->xwayland_display_index = display;
+  compositor->xwayland_lockfile = lockfile;
+
+  /* We want xwayland to be a wayland client so we make a socketpair to setup a
+   * wayland protocol connection. */
+  if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sp) < 0)
+    {
+      g_warning ("socketpair failed\n");
+      unlink (lockfile);
+      return 1;
+    }
+
+  switch ((pid = fork()))
+    {
+    case 0:
+        {
+          char *fd_string;
+          char *display_name;
+          /* Make sure the client end of the socket pair doesn't get closed
+           * when we exec xwayland. */
+          int flags = fcntl (sp[1], F_GETFD);
+          if (flags != -1)
+            fcntl (sp[1], F_SETFD, flags & ~FD_CLOEXEC);
+
+          fd_string = g_strdup_printf ("%d", sp[1]);
+          setenv ("WAYLAND_SOCKET", fd_string, 1);
+          g_free (fd_string);
+
+          display_name = g_strdup_printf (":%d",
+                                          compositor->xwayland_display_index);
+
+          if (execl (XWAYLAND_PATH,
+                     XWAYLAND_PATH,
+                     display_name,
+                     "-wayland",
+                     "-rootless",
+                     "-retro",
+                     /* FIXME: does it make sense to log to the filesystem by
+                      * default? */
+                     "-logfile", "/tmp/xwayland.log",
+                     "-nolisten", "all",
+                     "-terminate",
+                     NULL) < 0)
+            {
+              char *msg = strerror (errno);
+              g_warning ("xwayland exec failed: %s", msg);
+            }
+          exit (-1);
+          return FALSE;
+        }
+    default:
+      g_message ("forked X server, pid %d\n", pid);
+
+      close (sp[1]);
+      compositor->xwayland_client =
+        wl_client_create (compositor->wayland_display, sp[0]);
+
+      compositor->xwayland_pid = pid;
+      break;
+
+    case -1:
+      g_error ("Failed to fork for xwayland server");
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+stop_xwayland (MetaWaylandCompositor *compositor)
+{
+  char path[256];
+
+  snprintf (path, sizeof path, "/tmp/.X%d-lock",
+            compositor->xwayland_display_index);
+  unlink (path);
+  snprintf (path, sizeof path, "/tmp/.X11-unix/X%d",
+            compositor->xwayland_display_index);
+  unlink (path);
+
+  unlink (compositor->xwayland_lockfile);
+}
+
+static void
+xserver_set_window_id (struct wl_client *client,
+                       struct wl_resource *compositor_resource,
+                       struct wl_resource *surface_resource,
+                       guint32 xid)
+{
+  MetaWaylandCompositor *compositor = compositor_resource->data;
+  MetaWaylandSurface *surface = surface_resource->data;
+  MetaDisplay *display = meta_get_display ();
+  MetaWindow *window;
+
+  g_return_if_fail (surface->xid == None);
+
+  surface->xid = xid;
+
+  g_hash_table_insert (compositor->window_surfaces, &xid, surface);
+
+  window  = meta_display_lookup_x_window (display, xid);
+  if (window)
+    {
+      MetaWindowActor *window_actor =
+        META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
+      ClutterWaylandSurface *surface_actor = CLUTTER_WAYLAND_SURFACE (
+        meta_window_actor_get_shaped_texture (window_actor));
+
+      clutter_wayland_surface_set_surface (surface_actor,
+                                           &surface->wayland_surface);
+      if (surface->buffer)
+        clutter_wayland_surface_attach_buffer (surface_actor,
+                                               surface->buffer->wayland_buffer,
+                                               NULL);
+
+      surface->window = window;
+      surface->actor = surface_actor;
+
+      /* If the MetaWindow becomes unmanaged (surface->actor will be freed in
+       * this case) we need to make sure to clear our ->actor and ->window
+       * pointers in this case. */
+      g_object_weak_ref (G_OBJECT (surface->actor),
+                         surface_actor_destroyed_cb,
+                         surface);
+
+#if 0
+      if (window->visible_to_compositor)
+        meta_compositor_show_window (display->compositor, window,
+                                     META_COMP_EFFECT_NONE);
+#endif
+    }
+
+#warning "FIXME: Handle surface destroy and remove window_surfaces mapping"
+}
+
+MetaWaylandSurface *
+meta_wayland_lookup_surface_for_xid (guint32 xid)
+{
+  return g_hash_table_lookup (_meta_wayland_compositor.window_surfaces, &xid);
+}
+
+static const struct xserver_interface xserver_implementation = {
+    xserver_set_window_id
+};
+
+static void
+bind_xserver (struct wl_client *client,
+	      void *data,
+              guint32 version,
+              guint32 id)
+{
+  MetaWaylandCompositor *compositor = data;
+
+  /* If it's a different client than the xserver we launched,
+   * don't start the wm. */
+  if (client != compositor->xwayland_client)
+    return;
+
+  compositor->xserver_resource =
+    wl_client_add_object (client, &xserver_interface,
+                          &xserver_implementation, id,
+                          compositor);
+
+  wl_resource_post_event (compositor->xserver_resource,
+                          XSERVER_LISTEN_SOCKET,
+                          compositor->xwayland_abstract_fd);
+
+  wl_resource_post_event (compositor->xserver_resource,
+                          XSERVER_LISTEN_SOCKET,
+                          compositor->xwayland_unix_fd);
+  g_warning ("bind_xserver");
+
+  /* Make sure xwayland will recieve the above sockets in a finite
+   * time before unblocking the initialization mainloop since we are
+   * then going to immediately try and connect to those as the window
+   * manager. */
+  wl_client_flush (client);
+
+  /* At this point xwayland is all setup to start accepting
+   * connections so we can quit the transient initialization mainloop
+   * and unblock meta_wayland_init() to continue initializing mutter.
+   * */
+  g_main_loop_quit (compositor->init_loop);
+  compositor->init_loop = NULL;
+}
+
+static void
+stage_destroy_cb (void)
+{
+  meta_quit (META_EXIT_SUCCESS);
+}
+
+void
+meta_wayland_init (void)
+{
+  MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
+
+  memset (compositor, 0, sizeof (MetaWaylandCompositor));
+
+  compositor->wayland_display = wl_display_create ();
+  if (compositor->wayland_display == NULL)
+    g_error ("failed to create wayland display");
+
+  g_queue_init (&compositor->frame_callbacks);
+
+  if (!wl_display_add_global (compositor->wayland_display,
+                              &wl_compositor_interface,
+			      compositor,
+                              compositor_bind))
+    g_error ("Failed to register wayland compositor object");
+
+  compositor->wayland_shm = wl_shm_init (compositor->wayland_display,
+                                         &shm_callbacks);
+  if (!compositor->wayland_shm)
+    g_error ("Failed to allocate setup wayland shm callbacks");
+
+  compositor->wayland_loop =
+    wl_display_get_event_loop (compositor->wayland_display);
+  compositor->wayland_event_source =
+    wayland_event_source_new (compositor->wayland_loop);
+
+  /* XXX: Here we are setting the wayland event source to have a
+   * slightly lower priority than the X event source, because we are
+   * much more likely to get confused being told about surface changes
+   * relating to X clients when we don't know what's happened to them
+   * according to the X protocol.
+   *
+   * At some point we could perhaps try and get the X protocol proxied
+   * over the wayland protocol so that we don't have to worry about
+   * synchronizing the two command streams. */
+  g_source_set_priority (compositor->wayland_event_source,
+                         GDK_PRIORITY_EVENTS + 1);
+  g_source_attach (compositor->wayland_event_source, NULL);
+
+  clutter_wayland_set_compositor_display (compositor->wayland_display);
+
+  if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
+    g_error ("Failed to initialize Clutter");
+
+  compositor->stage = clutter_stage_new ();
+  clutter_stage_set_user_resizable (CLUTTER_STAGE (compositor->stage), FALSE);
+  g_signal_connect_after (compositor->stage, "paint",
+                          G_CALLBACK (paint_finished_cb), compositor);
+  g_signal_connect (compositor->stage, "destroy",
+                    G_CALLBACK (stage_destroy_cb), NULL);
+
+  meta_wayland_compositor_create_output (compositor, 0, 0, 1024, 600, 222, 125);
+
+  if (wl_display_add_global (compositor->wayland_display, &wl_shell_interface,
+                             compositor, bind_shell) == NULL)
+    g_error ("Failed to register a global shell object");
+
+  clutter_actor_show (compositor->stage);
+
+  if (wl_display_add_socket (compositor->wayland_display, "wayland-0"))
+    g_error ("Failed to create socket");
+
+  wl_display_add_global (compositor->wayland_display,
+                         &xserver_interface,
+                         compositor,
+                         bind_xserver);
+
+  /* We need a mapping from xids to wayland surfaces... */
+  compositor->window_surfaces = g_hash_table_new (g_int_hash, g_int_equal);
+
+  /* XXX: It's important that we only try and start xwayland after we
+   * have initialized EGL because EGL implements the "wl_drm"
+   * interface which xwayland requires to determine what drm device
+   * name it should use.
+   *
+   * By waiting until we've shown the stage above we ensure that the
+   * underlying GL resources for the surface have also been allocated
+   * and so EGL must be initialized by this point.
+   */
+
+  if (!start_xwayland (compositor))
+    g_error ("Failed to start X Wayland");
+
+  putenv (g_strdup_printf ("DISPLAY=:%d", compositor->xwayland_display_index));
+
+  /* We need to run a mainloop until we know xwayland has a binding
+   * for our xserver interface at which point we can assume it's
+   * ready to start accepting connections. */
+  compositor->init_loop = g_main_loop_new (NULL, FALSE);
+
+  g_main_loop_run (compositor->init_loop);
+}
+
+void
+meta_wayland_finalize (void)
+{
+  stop_xwayland (meta_wayland_compositor_get_default ());
+}
+
+void
+meta_wayland_handle_sig_child (void)
+{
+  int status;
+  pid_t pid = waitpid (-1, &status, WNOHANG);
+  MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
+
+  /* The simplest measure to avoid infinitely re-spawning a crashing
+   * X server */
+  if (pid == compositor->xwayland_pid)
+    {
+      if (!WIFEXITED (status))
+        g_critical ("X Wayland crashed; aborting");
+      else
+        {
+          /* For now we simply abort if we see the server exit.
+           *
+           * In the future X will only be loaded lazily for legacy X support
+           * but for now it's a hard requirement. */
+          g_critical ("Spurious exit of X Wayland server");
+        }
+    }
+}



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