diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..31242bd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/mutter-3.22.3.tar.xz
diff --git a/.mutter.metadata b/.mutter.metadata
new file mode 100644
index 0000000..0aaec90
--- /dev/null
+++ b/.mutter.metadata
@@ -0,0 +1 @@
+90bf3c4a65b474e958a1b13f80c47ebcdb411b42 SOURCES/mutter-3.22.3.tar.xz
diff --git a/README.md b/README.md
deleted file mode 100644
index 0e7897f..0000000
--- a/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-The master branch has no content
- 
-Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6
- 
-If you find this file in a distro specific branch, it means that no content has been checked in yet
diff --git a/SOURCES/0001-Revert-backend-x11-Ensure-the-Xkb-group-index-remain.patch b/SOURCES/0001-Revert-backend-x11-Ensure-the-Xkb-group-index-remain.patch
new file mode 100644
index 0000000..ee3b81c
--- /dev/null
+++ b/SOURCES/0001-Revert-backend-x11-Ensure-the-Xkb-group-index-remain.patch
@@ -0,0 +1,61 @@
+From 090ac268b91c3b07f90d9d4ebe481bfe649836df Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Mon, 13 Jun 2016 19:32:43 +0200
+Subject: [PATCH] Revert "backend-x11: Ensure the Xkb group index remains
+ properly set"
+
+This reverts commit 2857fdbdb887fcaa2e2f25d268c34ae039646e78.
+---
+ src/backends/x11/meta-backend-x11.c | 16 +++-------------
+ 1 file changed, 3 insertions(+), 13 deletions(-)
+
+diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
+index a645bbd..dbcd13f 100644
+--- a/src/backends/x11/meta-backend-x11.c
++++ b/src/backends/x11/meta-backend-x11.c
+@@ -82,7 +82,6 @@ struct _MetaBackendX11Private
+   gchar *keymap_layouts;
+   gchar *keymap_variants;
+   gchar *keymap_options;
+-  int locked_group;
+ };
+ typedef struct _MetaBackendX11Private MetaBackendX11Private;
+ 
+@@ -298,23 +297,15 @@ handle_host_xevent (MetaBackend *backend,
+ 
+   if (event->type == priv->xkb_event_base)
+     {
+-      XkbEvent *xkb_ev = (XkbEvent *) event;
++      XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event;
+ 
+-      if (xkb_ev->any.device == META_VIRTUAL_CORE_KEYBOARD_ID)
++      if (xkb_ev->device == META_VIRTUAL_CORE_KEYBOARD_ID)
+         {
+-          switch (xkb_ev->any.xkb_type)
++          switch (xkb_ev->xkb_type)
+             {
+             case XkbNewKeyboardNotify:
+             case XkbMapNotify:
+               keymap_changed (backend);
+-              break;
+-            case XkbStateNotify:
+-              if (xkb_ev->state.changed & XkbGroupLockMask)
+-                {
+-                  if (priv->locked_group != xkb_ev->state.locked_group)
+-                    XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, priv->locked_group);
+-                }
+-              break;
+             default:
+               break;
+             }
+@@ -785,7 +776,6 @@ meta_backend_x11_lock_layout_group (MetaBackend *backend,
+   MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
+   MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
+ 
+-  priv->locked_group = idx;
+   XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, idx);
+ }
+ 
+-- 
+2.7.4
+
diff --git a/SOURCES/0001-backends-x11-Support-synaptics-configuration.patch b/SOURCES/0001-backends-x11-Support-synaptics-configuration.patch
new file mode 100644
index 0000000..059728b
--- /dev/null
+++ b/SOURCES/0001-backends-x11-Support-synaptics-configuration.patch
@@ -0,0 +1,345 @@
+From 10b63b27ba84458884138cecc1b914b4f69bc9b9 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Thu, 19 Jan 2017 15:03:41 +0100
+Subject: [PATCH] backends/x11: Support synaptics configuration
+
+The code is taken mostly as-is from g-s-d, so we can drag the
+dead horse a bit longer.
+---
+ src/backends/x11/meta-input-settings-x11.c | 264 +++++++++++++++++++++++++++++
+ 1 file changed, 264 insertions(+)
+
+diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c
+index 8f962b4..75ceb0c 100644
+--- a/src/backends/x11/meta-input-settings-x11.c
++++ b/src/backends/x11/meta-input-settings-x11.c
+@@ -26,6 +26,7 @@
+ #include "meta-backend-x11.h"
+ #include "meta-input-settings-x11.h"
+ 
++#include <stdlib.h>
+ #include <string.h>
+ #include <gdk/gdkx.h>
+ #include <X11/Xatom.h>
+@@ -118,6 +119,177 @@ change_property (ClutterInputDevice *device,
+   meta_XFree (data_ret);
+ }
+ 
++static gboolean
++is_device_synaptics (ClutterInputDevice *device)
++{
++  guchar *has_setting;
++
++  /* We just need looking for a synaptics-specific property */
++  has_setting = get_property (device, "Synaptics Off", XA_INTEGER, 8, 1);
++  if (!has_setting)
++    return FALSE;
++
++  meta_XFree (has_setting);
++  return TRUE;
++}
++
++static void
++change_synaptics_tap_left_handed (ClutterInputDevice *device,
++                                  gboolean            tap_enabled,
++                                  gboolean            left_handed)
++{
++  MetaDisplay *display = meta_get_display ();
++  MetaBackend *backend = meta_get_backend ();
++  Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
++  XDevice *xdevice;
++  guchar *tap_action, *buttons;
++  guint buttons_capacity = 16, n_buttons;
++
++  xdevice = XOpenDevice(xdisplay, clutter_input_device_get_device_id (device));
++  if (!xdevice)
++    return;
++
++  tap_action = get_property (device, "Synaptics Tap Action",
++                             XA_INTEGER, 8, 7);
++  if (!tap_action)
++    goto out;
++
++  tap_action[4] = tap_enabled ? (left_handed ? 3 : 1) : 0;
++  tap_action[5] = tap_enabled ? (left_handed ? 1 : 3) : 0;
++  tap_action[6] = tap_enabled ? 2 : 0;
++
++  change_property (device, "Synaptics Tap Action",
++                   XA_INTEGER, 8, tap_action, 7);
++  meta_XFree (tap_action);
++
++  if (display)
++    meta_error_trap_push (display);
++  buttons = g_new (guchar, buttons_capacity);
++  n_buttons = XGetDeviceButtonMapping (xdisplay, xdevice,
++                                       buttons, buttons_capacity);
++
++  while (n_buttons > buttons_capacity)
++    {
++      buttons_capacity = n_buttons;
++      buttons = (guchar *) g_realloc (buttons,
++                                      buttons_capacity * sizeof (guchar));
++
++      n_buttons = XGetDeviceButtonMapping (xdisplay, xdevice,
++                                           buttons, buttons_capacity);
++    }
++
++  buttons[0] = left_handed ? 3 : 1;
++  buttons[2] = left_handed ? 1 : 3;
++  XSetDeviceButtonMapping (xdisplay, xdevice, buttons, n_buttons);
++
++  if (display && meta_error_trap_pop_with_return (display))
++    {
++      g_warning ("Could not set synaptics touchpad left-handed for %s",
++                 clutter_input_device_get_device_name (device));
++    }
++
++ out:
++  XCloseDevice (xdisplay, xdevice);
++}
++
++static void
++change_synaptics_speed (ClutterInputDevice *device,
++                        gdouble             speed)
++{
++  MetaDisplay *display = meta_get_display ();
++  MetaBackend *backend = meta_get_backend ();
++  Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
++  XDevice *xdevice;
++  XPtrFeedbackControl feedback;
++  XFeedbackState *states, *state;
++  int i, num_feedbacks, motion_threshold, numerator, denominator;
++  gfloat motion_acceleration;
++
++  xdevice = XOpenDevice(xdisplay, clutter_input_device_get_device_id (device));
++  if (!xdevice)
++    return;
++  /* Get the list of feedbacks for the device */
++  states = XGetFeedbackControl (xdisplay, xdevice, &num_feedbacks);
++  if (!states)
++    return;
++
++  /* Calculate acceleration and threshold */
++  motion_acceleration = (speed + 1) * 5; /* speed is [-1..1], map to [0..10] */
++  motion_threshold = CLAMP (10 - floor (motion_acceleration), 1, 10);
++
++  if (motion_acceleration >= 1.0)
++    {
++      /* we want to get the acceleration, with a resolution of 0.5
++       */
++      if ((motion_acceleration - floor (motion_acceleration)) < 0.25)
++        {
++          numerator = floor (motion_acceleration);
++          denominator = 1;
++        }
++      else if ((motion_acceleration - floor (motion_acceleration)) < 0.5)
++        {
++          numerator = ceil (2.0 * motion_acceleration);
++          denominator = 2;
++        }
++      else if ((motion_acceleration - floor (motion_acceleration)) < 0.75)
++        {
++          numerator = floor (2.0 *motion_acceleration);
++          denominator = 2;
++        }
++      else
++        {
++          numerator = ceil (motion_acceleration);
++          denominator = 1;
++        }
++    }
++  else if (motion_acceleration < 1.0 && motion_acceleration > 0)
++    {
++      /* This we do to 1/10ths */
++      numerator = floor (motion_acceleration * 10) + 1;
++      denominator= 10;
++    }
++  else
++    {
++      numerator = -1;
++      denominator = -1;
++    }
++
++  if (display)
++    meta_error_trap_push (display);
++
++  state = (XFeedbackState *) states;
++
++  for (i = 0; i < num_feedbacks; i++)
++    {
++      if (state->class == PtrFeedbackClass)
++        {
++          /* And tell the device */
++          feedback.class      = PtrFeedbackClass;
++          feedback.length     = sizeof (XPtrFeedbackControl);
++          feedback.id         = state->id;
++          feedback.threshold  = motion_threshold;
++          feedback.accelNum   = numerator;
++          feedback.accelDenom = denominator;
++
++          XChangeFeedbackControl (xdisplay, xdevice,
++                                  DvAccelNum | DvAccelDenom | DvThreshold,
++                                  (XFeedbackControl *) &feedback);
++          break;
++        }
++
++      state = (XFeedbackState *) ((char *) state + state->length);
++    }
++
++  if (display && meta_error_trap_pop_with_return (display))
++    {
++      g_warning ("Could not set synaptics touchpad acceleration for %s",
++                 clutter_input_device_get_device_name (device));
++    }
++
++  XFreeFeedbackList (states);
++  XCloseDevice (xdisplay, xdevice);
++}
++
+ static void
+ meta_input_settings_x11_set_send_events (MetaInputSettings        *settings,
+                                          ClutterInputDevice       *device,
+@@ -126,6 +298,13 @@ meta_input_settings_x11_set_send_events (MetaInputSettings        *settings,
+   guchar values[2] = { 0 }; /* disabled, disabled-on-external-mouse */
+   guchar *available;
+ 
++  if (is_device_synaptics (device))
++    {
++      values[0] = mode != G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED;
++      change_property (device, "Synaptics Off", XA_INTEGER, 8, &values, 1);
++      return;
++    }
++
+   available = get_property (device, "libinput Send Events Modes Available",
+                             XA_INTEGER, 8, 2);
+   if (!available)
+@@ -178,6 +357,12 @@ meta_input_settings_x11_set_speed (MetaInputSettings  *settings,
+   Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
+   gfloat value = speed;
+ 
++  if (is_device_synaptics (device))
++    {
++      change_synaptics_speed (device, speed);
++      return;
++    }
++
+   change_property (device, "libinput Accel Speed",
+                    XInternAtom (xdisplay, "FLOAT", False),
+                    32, &value, 1);
+@@ -190,6 +375,18 @@ meta_input_settings_x11_set_left_handed (MetaInputSettings  *settings,
+ {
+   guchar value = (enabled) ? 1 : 0;
+ 
++  if (is_device_synaptics (device))
++    {
++      GSettings *settings;
++
++      settings = g_settings_new ("org.gnome.desktop.peripherals.touchpad");
++      change_synaptics_tap_left_handed (device,
++                                        g_settings_get_boolean (settings, "tap-to-click"),
++                                        enabled);
++      g_object_unref (settings);
++      return;
++    }
++
+   change_property (device, "libinput Left Handed Enabled",
+                    XA_INTEGER, 8, &value, 1);
+ }
+@@ -201,6 +398,20 @@ meta_input_settings_x11_set_tap_enabled (MetaInputSettings  *settings,
+ {
+   guchar value = (enabled) ? 1 : 0;
+ 
++  if (is_device_synaptics (device))
++    {
++      GDesktopTouchpadHandedness handedness;
++      GSettings *settings;
++
++      settings = g_settings_new ("org.gnome.desktop.peripherals.touchpad");
++      handedness = g_settings_get_enum (settings, "left-handed");
++      g_object_unref (settings);
++
++      change_synaptics_tap_left_handed (device, enabled,
++                                        handedness == G_DESKTOP_TOUCHPAD_HANDEDNESS_LEFT);
++      return;
++    }
++
+   change_property (device, "libinput Tapping Enabled",
+                    XA_INTEGER, 8, &value, 1);
+ }
+@@ -212,6 +423,27 @@ meta_input_settings_x11_set_invert_scroll (MetaInputSettings  *settings,
+ {
+   guchar value = (inverted) ? 1 : 0;
+ 
++  if (is_device_synaptics (device))
++    {
++      gint32 *scrolling_distance;
++
++      scrolling_distance = get_property (device, "Synaptics Scrolling Distance",
++                                         XA_INTEGER, 32, 2);
++      if (scrolling_distance)
++        {
++          scrolling_distance[0] = inverted ?
++            -abs (scrolling_distance[0]) : abs (scrolling_distance[0]);
++          scrolling_distance[1] = inverted ?
++            -abs (scrolling_distance[1]) : abs (scrolling_distance[1]);
++
++          change_property (device, "Synaptics Scrolling Distance",
++                           XA_INTEGER, 32, scrolling_distance, 2);
++          meta_XFree (scrolling_distance);
++        }
++
++      return;
++    }
++
+   change_property (device, "libinput Natural Scrolling Enabled",
+                    XA_INTEGER, 8, &value, 1);
+ }
+@@ -225,6 +457,22 @@ meta_input_settings_x11_set_edge_scroll (MetaInputSettings            *settings,
+   guchar *current = NULL;
+   guchar *available = NULL;
+ 
++  if (is_device_synaptics (device))
++    {
++      current = get_property (device, "Synaptics Edge Scrolling",
++                              XA_INTEGER, 8, 3);
++      if (current)
++        {
++          current[0] = !!edge_scroll_enabled;
++          current[1] = !!edge_scroll_enabled;
++          change_property (device, "Synaptics Edge Scrolling",
++                           XA_INTEGER, 8, current, 3);
++          meta_XFree (current);
++        }
++
++      return;
++    }
++
+   available = get_property (device, "libinput Scroll Methods Available",
+                             XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
+   if (!available || !available[SCROLL_METHOD_FIELD_EDGE])
+@@ -254,6 +502,22 @@ meta_input_settings_x11_set_two_finger_scroll (MetaInputSettings            *set
+   guchar *current = NULL;
+   guchar *available = NULL;
+ 
++  if (is_device_synaptics (device))
++    {
++      current = get_property (device, "Synaptics Two-Finger Scrolling",
++                              XA_INTEGER, 8, 2);
++      if (current)
++        {
++          current[0] = !!two_finger_scroll_enabled;
++          current[1] = !!two_finger_scroll_enabled;
++          change_property (device, "Synaptics Two-Finger Scrolling",
++                           XA_INTEGER, 8, current, 2);
++          meta_XFree (current);
++        }
++
++      return;
++    }
++
+   available = get_property (device, "libinput Scroll Methods Available",
+                             XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
+   if (!available || !available[SCROLL_METHOD_FIELD_2FG])
+-- 
+2.9.3
+
diff --git a/SOURCES/0001-build-Lower-automake-requirement.patch b/SOURCES/0001-build-Lower-automake-requirement.patch
new file mode 100644
index 0000000..f7c7af6
--- /dev/null
+++ b/SOURCES/0001-build-Lower-automake-requirement.patch
@@ -0,0 +1,25 @@
+From e19b0723e829a102f930af735c9ff6d08ec9232f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Fri, 17 Mar 2017 16:44:11 +0100
+Subject: [PATCH] build: Lower automake requirement
+
+---
+ cogl/configure.ac | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/cogl/configure.ac b/cogl/configure.ac
+index 3ed761c57..1b259af58 100644
+--- a/cogl/configure.ac
++++ b/cogl/configure.ac
+@@ -113,7 +113,7 @@ AC_SUBST([WAYLAND_SERVER_REQ_VERSION], [wayland_server_req_version])
+ # want to know if the user specified custom cflags or not.
+ cflags_set=${CFLAGS+set}
+ 
+-AM_INIT_AUTOMAKE([1.14 foreign -Wno-portability no-define no-dist-gzip dist-xz tar-ustar subdir-objects])
++AM_INIT_AUTOMAKE([1.11 foreign -Wno-portability no-define no-dist-gzip dist-xz tar-ustar])
+ AM_SILENT_RULES([yes])
+ 
+ AH_BOTTOM([#include "config-custom.h"])
+-- 
+2.12.0
+
diff --git a/SOURCES/0001-cally-Fix-translation-to-screen-coordinates.patch b/SOURCES/0001-cally-Fix-translation-to-screen-coordinates.patch
new file mode 100644
index 0000000..33370b3
--- /dev/null
+++ b/SOURCES/0001-cally-Fix-translation-to-screen-coordinates.patch
@@ -0,0 +1,31 @@
+From 59eb6a6ff7d6356213db1ea22616315c215ae4a1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Fri, 28 Apr 2017 17:12:40 +0200
+Subject: [PATCH] cally: Fix translation to screen coordinates
+
+Due to an accidental swap of an else statement and a preprocessor #else,
+the output x coordinate is currently only set when not using the X11
+windowing system, whoops.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=781902
+---
+ clutter/clutter/cally/cally-actor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/clutter/clutter/cally/cally-actor.c b/clutter/clutter/cally/cally-actor.c
+index fe3e27433..8ff5b09e1 100644
+--- a/clutter/clutter/cally/cally-actor.c
++++ b/clutter/clutter/cally/cally-actor.c
+@@ -780,8 +780,8 @@ _cally_actor_get_top_level_origin (ClutterActor *actor,
+         g_warning ("[x11] We were not able to get proper absolute "
+                    "position of the stage");
+     }
+-  else
+ #else
++  else
+     {
+       static gboolean yet_warned = FALSE;
+ 
+-- 
+2.12.2
+
diff --git a/SOURCES/0001-clutter-clone-Unset-source-when-source-actor-is-dest.patch b/SOURCES/0001-clutter-clone-Unset-source-when-source-actor-is-dest.patch
new file mode 100644
index 0000000..f30481a
--- /dev/null
+++ b/SOURCES/0001-clutter-clone-Unset-source-when-source-actor-is-dest.patch
@@ -0,0 +1,60 @@
+From 82eb06def0b02efec2852aced4f0e609abb12557 Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Thu, 2 Mar 2017 19:18:43 +0100
+Subject: [PATCH] clutter-clone: Unset source when source actor is destroyed
+
+Otherwise we might be holding on to a source actor that's no longer
+fully functioning and cause crashes if for example we try to paint it.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=779483
+---
+ clutter/clutter/clutter-clone.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/clutter/clutter/clutter-clone.c b/clutter/clutter/clutter-clone.c
+index af03a4e81..f0eea2459 100644
+--- a/clutter/clutter/clutter-clone.c
++++ b/clutter/clutter/clutter-clone.c
+@@ -54,6 +54,7 @@
+ struct _ClutterClonePrivate
+ {
+   ClutterActor *clone_source;
++  gulong source_destroy_id;
+ };
+ 
+ G_DEFINE_TYPE_WITH_PRIVATE (ClutterClone, clutter_clone, CLUTTER_TYPE_ACTOR)
+@@ -377,6 +378,13 @@ clutter_clone_new (ClutterActor *source)
+ }
+ 
+ static void
++on_source_destroyed (ClutterActor *source,
++                     ClutterClone *self)
++{
++  clutter_clone_set_source_internal (self, NULL);
++}
++
++static void
+ clutter_clone_set_source_internal (ClutterClone *self,
+ 				   ClutterActor *source)
+ {
+@@ -387,6 +395,8 @@ clutter_clone_set_source_internal (ClutterClone *self,
+ 
+   if (priv->clone_source != NULL)
+     {
++      g_signal_handler_disconnect (priv->clone_source, priv->source_destroy_id);
++      priv->source_destroy_id = 0;
+       _clutter_actor_detach_clone (priv->clone_source, CLUTTER_ACTOR (self));
+       g_object_unref (priv->clone_source);
+       priv->clone_source = NULL;
+@@ -396,6 +406,8 @@ clutter_clone_set_source_internal (ClutterClone *self,
+     {
+       priv->clone_source = g_object_ref (source);
+       _clutter_actor_attach_clone (priv->clone_source, CLUTTER_ACTOR (self));
++      priv->source_destroy_id = g_signal_connect (priv->clone_source, "destroy",
++                                                  G_CALLBACK (on_source_destroyed), self);
+     }
+ 
+   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SOURCE]);
+-- 
+2.13.0
+
diff --git a/SOURCES/0001-cogl-Prefer-swizzling-to-convert-BGRA-buffers.patch b/SOURCES/0001-cogl-Prefer-swizzling-to-convert-BGRA-buffers.patch
new file mode 100644
index 0000000..5ef1fad
--- /dev/null
+++ b/SOURCES/0001-cogl-Prefer-swizzling-to-convert-BGRA-buffers.patch
@@ -0,0 +1,248 @@
+From 32faf80489f8ee7b4c973660c286f6d228f8e738 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Sat, 25 Feb 2017 23:21:06 +0100
+Subject: [PATCH] cogl: Prefer swizzling to convert BGRA buffers
+
+(squashed/rebased for gnome-3-22)
+
+If the GL implementation/hw supports the GL_*_texture_swizzle extension,
+pretend that BGRA textures shall contain RGBA data, and let the flipping
+happen when the texture will be used in the rendering pipeline.
+
+This avoids rather expensive format conversions when forcing BGRA buffers
+into RGBA textures, which happens rather often with WL_SHM_FORMAT_ARGB8888
+buffers (like gtk+ uses) in little-endian machines.
+
+In intel/mesa/wayland, the performance improvement is rather noticeable,
+CPU% as seen by top decreases from 45-50% to 25-30% when running
+gtk+/tests/scrolling-performance with a cairo renderer.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=779234
+---
+ cogl/cogl/cogl-driver.h                         |  7 +++++
+ cogl/cogl/driver/gl/cogl-framebuffer-gl.c       |  9 ++++++
+ cogl/cogl/driver/gl/cogl-texture-2d-gl.c        | 11 ++++----
+ cogl/cogl/driver/gl/gl/cogl-driver-gl.c         | 37 +++++++++++++++++++++----
+ cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c | 12 ++++++++
+ cogl/cogl/driver/gl/gles/cogl-driver-gles.c     | 26 +++++++++++++----
+ cogl/cogl/driver/nop/cogl-driver-nop.c          |  1 +
+ 7 files changed, 87 insertions(+), 16 deletions(-)
+
+diff --git a/cogl/cogl/cogl-driver.h b/cogl/cogl/cogl-driver.h
+index 648228c..85aa0d8 100644
+--- a/cogl/cogl/cogl-driver.h
++++ b/cogl/cogl/cogl-driver.h
+@@ -55,6 +55,13 @@ struct _CoglDriverVtable
+                           GLenum *out_glintformat,
+                           GLenum *out_glformat,
+                           GLenum *out_gltype);
++  CoglPixelFormat
++  (* pixel_format_to_gl_with_target) (CoglContext *context,
++                                      CoglPixelFormat format,
++                                      CoglPixelFormat target_format,
++                                      GLenum *out_glintformat,
++                                      GLenum *out_glformat,
++                                      GLenum *out_gltype);
+ 
+   CoglBool
+   (* update_features) (CoglContext *context,
+diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
+index 18ba08a..2af36f0 100644
+--- a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
++++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
+@@ -1418,6 +1418,15 @@ _cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
+                                                             &gl_format,
+                                                             &gl_type);
+ 
++  /* As we are reading pixels, we want to consider the bitmap according to
++   * its real pixel format, not the swizzled channels we pretend face to the
++   * pipeline.
++   */
++  if ((format == COGL_PIXEL_FORMAT_BGRA_8888 ||
++       format == COGL_PIXEL_FORMAT_BGRA_8888_PRE) &&
++      _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE))
++    gl_format = GL_BGRA;
++
+   /* NB: All offscreen rendering is done upside down so there is no need
+    * to flip in this case... */
+   if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_MESA_PACK_INVERT) &&
+diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
+index 1193df4..817dd53 100644
+--- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
++++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
+@@ -657,11 +657,12 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
+ 
+   upload_format = cogl_bitmap_get_format (upload_bmp);
+ 
+-  ctx->driver_vtable->pixel_format_to_gl (ctx,
+-                                          upload_format,
+-                                          NULL, /* internal format */
+-                                          &gl_format,
+-                                          &gl_type);
++  ctx->driver_vtable->pixel_format_to_gl_with_target (ctx,
++                                                      upload_format,
++                                                      _cogl_texture_get_format (tex),
++                                                      NULL, /* internal gl format */
++                                                      &gl_format,
++                                                      &gl_type);
+ 
+   /* If this touches the first pixel then we'll update our copy */
+   if (dst_x == 0 && dst_y == 0 &&
+diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
+index 2b9a49c..178262a 100644
+--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
++++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
+@@ -96,11 +96,12 @@ _cogl_driver_pixel_format_from_gl_internal (CoglContext *context,
+ }
+ 
+ static CoglPixelFormat
+-_cogl_driver_pixel_format_to_gl (CoglContext *context,
+-                                 CoglPixelFormat  format,
+-                                 GLenum *out_glintformat,
+-                                 GLenum *out_glformat,
+-                                 GLenum *out_gltype)
++_cogl_driver_pixel_format_to_gl_with_target (CoglContext *context,
++                                             CoglPixelFormat format,
++                                             CoglPixelFormat target_format,
++                                             GLenum *out_glintformat,
++                                             GLenum *out_glformat,
++                                             GLenum *out_gltype)
+ {
+   CoglPixelFormat required_format;
+   GLenum glintformat = 0;
+@@ -174,7 +175,16 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context,
+     case COGL_PIXEL_FORMAT_BGRA_8888:
+     case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
+       glintformat = GL_RGBA;
+-      glformat = GL_BGRA;
++      /* If the driver has texture_swizzle, pretend internal
++       * and buffer format are the same here, the pixels
++       * will be flipped through this extension.
++       */
++      if (target_format == format &&
++          _cogl_has_private_feature
++          (context, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE))
++        glformat = GL_RGBA;
++      else
++        glformat = GL_BGRA;
+       gltype = GL_UNSIGNED_BYTE;
+       break;
+ 
+@@ -289,6 +299,20 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context,
+   return required_format;
+ }
+ 
++static CoglPixelFormat
++_cogl_driver_pixel_format_to_gl (CoglContext *context,
++                                 CoglPixelFormat  format,
++                                 GLenum *out_glintformat,
++                                 GLenum *out_glformat,
++                                 GLenum *out_gltype)
++{
++  return _cogl_driver_pixel_format_to_gl_with_target (context,
++                                                      format, format,
++                                                      out_glintformat,
++                                                      out_glformat,
++                                                      out_gltype);
++}
++
+ static CoglBool
+ _cogl_get_gl_version (CoglContext *ctx,
+                       int *major_out,
+@@ -669,6 +693,7 @@ _cogl_driver_gl =
+   {
+     _cogl_driver_pixel_format_from_gl_internal,
+     _cogl_driver_pixel_format_to_gl,
++    _cogl_driver_pixel_format_to_gl_with_target,
+     _cogl_driver_update_features,
+     _cogl_offscreen_gl_allocate,
+     _cogl_offscreen_gl_free,
+diff --git a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
+index c76a0cf..d5ee4b4 100644
+--- a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
++++ b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
+@@ -114,6 +114,18 @@ _cogl_texture_driver_gen (CoglContext *ctx,
+                                  red_swizzle) );
+     }
+ 
++  /* If swizzle extension is available, prefer it to flip bgra buffers to rgba */
++  if ((internal_format == COGL_PIXEL_FORMAT_BGRA_8888 ||
++       internal_format == COGL_PIXEL_FORMAT_BGRA_8888_PRE) &&
++      _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE))
++    {
++      static const GLint bgra_swizzle[] = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
++
++      GE( ctx, glTexParameteriv (gl_target,
++                                 GL_TEXTURE_SWIZZLE_RGBA,
++                                 bgra_swizzle) );
++    }
++
+   return tex;
+ }
+ 
+diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
+index bf63fcc..521f6ef 100644
+--- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
++++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
+@@ -67,11 +67,12 @@ _cogl_driver_pixel_format_from_gl_internal (CoglContext *context,
+ }
+ 
+ static CoglPixelFormat
+-_cogl_driver_pixel_format_to_gl (CoglContext *context,
+-                                 CoglPixelFormat  format,
+-                                 GLenum *out_glintformat,
+-                                 GLenum *out_glformat,
+-                                 GLenum *out_gltype)
++_cogl_driver_pixel_format_to_gl_with_target (CoglContext *context,
++                                             CoglPixelFormat format,
++                                             CoglPixelFormat target_format,
++                                             GLenum *out_glintformat,
++                                             GLenum *out_glformat,
++                                             GLenum *out_gltype)
+ {
+   CoglPixelFormat required_format;
+   GLenum glintformat;
+@@ -219,6 +220,20 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context,
+   return required_format;
+ }
+ 
++static CoglPixelFormat
++_cogl_driver_pixel_format_to_gl (CoglContext *context,
++                                 CoglPixelFormat  format,
++                                 GLenum *out_glintformat,
++                                 GLenum *out_glformat,
++                                 GLenum *out_gltype)
++{
++  return _cogl_driver_pixel_format_to_gl_with_target (context,
++                                                      format, format,
++                                                      out_glintformat,
++                                                      out_glformat,
++                                                      out_gltype);
++}
++
+ static CoglBool
+ _cogl_get_gl_version (CoglContext *ctx,
+                       int *major_out,
+@@ -457,6 +472,7 @@ _cogl_driver_gles =
+   {
+     _cogl_driver_pixel_format_from_gl_internal,
+     _cogl_driver_pixel_format_to_gl,
++    _cogl_driver_pixel_format_to_gl_with_target,
+     _cogl_driver_update_features,
+     _cogl_offscreen_gl_allocate,
+     _cogl_offscreen_gl_free,
+diff --git a/cogl/cogl/driver/nop/cogl-driver-nop.c b/cogl/cogl/driver/nop/cogl-driver-nop.c
+index d9b1d0f..6e04e71 100644
+--- a/cogl/cogl/driver/nop/cogl-driver-nop.c
++++ b/cogl/cogl/driver/nop/cogl-driver-nop.c
+@@ -61,6 +61,7 @@ _cogl_driver_nop =
+   {
+     NULL, /* pixel_format_from_gl_internal */
+     NULL, /* pixel_format_to_gl */
++    NULL, /* pixel_format_to_gl_with_target */
+     _cogl_driver_update_features,
+     _cogl_offscreen_nop_allocate,
+     _cogl_offscreen_nop_free,
+-- 
+2.9.3
+
diff --git a/SOURCES/0001-display-Check-we-have-a-screen-before-freeing-it.patch b/SOURCES/0001-display-Check-we-have-a-screen-before-freeing-it.patch
new file mode 100644
index 0000000..5b8c284
--- /dev/null
+++ b/SOURCES/0001-display-Check-we-have-a-screen-before-freeing-it.patch
@@ -0,0 +1,32 @@
+From 91dced2ea5e4317c0067df28071c7694fb2f35ac Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Fri, 17 Feb 2017 14:24:38 +0100
+Subject: [PATCH] display: Check we have a screen before freeing it
+
+The reason for the display to be closed may be meta_screen_new()
+returning NULL, in which case we don't have a screen to free.
+Avoid a segfault on exit by adding a proper check.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=778831
+---
+ src/core/display.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/core/display.c b/src/core/display.c
+index 42a530f6c..c6248ce34 100644
+--- a/src/core/display.c
++++ b/src/core/display.c
+@@ -1113,7 +1113,9 @@ meta_display_close (MetaDisplay *display,
+   meta_display_free_events_x11 (display);
+   meta_display_free_events (display);
+ 
+-  meta_screen_free (display->screen, timestamp);
++  if (display->screen)
++    meta_screen_free (display->screen, timestamp);
++  display->screen = NULL;
+ 
+   /* Must be after all calls to meta_window_unmanage() since they
+    * unregister windows
+-- 
+2.12.0
+
diff --git a/SOURCES/0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch b/SOURCES/0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch
new file mode 100644
index 0000000..3a6d899
--- /dev/null
+++ b/SOURCES/0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch
@@ -0,0 +1,42 @@
+From def9c7e2cb32d8aeb7c48f126a43e2ff97fe14e2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Thu, 21 Jul 2016 15:43:12 +0200
+Subject: [PATCH] events: Don't move (sloppy) focus while buttons are pressed
+
+(https://bugzilla.redhat.com/show_bug.cgi?id=1358535)
+---
+ src/x11/events.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/src/x11/events.c b/src/x11/events.c
+index 98f5f03a9..b763af312 100644
+--- a/src/x11/events.c
++++ b/src/x11/events.c
+@@ -830,6 +830,16 @@ crossing_serial_is_ignored (MetaDisplay  *display,
+ }
+ 
+ static gboolean
++event_has_button_mask (XIEnterEvent *enter_event)
++{
++  int i;
++  for (i = 0; i < enter_event->buttons.mask_len; i++)
++    if (enter_event->buttons.mask[i] != '\0')
++      return TRUE;
++  return FALSE;
++}
++
++static gboolean
+ handle_input_xevent (MetaDisplay  *display,
+                      XIEvent      *input_event,
+                      unsigned long serial)
+@@ -870,6 +880,7 @@ handle_input_xevent (MetaDisplay  *display,
+        * avoid races.
+        */
+       if (window && !crossing_serial_is_ignored (display, serial) &&
++          !event_has_button_mask (enter_event) &&
+           enter_event->mode != XINotifyGrab &&
+           enter_event->mode != XINotifyUngrab &&
+           enter_event->detail != XINotifyInferior &&
+-- 
+2.12.0
+
diff --git a/SOURCES/0001-monitor-config-Consider-external-layout-before-defau.patch b/SOURCES/0001-monitor-config-Consider-external-layout-before-defau.patch
new file mode 100644
index 0000000..2527d38
--- /dev/null
+++ b/SOURCES/0001-monitor-config-Consider-external-layout-before-defau.patch
@@ -0,0 +1,127 @@
+From d2cc8089a6fd31e302b23ac787d84ff5a3257b6c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Thu, 28 Jan 2016 15:26:33 +0100
+Subject: [PATCH] monitor-config: Consider external layout before default
+ linear config
+
+In case of no existing configuration, we use a default layout of
+aligning attached displays horizontally. This sidesteps any layout
+configuration that is done externally, for instance via xorg.conf,
+which is not desirable. Instead, base the initial configuration on
+the existing layout if it passes some sanity checks before falling
+back to the default linear config.
+---
+ src/backends/meta-monitor-config.c | 76 +++++++++++++++++++++++++++++---------
+ 1 file changed, 59 insertions(+), 17 deletions(-)
+
+diff --git a/src/backends/meta-monitor-config.c b/src/backends/meta-monitor-config.c
+index 21e3126f2..492b0ffe1 100644
+--- a/src/backends/meta-monitor-config.c
++++ b/src/backends/meta-monitor-config.c
+@@ -1130,6 +1130,23 @@ init_config_from_preferred_mode (MetaOutputConfig *config,
+   config->is_presentation = FALSE;
+ }
+ 
++static void
++init_config_from_output (MetaOutputConfig *config,
++                         MetaOutput       *output)
++{
++  config->enabled = (output->crtc != NULL);
++
++  if (!config->enabled)
++    return;
++
++  config->rect = output->crtc->rect;
++  config->refresh_rate = output->crtc->current_mode->refresh_rate;
++  config->transform = output->crtc->transform;
++  config->is_primary = output->is_primary;
++  config->is_presentation = output->is_presentation;
++  config->is_underscanning = output->is_underscanning;
++}
++
+ /* This function handles configuring the outputs when the driver provides a
+  * suggested layout position for each output. This is done in recent versions
+  * of qxl and allows displays to be aligned on the guest in the same order as
+@@ -1368,6 +1385,45 @@ extend_stored_config (MetaMonitorConfig *self,
+   return FALSE;
+ }
+ 
++static gboolean
++make_initial_config_from_current (MetaMonitorConfig *self,
++                                  MetaOutput        *outputs,
++                                  unsigned           n_outputs,
++                                  int                max_width,
++                                  int                max_height,
++                                  MetaConfiguration *config)
++{
++  GList *region = NULL;
++  unsigned i;
++
++  g_return_val_if_fail (config != NULL, FALSE);
++
++  if (g_hash_table_size (self->configs) > 0)
++    return FALSE;
++
++  g_assert (config->n_outputs == n_outputs);
++
++  for (i = 0; i < n_outputs; i++)
++    {
++      init_config_from_output (&config->outputs[i], &outputs[i]);
++
++      /* Reject the configuration if the suggested positions result in
++       * overlapping displays */
++      if (meta_rectangle_overlaps_with_region (region, &config->outputs[i].rect))
++        {
++          g_warning ("Overlapping outputs, rejecting suggested configuration");
++          g_list_free (region);
++          return FALSE;
++        }
++
++      region = g_list_prepend (region, &config->outputs[i].rect);
++    }
++
++  g_list_free (region);
++
++  return TRUE;
++}
++
+ static MetaConfiguration *
+ make_default_config (MetaMonitorConfig *self,
+                      MetaOutput        *outputs,
+@@ -1399,6 +1455,9 @@ make_default_config (MetaMonitorConfig *self,
+       extend_stored_config (self, outputs, n_outputs, max_width, max_height, ret))
+       goto check_limits;
+ 
++  if (make_initial_config_from_current (self, outputs, n_outputs, max_width, max_height, ret))
++      goto check_limits;
++
+   make_linear_config (self, outputs, n_outputs, max_width, max_height, ret);
+ 
+ check_limits:
+@@ -1500,23 +1559,6 @@ meta_monitor_config_make_default (MetaMonitorConfig  *self,
+     }
+ }
+ 
+-static void
+-init_config_from_output (MetaOutputConfig *config,
+-                         MetaOutput       *output)
+-{
+-  config->enabled = (output->crtc != NULL);
+-
+-  if (!config->enabled)
+-    return;
+-
+-  config->rect = output->crtc->rect;
+-  config->refresh_rate = output->crtc->current_mode->refresh_rate;
+-  config->transform = output->crtc->transform;
+-  config->is_primary = output->is_primary;
+-  config->is_presentation = output->is_presentation;
+-  config->is_underscanning = output->is_underscanning;
+-}
+-
+ void
+ meta_monitor_config_update_current (MetaMonitorConfig  *self,
+                                     MetaMonitorManager *manager)
+-- 
+2.12.0
+
diff --git a/SOURCES/0001-monitor-manager-xrandr-Force-an-update-when-resuming.patch b/SOURCES/0001-monitor-manager-xrandr-Force-an-update-when-resuming.patch
new file mode 100644
index 0000000..c81b5bb
--- /dev/null
+++ b/SOURCES/0001-monitor-manager-xrandr-Force-an-update-when-resuming.patch
@@ -0,0 +1,228 @@
+From 677c216fbf52e5cbc1d5f0890ebc1ee9216cfd27 Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Sun, 25 Oct 2015 16:14:58 +0100
+Subject: [PATCH] monitor-manager-xrandr: Force an update when resuming from
+ suspend
+
+The stack below us isn't as reliable as we'd like and in some cases
+doesn't generate RRScreenChangeNotify events when e.g. resuming a
+laptop on a dock, meaning that we'd miss newly attached outputs.
+---
+ src/backends/x11/meta-monitor-manager-xrandr.c | 157 +++++++++++++++++++------
+ 1 file changed, 122 insertions(+), 35 deletions(-)
+
+diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
+index 4a27b3a14..aa3ff76f5 100644
+--- a/src/backends/x11/meta-monitor-manager-xrandr.c
++++ b/src/backends/x11/meta-monitor-manager-xrandr.c
+@@ -58,6 +58,11 @@ struct _MetaMonitorManagerXrandr
+   XRRScreenResources *resources;
+   int rr_event_base;
+   int rr_error_base;
++
++  guint logind_watch_id;
++  guint logind_signal_sub_id;
++
++  gboolean need_hardware_poll;
+   gboolean has_randr15;
+ };
+ 
+@@ -763,8 +768,15 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
+   manager->screen_width = WidthOfScreen (screen);
+   manager->screen_height = HeightOfScreen (screen);
+ 
+-  resources = XRRGetScreenResourcesCurrent (manager_xrandr->xdisplay,
+-					    DefaultRootWindow (manager_xrandr->xdisplay));
++  if (manager_xrandr->need_hardware_poll)
++    {
++      resources = XRRGetScreenResources (manager_xrandr->xdisplay,
++                                         DefaultRootWindow (manager_xrandr->xdisplay));
++      manager_xrandr->need_hardware_poll = FALSE;
++    }
++  else
++    resources = XRRGetScreenResourcesCurrent (manager_xrandr->xdisplay,
++                                              DefaultRootWindow (manager_xrandr->xdisplay));
+   if (!resources)
+     return;
+ 
+@@ -1414,6 +1426,100 @@ meta_monitor_manager_xrandr_init_monitors(MetaMonitorManagerXrandr *manager_xran
+ }
+ #endif
+ 
++static gboolean
++is_xvnc (MetaMonitorManager *manager)
++{
++  unsigned int i;
++
++  for (i = 0; i < manager->n_outputs; ++i)
++    if (g_str_has_prefix (manager->outputs[i].name, "VNC-"))
++      return TRUE;
++
++  return FALSE;
++}
++
++static void
++meta_monitor_manager_xrandr_update (MetaMonitorManagerXrandr *manager_xrandr)
++{
++  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
++  gboolean hotplug;
++  unsigned int timestamp;
++
++  meta_monitor_manager_read_current_config (manager);
++
++  timestamp = manager_xrandr->resources->timestamp;
++  if (is_xvnc (manager))
++    timestamp += 100;
++
++  hotplug = timestamp < manager_xrandr->resources->configTimestamp;
++  if (hotplug)
++    {
++      /* This is a hotplug event, so go ahead and build a new configuration. */
++      meta_monitor_manager_on_hotplug (manager);
++    }
++  else
++    {
++      /* Something else changed -- tell the world about it. */
++      meta_monitor_manager_rebuild_derived (manager);
++    }
++}
++
++static void
++logind_signal_handler (GDBusConnection *connection,
++                       const gchar     *sender_name,
++                       const gchar     *object_path,
++                       const gchar     *interface_name,
++                       const gchar     *signal_name,
++                       GVariant        *parameters,
++                       gpointer         user_data)
++{
++  MetaMonitorManagerXrandr *manager_xrandr = user_data;
++  gboolean suspending;
++
++  if (!g_str_equal (signal_name, "PrepareForSleep"))
++    return;
++
++  g_variant_get (parameters, "(b)", &suspending);
++  if (!suspending)
++    {
++      manager_xrandr->need_hardware_poll = TRUE;
++      meta_monitor_manager_xrandr_update (manager_xrandr);
++    }
++}
++
++static void
++logind_appeared (GDBusConnection *connection,
++                 const gchar     *name,
++                 const gchar     *name_owner,
++                 gpointer         user_data)
++{
++  MetaMonitorManagerXrandr *manager_xrandr = user_data;
++
++  manager_xrandr->logind_signal_sub_id = g_dbus_connection_signal_subscribe (connection,
++                                                                             "org.freedesktop.login1",
++                                                                             "org.freedesktop.login1.Manager",
++                                                                             "PrepareForSleep",
++                                                                             "/org/freedesktop/login1",
++                                                                             NULL,
++                                                                             G_DBUS_SIGNAL_FLAGS_NONE,
++                                                                             logind_signal_handler,
++                                                                             manager_xrandr,
++                                                                             NULL);
++}
++
++static void
++logind_vanished (GDBusConnection *connection,
++                 const gchar     *name,
++                 gpointer         user_data)
++{
++  MetaMonitorManagerXrandr *manager_xrandr = user_data;
++
++  if (connection && manager_xrandr->logind_signal_sub_id > 0)
++    g_dbus_connection_signal_unsubscribe (connection, manager_xrandr->logind_signal_sub_id);
++
++  manager_xrandr->logind_signal_sub_id = 0;
++}
++
+ static void
+ meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
+ {
+@@ -1449,6 +1555,15 @@ meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
+       meta_monitor_manager_xrandr_init_monitors (manager_xrandr);
+ #endif
+     }
++
++  manager_xrandr->logind_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
++                                                      "org.freedesktop.login1",
++                                                      G_BUS_NAME_WATCHER_FLAGS_NONE,
++                                                      logind_appeared,
++                                                      logind_vanished,
++                                                      manager_xrandr,
++                                                      NULL);
++  manager_xrandr->need_hardware_poll = TRUE;
+ }
+ 
+ static void
+@@ -1460,6 +1575,10 @@ meta_monitor_manager_xrandr_finalize (GObject *object)
+     XRRFreeScreenResources (manager_xrandr->resources);
+   manager_xrandr->resources = NULL;
+ 
++  if (manager_xrandr->logind_watch_id > 0)
++    g_bus_unwatch_name (manager_xrandr->logind_watch_id);
++  manager_xrandr->logind_watch_id = 0;
++
+   G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->finalize (object);
+ }
+ 
+@@ -1484,48 +1603,16 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass)
+ #endif
+ }
+ 
+-static gboolean
+-is_xvnc (MetaMonitorManager *manager)
+-{
+-  unsigned int i;
+-
+-  for (i = 0; i < manager->n_outputs; ++i)
+-    if (g_str_has_prefix (manager->outputs[i].name, "VNC-"))
+-      return TRUE;
+-
+-  return FALSE;
+-}
+-
+ gboolean
+ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr,
+ 					   XEvent                   *event)
+ {
+-  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
+-  gboolean hotplug;
+-  unsigned int timestamp;
+-
+   if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
+     return FALSE;
+ 
+   XRRUpdateConfiguration (event);
+ 
+-  meta_monitor_manager_read_current_config (manager);
+-
+-  timestamp = manager_xrandr->resources->timestamp;
+-  if (is_xvnc (manager))
+-    timestamp += 100;
+-
+-  hotplug = timestamp < manager_xrandr->resources->configTimestamp;
+-  if (hotplug)
+-    {
+-      /* This is a hotplug event, so go ahead and build a new configuration. */
+-      meta_monitor_manager_on_hotplug (manager);
+-    }
+-  else
+-    {
+-      /* Something else changed -- tell the world about it. */
+-      meta_monitor_manager_rebuild_derived (manager);
+-    }
++  meta_monitor_manager_xrandr_update (manager_xrandr);
+ 
+   return TRUE;
+ }
+-- 
+2.12.0
+
diff --git a/SOURCES/0001-monitor-manager-xrandr-Work-around-spurious-hotplugs.patch b/SOURCES/0001-monitor-manager-xrandr-Work-around-spurious-hotplugs.patch
new file mode 100644
index 0000000..f77a18f
--- /dev/null
+++ b/SOURCES/0001-monitor-manager-xrandr-Work-around-spurious-hotplugs.patch
@@ -0,0 +1,60 @@
+From 257c8e8d3b7103973dfdc2665d210c63496be457 Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Tue, 6 Oct 2015 21:16:18 +0200
+Subject: [PATCH] monitor-manager-xrandr: Work around spurious hotplugs on Xvnc
+
+Xvnc turns its outputs off/on on every mode set which makes us believe
+there was an hotplug when there actually wasn't. Work around this by
+requiring new randr configuration timestamps to be ahead of the last
+set timestamp by at least 100 ms for us to consider them an actual
+hotplug.
+---
+ src/backends/x11/meta-monitor-manager-xrandr.c | 19 ++++++++++++++++++-
+ 1 file changed, 18 insertions(+), 1 deletion(-)
+
+diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
+index b82120af9..4a27b3a14 100644
+--- a/src/backends/x11/meta-monitor-manager-xrandr.c
++++ b/src/backends/x11/meta-monitor-manager-xrandr.c
+@@ -1484,12 +1484,25 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass)
+ #endif
+ }
+ 
++static gboolean
++is_xvnc (MetaMonitorManager *manager)
++{
++  unsigned int i;
++
++  for (i = 0; i < manager->n_outputs; ++i)
++    if (g_str_has_prefix (manager->outputs[i].name, "VNC-"))
++      return TRUE;
++
++  return FALSE;
++}
++
+ gboolean
+ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr,
+ 					   XEvent                   *event)
+ {
+   MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
+   gboolean hotplug;
++  unsigned int timestamp;
+ 
+   if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
+     return FALSE;
+@@ -1498,7 +1511,11 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
+ 
+   meta_monitor_manager_read_current_config (manager);
+ 
+-  hotplug = manager_xrandr->resources->timestamp < manager_xrandr->resources->configTimestamp;
++  timestamp = manager_xrandr->resources->timestamp;
++  if (is_xvnc (manager))
++    timestamp += 100;
++
++  hotplug = timestamp < manager_xrandr->resources->configTimestamp;
+   if (hotplug)
+     {
+       /* This is a hotplug event, so go ahead and build a new configuration. */
+-- 
+2.12.0
+
diff --git a/SOURCES/0001-screen-Remove-stray-assert.patch b/SOURCES/0001-screen-Remove-stray-assert.patch
new file mode 100644
index 0000000..221f9ef
--- /dev/null
+++ b/SOURCES/0001-screen-Remove-stray-assert.patch
@@ -0,0 +1,41 @@
+From fd41db64169f6e0b36d56e054967cb406e32fa74 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Mon, 26 Jun 2017 17:56:36 +0200
+Subject: [PATCH] screen: Remove stray assert
+
+When the number of (static) workspaces decreases, we relocate windows
+from extra workspaces before removing them. As removing a non-empty
+workspace is not allowed, we assert that it doesn't contain any windows
+before removing it.
+
+However that assert is
+
+ - pointless, because meta_workspace_remove() already asserts that
+   the workspace is empty
+
+ - wrong, because even empty workspaces contain windows that are set
+   to show on all workspaces
+
+Simply drop the assert to avoid a crash when trying to remove a workspace
+while on-all-workspaces windows are present.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=784223
+---
+ src/core/screen.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/src/core/screen.c b/src/core/screen.c
+index d6b5eac53..c6aa9e194 100644
+--- a/src/core/screen.c
++++ b/src/core/screen.c
+@@ -1260,7 +1260,6 @@ update_num_workspaces (MetaScreen *screen,
+     {
+       MetaWorkspace *w = l->data;
+ 
+-      g_assert (w->windows == NULL);
+       meta_workspace_remove (w);
+     }
+ 
+-- 
+2.13.0
+
diff --git a/SOURCES/0001-stack-tracker-Keep-override-redirect-windows-on-top.patch b/SOURCES/0001-stack-tracker-Keep-override-redirect-windows-on-top.patch
new file mode 100644
index 0000000..3ee1d5d
--- /dev/null
+++ b/SOURCES/0001-stack-tracker-Keep-override-redirect-windows-on-top.patch
@@ -0,0 +1,83 @@
+From 245a3c2e12b4aad2e752675f82be9517235d5498 Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Fri, 19 May 2017 17:11:19 +0200
+Subject: [PATCH] stack-tracker: Keep override redirect windows on top
+
+Since commit 6b5cf2e, we keep override redirect windows on a layer
+above regular windows in the clutter actor scene graph. In the X
+server, and thus for input purposes, these windows might end up being
+stacked below regular windows though, e.g. because a new regular
+window is mapped after an OR window.
+
+Fix this disconnect by re-stacking OR windows on top when syncing the
+window stack with the compositor.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=780485
+---
+ src/core/stack-tracker.c | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c
+index a76b42cbf..82afd644a 100644
+--- a/src/core/stack-tracker.c
++++ b/src/core/stack-tracker.c
+@@ -168,6 +168,9 @@ struct _MetaStackTracker
+   guint sync_stack_later;
+ };
+ 
++static void
++meta_stack_tracker_keep_override_redirect_on_top (MetaStackTracker *tracker);
++
+ static inline const char *
+ get_window_desc (MetaStackTracker *tracker,
+                  guint64           window)
+@@ -835,6 +838,8 @@ meta_stack_tracker_sync_stack (MetaStackTracker *tracker)
+       tracker->sync_stack_later = 0;
+     }
+ 
++  meta_stack_tracker_keep_override_redirect_on_top (tracker);
++
+   meta_stack_tracker_get_stack (tracker, &windows, &n_windows);
+ 
+   meta_windows = NULL;
+@@ -1040,6 +1045,37 @@ meta_stack_tracker_lower (MetaStackTracker *tracker,
+   meta_stack_tracker_raise_above (tracker, window, None);
+ }
+ 
++static void
++meta_stack_tracker_keep_override_redirect_on_top (MetaStackTracker *tracker)
++{
++  MetaWindow *window;
++  guint64 *stack;
++  int n_windows, i;
++  int topmost_non_or;
++
++  meta_stack_tracker_get_stack (tracker, &stack, &n_windows);
++
++  for (i = n_windows - 1; i >= 0; i--)
++    {
++      window = meta_display_lookup_stack_id (tracker->screen->display, stack[i]);
++      if (window && window->layer != META_LAYER_OVERRIDE_REDIRECT)
++        break;
++    }
++
++  topmost_non_or = i;
++
++  for (i -= 1; i >= 0; i--)
++    {
++      window = meta_display_lookup_stack_id (tracker->screen->display, stack[i]);
++      if (window && window->layer == META_LAYER_OVERRIDE_REDIRECT)
++        {
++          meta_stack_tracker_raise_above (tracker, stack[i], stack[topmost_non_or]);
++          meta_stack_tracker_get_stack (tracker, &stack, &n_windows);
++          topmost_non_or -= 1;
++        }
++    }
++}
++
+ void
+ meta_stack_tracker_restack_managed (MetaStackTracker *tracker,
+                                     const guint64    *managed,
+-- 
+2.13.0
+
diff --git a/SOURCES/0001-wayland-xdg-shell-Handle-the-wl_output-on-the-set_fu.patch b/SOURCES/0001-wayland-xdg-shell-Handle-the-wl_output-on-the-set_fu.patch
new file mode 100644
index 0000000..5ef1077
--- /dev/null
+++ b/SOURCES/0001-wayland-xdg-shell-Handle-the-wl_output-on-the-set_fu.patch
@@ -0,0 +1,42 @@
+From 4ee272a5a88351a03619deae4e5dd4ab16f32b07 Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Wed, 2 Nov 2016 17:55:01 +0100
+Subject: [PATCH] wayland-xdg-shell: Handle the wl_output on the set_fullscreen
+ request
+
+This makes us fullscreen wayland windows on the requested monitor.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=772525
+---
+ src/wayland/meta-wayland-xdg-shell.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c
+index 450acda..e1195c7 100644
+--- a/src/wayland/meta-wayland-xdg-shell.c
++++ b/src/wayland/meta-wayland-xdg-shell.c
+@@ -27,6 +27,7 @@
+ 
+ #include "core/window-private.h"
+ #include "wayland/meta-wayland.h"
++#include "wayland/meta-wayland-outputs.h"
+ #include "wayland/meta-wayland-popup.h"
+ #include "wayland/meta-wayland-private.h"
+ #include "wayland/meta-wayland-seat.h"
+@@ -363,6 +364,13 @@ xdg_toplevel_set_fullscreen (struct wl_client   *client,
+ {
+   MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource);
+ 
++  if (output_resource)
++    {
++      MetaWaylandOutput *output = wl_resource_get_user_data (output_resource);
++      if (output)
++        meta_window_move_to_monitor (surface->window, output->monitor_info->number);
++    }
++
+   meta_window_make_fullscreen (surface->window);
+ }
+ 
+-- 
+2.9.3
+
diff --git a/SOURCES/0001-window-actor-Special-case-shaped-Java-windows.patch b/SOURCES/0001-window-actor-Special-case-shaped-Java-windows.patch
new file mode 100644
index 0000000..fad3a5f
--- /dev/null
+++ b/SOURCES/0001-window-actor-Special-case-shaped-Java-windows.patch
@@ -0,0 +1,35 @@
+From 4cd334074a411f1bdc018f74ef51e9ac8dea9fa0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Fri, 12 May 2017 13:40:31 +0200
+Subject: [PATCH] window-actor: Special-case shaped Java windows
+
+OpenJDK wrongly assumes that shaping a window implies no shadows.
+They got lucky until commit b975676c changed the fallback case,
+but now their compliance tests are broken. Make them happy again
+by special-casing shaped Java windows.
+---
+ src/compositor/meta-window-actor.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
+index 7595adb66..8768b477c 100644
+--- a/src/compositor/meta-window-actor.c
++++ b/src/compositor/meta-window-actor.c
+@@ -842,6 +842,14 @@ meta_window_actor_has_shadow (MetaWindowActor *self)
+     return FALSE;
+ 
+   /*
++   * OpenJDK wrongly assumes that shaping a window implies no compositor
++   * shadows; make its compliance tests happy to give it what it wants ...
++   */
++  if (g_strcmp0 (priv->window->res_name, "sun-awt-X11-XWindowPeer") == 0 &&
++      priv->window->shape_region != NULL)
++    return FALSE;
++
++  /*
+    * Generate shadows for all other windows.
+    */
+   return TRUE;
+-- 
+2.12.2
+
diff --git a/SOURCES/0008-Add-support-for-quad-buffer-stereo.patch b/SOURCES/0008-Add-support-for-quad-buffer-stereo.patch
new file mode 100644
index 0000000..1a44410
--- /dev/null
+++ b/SOURCES/0008-Add-support-for-quad-buffer-stereo.patch
@@ -0,0 +1,978 @@
+From 1292ea32ce34e804b709af0cdbc9fda87d142e9b Mon Sep 17 00:00:00 2001
+From: "Owen W. Taylor" <otaylor@fishsoup.net>
+Date: Thu, 8 May 2014 18:44:15 -0400
+Subject: [PATCH 8/8] Add support for quad-buffer stereo
+
+Track the stereo status of windows using the new EXT_stereo_tree
+GLX extension.
+
+When stereo is enabled or disabled, a restart is triggered via
+meta_restart() after a timeout, setting a _META_ENABLE_STEREO
+property on the root window to indicate whether we should
+turn on a stereo stage for clutter. The property avoids a loop,
+since we need to enable stereo *before* initializing Clutter and GL,
+but we need GL to figure out whether we have stereo windows.
+
+Stereo windows are drawn to the stage using new functionality
+in Cogl to setup a stereo context, select which buffer to draw
+to, and draw either the left or right buffer of a stereo
+texture_from_pixmap.
+---
+ src/Makefile.am                              |   2 +
+ src/compositor/compositor-private.h          |   9 ++
+ src/compositor/compositor.c                  | 128 ++++++++++++++++++++++
+ src/compositor/meta-shaped-texture-private.h |   5 +-
+ src/compositor/meta-shaped-texture.c         | 157 ++++++++++++++++++++-------
+ src/compositor/meta-surface-actor-wayland.c  |   2 +-
+ src/compositor/meta-surface-actor-x11.c      |  56 ++++++++--
+ src/compositor/meta-surface-actor-x11.h      |   5 +
+ src/compositor/meta-window-actor-private.h   |   5 +
+ src/compositor/meta-window-actor.c           |  22 ++++
+ src/core/main.c                              |   4 +
+ src/core/stereo.c                            | 153 ++++++++++++++++++++++++++
+ src/core/stereo.h                            |  28 +++++
+ 13 files changed, 526 insertions(+), 50 deletions(-)
+ create mode 100644 src/core/stereo.c
+ create mode 100644 src/core/stereo.h
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index da4e3df..aea37da 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -233,6 +233,8 @@ libmutter_la_SOURCES =				\
+ 	core/stack.h				\
+ 	core/stack-tracker.c			\
+ 	core/stack-tracker.h			\
++	core/stereo.c				\
++	core/stereo.h				\
+ 	core/util.c				\
+ 	meta/util.h				\
+ 	core/util-private.h			\
+diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
+index 4629fa5..27813ba 100644
+--- a/src/compositor/compositor-private.h
++++ b/src/compositor/compositor-private.h
+@@ -21,6 +21,10 @@ struct _MetaCompositor
+   gint64          server_time_query_time;
+   gint64          server_time_offset;
+ 
++  int             glx_opcode;
++  guint           stereo_tree_ext : 1;
++  guint           have_stereo_windows : 1;
++
+   guint           server_time_is_monotonic_time : 1;
+   guint           no_mipmaps  : 1;
+ 
+@@ -59,6 +63,11 @@ void     meta_end_modal_for_plugin   (MetaCompositor   *compositor,
+ gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
+                                                       gint64       monotonic_time);
+ 
++gboolean meta_compositor_window_is_stereo     (MetaScreen *screen,
++                                               Window      xwindow);
++void     meta_compositor_select_stereo_notify (MetaScreen *screen,
++                                               Window      xwindow);
++
+ void meta_compositor_flash_window (MetaCompositor *compositor,
+                                    MetaWindow     *window);
+ 
+diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
+index f001dfd..f8198d5 100644
+--- a/src/compositor/compositor.c
++++ b/src/compositor/compositor.c
+@@ -70,6 +70,8 @@
+ #include "meta-window-group.h"
+ #include "window-private.h" /* to check window->hidden */
+ #include "display-private.h" /* for meta_display_lookup_x_window() and meta_display_cancel_touch() */
++#include "stack-tracker.h"
++#include "stereo.h"
+ #include "util-private.h"
+ #include "frame.h"
+ #include <X11/extensions/shape.h>
+@@ -477,6 +479,97 @@ redirect_windows (MetaScreen *screen)
+     }
+ }
+ 
++#define GLX_STEREO_TREE_EXT        0x20F5
++#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001
++#define GLX_STEREO_NOTIFY_EXT      0x00000000
++
++typedef struct {
++  int type;
++  unsigned long serial;
++  Bool send_event;
++  Display *display;
++  int extension;
++  int evtype;
++  Drawable window;
++  Bool stereo_tree;
++} StereoNotifyEvent;
++
++static gboolean
++screen_has_stereo_tree_ext (MetaScreen *screen)
++{
++  MetaDisplay *display = meta_screen_get_display (screen);
++  Display     *xdisplay = meta_display_get_xdisplay (display);
++  const char  *extensions_string;
++
++  static const char * (*query_extensions_string) (Display *display,
++                                                  int      screen);
++
++  if (query_extensions_string == NULL)
++    query_extensions_string =
++      (const char * (*) (Display *, int))
++      cogl_get_proc_address ("glXQueryExtensionsString");
++
++  extensions_string = query_extensions_string (xdisplay,
++                                               meta_screen_get_screen_number (screen));
++
++  return strstr (extensions_string, "EXT_stereo_tree") != 0;
++}
++
++#include <GL/gl.h>
++
++gboolean
++meta_compositor_window_is_stereo (MetaScreen *screen,
++                                  Window      xwindow)
++{
++  MetaCompositor *compositor = get_compositor_for_screen (screen);
++  MetaDisplay    *display = meta_screen_get_display (screen);
++  Display        *xdisplay = meta_display_get_xdisplay (display);
++
++  static int (*query_drawable) (Display      *dpy,
++                                Drawable      draw,
++                                int           attribute,
++                                unsigned int *value);
++
++  if (compositor->stereo_tree_ext)
++    {
++      unsigned int stereo_tree = 0;
++
++      if (query_drawable == NULL)
++        query_drawable =
++          (int (*) (Display *, Drawable, int, unsigned int *))
++          cogl_get_proc_address ("glXQueryDrawable");
++
++      query_drawable (xdisplay, xwindow, GLX_STEREO_TREE_EXT, &stereo_tree);
++
++      return stereo_tree != 0;
++    }
++  else
++    return FALSE;
++}
++
++void
++meta_compositor_select_stereo_notify (MetaScreen *screen,
++                                      Window      xwindow)
++{
++  MetaCompositor *compositor = get_compositor_for_screen (screen);
++  MetaDisplay    *display = meta_screen_get_display (screen);
++  Display        *xdisplay = meta_display_get_xdisplay (display);
++
++  static void (*select_event) (Display      *dpy,
++                               Drawable      draw,
++                               unsigned long event_mask);
++
++  if (compositor->stereo_tree_ext)
++    {
++      if (select_event == NULL)
++        select_event =
++          (void (*) (Display *, Drawable, unsigned long))
++          cogl_get_proc_address ("glXSelectEvent");
++
++      select_event (xdisplay, xwindow, GLX_STEREO_NOTIFY_MASK_EXT);
++    }
++}
++
+ void
+ meta_compositor_manage (MetaCompositor *compositor)
+ {
+@@ -485,6 +578,8 @@ meta_compositor_manage (MetaCompositor *compositor)
+   MetaScreen *screen = display->screen;
+   MetaBackend *backend = meta_get_backend ();
+ 
++  compositor->stereo_tree_ext = screen_has_stereo_tree_ext (screen);
++
+   meta_screen_set_cm_selection (display->screen);
+ 
+   compositor->stage = meta_backend_get_stage (backend);
+@@ -749,6 +844,23 @@ meta_compositor_process_event (MetaCompositor *compositor,
+       if (window)
+         process_damage (compositor, (XDamageNotifyEvent *) event, window);
+     }
++  else if (!meta_is_wayland_compositor () &&
++           event->type == GenericEvent &&
++           event->xcookie.extension == compositor->glx_opcode)
++    {
++      if (event->xcookie.evtype == GLX_STEREO_NOTIFY_EXT)
++        {
++          StereoNotifyEvent *stereo_event = (StereoNotifyEvent *)(event->xcookie.data);
++          window = meta_display_lookup_x_window (compositor->display, stereo_event->window);
++
++          if (window != NULL)
++            {
++              MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
++              meta_window_actor_stereo_notify (window_actor, stereo_event->stereo_tree);
++              meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
++            }
++        }
++    }
+ 
+   if (compositor->have_x11_sync_object)
+     meta_sync_ring_handle_event (event);
+@@ -923,6 +1035,7 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
+ 			    GList	    *stack)
+ {
+   GList *old_stack;
++  int stereo_window_count = 0;
+ 
+   /* This is painful because hidden windows that we are in the process
+    * of animating out of existence. They'll be at the bottom of the
+@@ -998,12 +1111,16 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
+        * near the front of the other.)
+        */
+       compositor->windows = g_list_prepend (compositor->windows, actor);
++      if (meta_window_actor_is_stereo (actor))
++        stereo_window_count++;
+ 
+       stack = g_list_remove (stack, window);
+       old_stack = g_list_remove (old_stack, actor);
+     }
+ 
+   sync_actor_stacking (compositor);
++
++  meta_stereo_set_have_stereo_windows (stereo_window_count > 0);
+ }
+ 
+ void
+@@ -1193,6 +1310,17 @@ meta_compositor_new (MetaDisplay *display)
+                                            meta_post_paint_func,
+                                            compositor,
+                                            NULL);
++  if (!meta_is_wayland_compositor ())
++    {
++      Display *xdisplay = meta_display_get_xdisplay (display);
++      int glx_major_opcode, glx_first_event, glx_first_error;
++
++      if (XQueryExtension (xdisplay,
++                           "GLX",
++                           &glx_major_opcode, &glx_first_event, &glx_first_error))
++        compositor->glx_opcode = glx_major_opcode;
++    }
++
+   return compositor;
+ }
+ 
+diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h
+index 1a841de..79912e7 100644
+--- a/src/compositor/meta-shaped-texture-private.h
++++ b/src/compositor/meta-shaped-texture-private.h
+@@ -30,8 +30,9 @@
+ #include <meta/meta-shaped-texture.h>
+ 
+ ClutterActor *meta_shaped_texture_new (void);
+-void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
+-                                      CoglTexture       *texture);
++void meta_shaped_texture_set_textures (MetaShapedTexture *stex,
++                                       CoglTexture       *texture,
++                                       CoglTexture       *texture_right);
+ void meta_shaped_texture_set_fallback_size (MetaShapedTexture *stex,
+                                             guint              fallback_width,
+                                             guint              fallback_height);
+diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
+index 5b2630b..830aa67 100644
+--- a/src/compositor/meta-shaped-texture.c
++++ b/src/compositor/meta-shaped-texture.c
+@@ -74,8 +74,10 @@ static guint signals[LAST_SIGNAL];
+ struct _MetaShapedTexturePrivate
+ {
+   MetaTextureTower *paint_tower;
++  MetaTextureTower *paint_tower_right;
+ 
+   CoglTexture *texture;
++  CoglTexture *texture_right;
+   CoglTexture *mask_texture;
+ 
+   /* The region containing only fully opaque pixels */
+@@ -122,8 +124,10 @@ meta_shaped_texture_init (MetaShapedTexture *self)
+   priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
+ 
+   priv->paint_tower = meta_texture_tower_new ();
++  priv->paint_tower_right = NULL; /* demand create */
+ 
+   priv->texture = NULL;
++  priv->texture_right = NULL;
+   priv->mask_texture = NULL;
+   priv->create_mipmaps = TRUE;
+ }
+@@ -173,11 +177,11 @@ meta_shaped_texture_dispose (GObject *object)
+   MetaShapedTexture *self = (MetaShapedTexture *) object;
+   MetaShapedTexturePrivate *priv = self->priv;
+ 
+-  if (priv->paint_tower)
+-    meta_texture_tower_free (priv->paint_tower);
+-  priv->paint_tower = NULL;
++  g_clear_pointer (&priv->paint_tower, meta_texture_tower_free);
++  g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
+ 
+   g_clear_pointer (&priv->texture, cogl_object_unref);
++  g_clear_pointer (&priv->texture_right, cogl_object_unref);
+   g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
+ 
+   meta_shaped_texture_set_mask_texture (self, NULL);
+@@ -271,8 +275,9 @@ paint_clipped_rectangle (CoglFramebuffer       *fb,
+ }
+ 
+ static void
+-set_cogl_texture (MetaShapedTexture *stex,
+-                  CoglTexture       *cogl_tex)
++set_cogl_textures (MetaShapedTexture *stex,
++                   CoglTexture       *cogl_tex,
++                   CoglTexture       *cogl_tex_right)
+ {
+   MetaShapedTexturePrivate *priv;
+   guint width, height;
+@@ -283,8 +288,11 @@ set_cogl_texture (MetaShapedTexture *stex,
+ 
+   if (priv->texture)
+     cogl_object_unref (priv->texture);
++  if (priv->texture_right)
++    cogl_object_unref (priv->texture_right);
+ 
+   priv->texture = cogl_tex;
++  priv->texture_right = cogl_tex_right;
+ 
+   if (cogl_tex != NULL)
+     {
+@@ -298,6 +306,9 @@ set_cogl_texture (MetaShapedTexture *stex,
+       height = 0;
+     }
+ 
++  if (cogl_tex_right != NULL)
++    cogl_object_ref (cogl_tex_right);
++
+   if (priv->tex_width != width ||
+       priv->tex_height != height)
+     {
+@@ -313,52 +324,41 @@ set_cogl_texture (MetaShapedTexture *stex,
+    * previous buffer. We only queue a redraw in response to surface
+    * damage. */
+ 
++  if (cogl_tex_right != NULL)
++    {
++      if (priv->paint_tower_right == NULL)
++        priv->paint_tower_right = meta_texture_tower_new ();
++    }
++  else
++    {
++      g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
++    }
++
+   if (priv->create_mipmaps)
+-    meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
++    {
++      meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
++
++      if (priv->paint_tower_right)
++        meta_texture_tower_set_base_texture (priv->paint_tower_right, cogl_tex_right);
++    }
+ }
+ 
+ static void
+-meta_shaped_texture_paint (ClutterActor *actor)
++paint_texture (MetaShapedTexture *stex,
++               CoglTexture       *paint_tex)
+ {
+-  MetaShapedTexture *stex = (MetaShapedTexture *) actor;
++  ClutterActor *actor = CLUTTER_ACTOR (stex);
+   MetaShapedTexturePrivate *priv = stex->priv;
+   guint tex_width, tex_height;
+   guchar opacity;
+   CoglContext *ctx;
+   CoglFramebuffer *fb;
+-  CoglTexture *paint_tex;
+   ClutterActorBox alloc;
+   CoglPipelineFilter filter;
+ 
+   if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
+     return;
+ 
+-  if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
+-    clutter_actor_realize (CLUTTER_ACTOR (stex));
+-
+-  /* The GL EXT_texture_from_pixmap extension does allow for it to be
+-   * used together with SGIS_generate_mipmap, however this is very
+-   * rarely supported. Also, even when it is supported there
+-   * are distinct performance implications from:
+-   *
+-   *  - Updating mipmaps that we don't need
+-   *  - Having to reallocate pixmaps on the server into larger buffers
+-   *
+-   * So, we just unconditionally use our mipmap emulation code. If we
+-   * wanted to use SGIS_generate_mipmap, we'd have to  query COGL to
+-   * see if it was supported (no API currently), and then if and only
+-   * if that was the case, set the clutter texture quality to HIGH.
+-   * Setting the texture quality to high without SGIS_generate_mipmap
+-   * support for TFP textures will result in fallbacks to XGetImage.
+-   */
+-  if (priv->create_mipmaps)
+-    paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
+-  else
+-    paint_tex = COGL_TEXTURE (priv->texture);
+-
+-  if (paint_tex == NULL)
+-    return;
+-
+   tex_width = priv->tex_width;
+   tex_height = priv->tex_height;
+ 
+@@ -519,6 +519,76 @@ meta_shaped_texture_paint (ClutterActor *actor)
+ }
+ 
+ static void
++meta_shaped_texture_paint (ClutterActor *actor)
++{
++  MetaShapedTexture *stex = (MetaShapedTexture *) actor;
++  MetaShapedTexturePrivate *priv = stex->priv;
++  CoglFramebuffer *fb;
++  gboolean stereo;
++  CoglTexture *paint_tex;
++  CoglTexture *paint_tex_right;
++
++  if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
++    return;
++
++  if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
++    clutter_actor_realize (CLUTTER_ACTOR (stex));
++
++  /* The GL EXT_texture_from_pixmap extension does allow for it to be
++   * used together with SGIS_generate_mipmap, however this is very
++   * rarely supported. Also, even when it is supported there
++   * are distinct performance implications from:
++   *
++   *  - Updating mipmaps that we don't need
++   *  - Having to reallocate pixmaps on the server into larger buffers
++   *
++   * So, we just unconditionally use our mipmap emulation code. If we
++   * wanted to use SGIS_generate_mipmap, we'd have to  query COGL to
++   * see if it was supported (no API currently), and then if and only
++   * if that was the case, set the clutter texture quality to HIGH.
++   * Setting the texture quality to high without SGIS_generate_mipmap
++   * support for TFP textures will result in fallbacks to XGetImage.
++   */
++  if (priv->create_mipmaps)
++    paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
++  else
++    paint_tex = COGL_TEXTURE (priv->texture);
++
++  if (paint_tex == NULL)
++    return;
++
++  fb = cogl_get_draw_framebuffer ();
++
++  stereo = priv->texture_right && cogl_framebuffer_get_is_stereo (fb);
++
++  if (stereo)
++    {
++      if (priv->create_mipmaps)
++	paint_tex_right = meta_texture_tower_get_paint_texture (priv->paint_tower_right);
++      else
++	paint_tex_right = COGL_TEXTURE (priv->texture_right);
++    }
++  else
++    paint_tex_right = NULL;
++
++  if (paint_tex != NULL)
++    {
++      if (stereo)
++	cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_LEFT);
++      paint_texture (stex, paint_tex);
++      if (stereo)
++	cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
++    }
++
++  if (paint_tex_right != NULL)
++    {
++      cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_RIGHT);
++      paint_texture (stex, paint_tex_right);
++      cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
++    }
++}
++
++static void
+ meta_shaped_texture_get_preferred_width (ClutterActor *self,
+                                          gfloat        for_height,
+                                          gfloat       *min_width_p,
+@@ -637,6 +707,12 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
+       priv->create_mipmaps = create_mipmaps;
+       base_texture = create_mipmaps ? priv->texture : NULL;
+       meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
++
++      if (priv->paint_tower_right)
++        {
++          base_texture = create_mipmaps ? priv->texture_right : NULL;
++          meta_texture_tower_set_base_texture (priv->paint_tower_right, base_texture);
++        }
+     }
+ }
+ 
+@@ -702,6 +778,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
+     return FALSE;
+ 
+   meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
++  if (priv->paint_tower_right)
++    meta_texture_tower_update_area (priv->paint_tower_right, x, y, width, height);
+ 
+   unobscured_region = effective_unobscured_region (stex);
+   if (unobscured_region)
+@@ -734,17 +812,18 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
+ }
+ 
+ /**
+- * meta_shaped_texture_set_texture:
++ * meta_shaped_texture_set_textures:
+  * @stex: The #MetaShapedTexture
+  * @pixmap: The #CoglTexture to display
+  */
+ void
+-meta_shaped_texture_set_texture (MetaShapedTexture *stex,
+-                                 CoglTexture       *texture)
++meta_shaped_texture_set_textures (MetaShapedTexture *stex,
++                                  CoglTexture       *texture,
++                                  CoglTexture       *texture_right)
+ {
+   g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
+ 
+-  set_cogl_texture (stex, texture);
++  set_cogl_textures (stex, texture, texture_right);
+ }
+ 
+ /**
+diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c
+index 33036d8..f38c7d3 100644
+--- a/src/compositor/meta-surface-actor-wayland.c
++++ b/src/compositor/meta-surface-actor-wayland.c
+@@ -477,7 +477,7 @@ meta_surface_actor_wayland_set_texture (MetaSurfaceActorWayland *self,
+                                         CoglTexture *texture)
+ {
+   MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
+-  meta_shaped_texture_set_texture (stex, texture);
++  meta_shaped_texture_set_textures (stex, texture, NULL);
+ }
+ 
+ MetaWaylandSurface *
+diff --git a/src/compositor/meta-surface-actor-x11.c b/src/compositor/meta-surface-actor-x11.c
+index d32aeb6..52db380 100644
+--- a/src/compositor/meta-surface-actor-x11.c
++++ b/src/compositor/meta-surface-actor-x11.c
+@@ -31,6 +31,7 @@
+ #include <cogl/winsys/cogl-texture-pixmap-x11.h>
+ 
+ #include <meta/errors.h>
++#include "compositor-private.h"
+ #include "window-private.h"
+ #include "meta-shaped-texture-private.h"
+ #include "meta-cullable.h"
+@@ -43,6 +44,7 @@ struct _MetaSurfaceActorX11Private
+   MetaDisplay *display;
+ 
+   CoglTexture *texture;
++  CoglTexture *texture_right;
+   Pixmap pixmap;
+   Damage damage;
+ 
+@@ -58,6 +60,8 @@ struct _MetaSurfaceActorX11Private
+   guint size_changed : 1;
+ 
+   guint unredirected   : 1;
++
++  guint stereo : 1;
+ };
+ typedef struct _MetaSurfaceActorX11Private MetaSurfaceActorX11Private;
+ 
+@@ -94,7 +98,7 @@ detach_pixmap (MetaSurfaceActorX11 *self)
+    * you are supposed to be able to free a GLXPixmap after freeing the underlying
+    * pixmap, but it certainly doesn't work with current DRI/Mesa
+    */
+-  meta_shaped_texture_set_texture (stex, NULL);
++  meta_shaped_texture_set_textures (stex, NULL, NULL);
+   cogl_flush ();
+ 
+   meta_error_trap_push (display);
+@@ -103,6 +107,7 @@ detach_pixmap (MetaSurfaceActorX11 *self)
+   meta_error_trap_pop (display);
+ 
+   g_clear_pointer (&priv->texture, cogl_object_unref);
++  g_clear_pointer (&priv->texture_right, cogl_object_unref);
+ }
+ 
+ static void
+@@ -114,23 +119,35 @@ set_pixmap (MetaSurfaceActorX11 *self,
+   CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
+   MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
+   CoglError *error = NULL;
+-  CoglTexture *texture;
++  CoglTexturePixmapX11 *texture;
++  CoglTexturePixmapX11 *texture_right;
+ 
+   g_assert (priv->pixmap == None);
+   priv->pixmap = pixmap;
+ 
+-  texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->pixmap, FALSE, &error));
++  if (priv->stereo)
++    texture = cogl_texture_pixmap_x11_new_left (ctx, pixmap, FALSE, &error);
++  else
++    texture = cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, &error);
++
++  if (priv->stereo)
++    texture_right = cogl_texture_pixmap_x11_new_right (texture);
++  else
++    texture_right = NULL;
+ 
+   if (error != NULL)
+     {
+       g_warning ("Failed to allocate stex texture: %s", error->message);
+       cogl_error_free (error);
+     }
+-  else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture))))
++  else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (texture)))
+     g_warning ("NOTE: Not using GLX TFP!\n");
+ 
+-  priv->texture = texture;
+-  meta_shaped_texture_set_texture (stex, texture);
++  priv->texture = COGL_TEXTURE (texture);
++  if (priv->stereo)
++    priv->texture_right = COGL_TEXTURE (texture_right);
++
++  meta_shaped_texture_set_textures (stex, COGL_TEXTURE (texture), COGL_TEXTURE (texture_right));
+ }
+ 
+ static void
+@@ -433,8 +450,8 @@ reset_texture (MetaSurfaceActorX11 *self)
+   /* Setting the texture to NULL will cause all the FBO's cached by the
+    * shaped texture's MetaTextureTower to be discarded and recreated.
+    */
+-  meta_shaped_texture_set_texture (stex, NULL);
+-  meta_shaped_texture_set_texture (stex, priv->texture);
++  meta_shaped_texture_set_textures (stex, NULL, NULL);
++  meta_shaped_texture_set_textures (stex, priv->texture, priv->texture_right);
+ }
+ 
+ MetaSurfaceActor *
+@@ -443,12 +460,17 @@ meta_surface_actor_x11_new (MetaWindow *window)
+   MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL);
+   MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
+   MetaDisplay *display = meta_window_get_display (window);
++  Window xwindow;
+ 
+   g_assert (!meta_is_wayland_compositor ());
+ 
+   priv->window = window;
+   priv->display = display;
+ 
++  xwindow = meta_window_x11_get_toplevel_xwindow (window);
++  priv->stereo = meta_compositor_window_is_stereo (display->screen, xwindow);
++  meta_compositor_select_stereo_notify (display->screen, xwindow);
++
+   g_signal_connect_object (priv->display, "gl-video-memory-purged",
+                            G_CALLBACK (reset_texture), self, G_CONNECT_SWAPPED);
+ 
+@@ -479,3 +501,21 @@ meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
+   priv->last_height = height;
+   meta_shaped_texture_set_fallback_size (stex, width, height);
+ }
++
++void
++meta_surface_actor_x11_stereo_notify (MetaSurfaceActorX11 *self,
++                                      gboolean             stereo_tree)
++{
++  MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
++
++  priv->stereo = stereo_tree != FALSE;
++  detach_pixmap (self);
++}
++
++gboolean
++meta_surface_actor_x11_is_stereo (MetaSurfaceActorX11 *self)
++{
++  MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
++
++  return priv->stereo;
++}
+diff --git a/src/compositor/meta-surface-actor-x11.h b/src/compositor/meta-surface-actor-x11.h
+index 0e692ee..4b2eccc 100644
+--- a/src/compositor/meta-surface-actor-x11.h
++++ b/src/compositor/meta-surface-actor-x11.h
+@@ -64,6 +64,11 @@ MetaSurfaceActor * meta_surface_actor_x11_new (MetaWindow *window);
+ void meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
+                                       int width, int height);
+ 
++void meta_surface_actor_x11_stereo_notify (MetaSurfaceActorX11 *self,
++                                           gboolean             stereo_tree);
++
++gboolean meta_surface_actor_x11_is_stereo (MetaSurfaceActorX11 *self);
++
+ G_END_DECLS
+ 
+ #endif /* __META_SURFACE_ACTOR_X11_H__ */
+diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
+index 72dcd14..035d756 100644
+--- a/src/compositor/meta-window-actor-private.h
++++ b/src/compositor/meta-window-actor-private.h
+@@ -59,4 +59,9 @@ void meta_window_actor_effect_completed (MetaWindowActor  *actor,
+ MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self);
+ void meta_window_actor_update_surface (MetaWindowActor *self);
+ 
++void meta_window_actor_stereo_notify (MetaWindowActor *actor,
++                                      gboolean         stereo_tree);
++
++gboolean meta_window_actor_is_stereo (MetaWindowActor *actor);
++
+ #endif /* META_WINDOW_ACTOR_PRIVATE_H */
+diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
+index 9395caa..f763964 100644
+--- a/src/compositor/meta-window-actor.c
++++ b/src/compositor/meta-window-actor.c
+@@ -2146,3 +2146,25 @@ meta_window_actor_sync_updates_frozen (MetaWindowActor *self)
+ 
+   meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (window));
+ }
++
++void
++meta_window_actor_stereo_notify (MetaWindowActor *self,
++                                 gboolean         stereo_tree)
++{
++  MetaWindowActorPrivate *priv = self->priv;
++
++  if (META_IS_SURFACE_ACTOR_X11 (priv->surface))
++    meta_surface_actor_x11_stereo_notify (META_SURFACE_ACTOR_X11 (priv->surface),
++                                          stereo_tree);
++}
++
++gboolean
++meta_window_actor_is_stereo (MetaWindowActor *self)
++{
++  MetaWindowActorPrivate *priv = self->priv;
++
++  if (META_IS_SURFACE_ACTOR_X11 (priv->surface))
++    return meta_surface_actor_x11_is_stereo (META_SURFACE_ACTOR_X11 (priv->surface));
++  else
++    return FALSE;
++}
+diff --git a/src/core/main.c b/src/core/main.c
+index 25586be..23d9d6d 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -47,6 +47,7 @@
+ #include <meta/main.h>
+ #include "util-private.h"
+ #include "display-private.h"
++#include "stereo.h"
+ #include <meta/errors.h>
+ #include "ui.h"
+ #include <meta/prefs.h>
+@@ -490,6 +491,9 @@ meta_init (void)
+ 
+   meta_init_backend (backend_type);
+ 
++  if (!meta_is_wayland_compositor ())
++    meta_stereo_init ();
++
+   meta_clutter_init ();
+ 
+ #ifdef HAVE_WAYLAND
+diff --git a/src/core/stereo.c b/src/core/stereo.c
+new file mode 100644
+index 0000000..5a232b6
+--- /dev/null
++++ b/src/core/stereo.c
+@@ -0,0 +1,153 @@
++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
++
++/*
++ * Copyright (C) 2014 Red Hat, Inc.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++/*
++ * SECTION:stereo
++ * @short_description: Keep track of whether we are a stereo compositor
++ *
++ * With GLX, we need to use a different GL context for stereo and
++ * non-stereo support. Support for multiple GL contexts is unfinished
++ * in Cogl and entirely lacking in Clutter, so it's by far easier
++ * to just restart Mutter when we detect a stereo window.
++ *
++ * A property _MUTTER_ENABLE_STEREO is maintained on the root window
++ * to know whether we should initialize clutter for stereo or not.
++ * When the presence or absence of stereo windows mismatches the
++ * stereo-enabled state for a sufficiently long period of time,
++ * we restart Mutter.
++ */
++
++#include <config.h>
++
++#include <clutter/x11/clutter-x11.h>
++#include <gio/gunixinputstream.h>
++#include <X11/Xatom.h>
++
++#include <meta/main.h>
++#include "ui.h"
++#include <meta/util.h>
++#include "display-private.h"
++#include "stereo.h"
++#include "util-private.h"
++
++static guint stereo_switch_id = 0;
++static gboolean stereo_enabled = FALSE;
++/* -1 so the first time meta_stereo_set_have_stereo_windows() is called
++ * we avoid the short-circuit and set up a timeout to restart
++ * if necessary */
++static gboolean stereo_have_windows = (gboolean)-1;
++static gboolean stereo_restart = FALSE;
++
++#define STEREO_ENABLE_WAIT 1000
++#define STEREO_DISABLE_WAIT 5000
++
++void
++meta_stereo_init (void)
++{
++  Display *xdisplay;
++  Window root;
++  Atom atom_enable_stereo;
++  Atom type;
++  int format;
++  unsigned long n_items, bytes_after;
++  guchar *data;
++
++  xdisplay = XOpenDisplay (NULL);
++  if (xdisplay == NULL)
++    meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL));
++
++  root = DefaultRootWindow (xdisplay);
++  atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
++
++  XGetWindowProperty (xdisplay, root, atom_enable_stereo,
++                      0, 1, False, XA_INTEGER,
++                      &type, &format, &n_items, &bytes_after, &data);
++  if (type == XA_INTEGER)
++    {
++      if (format == 32 && n_items == 1 && bytes_after == 0)
++        {
++          stereo_enabled = *(long *)data;
++        }
++      else
++        {
++          meta_warning ("Bad value for _MUTTER_ENABLE_STEREO property\n");
++        }
++
++      XFree (data);
++    }
++  else if (type != None)
++    {
++      meta_warning ("Bad type for _MUTTER_ENABLE_STEREO property\n");
++    }
++
++  meta_verbose ("On startup, _MUTTER_ENABLE_STEREO=%s",
++                stereo_enabled ? "yes" : "no");
++  clutter_x11_set_use_stereo_stage (stereo_enabled);
++  XCloseDisplay (xdisplay);
++}
++
++static gboolean
++meta_stereo_switch (gpointer data)
++{
++  stereo_switch_id = 0;
++  stereo_restart = TRUE;
++
++  meta_restart (stereo_have_windows ?
++                _("Enabling stereo...") :
++                _("Disabling stereo..."));
++
++  return FALSE;
++}
++
++void
++meta_stereo_set_have_stereo_windows (gboolean have_windows)
++{
++  have_windows = have_windows != FALSE;
++
++  if (!stereo_restart && have_windows != stereo_have_windows)
++    {
++      MetaDisplay *display = meta_get_display ();
++      Display *xdisplay = meta_display_get_xdisplay (display);
++      Window root = DefaultRootWindow (xdisplay);
++      Atom atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
++      long value;
++
++      stereo_have_windows = have_windows;
++
++      if (stereo_have_windows)
++        meta_verbose ("Detected stereo windows\n");
++      else
++        meta_verbose ("No stereo windows detected\n");
++
++      value = stereo_have_windows;
++      XChangeProperty (xdisplay, root,
++                       atom_enable_stereo, XA_INTEGER, 32,
++                       PropModeReplace, (guchar *)&value, 1);
++
++      if (stereo_switch_id != 0)
++        {
++          g_source_remove (stereo_switch_id);
++          stereo_switch_id = 0;
++        }
++
++      if (stereo_have_windows != stereo_enabled)
++        stereo_switch_id = g_timeout_add (stereo_have_windows ? STEREO_ENABLE_WAIT : STEREO_DISABLE_WAIT,
++                                          meta_stereo_switch, NULL);
++    }
++}
+diff --git a/src/core/stereo.h b/src/core/stereo.h
+new file mode 100644
+index 0000000..ccd1d70
+--- /dev/null
++++ b/src/core/stereo.h
+@@ -0,0 +1,28 @@
++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
++
++/*
++ * Copyright (C) 2014 Red Hat, Inc.
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef META_STEREO_H
++#define META_STEREO_H
++
++void     meta_stereo_init                    (void);
++void     meta_stereo_set_have_stereo_windows (gboolean have_windows);
++gboolean meta_stereo_is_restart              (void);
++void     meta_stereo_finish_restart          (void);
++
++#endif
+-- 
+2.9.3
+
diff --git a/SOURCES/Enable-threeaded-swap-wait.patch b/SOURCES/Enable-threeaded-swap-wait.patch
new file mode 100644
index 0000000..5e27d79
--- /dev/null
+++ b/SOURCES/Enable-threeaded-swap-wait.patch
@@ -0,0 +1,887 @@
+From 4d1005e3b86050f8b5bab41baf08704117f89b21 Mon Sep 17 00:00:00 2001
+From: "Owen W. Taylor" <otaylor@fishsoup.net>
+Date: Thu, 11 Feb 2016 15:06:23 -0500
+Subject: [PATCH 1/7] CoglGPUInfo - fix check for NVIDIA
+
+NVIDIA drivers have a vendor of "NVIDIA Corporation" not "NVIDIA".
+Check for both in case older drivers did use "NVIDIA"
+
+https://bugzilla.gnome.org/show_bug.cgi?id=779039
+---
+ cogl/cogl/cogl-gpu-info.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/cogl/cogl/cogl-gpu-info.c b/cogl/cogl/cogl-gpu-info.c
+index 845382881..23a846616 100644
+--- a/cogl/cogl/cogl-gpu-info.c
++++ b/cogl/cogl/cogl-gpu-info.c
+@@ -169,7 +169,8 @@ check_qualcomm_vendor (const CoglGpuInfoStrings *strings)
+ static CoglBool
+ check_nvidia_vendor (const CoglGpuInfoStrings *strings)
+ {
+-  if (strcmp (strings->vendor_string, "NVIDIA") != 0)
++  if (strcmp (strings->vendor_string, "NVIDIA") != 0 &&
++      strcmp (strings->vendor_string, "NVIDIA Corporation") != 0)
+     return FALSE;
+ 
+   return TRUE;
+-- 
+2.12.0
+
+
+From 62a66bddf3aba14e65ab913746237d3d19a502dd Mon Sep 17 00:00:00 2001
+From: "Owen W. Taylor" <otaylor@fishsoup.net>
+Date: Thu, 11 Feb 2016 16:33:03 -0500
+Subject: [PATCH 2/7] CoglWinsysGLX: factor out some duplicated code
+
+Add a helper function for repeated calls to clock_gettime(CLOCK_MONOTONIC)
+
+https://bugzilla.gnome.org/show_bug.cgi?id=779039
+---
+ cogl/cogl/winsys/cogl-winsys-glx.c | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
+index c50db3a04..379658e8a 100644
+--- a/cogl/cogl/winsys/cogl-winsys-glx.c
++++ b/cogl/cogl/winsys/cogl-winsys-glx.c
+@@ -192,6 +192,15 @@ find_onscreen_for_xid (CoglContext *context, uint32_t xid)
+   return NULL;
+ }
+ 
++static int64_t
++get_monotonic_time_ns (void)
++{
++  struct timespec ts;
++
++  clock_gettime (CLOCK_MONOTONIC, &ts);
++  return ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec;
++}
++
+ static void
+ ensure_ust_type (CoglRenderer *renderer,
+                  GLXDrawable drawable)
+@@ -202,7 +211,6 @@ ensure_ust_type (CoglRenderer *renderer,
+   int64_t msc;
+   int64_t sbc;
+   struct timeval tv;
+-  struct timespec ts;
+   int64_t current_system_time;
+   int64_t current_monotonic_time;
+ 
+@@ -232,9 +240,7 @@ ensure_ust_type (CoglRenderer *renderer,
+ 
+   /* This is the time source that the newer (fixed) linux drm
+    * drivers use (Linux >= 3.8) */
+-  clock_gettime (CLOCK_MONOTONIC, &ts);
+-  current_monotonic_time = (ts.tv_sec * G_GINT64_CONSTANT (1000000)) +
+-    (ts.tv_nsec / G_GINT64_CONSTANT (1000));
++  current_monotonic_time = get_monotonic_time_ns () / 1000;
+ 
+   if (current_monotonic_time > ust - 1000000 &&
+       current_monotonic_time < ust + 1000000)
+@@ -310,10 +316,7 @@ _cogl_winsys_get_clock_time (CoglContext *context)
+       }
+     case COGL_GLX_UST_IS_MONOTONIC_TIME:
+       {
+-        struct timespec ts;
+-
+-        clock_gettime (CLOCK_MONOTONIC, &ts);
+-        return ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec;
++        return get_monotonic_time_ns ();
+       }
+     }
+ 
+@@ -1682,16 +1685,13 @@ _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen)
+       else
+         {
+           uint32_t current_count;
+-          struct timespec ts;
+ 
+           glx_renderer->glXGetVideoSync (&current_count);
+           glx_renderer->glXWaitVideoSync (2,
+                                           (current_count + 1) % 2,
+                                           &current_count);
+ 
+-          clock_gettime (CLOCK_MONOTONIC, &ts);
+-          info->presentation_time =
+-            ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec;
++          info->presentation_time = get_monotonic_time_ns ();
+         }
+     }
+ }
+-- 
+2.12.0
+
+
+From 69e156c91c663e6f41759eec9f7c729a67da7dc5 Mon Sep 17 00:00:00 2001
+From: "Owen W. Taylor" <otaylor@fishsoup.net>
+Date: Thu, 11 Feb 2016 17:04:08 -0500
+Subject: [PATCH 3/7] Usability of SGI_video_sync is per-display not
+ per-renderer
+
+As previously commented in the code, SGI_video_sync is per-display, rather
+than per-renderer. The is_direct flag for the renderer was tested before
+it was initialized (per-display) and that resulted in SGI_video_sync
+never being used.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=779039
+---
+ cogl/cogl/cogl-glx-display-private.h  |  3 ++
+ cogl/cogl/cogl-glx-renderer-private.h |  2 --
+ cogl/cogl/winsys/cogl-winsys-glx.c    | 52 +++++++++++++++++++----------------
+ 3 files changed, 31 insertions(+), 26 deletions(-)
+
+diff --git a/cogl/cogl/cogl-glx-display-private.h b/cogl/cogl/cogl-glx-display-private.h
+index 133c1188c..1d1afc0cf 100644
+--- a/cogl/cogl/cogl-glx-display-private.h
++++ b/cogl/cogl/cogl-glx-display-private.h
+@@ -51,6 +51,9 @@ typedef struct _CoglGLXDisplay
+ 
+   CoglBool found_fbconfig;
+   CoglBool fbconfig_has_rgba_visual;
++  CoglBool is_direct;
++  CoglBool have_vblank_counter;
++  CoglBool can_vblank_wait;
+   GLXFBConfig fbconfig;
+ 
+   /* Single context for all wins */
+diff --git a/cogl/cogl/cogl-glx-renderer-private.h b/cogl/cogl/cogl-glx-renderer-private.h
+index cb8ff97f8..061f2ccb5 100644
+--- a/cogl/cogl/cogl-glx-renderer-private.h
++++ b/cogl/cogl/cogl-glx-renderer-private.h
+@@ -43,8 +43,6 @@ typedef struct _CoglGLXRenderer
+   int glx_error_base;
+   int glx_event_base;
+ 
+-  CoglBool is_direct;
+-
+   /* Vblank stuff */
+   int dri_fd;
+ 
+diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
+index 379658e8a..5a2700176 100644
+--- a/cogl/cogl/winsys/cogl-winsys-glx.c
++++ b/cogl/cogl/winsys/cogl-winsys-glx.c
+@@ -715,23 +715,25 @@ update_base_winsys_features (CoglRenderer *renderer)
+ 
+   g_strfreev (split_extensions);
+ 
+-  /* Note: the GLX_SGI_video_sync spec explicitly states this extension
+-   * only works for direct contexts. */
+-  if (!glx_renderer->is_direct)
+-    {
+-      glx_renderer->glXGetVideoSync = NULL;
+-      glx_renderer->glXWaitVideoSync = NULL;
+-      COGL_FLAGS_SET (glx_renderer->base_winsys_features,
+-                      COGL_WINSYS_FEATURE_VBLANK_COUNTER,
+-                      FALSE);
+-    }
++  /* The GLX_SGI_video_sync spec explicitly states this extension
++   * only works for direct contexts; we don't know per-renderer
++   * if the context is direct or not, so we turn off the feature
++   * flag; we still use the extension within this file looking
++   * instead at glx_display->have_vblank_counter.
++   */
++  COGL_FLAGS_SET (glx_renderer->base_winsys_features,
++                  COGL_WINSYS_FEATURE_VBLANK_COUNTER,
++                  FALSE);
++
+ 
+   COGL_FLAGS_SET (glx_renderer->base_winsys_features,
+                   COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
+                   TRUE);
+ 
+-  if (glx_renderer->glXWaitVideoSync ||
+-      glx_renderer->glXWaitForMsc)
++  /* Because of the direct-context dependency, the VBLANK_WAIT feature
++   * doesn't reflect the presence of GLX_SGI_video_sync.
++   */
++  if (glx_renderer->glXWaitForMsc)
+     COGL_FLAGS_SET (glx_renderer->base_winsys_features,
+                     COGL_WINSYS_FEATURE_VBLANK_WAIT,
+                     TRUE);
+@@ -864,7 +866,7 @@ update_winsys_features (CoglContext *context, CoglError **error)
+    * by the SwapInterval so we have to throttle swap_region requests
+    * manually... */
+   if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION) &&
+-      _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT))
++      (glx_display->have_vblank_counter || glx_display->can_vblank_wait))
+     COGL_FLAGS_SET (context->winsys_features,
+                     COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE);
+ 
+@@ -1142,11 +1144,13 @@ create_context (CoglDisplay *display, CoglError **error)
+       return FALSE;
+     }
+ 
+-  glx_renderer->is_direct =
++  glx_display->is_direct =
+     glx_renderer->glXIsDirect (xlib_renderer->xdpy, glx_display->glx_context);
++  glx_display->have_vblank_counter = glx_display->is_direct && glx_renderer->glXWaitVideoSync;
++  glx_display->can_vblank_wait = glx_renderer->glXWaitForMsc || glx_display->have_vblank_counter;
+ 
+   COGL_NOTE (WINSYS, "Setting %s context",
+-             glx_renderer->is_direct ? "direct" : "indirect");
++             glx_display->is_direct ? "direct" : "indirect");
+ 
+   /* XXX: GLX doesn't let us make a context current without a window
+    * so we create a dummy window that we can use while no CoglOnscreen
+@@ -1658,12 +1662,13 @@ _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen)
+   CoglContext *ctx = framebuffer->context;
+   CoglGLXRenderer *glx_renderer;
+   CoglXlibRenderer *xlib_renderer;
++  CoglGLXDisplay *glx_display;
+ 
+   glx_renderer = ctx->display->renderer->winsys;
+   xlib_renderer = _cogl_xlib_renderer_get_data (ctx->display->renderer);
++  glx_display = ctx->display->winsys;
+ 
+-  if (glx_renderer->glXWaitForMsc ||
+-      glx_renderer->glXGetVideoSync)
++  if (glx_display->can_vblank_wait)
+     {
+       CoglFrameInfo *info = g_queue_peek_tail (&onscreen->pending_frame_infos);
+ 
+@@ -1759,6 +1764,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
+   CoglXlibRenderer *xlib_renderer =
+     _cogl_xlib_renderer_get_data (context->display->renderer);
+   CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
++  CoglGLXDisplay *glx_display = context->display->winsys;
+   CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
+   CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
+   GLXDrawable drawable =
+@@ -1815,9 +1821,8 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
+ 
+   if (framebuffer->config.swap_throttled)
+     {
+-      have_counter =
+-        _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_COUNTER);
+-      can_wait = _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT);
++      have_counter = glx_display->have_vblank_counter;
++      can_wait = glx_display->can_vblank_wait;
+     }
+   else
+     {
+@@ -1974,6 +1979,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
+   CoglXlibRenderer *xlib_renderer =
+     _cogl_xlib_renderer_get_data (context->display->renderer);
+   CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
++  CoglGLXDisplay *glx_display = context->display->winsys;
+   CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
+   CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
+   CoglBool have_counter;
+@@ -1993,8 +1999,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
+     {
+       uint32_t end_frame_vsync_counter = 0;
+ 
+-      have_counter =
+-        _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_COUNTER);
++      have_counter = glx_display->have_vblank_counter;
+ 
+       /* If the swap_region API is also being used then we need to track
+        * the vsync counter for each swap request so we can manually
+@@ -2004,8 +2009,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
+ 
+       if (!glx_renderer->glXSwapInterval)
+         {
+-          CoglBool can_wait =
+-            _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT);
++          CoglBool can_wait = glx_display->can_vblank_wait;
+ 
+           /* If we are going to wait for VBLANK manually, we not only
+            * need to flush out pending drawing to the GPU before we
+-- 
+2.12.0
+
+
+From 55b8900c1d66a4568ff261a0498d12ca857d2431 Mon Sep 17 00:00:00 2001
+From: "Owen W. Taylor" <otaylor@fishsoup.net>
+Date: Thu, 11 Feb 2016 17:12:09 -0500
+Subject: [PATCH 4/7] Fix the get_clock_time() without GLX_OML_sync_control
+
+When we don't have GLX_OML_sync_control, we still can set the
+frame presentation time, but we always use the system monotonic time,
+so return that from get_clock_time().
+
+https://bugzilla.gnome.org/show_bug.cgi?id=779039
+---
+ cogl/cogl/winsys/cogl-winsys-glx.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
+index 5a2700176..7ad1a3fdf 100644
+--- a/cogl/cogl/winsys/cogl-winsys-glx.c
++++ b/cogl/cogl/winsys/cogl-winsys-glx.c
+@@ -296,6 +296,9 @@ _cogl_winsys_get_clock_time (CoglContext *context)
+ {
+   CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
+ 
++  if (!glx_renderer->glXWaitForMsc)
++    return get_monotonic_time_ns ();
++
+   /* We don't call ensure_ust_type() because we don't have a drawable
+    * to work with. cogl_get_clock_time() is documented to only work
+    * once a valid, non-zero, timestamp has been retrieved from Cogl.
+-- 
+2.12.0
+
+
+From cb784a7be6c72453bc441f03ced27a531ee687d5 Mon Sep 17 00:00:00 2001
+From: "Owen W. Taylor" <otaylor@fishsoup.net>
+Date: Thu, 11 Feb 2016 17:15:13 -0500
+Subject: [PATCH 5/7] For NVIDIA proprietary drivers, implement sync events
+ with a thread
+
+It's a good guess that the buffer swap will occur at the next vblank,
+so use glXWaitVideoSync in a separate thread to deliver a sync event
+rather than just letting the client block when frame drawing, which
+can signficantly change app logic as compared to the INTEL_swap_event
+case.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=779039
+---
+ cogl/cogl/cogl-private.h           |   3 +
+ cogl/cogl/winsys/cogl-winsys-glx.c | 294 +++++++++++++++++++++++++++++++++++--
+ 2 files changed, 286 insertions(+), 11 deletions(-)
+
+diff --git a/cogl/cogl/cogl-private.h b/cogl/cogl/cogl-private.h
+index 333955c65..e5dc9feda 100644
+--- a/cogl/cogl/cogl-private.h
++++ b/cogl/cogl/cogl-private.h
+@@ -77,6 +77,9 @@ typedef enum
+   COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE,
+   COGL_PRIVATE_FEATURE_GL_EMBEDDED,
+   COGL_PRIVATE_FEATURE_GL_WEB,
++  /* This is currently only implemented for GLX, but isn't actually
++   * that winsys dependent */
++  COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT,
+ 
+   COGL_N_PRIVATE_FEATURES
+ } CoglPrivateFeature;
+diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
+index 7ad1a3fdf..1418d1501 100644
+--- a/cogl/cogl/winsys/cogl-winsys-glx.c
++++ b/cogl/cogl/winsys/cogl-winsys-glx.c
+@@ -65,12 +65,16 @@
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/time.h>
++#include <errno.h>
+ #include <fcntl.h>
+ #include <time.h>
++#include <unistd.h>
+ 
+ #include <GL/glx.h>
+ #include <X11/Xlib.h>
+ 
++#include <glib.h>
++
+ /* This is a relatively new extension */
+ #ifndef GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV
+ #define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7
+@@ -100,6 +104,14 @@ typedef struct _CoglOnscreenGLX
+   CoglBool pending_sync_notify;
+   CoglBool pending_complete_notify;
+   CoglBool pending_resize_notify;
++
++  GThread *swap_wait_thread;
++  GQueue *swap_wait_queue;
++  GCond swap_wait_cond;
++  GMutex swap_wait_mutex;
++  int swap_wait_pipe[2];
++  GLXContext swap_wait_context;
++  CoglBool closing_down;
+ } CoglOnscreenGLX;
+ 
+ typedef struct _CoglPixmapTextureEyeGLX
+@@ -885,6 +897,28 @@ update_winsys_features (CoglContext *context, CoglError **error)
+                       COGL_FEATURE_ID_PRESENTATION_TIME,
+                       TRUE);
+     }
++  else
++    {
++      CoglGpuInfo *info = &context->gpu;
++      if (glx_display->have_vblank_counter &&
++	  info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA)
++        {
++          COGL_FLAGS_SET (context->winsys_features,
++                          COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT, TRUE);
++          COGL_FLAGS_SET (context->winsys_features,
++                          COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT, TRUE);
++          /* TODO: remove this deprecated feature */
++          COGL_FLAGS_SET (context->features,
++                          COGL_FEATURE_ID_SWAP_BUFFERS_EVENT,
++                          TRUE);
++          COGL_FLAGS_SET (context->features,
++                          COGL_FEATURE_ID_PRESENTATION_TIME,
++                          TRUE);
++          COGL_FLAGS_SET (context->private_features,
++                          COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT,
++                          TRUE);
++        }
++    }
+ 
+   /* We'll manually handle queueing dirty events in response to
+    * Expose events from X */
+@@ -1481,7 +1515,8 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
+     }
+ 
+ #ifdef GLX_INTEL_swap_event
+-  if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
++  if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT) &&
++      !_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT))
+     {
+       GLXDrawable drawable =
+         glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin;
+@@ -1524,6 +1559,31 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
+       xlib_onscreen->output = NULL;
+     }
+ 
++  if (glx_onscreen->swap_wait_thread)
++    {
++      g_mutex_lock (&glx_onscreen->swap_wait_mutex);
++      glx_onscreen->closing_down = TRUE;
++      g_cond_signal (&glx_onscreen->swap_wait_cond);
++      g_mutex_unlock (&glx_onscreen->swap_wait_mutex);
++      g_thread_join (glx_onscreen->swap_wait_thread);
++      glx_onscreen->swap_wait_thread = NULL;
++
++      g_cond_clear (&glx_onscreen->swap_wait_cond);
++      g_mutex_clear (&glx_onscreen->swap_wait_mutex);
++
++      g_queue_free (glx_onscreen->swap_wait_queue);
++      glx_onscreen->swap_wait_queue = NULL;
++
++      _cogl_poll_renderer_remove_fd (context->display->renderer,
++                                     glx_onscreen->swap_wait_pipe[0]);
++      
++      close (glx_onscreen->swap_wait_pipe[0]);
++      close (glx_onscreen->swap_wait_pipe[1]);
++
++      glx_renderer->glXDestroyContext (xlib_renderer->xdpy,
++                                       glx_onscreen->swap_wait_context);
++    }
++
+   _cogl_xlib_renderer_trap_errors (context->display->renderer, &old_state);
+ 
+   drawable =
+@@ -1757,6 +1817,199 @@ set_frame_info_output (CoglOnscreen *onscreen,
+     }
+ }
+ 
++static gpointer
++threaded_swap_wait (gpointer data)
++{
++  CoglOnscreen *onscreen = data;
++
++  CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
++
++  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
++  CoglContext *context = framebuffer->context;
++  CoglDisplay *display = context->display;
++  CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (display->renderer);
++  CoglGLXDisplay *glx_display = display->winsys;
++  CoglGLXRenderer *glx_renderer = display->renderer->winsys;
++  GLXDrawable dummy_drawable;
++
++  if (glx_display->dummy_glxwin)
++    dummy_drawable = glx_display->dummy_glxwin;
++  else
++    dummy_drawable = glx_display->dummy_xwin;
++
++  glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy,
++                                       dummy_drawable,
++                                       dummy_drawable,
++                                       glx_onscreen->swap_wait_context);
++
++  g_mutex_lock (&glx_onscreen->swap_wait_mutex);
++
++  while (TRUE)
++    {
++      gpointer queue_element;
++      uint32_t vblank_counter;
++
++      while (!glx_onscreen->closing_down && glx_onscreen->swap_wait_queue->length == 0)
++         g_cond_wait (&glx_onscreen->swap_wait_cond, &glx_onscreen->swap_wait_mutex);
++
++      if (glx_onscreen->closing_down)
++         break;
++
++      queue_element = g_queue_pop_tail (glx_onscreen->swap_wait_queue);
++      vblank_counter = GPOINTER_TO_UINT(queue_element);
++
++      g_mutex_unlock (&glx_onscreen->swap_wait_mutex);
++      glx_renderer->glXWaitVideoSync (2,
++                                      (vblank_counter + 1) % 2,
++                                      &vblank_counter);
++      g_mutex_lock (&glx_onscreen->swap_wait_mutex);
++
++      if (!glx_onscreen->closing_down)
++         {
++           int bytes_written = 0;
++
++           union {
++             char bytes[8];
++             int64_t presentation_time;
++           } u;
++
++           u.presentation_time = get_monotonic_time_ns ();
++
++           while (bytes_written < 8)
++             {
++               int res = write (glx_onscreen->swap_wait_pipe[1], u.bytes + bytes_written, 8 - bytes_written);
++               if (res == -1)
++                 {
++                   if (errno != EINTR)
++                     g_error ("Error writing to swap notification pipe: %s\n",
++                              g_strerror (errno));
++                 }
++               else
++                 {
++                   bytes_written += res;
++                 }
++             }
++         }
++    }
++
++  g_mutex_unlock (&glx_onscreen->swap_wait_mutex);
++
++  glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy,
++                                       None,
++                                       None,
++                                       NULL);
++
++  return NULL;
++}
++
++static int64_t
++threaded_swap_wait_pipe_prepare (void *user_data)
++{
++  return -1;
++}
++
++static void
++threaded_swap_wait_pipe_dispatch (void *user_data, int revents)
++{
++  CoglOnscreen *onscreen = user_data;
++  CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
++
++  CoglFrameInfo *info;
++
++  if ((revents & COGL_POLL_FD_EVENT_IN))
++    {
++      int bytes_read = 0;
++
++      union {
++         char bytes[8];
++         int64_t presentation_time;
++      } u;
++
++      while (bytes_read < 8)
++         {
++           int res = read (glx_onscreen->swap_wait_pipe[0], u.bytes + bytes_read, 8 - bytes_read);
++           if (res == -1)
++             {
++               if (errno != EINTR)
++                 g_error ("Error reading from swap notification pipe: %s\n",
++                          g_strerror (errno));
++             }
++           else
++             {
++               bytes_read += res;
++             }
++         }
++
++      set_sync_pending (onscreen);
++      set_complete_pending (onscreen);
++
++      info = g_queue_peek_head (&onscreen->pending_frame_infos);
++      info->presentation_time = u.presentation_time;
++    }
++}
++
++static void
++start_threaded_swap_wait (CoglOnscreen *onscreen,
++                           uint32_t      vblank_counter)
++{
++  CoglOnscreenGLX *glx_onscreen = onscreen->winsys;
++  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
++  CoglContext *context = framebuffer->context;
++
++  if (glx_onscreen->swap_wait_thread == NULL)
++    {
++      CoglDisplay *display = context->display;
++      CoglGLXRenderer *glx_renderer = display->renderer->winsys;
++      CoglGLXDisplay *glx_display = display->winsys;
++      CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
++      CoglXlibRenderer *xlib_renderer =
++        _cogl_xlib_renderer_get_data (display->renderer);
++
++      GLXDrawable drawable =
++        glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin;
++      int i;
++
++      ensure_ust_type (display->renderer, drawable);
++      
++      if ((pipe (glx_onscreen->swap_wait_pipe) == -1))
++        g_error ("Couldn't create pipe for swap notification: %s\n",
++                 g_strerror (errno));
++
++      for (i = 0; i < 2; i++)
++	{
++	  if (fcntl(glx_onscreen->swap_wait_pipe[i], F_SETFD,
++		    fcntl(glx_onscreen->swap_wait_pipe[i], F_GETFD, 0) | FD_CLOEXEC) == -1)
++	    g_error ("Couldn't set swap notification pipe CLOEXEC: %s\n",
++		     g_strerror (errno));
++	}
++
++      _cogl_poll_renderer_add_fd (display->renderer,
++                                  glx_onscreen->swap_wait_pipe[0],
++                                  COGL_POLL_FD_EVENT_IN,
++                                  threaded_swap_wait_pipe_prepare,
++                                  threaded_swap_wait_pipe_dispatch,
++                                  onscreen);
++
++      glx_onscreen->swap_wait_queue = g_queue_new ();
++      g_mutex_init (&glx_onscreen->swap_wait_mutex);
++      g_cond_init (&glx_onscreen->swap_wait_cond);
++      glx_onscreen->swap_wait_context =
++         glx_renderer->glXCreateNewContext (xlib_renderer->xdpy,
++                                            glx_display->fbconfig,
++                                            GLX_RGBA_TYPE,
++                                            glx_display->glx_context,
++                                            True);
++      glx_onscreen->swap_wait_thread = g_thread_new ("cogl_glx_swap_wait",
++                                                     threaded_swap_wait,
++                                                     onscreen);
++    }
++
++  g_mutex_lock (&glx_onscreen->swap_wait_mutex);
++  g_queue_push_head (glx_onscreen->swap_wait_queue, GUINT_TO_POINTER(vblank_counter));
++  g_cond_signal (&glx_onscreen->swap_wait_cond);
++  g_mutex_unlock (&glx_onscreen->swap_wait_mutex);
++}
++
+ static void
+ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
+                                    const int *user_rectangles,
+@@ -2000,19 +2253,38 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
+ 
+   if (framebuffer->config.swap_throttled)
+     {
+-      uint32_t end_frame_vsync_counter = 0;
+-
+       have_counter = glx_display->have_vblank_counter;
+ 
+-      /* If the swap_region API is also being used then we need to track
+-       * the vsync counter for each swap request so we can manually
+-       * throttle swap_region requests. */
+-      if (have_counter)
+-        end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context);
+-
+-      if (!glx_renderer->glXSwapInterval)
++      if (glx_renderer->glXSwapInterval)
+         {
+-          CoglBool can_wait = glx_display->can_vblank_wait;
++          if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT))
++            {
++	      /* If we didn't wait for the GPU here, then it's easy to get the case
++	       * where there is a VBlank between the point where we get the vsync counter
++	       * and the point where the GPU is ready to actually perform the glXSwapBuffers(),
++	       * and the swap wait terminates at the first VBlank rather than the one
++	       * where the swap buffers happens. Calling glFinish() here makes this a
++	       * rare race since the GPU is already ready to swap when we call glXSwapBuffers().
++	       * The glFinish() also prevents any serious damage if the rare race happens,
++	       * since it will wait for the preceding glXSwapBuffers() and prevent us from
++	       * getting premanently ahead. (For NVIDIA drivers, glFinish() after glXSwapBuffers()
++	       * waits for the buffer swap to happen.)
++	       */
++              _cogl_winsys_wait_for_gpu (onscreen);
++              start_threaded_swap_wait (onscreen, _cogl_winsys_get_vsync_counter (context));
++            }
++        }
++      else
++        {
++          CoglBool can_wait = have_counter || glx_display->can_vblank_wait;
++
++          uint32_t end_frame_vsync_counter = 0;
++
++          /* If the swap_region API is also being used then we need to track
++           * the vsync counter for each swap request so we can manually
++           * throttle swap_region requests. */
++          if (have_counter)
++            end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context);
+ 
+           /* If we are going to wait for VBLANK manually, we not only
+            * need to flush out pending drawing to the GPU before we
+-- 
+2.12.0
+
+
+From fb0978b4ea33c88e7a42d4f478d60ef86e271414 Mon Sep 17 00:00:00 2001
+From: "Owen W. Taylor" <otaylor@fishsoup.net>
+Date: Wed, 29 Jun 2016 13:52:59 -0400
+Subject: [PATCH 6/7] Add cogl_xlib_renderer_set_threaded_swap_wait_enabled()
+
+Because the threaded-swap-wait functionality requires XInitThreads(),
+and because it isn't clear that it is a win for all applications,
+add a API function to conditionally enable it.
+
+Fix the cogl-crate example not to just have a hard-coded dependency
+on libX11.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=779039
+---
+ cogl/cogl/cogl-renderer-private.h  |  1 +
+ cogl/cogl/cogl-renderer.c          | 11 +++++++++++
+ cogl/cogl/cogl-xlib-renderer.h     | 30 ++++++++++++++++++++++++++++++
+ cogl/cogl/winsys/cogl-winsys-glx.c |  1 +
+ 4 files changed, 43 insertions(+)
+
+diff --git a/cogl/cogl/cogl-renderer-private.h b/cogl/cogl/cogl-renderer-private.h
+index 8627b6cc6..33ed0ceac 100644
+--- a/cogl/cogl/cogl-renderer-private.h
++++ b/cogl/cogl/cogl-renderer-private.h
+@@ -69,6 +69,7 @@ struct _CoglRenderer
+   Display *foreign_xdpy;
+   CoglBool xlib_enable_event_retrieval;
+   CoglBool xlib_want_reset_on_video_memory_purge;
++  CoglBool xlib_enable_threaded_swap_wait;
+ #endif
+ 
+   CoglDriver driver;
+diff --git a/cogl/cogl/cogl-renderer.c b/cogl/cogl/cogl-renderer.c
+index 51a04ffdd..e6575d808 100644
+--- a/cogl/cogl/cogl-renderer.c
++++ b/cogl/cogl/cogl-renderer.c
+@@ -285,6 +285,17 @@ cogl_xlib_renderer_request_reset_on_video_memory_purge (CoglRenderer *renderer,
+ 
+   renderer->xlib_want_reset_on_video_memory_purge = enable;
+ }
++
++void
++cogl_xlib_renderer_set_threaded_swap_wait_enabled (CoglRenderer *renderer,
++						   CoglBool enable)
++{
++  _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
++  /* NB: Renderers are considered immutable once connected */
++  _COGL_RETURN_IF_FAIL (!renderer->connected);
++
++  renderer->xlib_enable_threaded_swap_wait = enable;
++}
+ #endif /* COGL_HAS_XLIB_SUPPORT */
+ 
+ CoglBool
+diff --git a/cogl/cogl/cogl-xlib-renderer.h b/cogl/cogl/cogl-xlib-renderer.h
+index f3c1d7c09..3c0db189b 100644
+--- a/cogl/cogl/cogl-xlib-renderer.h
++++ b/cogl/cogl/cogl-xlib-renderer.h
+@@ -168,6 +168,36 @@ cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer,
+                                                 CoglBool enable);
+ 
+ /**
++ * cogl_xlib_renderer_set_threaded_swap_wait_enabled:
++ * @renderer: a #CoglRenderer
++ * @enable: The new value
++ *
++ * Sets whether Cogl is allowed to use a separate threaded to wait for the
++ * completion of glXSwapBuffers() and call the frame callback for the
++ * corresponding #CoglOnscreen. This is a way of emulating the
++ * INTEL_swap_event extension, and will only ever be used if
++ * INTEL_swap_event is not present; it will also only be used for
++ * specific white-listed drivers that are known to work correctly with
++ * multiple contexts sharing state between threads.
++ *
++ * The advantage of enabling this is that it will allow your main loop
++ * to do other work while waiting for the system to be ready to draw
++ * the next frame, instead of blocking in glXSwapBuffers(). A disadvantage
++ * is that the driver will be prevented from buffering up multiple frames
++ * even if it thinks that it would be advantageous. In general, this
++ * will work best for something like a system compositor that is doing
++ * simple drawing but handling lots of other complex tasks.
++ * 
++ * If you enable this, you must call XInitThreads() before any other
++ * X11 calls in your program. (See the documentation for XInitThreads())
++ *
++ * Stability: unstable
++ */
++void
++cogl_xlib_renderer_set_threaded_swap_wait_enabled (CoglRenderer *renderer,
++						   CoglBool enable);
++
++/**
+  * cogl_xlib_renderer_get_display: (skip)
+  */
+ Display *
+diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
+index 1418d1501..74b0895d1 100644
+--- a/cogl/cogl/winsys/cogl-winsys-glx.c
++++ b/cogl/cogl/winsys/cogl-winsys-glx.c
+@@ -901,6 +901,7 @@ update_winsys_features (CoglContext *context, CoglError **error)
+     {
+       CoglGpuInfo *info = &context->gpu;
+       if (glx_display->have_vblank_counter &&
++	  context->display->renderer->xlib_enable_threaded_swap_wait &&
+ 	  info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA)
+         {
+           COGL_FLAGS_SET (context->winsys_features,
+-- 
+2.12.0
+
+
+From 9505ce8cce4fe14443b5c9868e4e7301268a8d23 Mon Sep 17 00:00:00 2001
+From: "Owen W. Taylor" <otaylor@fishsoup.net>
+Date: Tue, 21 Feb 2017 13:51:16 -0500
+Subject: [PATCH 7/7] Call cogl_xlib_renderer_set_threaded_swap_wait_enabled()
+
+Set up things so that if the INTEL_swap_event extension is not present,
+but the driver is known to have good thread support, we use an extra
+thread and call glXWaitVideoSync() in the thread. This allows idles
+to work properly, even when Mutter is constantly redrawing new frames;
+otherwise, without INTEL_swap_event, we'll just block in glXSwapBuffers().
+
+https://bugzilla.gnome.org/show_bug.cgi?id=779039
+---
+ src/backends/x11/meta-backend-x11.c  | 6 ++++++
+ src/backends/x11/meta-renderer-x11.c | 8 ++++++++
+ 2 files changed, 14 insertions(+)
+
+diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
+index a0b196efe..413b0622a 100644
+--- a/src/backends/x11/meta-backend-x11.c
++++ b/src/backends/x11/meta-backend-x11.c
+@@ -913,6 +913,12 @@ meta_backend_x11_init (MetaBackendX11 *x11)
+ {
+   MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
+ 
++  /* XInitThreads() is needed to use the "threaded swap wait" functionality
++   * in Cogl - see meta_renderer_x11_create_cogl_renderer(). We call it here
++   * to hopefully call it before any other use of XLib.
++   */
++  XInitThreads();
++
+   clutter_x11_request_reset_on_video_memory_purge ();
+ 
+   /* We do X11 event retrieval ourselves */
+diff --git a/src/backends/x11/meta-renderer-x11.c b/src/backends/x11/meta-renderer-x11.c
+index c0405bedc..9a86f493a 100644
+--- a/src/backends/x11/meta-renderer-x11.c
++++ b/src/backends/x11/meta-renderer-x11.c
+@@ -65,6 +65,14 @@ meta_renderer_x11_create_cogl_renderer (MetaRenderer *renderer)
+   cogl_renderer_set_custom_winsys (cogl_renderer, get_x11_cogl_winsys_vtable);
+   cogl_xlib_renderer_set_foreign_display (cogl_renderer, xdisplay);
+ 
++  /* Set up things so that if the INTEL_swap_event extension is not present,
++   * but the driver is known to have good thread support, we use an extra
++   * thread and call glXWaitVideoSync() in the thread. This allows idles
++   * to work properly, even when Mutter is constantly redrawing new frames;
++   * otherwise, without INTEL_swap_event, we'll just block in glXSwapBuffers().
++   */
++  cogl_xlib_renderer_set_threaded_swap_wait_enabled (cogl_renderer, TRUE);
++
+   return cogl_renderer;
+ }
+ 
+-- 
+2.12.0
+
diff --git a/SOURCES/add-support-for-plain-old-x-device-configuration.patch b/SOURCES/add-support-for-plain-old-x-device-configuration.patch
new file mode 100644
index 0000000..39ec339
--- /dev/null
+++ b/SOURCES/add-support-for-plain-old-x-device-configuration.patch
@@ -0,0 +1,395 @@
+From e9cd700f11565fd1723828a5cf77f994c8494ddd Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Mon, 9 Oct 2017 18:37:11 +0200
+Subject: [PATCH 1/4] backends/x11: Fix a small memory leak
+
+Introduced in "backends/x11: Support synaptics configuration".
+---
+ src/backends/x11/meta-input-settings-x11.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c
+index 75ceb0c93..cfdd2ffef 100644
+--- a/src/backends/x11/meta-input-settings-x11.c
++++ b/src/backends/x11/meta-input-settings-x11.c
+@@ -181,6 +181,7 @@ change_synaptics_tap_left_handed (ClutterInputDevice *device,
+   buttons[0] = left_handed ? 3 : 1;
+   buttons[2] = left_handed ? 1 : 3;
+   XSetDeviceButtonMapping (xdisplay, xdevice, buttons, n_buttons);
++  g_free (buttons);
+ 
+   if (display && meta_error_trap_pop_with_return (display))
+     {
+-- 
+2.13.5
+
+From 1df0d3b1a0d85c3a565ce6dde4faedf7c1f57930 Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Mon, 9 Oct 2017 18:39:52 +0200
+Subject: [PATCH 2/4] backends/x11: Add a synaptics check for two finger scroll
+ availability
+
+Commit "backends/x11: Support synaptics configuration" added support
+for synaptics two finger scrolling but didn't add the code to check
+that it is available resulting in the upper layer always assuming it
+isn't.
+---
+ src/backends/x11/meta-input-settings-x11.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c
+index cfdd2ffef..8aa8a497b 100644
+--- a/src/backends/x11/meta-input-settings-x11.c
++++ b/src/backends/x11/meta-input-settings-x11.c
+@@ -546,6 +546,17 @@ meta_input_settings_x11_has_two_finger_scroll (MetaInputSettings  *settings,
+   guchar *available = NULL;
+   gboolean has_two_finger = TRUE;
+ 
++  if (is_device_synaptics (device))
++    {
++      available = get_property (device, "Synaptics Capabilities",
++                                XA_INTEGER, 8, 4);
++      if (!available || !available[3])
++          has_two_finger = FALSE;
++
++      meta_XFree (available);
++      return has_two_finger;
++    }
++
+   available = get_property (device, "libinput Scroll Methods Available",
+                             XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
+   if (!available || !available[SCROLL_METHOD_FIELD_2FG])
+-- 
+2.13.5
+
+From 05b6600752ee85e0c48d4055b3ca1c2d010d2851 Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Mon, 9 Oct 2017 18:55:56 +0200
+Subject: [PATCH 3/4] backends/x11: Add disable while typing support for
+ synaptics
+
+This is basically a copy of the old g-s-d mouse plugin code to manage
+syndaemon when the synaptics driver is being used.
+---
+ src/backends/x11/meta-input-settings-x11.c | 107 +++++++++++++++++++++++++++++
+ 1 file changed, 107 insertions(+)
+
+diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c
+index 8aa8a497b..d38e1b454 100644
+--- a/src/backends/x11/meta-input-settings-x11.c
++++ b/src/backends/x11/meta-input-settings-x11.c
+@@ -35,6 +35,9 @@
+ #ifdef HAVE_LIBGUDEV
+ #include <gudev/gudev.h>
+ #endif
++#ifdef __linux
++#include <sys/prctl.h>
++#endif
+ 
+ #include <meta/errors.h>
+ 
+@@ -43,6 +46,8 @@ typedef struct _MetaInputSettingsX11Private
+ #ifdef HAVE_LIBGUDEV
+   GUdevClient *udev_client;
+ #endif
++  gboolean syndaemon_spawned;
++  GPid syndaemon_pid;
+ } MetaInputSettingsX11Private;
+ 
+ G_DEFINE_TYPE_WITH_PRIVATE (MetaInputSettingsX11, meta_input_settings_x11,
+@@ -291,6 +296,107 @@ change_synaptics_speed (ClutterInputDevice *device,
+   XCloseDevice (xdisplay, xdevice);
+ }
+ 
++/* Ensure that syndaemon dies together with us, to avoid running several of
++ * them */
++static void
++setup_syndaemon (gpointer user_data)
++{
++#ifdef __linux
++  prctl (PR_SET_PDEATHSIG, SIGHUP);
++#endif
++}
++
++static gboolean
++have_program_in_path (const char *name)
++{
++  gchar *path;
++  gboolean result;
++
++  path = g_find_program_in_path (name);
++  result = (path != NULL);
++  g_free (path);
++  return result;
++}
++
++static void
++syndaemon_died (GPid     pid,
++                gint     status,
++                gpointer user_data)
++{
++  MetaInputSettingsX11 *settings_x11 = META_INPUT_SETTINGS_X11 (user_data);
++  MetaInputSettingsX11Private *priv =
++    meta_input_settings_x11_get_instance_private (settings_x11);
++  GError *error = NULL;
++
++  if (!g_spawn_check_exit_status (status, &error))
++    {
++      if ((WIFSIGNALED (status) && WTERMSIG (status) != SIGHUP) ||
++          error->domain == G_SPAWN_EXIT_ERROR)
++        g_warning ("Syndaemon exited unexpectedly: %s", error->message);
++      g_error_free (error);
++    }
++
++  g_spawn_close_pid (pid);
++  priv->syndaemon_spawned = FALSE;
++}
++
++static void
++set_synaptics_disable_w_typing (MetaInputSettings *settings,
++                                gboolean           state)
++{
++  MetaInputSettingsX11 *settings_x11 = META_INPUT_SETTINGS_X11 (settings);
++  MetaInputSettingsX11Private *priv =
++    meta_input_settings_x11_get_instance_private (settings_x11);
++
++  if (state)
++    {
++      GError *error = NULL;
++      GPtrArray *args;
++
++      if (priv->syndaemon_spawned)
++        return;
++
++      if (!have_program_in_path ("syndaemon"))
++        return;
++
++      args = g_ptr_array_new ();
++
++      g_ptr_array_add (args, "syndaemon");
++      g_ptr_array_add (args, "-i");
++      g_ptr_array_add (args, "1.0");
++      g_ptr_array_add (args, "-t");
++      g_ptr_array_add (args, "-K");
++      g_ptr_array_add (args, "-R");
++      g_ptr_array_add (args, NULL);
++
++      /* we must use G_SPAWN_DO_NOT_REAP_CHILD to avoid
++       * double-forking, otherwise syndaemon will immediately get
++       * killed again through (PR_SET_PDEATHSIG when the intermediate
++       * process dies */
++      g_spawn_async (g_get_home_dir (), (char **) args->pdata, NULL,
++                     G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, setup_syndaemon, NULL,
++                     &priv->syndaemon_pid, &error);
++
++      priv->syndaemon_spawned = (error == NULL);
++      g_ptr_array_free (args, TRUE);
++
++      if (error)
++        {
++          g_warning ("Failed to launch syndaemon: %s", error->message);
++          g_error_free (error);
++        }
++      else
++        {
++          g_child_watch_add (priv->syndaemon_pid, syndaemon_died, settings);
++        }
++    }
++  else if (priv->syndaemon_spawned)
++    {
++      kill (priv->syndaemon_pid, SIGHUP);
++      priv->syndaemon_spawned = FALSE;
++    }
++}
++
+ static void
+ meta_input_settings_x11_set_send_events (MetaInputSettings        *settings,
+                                          ClutterInputDevice       *device,
+@@ -303,6 +409,7 @@ meta_input_settings_x11_set_send_events (MetaInputSettings        *settings,
+     {
+       values[0] = mode != G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED;
+       change_property (device, "Synaptics Off", XA_INTEGER, 8, &values, 1);
++      set_synaptics_disable_w_typing (settings, mode == G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED);
+       return;
+     }
+ 
+-- 
+2.13.5
+
+From 94aa02bfe8364c9be9ca0251f66e8f91c38d1bdd Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Tue, 10 Oct 2017 19:07:27 +0200
+Subject: [PATCH 4/4] backends/x11: Support plain old X device configuration
+
+We re-use part of the code added to support synaptics and add a few
+bits specific for xorg-x11-drv-evdev devices.
+---
+ src/backends/x11/meta-input-settings-x11.c | 97 +++++++++++++++++++++++-------
+ 1 file changed, 74 insertions(+), 23 deletions(-)
+
+diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c
+index d38e1b454..63a8fe79e 100644
+--- a/src/backends/x11/meta-input-settings-x11.c
++++ b/src/backends/x11/meta-input-settings-x11.c
+@@ -138,35 +138,35 @@ is_device_synaptics (ClutterInputDevice *device)
+   return TRUE;
+ }
+ 
++static gboolean
++is_device_libinput (ClutterInputDevice *device)
++{
++  guchar *has_setting;
++
++  /* We just need looking for a synaptics-specific property */
++  has_setting = get_property (device, "libinput Send Events Modes Available", XA_INTEGER, 8, 2);
++  if (!has_setting)
++    return FALSE;
++
++  meta_XFree (has_setting);
++  return TRUE;
++}
++
+ static void
+-change_synaptics_tap_left_handed (ClutterInputDevice *device,
+-                                  gboolean            tap_enabled,
+-                                  gboolean            left_handed)
++change_x_device_left_handed (ClutterInputDevice *device,
++                             gboolean            left_handed)
+ {
+   MetaDisplay *display = meta_get_display ();
+   MetaBackend *backend = meta_get_backend ();
+   Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
+   XDevice *xdevice;
+-  guchar *tap_action, *buttons;
++  guchar *buttons;
+   guint buttons_capacity = 16, n_buttons;
+ 
+   xdevice = XOpenDevice(xdisplay, clutter_input_device_get_device_id (device));
+   if (!xdevice)
+     return;
+ 
+-  tap_action = get_property (device, "Synaptics Tap Action",
+-                             XA_INTEGER, 8, 7);
+-  if (!tap_action)
+-    goto out;
+-
+-  tap_action[4] = tap_enabled ? (left_handed ? 3 : 1) : 0;
+-  tap_action[5] = tap_enabled ? (left_handed ? 1 : 3) : 0;
+-  tap_action[6] = tap_enabled ? 2 : 0;
+-
+-  change_property (device, "Synaptics Tap Action",
+-                   XA_INTEGER, 8, tap_action, 7);
+-  meta_XFree (tap_action);
+-
+   if (display)
+     meta_error_trap_push (display);
+   buttons = g_new (guchar, buttons_capacity);
+@@ -190,17 +190,39 @@ change_synaptics_tap_left_handed (ClutterInputDevice *device,
+ 
+   if (display && meta_error_trap_pop_with_return (display))
+     {
+-      g_warning ("Could not set synaptics touchpad left-handed for %s",
++      g_warning ("Could not set left-handed for %s",
+                  clutter_input_device_get_device_name (device));
+     }
+ 
+- out:
+   XCloseDevice (xdisplay, xdevice);
+ }
+ 
+ static void
+-change_synaptics_speed (ClutterInputDevice *device,
+-                        gdouble             speed)
++change_synaptics_tap_left_handed (ClutterInputDevice *device,
++                                  gboolean            tap_enabled,
++                                  gboolean            left_handed)
++{
++  guchar *tap_action;
++
++  tap_action = get_property (device, "Synaptics Tap Action",
++                             XA_INTEGER, 8, 7);
++  if (!tap_action)
++    return;
++
++  tap_action[4] = tap_enabled ? (left_handed ? 3 : 1) : 0;
++  tap_action[5] = tap_enabled ? (left_handed ? 1 : 3) : 0;
++  tap_action[6] = tap_enabled ? 2 : 0;
++
++  change_property (device, "Synaptics Tap Action",
++                   XA_INTEGER, 8, tap_action, 7);
++  meta_XFree (tap_action);
++
++  change_x_device_left_handed (device, left_handed);
++}
++
++static void
++change_x_device_speed (ClutterInputDevice *device,
++                       gdouble             speed)
+ {
+   MetaDisplay *display = meta_get_display ();
+   MetaBackend *backend = meta_get_backend ();
+@@ -296,6 +318,23 @@ change_synaptics_speed (ClutterInputDevice *device,
+   XCloseDevice (xdisplay, xdevice);
+ }
+ 
++static void
++change_x_device_scroll_button (ClutterInputDevice *device,
++                               guint               button)
++{
++  guchar value;
++
++  value = button > 0 ? 1 : 0;
++  change_property (device, "Evdev Wheel Emulation",
++                   XA_INTEGER, 8, &value, 1);
++  if (button > 0)
++    {
++      value = button;
++      change_property (device, "Evdev Wheel Emulation Button",
++                       XA_INTEGER, 8, &value, 1);
++    }
++}
++
+ /* Ensure that syndaemon dies together with us, to avoid running several of
+  * them */
+ static void
+@@ -465,9 +504,10 @@ meta_input_settings_x11_set_speed (MetaInputSettings  *settings,
+   Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
+   gfloat value = speed;
+ 
+-  if (is_device_synaptics (device))
++  if (is_device_synaptics (device) ||
++      !is_device_libinput (device))
+     {
+-      change_synaptics_speed (device, speed);
++      change_x_device_speed (device, speed);
+       return;
+     }
+ 
+@@ -494,6 +534,11 @@ meta_input_settings_x11_set_left_handed (MetaInputSettings  *settings,
+       g_object_unref (settings);
+       return;
+     }
++  else if (!is_device_libinput (device))
++    {
++      change_x_device_left_handed (device, enabled);
++      return;
++    }
+ 
+   change_property (device, "libinput Left Handed Enabled",
+                    XA_INTEGER, 8, &value, 1);
+@@ -678,6 +723,12 @@ meta_input_settings_x11_set_scroll_button (MetaInputSettings  *settings,
+                                            ClutterInputDevice *device,
+                                            guint               button)
+ {
++  if (!is_device_libinput (device))
++    {
++      change_x_device_scroll_button (device, button);
++      return;
++    }
++
+   change_property (device, "libinput Button Scrolling Button",
+                    XA_INTEGER, 32, &button, 1);
+ }
+-- 
+2.13.5
+
diff --git a/SOURCES/deal-more-gracefully-with-oversized-windows.patch b/SOURCES/deal-more-gracefully-with-oversized-windows.patch
new file mode 100644
index 0000000..b91bd6f
--- /dev/null
+++ b/SOURCES/deal-more-gracefully-with-oversized-windows.patch
@@ -0,0 +1,85 @@
+From 196f9e68c5c95989225870a8554eac7f61e974f2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Wed, 12 Mar 2014 02:04:13 +0100
+Subject: [PATCH] constraints: Enforce X11 size limits
+
+X11 limits windows to a maximum of 32767x32767, enforce that restriction
+to keep insanely huge windows from crashing the WM.
+---
+ src/core/constraints.c | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+diff --git a/src/core/constraints.c b/src/core/constraints.c
+index e7dcacd84..67b52c994 100644
+--- a/src/core/constraints.c
++++ b/src/core/constraints.c
+@@ -103,6 +103,7 @@ typedef enum
+   PRIORITY_TITLEBAR_VISIBLE = 4,
+   PRIORITY_PARTIALLY_VISIBLE_ON_WORKAREA = 4,
+   PRIORITY_CUSTOM_RULE = 4,
++  PRIORITY_XLIMITS = 4,
+   PRIORITY_MAXIMUM = 4 /* Dummy value used for loop end = max(all priorities) */
+ } ConstraintPriority;
+ 
+@@ -193,6 +194,10 @@ static gboolean constrain_partially_onscreen (MetaWindow         *window,
+                                               ConstraintInfo     *info,
+                                               ConstraintPriority  priority,
+                                               gboolean            check_only);
++static gboolean constrain_xlimits            (MetaWindow         *window,
++                                              ConstraintInfo     *info,
++                                              ConstraintPriority  priority,
++                                              gboolean            check_only);
+ 
+ static void setup_constraint_info        (ConstraintInfo      *info,
+                                           MetaWindow          *window,
+@@ -228,6 +233,7 @@ static const Constraint all_constraints[] = {
+   {constrain_fully_onscreen,     "constrain_fully_onscreen"},
+   {constrain_titlebar_visible,   "constrain_titlebar_visible"},
+   {constrain_partially_onscreen, "constrain_partially_onscreen"},
++  {constrain_xlimits,            "constrain_xlimits"},
+   {NULL,                         NULL}
+ };
+ 
+@@ -1659,3 +1665,39 @@ constrain_partially_onscreen (MetaWindow         *window,
+ 
+   return retval;
+ }
++
++
++#define MAX_WINDOW_SIZE 32767
++
++static gboolean
++constrain_xlimits (MetaWindow         *window,
++                   ConstraintInfo     *info,
++                   ConstraintPriority  priority,
++                   gboolean            check_only)
++{
++  int max_w, max_h;
++  gboolean constraint_already_satisfied;
++
++  if (priority > PRIORITY_XLIMITS)
++    return TRUE;
++
++  max_w = max_h = MAX_WINDOW_SIZE;
++
++  if (window->frame)
++    {
++      MetaFrameBorders borders;
++      meta_frame_calc_borders (window->frame, &borders);
++
++      max_w -= (borders.total.left + borders.total.right);
++      max_h -= (borders.total.top + borders.total.bottom);
++    }
++
++  constraint_already_satisfied = info->current.width < max_w && info->current.height < max_h;
++  if (check_only || constraint_already_satisfied)
++    return constraint_already_satisfied;
++
++  info->current.width = MIN (info->current.width, max_w);
++  info->current.height = MIN (info->current.height, max_h);
++
++  return TRUE;
++}
+-- 
+2.12.0
+
diff --git a/SOURCES/fall-back-to-xorg-on-hybrid-gpus.patch b/SOURCES/fall-back-to-xorg-on-hybrid-gpus.patch
new file mode 100644
index 0000000..0e26bc3
--- /dev/null
+++ b/SOURCES/fall-back-to-xorg-on-hybrid-gpus.patch
@@ -0,0 +1,596 @@
+From 5bea406b353f39867eb86307b1c8b4093f22968e Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode@redhat.com>
+Date: Tue, 18 Oct 2016 16:40:14 -0400
+Subject: [PATCH 1/4] native: only match drm subsystem devices
+
+Despite g_udev_client_new taking a list of subsystems, it doesn't
+implicitly filter results to those subsystems.
+
+This commit explicitly adds a subsystem match to make sure sound cards
+don't end up in the resulting list of video cards.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=771442
+---
+ src/backends/native/meta-launcher.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c
+index ea28e5a..03a928a 100644
+--- a/src/backends/native/meta-launcher.c
++++ b/src/backends/native/meta-launcher.c
+@@ -268,60 +268,65 @@ sync_active (MetaLauncher *self)
+   self->session_active = active;
+ 
+   if (active)
+     session_unpause ();
+   else
+     session_pause ();
+ }
+ 
+ static void
+ on_active_changed (Login1Session *session,
+                    GParamSpec    *pspec,
+                    gpointer       user_data)
+ {
+   MetaLauncher *self = user_data;
+   sync_active (self);
+ }
+ 
+ static gchar *
+ get_primary_gpu_path (const gchar *seat_name)
+ {
+   const gchar *subsystems[] = {"drm", NULL};
+   gchar *path = NULL;
+   GList *devices, *tmp;
+ 
+   g_autoptr (GUdevClient) gudev_client = g_udev_client_new (subsystems);
+   g_autoptr (GUdevEnumerator) enumerator = g_udev_enumerator_new (gudev_client);
+ 
+   g_udev_enumerator_add_match_name (enumerator, "card*");
+   g_udev_enumerator_add_match_tag (enumerator, "seat");
+ 
++  /* We need to explicitly match the subsystem for now.
++   * https://bugzilla.gnome.org/show_bug.cgi?id=773224
++   */
++  g_udev_enumerator_add_match_subsystem (enumerator, "drm");
++
+   devices = g_udev_enumerator_execute (enumerator);
+   if (!devices)
+     goto out;
+ 
+   for (tmp = devices; tmp != NULL; tmp = tmp->next)
+     {
+       g_autoptr (GUdevDevice) platform_device = NULL;
+       g_autoptr (GUdevDevice) pci_device = NULL;
+       GUdevDevice *dev = tmp->data;
+       gint boot_vga;
+       const gchar *device_seat;
+ 
+       /* filter out devices that are not character device, like card0-VGA-1 */
+       if (g_udev_device_get_device_type (dev) != G_UDEV_DEVICE_TYPE_CHAR)
+         continue;
+ 
+       device_seat = g_udev_device_get_property (dev, "ID_SEAT");
+       if (!device_seat)
+         {
+           /* when ID_SEAT is not set, it means seat0 */
+           device_seat = "seat0";
+         }
+       else if (g_strcmp0 (device_seat, "seat0") != 0)
+         {
+           /* if the device has been explicitly assigned other seat
+            * than seat0, it is probably the right device to use */
+           path = g_strdup (g_udev_device_get_device_file (dev));
+           break;
+         }
+ 
+-- 
+2.10.1
+
+
+From d9dc6ac094080a4190508297e8244a8905a8dcb4 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode@redhat.com>
+Date: Wed, 19 Oct 2016 10:41:14 -0400
+Subject: [PATCH 2/4] native: shore up matching of card device
+
+Right now we accept any character device that matches the glob card*.
+
+That's fine, but we can be a little more specific by checking that
+the devtype is what we expect.
+
+This commit does that.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=771442
+---
+ src/backends/native/meta-launcher.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c
+index 03a928a..765e5ef 100644
+--- a/src/backends/native/meta-launcher.c
++++ b/src/backends/native/meta-launcher.c
+@@ -20,60 +20,62 @@
+ #include "config.h"
+ 
+ #include "meta-launcher.h"
+ 
+ #include <gio/gunixfdlist.h>
+ 
+ #include <clutter/clutter.h>
+ #include <clutter/egl/clutter-egl.h>
+ #include <clutter/evdev/clutter-evdev.h>
+ 
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <malloc.h>
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ 
+ #include <systemd/sd-login.h>
+ #include <gudev/gudev.h>
+ 
+ #include "dbus-utils.h"
+ #include "meta-dbus-login1.h"
+ 
+ #include "backends/meta-backend-private.h"
+ #include "meta-cursor-renderer-native.h"
+ #include "meta-idle-monitor-native.h"
+ #include "meta-renderer-native.h"
+ 
++#define DRM_CARD_UDEV_DEVICE_TYPE "drm_minor"
++
+ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref)
+ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevClient, g_object_unref)
+ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevEnumerator, g_object_unref)
+ 
+ struct _MetaLauncher
+ {
+   Login1Session *session_proxy;
+   Login1Seat *seat_proxy;
+ 
+   gboolean session_active;
+ 
+   int kms_fd;
+ };
+ 
+ static Login1Session *
+ get_session_proxy (GCancellable *cancellable,
+                    GError      **error)
+ {
+   g_autofree char *proxy_path = NULL;
+   g_autofree char *session_id = NULL;
+   Login1Session *session_proxy;
+ 
+   if (sd_pid_get_session (getpid (), &session_id) < 0)
+     {
+       g_set_error (error,
+                    G_IO_ERROR,
+                    G_IO_ERROR_NOT_FOUND,
+                    "Could not get session ID: %m");
+       return NULL;
+     }
+@@ -283,66 +285,71 @@ on_active_changed (Login1Session *session,
+ }
+ 
+ static gchar *
+ get_primary_gpu_path (const gchar *seat_name)
+ {
+   const gchar *subsystems[] = {"drm", NULL};
+   gchar *path = NULL;
+   GList *devices, *tmp;
+ 
+   g_autoptr (GUdevClient) gudev_client = g_udev_client_new (subsystems);
+   g_autoptr (GUdevEnumerator) enumerator = g_udev_enumerator_new (gudev_client);
+ 
+   g_udev_enumerator_add_match_name (enumerator, "card*");
+   g_udev_enumerator_add_match_tag (enumerator, "seat");
+ 
+   /* We need to explicitly match the subsystem for now.
+    * https://bugzilla.gnome.org/show_bug.cgi?id=773224
+    */
+   g_udev_enumerator_add_match_subsystem (enumerator, "drm");
+ 
+   devices = g_udev_enumerator_execute (enumerator);
+   if (!devices)
+     goto out;
+ 
+   for (tmp = devices; tmp != NULL; tmp = tmp->next)
+     {
+       g_autoptr (GUdevDevice) platform_device = NULL;
+       g_autoptr (GUdevDevice) pci_device = NULL;
+       GUdevDevice *dev = tmp->data;
+       gint boot_vga;
++      const gchar *device_type;
+       const gchar *device_seat;
+ 
+       /* filter out devices that are not character device, like card0-VGA-1 */
+       if (g_udev_device_get_device_type (dev) != G_UDEV_DEVICE_TYPE_CHAR)
+         continue;
+ 
++      device_type = g_udev_device_get_property (dev, "DEVTYPE");
++      if (g_strcmp0 (device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0)
++        continue;
++
+       device_seat = g_udev_device_get_property (dev, "ID_SEAT");
+       if (!device_seat)
+         {
+           /* when ID_SEAT is not set, it means seat0 */
+           device_seat = "seat0";
+         }
+       else if (g_strcmp0 (device_seat, "seat0") != 0)
+         {
+           /* if the device has been explicitly assigned other seat
+            * than seat0, it is probably the right device to use */
+           path = g_strdup (g_udev_device_get_device_file (dev));
+           break;
+         }
+ 
+       /* skip devices that do not belong to our seat */
+       if (g_strcmp0 (seat_name, device_seat))
+         continue;
+ 
+       platform_device = g_udev_device_get_parent_with_subsystem (dev, "platform", NULL);
+       if (platform_device != NULL)
+         {
+           path = g_strdup (g_udev_device_get_device_file (dev));
+           break;
+         }
+ 
+       pci_device = g_udev_device_get_parent_with_subsystem (dev, "pci", NULL);
+       if (pci_device != NULL)
+         {
+           /* get value of boot_vga attribute or 0 if the device has no boot_vga */
+           boot_vga = g_udev_device_get_sysfs_attr_as_int (pci_device, "boot_vga");
+-- 
+2.10.1
+
+
+From 54ceafff8c8b0b02cd9124eae56a05da4f117033 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode@redhat.com>
+Date: Tue, 18 Oct 2016 16:43:04 -0400
+Subject: [PATCH 3/4] native: fail on systems with connectors spread across
+ multiple gpus
+
+We don't support using more than one GPU for output yet, so we should fail
+if we encounter that situation, so GDM will fall back to X.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=771442
+---
+ src/backends/native/meta-launcher.c | 63 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 62 insertions(+), 1 deletion(-)
+
+diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c
+index 765e5ef..a2885a1 100644
+--- a/src/backends/native/meta-launcher.c
++++ b/src/backends/native/meta-launcher.c
+@@ -257,141 +257,202 @@ on_evdev_device_close (int      fd,
+ 
+ out:
+   close (fd);
+ }
+ 
+ static void
+ sync_active (MetaLauncher *self)
+ {
+   gboolean active = login1_session_get_active (LOGIN1_SESSION (self->session_proxy));
+ 
+   if (active == self->session_active)
+     return;
+ 
+   self->session_active = active;
+ 
+   if (active)
+     session_unpause ();
+   else
+     session_pause ();
+ }
+ 
+ static void
+ on_active_changed (Login1Session *session,
+                    GParamSpec    *pspec,
+                    gpointer       user_data)
+ {
+   MetaLauncher *self = user_data;
+   sync_active (self);
+ }
+ 
++static guint
++count_devices_with_connectors (const gchar *seat_name,
++                               GList       *devices)
++{
++  g_autoptr (GHashTable) cards = NULL;
++  GList *tmp;
++
++  cards = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
++  for (tmp = devices; tmp != NULL; tmp = tmp->next)
++    {
++      GUdevDevice *device = tmp->data;
++      g_autoptr (GUdevDevice) parent_device = NULL;
++      const gchar *parent_device_type = NULL;
++      const gchar *card_seat;
++
++      /* filter out the real card devices, we only care about the connectors */
++      if (g_udev_device_get_device_type (device) != G_UDEV_DEVICE_TYPE_NONE)
++        continue;
++
++      /* only connectors have a modes attribute */
++      if (!g_udev_device_has_sysfs_attr (device, "modes"))
++        continue;
++
++      parent_device = g_udev_device_get_parent (device);
++
++      if (g_udev_device_get_device_type (parent_device) == G_UDEV_DEVICE_TYPE_CHAR)
++        parent_device_type = g_udev_device_get_property (parent_device, "DEVTYPE");
++
++      if (g_strcmp0 (parent_device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0)
++        continue;
++
++      card_seat = g_udev_device_get_property (parent_device, "ID_SEAT");
++
++      if (!card_seat)
++        card_seat = "seat0";
++
++      if (g_strcmp0 (seat_name, card_seat) != 0)
++        continue;
++
++      g_hash_table_insert (cards,
++                           (gpointer) g_udev_device_get_name (parent_device),
++                           g_steal_pointer (&parent_device));
++    }
++
++  return g_hash_table_size (cards);
++}
++
+ static gchar *
+ get_primary_gpu_path (const gchar *seat_name)
+ {
+   const gchar *subsystems[] = {"drm", NULL};
+   gchar *path = NULL;
+   GList *devices, *tmp;
+ 
+   g_autoptr (GUdevClient) gudev_client = g_udev_client_new (subsystems);
+   g_autoptr (GUdevEnumerator) enumerator = g_udev_enumerator_new (gudev_client);
+ 
+   g_udev_enumerator_add_match_name (enumerator, "card*");
+   g_udev_enumerator_add_match_tag (enumerator, "seat");
+ 
+   /* We need to explicitly match the subsystem for now.
+    * https://bugzilla.gnome.org/show_bug.cgi?id=773224
+    */
+   g_udev_enumerator_add_match_subsystem (enumerator, "drm");
+ 
+   devices = g_udev_enumerator_execute (enumerator);
+   if (!devices)
+     goto out;
+ 
++  /* For now, fail on systems where some of the connectors
++   * are connected to secondary gpus.
++   *
++   * https://bugzilla.gnome.org/show_bug.cgi?id=771442
++   */
++  if (g_getenv ("MUTTER_ALLOW_HYBRID_GPUS") == NULL)
++    {
++      guint num_devices;
++
++      num_devices = count_devices_with_connectors (seat_name, devices);
++      if (num_devices != 1)
++        goto out;
++    }
++
+   for (tmp = devices; tmp != NULL; tmp = tmp->next)
+     {
+       g_autoptr (GUdevDevice) platform_device = NULL;
+       g_autoptr (GUdevDevice) pci_device = NULL;
+       GUdevDevice *dev = tmp->data;
+       gint boot_vga;
+       const gchar *device_type;
+       const gchar *device_seat;
+ 
+       /* filter out devices that are not character device, like card0-VGA-1 */
+       if (g_udev_device_get_device_type (dev) != G_UDEV_DEVICE_TYPE_CHAR)
+         continue;
+ 
+       device_type = g_udev_device_get_property (dev, "DEVTYPE");
+       if (g_strcmp0 (device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0)
+         continue;
+ 
+       device_seat = g_udev_device_get_property (dev, "ID_SEAT");
+       if (!device_seat)
+         {
+           /* when ID_SEAT is not set, it means seat0 */
+           device_seat = "seat0";
+         }
+       else if (g_strcmp0 (device_seat, "seat0") != 0)
+         {
+           /* if the device has been explicitly assigned other seat
+            * than seat0, it is probably the right device to use */
+           path = g_strdup (g_udev_device_get_device_file (dev));
+           break;
+         }
+ 
+       /* skip devices that do not belong to our seat */
+       if (g_strcmp0 (seat_name, device_seat))
+         continue;
+ 
+       platform_device = g_udev_device_get_parent_with_subsystem (dev, "platform", NULL);
+       if (platform_device != NULL)
+         {
+           path = g_strdup (g_udev_device_get_device_file (dev));
+           break;
+         }
+ 
+       pci_device = g_udev_device_get_parent_with_subsystem (dev, "pci", NULL);
+       if (pci_device != NULL)
+         {
+           /* get value of boot_vga attribute or 0 if the device has no boot_vga */
+           boot_vga = g_udev_device_get_sysfs_attr_as_int (pci_device, "boot_vga");
+           if (boot_vga == 1)
+             {
+               /* found the boot_vga device */
+               path = g_strdup (g_udev_device_get_device_file (dev));
+               break;
+             }
+         }
+     }
+ 
++out:
+   g_list_free_full (devices, g_object_unref);
+ 
+-out:
+   return path;
+ }
+ 
+ static gboolean
+ get_kms_fd (Login1Session *session_proxy,
+             const gchar   *seat_id,
+             int           *fd_out,
+             GError       **error)
+ {
+   int major, minor;
+   int fd;
+ 
+   g_autofree gchar *path = get_primary_gpu_path (seat_id);
+   if (!path)
+     {
+       g_set_error (error,
+                    G_IO_ERROR,
+                    G_IO_ERROR_NOT_FOUND,
+                    "could not find drm kms device");
+       return FALSE;
+     }
+ 
+   if (!get_device_info_from_path (path, &major, &minor))
+     {
+       g_set_error (error,
+                    G_IO_ERROR,
+                    G_IO_ERROR_NOT_FOUND,
+                    "Could not get device info for path %s: %m", path);
+       return FALSE;
+     }
+-- 
+2.10.1
+
+
+From 0d87baa029329c409646e04bcf40bea5da67b5f7 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode@redhat.com>
+Date: Wed, 19 Oct 2016 14:27:24 -0400
+Subject: [PATCH 4/4] native: don't call steal_pointer prematurely
+
+commit e2bfaf07514ed633f8721b5f521577685b6cccc0 does this:
+
+g_hash_table_insert (cards,
+                     g_udev_device_get_name (parent_device),
+                     g_steal_pointer (&parent_device));
+
+The problem is the g_steal_pointer call may happen before the
+g_udev_device_get_name call leading to a crash.
+
+This commit does the get_name call on an earlier line
+
+https://bugzilla.gnome.org/show_bug.cgi?id=771442
+---
+ src/backends/native/meta-launcher.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c
+index a2885a1..ddb7080 100644
+--- a/src/backends/native/meta-launcher.c
++++ b/src/backends/native/meta-launcher.c
+@@ -270,88 +270,90 @@ sync_active (MetaLauncher *self)
+   self->session_active = active;
+ 
+   if (active)
+     session_unpause ();
+   else
+     session_pause ();
+ }
+ 
+ static void
+ on_active_changed (Login1Session *session,
+                    GParamSpec    *pspec,
+                    gpointer       user_data)
+ {
+   MetaLauncher *self = user_data;
+   sync_active (self);
+ }
+ 
+ static guint
+ count_devices_with_connectors (const gchar *seat_name,
+                                GList       *devices)
+ {
+   g_autoptr (GHashTable) cards = NULL;
+   GList *tmp;
+ 
+   cards = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
+   for (tmp = devices; tmp != NULL; tmp = tmp->next)
+     {
+       GUdevDevice *device = tmp->data;
+       g_autoptr (GUdevDevice) parent_device = NULL;
+       const gchar *parent_device_type = NULL;
++      const gchar *parent_device_name = NULL;
+       const gchar *card_seat;
+ 
+       /* filter out the real card devices, we only care about the connectors */
+       if (g_udev_device_get_device_type (device) != G_UDEV_DEVICE_TYPE_NONE)
+         continue;
+ 
+       /* only connectors have a modes attribute */
+       if (!g_udev_device_has_sysfs_attr (device, "modes"))
+         continue;
+ 
+       parent_device = g_udev_device_get_parent (device);
+ 
+       if (g_udev_device_get_device_type (parent_device) == G_UDEV_DEVICE_TYPE_CHAR)
+         parent_device_type = g_udev_device_get_property (parent_device, "DEVTYPE");
+ 
+       if (g_strcmp0 (parent_device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0)
+         continue;
+ 
+       card_seat = g_udev_device_get_property (parent_device, "ID_SEAT");
+ 
+       if (!card_seat)
+         card_seat = "seat0";
+ 
+       if (g_strcmp0 (seat_name, card_seat) != 0)
+         continue;
+ 
++      parent_device_name = g_udev_device_get_name (parent_device);
+       g_hash_table_insert (cards,
+-                           (gpointer) g_udev_device_get_name (parent_device),
++                           (gpointer) parent_device_name ,
+                            g_steal_pointer (&parent_device));
+     }
+ 
+   return g_hash_table_size (cards);
+ }
+ 
+ static gchar *
+ get_primary_gpu_path (const gchar *seat_name)
+ {
+   const gchar *subsystems[] = {"drm", NULL};
+   gchar *path = NULL;
+   GList *devices, *tmp;
+ 
+   g_autoptr (GUdevClient) gudev_client = g_udev_client_new (subsystems);
+   g_autoptr (GUdevEnumerator) enumerator = g_udev_enumerator_new (gudev_client);
+ 
+   g_udev_enumerator_add_match_name (enumerator, "card*");
+   g_udev_enumerator_add_match_tag (enumerator, "seat");
+ 
+   /* We need to explicitly match the subsystem for now.
+    * https://bugzilla.gnome.org/show_bug.cgi?id=773224
+    */
+   g_udev_enumerator_add_match_subsystem (enumerator, "drm");
+ 
+   devices = g_udev_enumerator_execute (enumerator);
+   if (!devices)
+     goto out;
+ 
+   /* For now, fail on systems where some of the connectors
+    * are connected to secondary gpus.
+-- 
+2.10.1
+
diff --git a/SOURCES/startup-notification.patch b/SOURCES/startup-notification.patch
new file mode 100644
index 0000000..1a4dd0b
--- /dev/null
+++ b/SOURCES/startup-notification.patch
@@ -0,0 +1,45 @@
+From 4ed430b4ef3013c96fa56cdc57b925b42d20ead9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Thu, 20 Oct 2016 18:00:04 +0200
+Subject: [PATCH] gtk-shell: Work around non-working startup notifications
+
+GNOME Shell relies on the MetaScreen::startup-sequence-changed signal,
+which is tied to (lib)startup-notification and therefore X11. As a result,
+when we remove the startup sequence of a wayland client, GNOME Shell will
+not be notified about this until startup-notification's timeout is hit.
+As a temporary stop-gap, go through XWayland even for wayland clients,
+so that the signal is emitted when expected.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=768531
+---
+ src/wayland/meta-wayland-gtk-shell.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/src/wayland/meta-wayland-gtk-shell.c b/src/wayland/meta-wayland-gtk-shell.c
+index d6e249f..9d1a19e 100644
+--- a/src/wayland/meta-wayland-gtk-shell.c
++++ b/src/wayland/meta-wayland-gtk-shell.c
+@@ -219,11 +219,21 @@ gtk_shell_set_startup_id (struct wl_client   *client,
+                           struct wl_resource *resource,
+                           const char         *startup_id)
+ {
++#if 0
+   MetaDisplay *display;
+ 
+   display = meta_get_display ();
+   meta_startup_notification_remove_sequence (display->startup_notification,
+                                              startup_id);
++#else
++  /* HACK: MetaScreen::startup-sequence-changed is currently tied to
++           (lib)startup-notification, which means it only works on X11;
++           so for now, always go through XWayland, even for wayland clients */
++  gdk_x11_display_broadcast_startup_message (gdk_display_get_default (),
++                                             "remove",
++                                             "ID", startup_id,
++                                             NULL);
++#endif
+ }
+ 
+ static void
+-- 
+2.9.3
diff --git a/SOURCES/support-headless-mode.patch b/SOURCES/support-headless-mode.patch
new file mode 100644
index 0000000..57245e4
--- /dev/null
+++ b/SOURCES/support-headless-mode.patch
@@ -0,0 +1,481 @@
+From 0826616da1dacf29e3e08dae6d2ffe4116e5bdff Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Thu, 16 Jul 2015 15:07:38 +0200
+Subject: [PATCH 1/2] barrier: Guard against X errors
+
+---
+ src/backends/x11/meta-barrier-x11.c | 22 +++++++++++++++-------
+ 1 file changed, 15 insertions(+), 7 deletions(-)
+
+diff --git a/src/backends/x11/meta-barrier-x11.c b/src/backends/x11/meta-barrier-x11.c
+index 054e5cdc6..1fc3fd8cc 100644
+--- a/src/backends/x11/meta-barrier-x11.c
++++ b/src/backends/x11/meta-barrier-x11.c
+@@ -38,6 +38,7 @@
+ #include <X11/extensions/XInput2.h>
+ #include <X11/extensions/Xfixes.h>
+ #include <meta/barrier.h>
++#include <meta/errors.h>
+ #include "backends/x11/meta-barrier-x11.h"
+ #include "display-private.h"
+ 
+@@ -107,6 +108,7 @@ meta_barrier_impl_x11_new (MetaBarrier *barrier)
+   MetaDisplay *display = barrier->priv->display;
+   Display *dpy;
+   Window root;
++  PointerBarrier xbarrier;
+   unsigned int allowed_motion_dirs;
+ 
+   if (display == NULL)
+@@ -119,18 +121,24 @@ meta_barrier_impl_x11_new (MetaBarrier *barrier)
+   priv = meta_barrier_impl_x11_get_instance_private (self);
+   priv->barrier = barrier;
+ 
++  meta_error_trap_push (display);
+   dpy = display->xdisplay;
+   root = DefaultRootWindow (dpy);
+ 
+   allowed_motion_dirs =
+     meta_border_get_allows_directions (&barrier->priv->border);
+-  priv->xbarrier = XFixesCreatePointerBarrier (dpy, root,
+-                                               barrier->priv->border.line.a.x,
+-                                               barrier->priv->border.line.a.y,
+-                                               barrier->priv->border.line.b.x,
+-                                               barrier->priv->border.line.b.y,
+-                                               allowed_motion_dirs,
+-                                               0, NULL);
++  xbarrier = XFixesCreatePointerBarrier (dpy, root,
++                                         barrier->priv->border.line.a.x,
++                                         barrier->priv->border.line.a.y,
++                                         barrier->priv->border.line.b.x,
++                                         barrier->priv->border.line.b.y,
++                                         allowed_motion_dirs,
++                                         0, NULL);
++
++  if (meta_error_trap_pop_with_return (display) != Success)
++    return NULL;
++
++  priv->xbarrier = xbarrier;
+ 
+   g_hash_table_insert (display->xids, &priv->xbarrier, barrier);
+ 
+-- 
+2.12.0
+
+
+From 2da829399dc79b5c51ca55ab6e633c4a4769c15a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Thu, 16 Jul 2015 15:12:55 +0200
+Subject: [PATCH 2/2] Do not crash when starting up with no monitor connected
+
+Some parts of Mutter currently assume there's always a monitor connected
+to the screen. This assumption can be incorrect - e.g. a desktop
+computer can be powered on and a monitor only plugged in after the
+desktop session - or the GDM login - has already been reached.
+
+Fix the various places that assume so, making the code robust to the
+above use case.
+
+Based on an initial patch by Cosimo Cecchi.
+---
+ src/backends/x11/meta-monitor-manager-xrandr.c |  4 +-
+ src/compositor/meta-window-actor.c             |  2 +-
+ src/core/constraints.c                         | 71 +++++++++++++++-----------
+ src/core/place.c                               |  4 ++
+ src/core/screen.c                              | 10 +++-
+ src/core/window.c                              | 57 ++++++++++++++-------
+ src/core/workspace.c                           |  3 ++
+ src/x11/window-x11.c                           |  3 +-
+ 8 files changed, 100 insertions(+), 54 deletions(-)
+
+diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
+index b0a77dadb..b82120af9 100644
+--- a/src/backends/x11/meta-monitor-manager-xrandr.c
++++ b/src/backends/x11/meta-monitor-manager-xrandr.c
+@@ -1141,7 +1141,9 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
+       crtc->current_mode = NULL;
+     }
+ 
+-  g_assert (width > 0 && height > 0);
++  if (width == 0 || height == 0)
++    return;
++
+   /* The 'physical size' of an X screen is meaningless if that screen
+    * can consist of many monitors. So just pick a size that make the
+    * dpi 96.
+diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
+index 9395caac5..fb29ca1c9 100644
+--- a/src/compositor/meta-window-actor.c
++++ b/src/compositor/meta-window-actor.c
+@@ -959,7 +959,7 @@ queue_send_frame_messages_timeout (MetaWindowActor *self)
+   outputs = meta_monitor_manager_get_outputs (monitor_manager, &n_outputs);
+   for (i = 0; i < n_outputs; i++)
+     {
+-      if (outputs[i].winsys_id == window->monitor->winsys_id && outputs[i].crtc)
++      if (window->monitor && outputs[i].winsys_id == window->monitor->winsys_id && outputs[i].crtc)
+         {
+           refresh_rate = outputs[i].crtc->current_mode->refresh_rate;
+           break;
+diff --git a/src/core/constraints.c b/src/core/constraints.c
+index 67b52c994..3d1701e88 100644
+--- a/src/core/constraints.c
++++ b/src/core/constraints.c
+@@ -29,6 +29,7 @@
+ #include <meta/prefs.h>
+ 
+ #include <stdlib.h>
++#include <string.h>
+ #include <math.h>
+ 
+ #if 0
+@@ -337,6 +338,8 @@ setup_constraint_info (ConstraintInfo      *info,
+   const MetaMonitorInfo *monitor_info;
+   MetaWorkspace *cur_workspace;
+ 
++  memset (info, 0, sizeof (ConstraintInfo));
++
+   info->orig    = *orig;
+   info->current = *new;
+ 
+@@ -382,40 +385,43 @@ setup_constraint_info (ConstraintInfo      *info,
+   if (!info->is_user_action)
+     info->fixed_directions = FIXED_DIRECTION_NONE;
+ 
++  cur_workspace = window->screen->active_workspace;
+   monitor_info =
+     meta_screen_get_monitor_for_rect (window->screen, &info->current);
+-  meta_window_get_work_area_for_monitor (window,
+-                                         monitor_info->number,
+-                                         &info->work_area_monitor);
+ 
+-  if (!window->fullscreen || window->fullscreen_monitors[0] == -1)
++  if (monitor_info)
+     {
+-      info->entire_monitor = monitor_info->rect;
+-    }
+-  else
+-    {
+-      int i = 0;
+-      long monitor;
++      meta_window_get_work_area_for_monitor (window,
++                                             monitor_info->number,
++                                             &info->work_area_monitor);
+ 
+-      monitor = window->fullscreen_monitors[i];
+-      info->entire_monitor =
+-        window->screen->monitor_infos[monitor].rect;
+-      for (i = 1; i <= 3; i++)
++      if (!window->fullscreen || window->fullscreen_monitors[0] == -1)
++        {
++          info->entire_monitor = monitor_info->rect;
++        }
++      else
+         {
++          int i = 0;
++          long monitor;
++
+           monitor = window->fullscreen_monitors[i];
+-          meta_rectangle_union (&info->entire_monitor,
+-                                &window->screen->monitor_infos[monitor].rect,
+-                                &info->entire_monitor);
++          info->entire_monitor =
++            window->screen->monitor_infos[monitor].rect;
++          for (i = 1; i <= 3; i++)
++            {
++              monitor = window->fullscreen_monitors[i];
++              meta_rectangle_union (&info->entire_monitor,
++                                    &window->screen->monitor_infos[monitor].rect,
++                                    &info->entire_monitor);
++            }
+         }
++      info->usable_screen_region  =
++        meta_workspace_get_onscreen_region (cur_workspace);
++      info->usable_monitor_region =
++        meta_workspace_get_onmonitor_region (cur_workspace,
++                                             monitor_info->number);
+     }
+ 
+-  cur_workspace = window->screen->active_workspace;
+-  info->usable_screen_region   =
+-    meta_workspace_get_onscreen_region (cur_workspace);
+-  info->usable_monitor_region =
+-    meta_workspace_get_onmonitor_region (cur_workspace,
+-                                         monitor_info->number);
+-
+   /* Log all this information for debugging */
+   meta_topic (META_DEBUG_GEOMETRY,
+               "Setting up constraint info:\n"
+@@ -489,14 +495,17 @@ place_window_if_needed(MetaWindow     *window,
+        */
+       monitor_info =
+         meta_screen_get_monitor_for_rect (window->screen, &placed_rect);
+-      info->entire_monitor = monitor_info->rect;
+-      meta_window_get_work_area_for_monitor (window,
+-                                             monitor_info->number,
+-                                             &info->work_area_monitor);
+       cur_workspace = window->screen->active_workspace;
+-      info->usable_monitor_region =
+-        meta_workspace_get_onmonitor_region (cur_workspace,
+-                                             monitor_info->number);
++      if (monitor_info)
++        {
++          info->entire_monitor = monitor_info->rect;
++          meta_window_get_work_area_for_monitor (window,
++                                                 monitor_info->number,
++                                                 &info->work_area_monitor);
++          info->usable_monitor_region =
++            meta_workspace_get_onmonitor_region (cur_workspace,
++                                                 monitor_info->number);
++        }
+ 
+       info->current.x = placed_rect.x;
+       info->current.y = placed_rect.y;
+diff --git a/src/core/place.c b/src/core/place.c
+index db71b83ce..0f046f046 100644
+--- a/src/core/place.c
++++ b/src/core/place.c
+@@ -811,6 +811,8 @@ meta_window_place (MetaWindow        *window,
+ 
+       /* Warning, this function is a round trip! */
+       xi = meta_screen_get_current_monitor_info (window->screen);
++      if (!xi)
++        goto done;
+ 
+       w = xi->rect.width;
+       h = xi->rect.height;
+@@ -856,6 +858,8 @@ meta_window_place (MetaWindow        *window,
+ 
+   /* Warning, this is a round trip! */
+   xi = meta_screen_get_current_monitor_info (window->screen);
++  if (!xi)
++    goto done;
+ 
+   /* Maximize windows if they are too big for their work area (bit of
+    * a hack here). Assume undecorated windows probably don't intend to
+diff --git a/src/core/screen.c b/src/core/screen.c
+index b8ac22f76..54a0b0aba 100644
+--- a/src/core/screen.c
++++ b/src/core/screen.c
+@@ -381,7 +381,10 @@ meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
+ 
+   meta_screen_ensure_xinerama_indices (screen);
+ 
+-  return screen->monitor_infos[index].xinerama_index;
++  if (index >= 0 && index < screen->n_monitor_infos)
++    return screen->monitor_infos[index].xinerama_index;
++
++  return -1;
+ }
+ 
+ int
+@@ -1395,6 +1398,9 @@ meta_screen_get_monitor_for_rect (MetaScreen    *screen,
+   int i;
+   int best_monitor, monitor_score, rect_area;
+ 
++  if (screen->n_monitor_infos == 0)
++    return NULL;
++
+   if (screen->n_monitor_infos == 1)
+     return &screen->monitor_infos[0];
+ 
+@@ -1448,7 +1454,7 @@ meta_screen_get_monitor_index_for_rect (MetaScreen    *screen,
+                                         MetaRectangle *rect)
+ {
+   const MetaMonitorInfo *monitor = meta_screen_get_monitor_for_rect (screen, rect);
+-  return monitor->number;
++  return monitor ? monitor->number : -1;
+ }
+ 
+ const MetaMonitorInfo *
+diff --git a/src/core/window.c b/src/core/window.c
+index e3e15cf26..9745b42e0 100644
+--- a/src/core/window.c
++++ b/src/core/window.c
+@@ -1029,7 +1029,8 @@ _meta_window_shared_new (MetaDisplay         *display,
+ 
+   window->monitor = meta_screen_calculate_monitor_for_window (window->screen,
+                                                               window);
+-  window->preferred_output_winsys_id = window->monitor->winsys_id;
++  window->preferred_output_winsys_id = window->monitor ? window->monitor->winsys_id
++                                                       : -1;
+ 
+   window->tile_match = NULL;
+ 
+@@ -2280,7 +2281,10 @@ meta_window_show (MetaWindow *window)
+       if (meta_prefs_get_auto_maximize() && window->showing_for_first_time && window->has_maximize_func)
+         {
+           MetaRectangle work_area;
+-          meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area);
++          if (window->monitor)
++            meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area);
++          else
++            meta_window_get_work_area_current_monitor (window, &work_area);
+           /* Automaximize windows that map with a size > MAX_UNMAXIMIZED_WINDOW_AREA of the work area */
+           if (window->rect.width * window->rect.height > work_area.width * work_area.height * MAX_UNMAXIMIZED_WINDOW_AREA)
+             {
+@@ -2677,7 +2681,7 @@ meta_window_maximize_internal (MetaWindow        *window,
+   meta_window_recalc_features (window);
+   set_net_wm_state (window);
+ 
+-  if (window->monitor->in_fullscreen)
++  if (window->monitor && window->monitor->in_fullscreen)
+     meta_screen_queue_check_fullscreen (window->screen);
+ 
+   g_object_freeze_notify (G_OBJECT (window));
+@@ -2863,6 +2867,9 @@ meta_window_is_monitor_sized (MetaWindow *window)
+   if (meta_window_is_screen_sized (window))
+     return TRUE;
+ 
++  if (!window->monitor)
++    return FALSE;
++
+   if (window->override_redirect)
+     {
+       MetaRectangle window_rect, monitor_rect;
+@@ -2886,7 +2893,7 @@ meta_window_is_monitor_sized (MetaWindow *window)
+ gboolean
+ meta_window_is_on_primary_monitor (MetaWindow *window)
+ {
+-  return window->monitor->is_primary;
++  return window->monitor ? window->monitor->is_primary : FALSE;
+ }
+ 
+ /**
+@@ -3027,7 +3034,10 @@ meta_window_unmaximize (MetaWindow        *window,
+       MetaRectangle work_area;
+       MetaRectangle old_frame_rect, old_buffer_rect;
+ 
+-      meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area);
++      if (window->monitor)
++        meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area);
++      else
++        meta_window_get_work_area_current_monitor (window, &work_area);
+       meta_window_get_frame_rect (window, &old_frame_rect);
+       meta_window_get_buffer_rect (window, &old_buffer_rect);
+ 
+@@ -3123,7 +3133,7 @@ meta_window_unmaximize (MetaWindow        *window,
+ 
+       meta_window_recalc_features (window);
+       set_net_wm_state (window);
+-      if (!window->monitor->in_fullscreen)
++      if (window->monitor && !window->monitor->in_fullscreen)
+         meta_screen_queue_check_fullscreen (window->screen);
+     }
+ 
+@@ -3522,7 +3532,7 @@ maybe_move_attached_dialog (MetaWindow *window,
+ int
+ meta_window_get_monitor (MetaWindow *window)
+ {
+-  return window->monitor->number;
++  return window->monitor ? window->monitor->number : -1;
+ }
+ 
+ static MetaMonitorInfo *
+@@ -3549,14 +3559,15 @@ meta_window_update_for_monitors_changed (MetaWindow *window)
+ {
+   const MetaMonitorInfo *old, *new;
+ 
+-  if (window->override_redirect || window->type == META_WINDOW_DESKTOP)
++  old = window->monitor;
++
++  if (!old || window->screen->n_monitor_infos == 0 ||
++      window->override_redirect || window->type == META_WINDOW_DESKTOP)
+     {
+       meta_window_update_monitor (window, FALSE);
+       return;
+     }
+ 
+-  old = window->monitor;
+-
+   /* Try the preferred output first */
+   new = find_monitor_by_winsys_id (window, window->preferred_output_winsys_id);
+ 
+@@ -3643,7 +3654,7 @@ meta_window_move_resize_internal (MetaWindow          *window,
+    */
+ 
+   gboolean did_placement;
+-  guint old_output_winsys_id;
++  guint old_output_winsys_id, new_output_winsys_id;
+   MetaRectangle unconstrained_rect;
+   MetaRectangle constrained_rect;
+   MetaMoveResizeResultFlags result = 0;
+@@ -3737,13 +3748,15 @@ meta_window_move_resize_internal (MetaWindow          *window,
+                                               did_placement);
+     }
+ 
+-  old_output_winsys_id = window->monitor->winsys_id;
++  old_output_winsys_id = window->monitor ? window->monitor->winsys_id : -1;
+ 
+   meta_window_update_monitor (window, flags & META_MOVE_RESIZE_USER_ACTION);
+ 
+-  if (old_output_winsys_id != window->monitor->winsys_id &&
++  new_output_winsys_id = window->monitor ? window->monitor->winsys_id : -1;
++
++  if (old_output_winsys_id != new_output_winsys_id &&
+       flags & META_MOVE_RESIZE_MOVE_ACTION && flags & META_MOVE_RESIZE_USER_ACTION)
+-    window->preferred_output_winsys_id = window->monitor->winsys_id;
++    window->preferred_output_winsys_id = new_output_winsys_id;
+ 
+   if ((result & META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED) && window->frame_bounds)
+     {
+@@ -3849,7 +3862,7 @@ meta_window_move_to_monitor (MetaWindow  *window,
+ {
+   MetaRectangle old_area, new_area;
+ 
+-  if (monitor == window->monitor->number)
++  if (!window->monitor || monitor == window->monitor->number)
+     return;
+ 
+   meta_window_get_work_area_for_monitor (window,
+@@ -6104,9 +6117,17 @@ void
+ meta_window_get_work_area_current_monitor (MetaWindow    *window,
+                                            MetaRectangle *area)
+ {
+-  meta_window_get_work_area_for_monitor (window,
+-                                         window->monitor->number,
+-                                         area);
++  if (window->monitor)
++    {
++      meta_window_get_work_area_for_monitor (window,
++                                             window->monitor->number,
++                                             area);
++    }
++  else if (area)
++    {
++      MetaRectangle empty = { 0, 0, 0, 0 };
++      *area = empty;
++    }
+ }
+ 
+ /**
+diff --git a/src/core/workspace.c b/src/core/workspace.c
+index cfac7dc48..a73ac6bb7 100644
+--- a/src/core/workspace.c
++++ b/src/core/workspace.c
+@@ -765,6 +765,9 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
+   g_assert (workspace->screen_edges == NULL);
+   g_assert (workspace->monitor_edges == NULL);
+ 
++  if (workspace->screen->n_monitor_infos == 0)
++    return;
++
+   /* STEP 1: Get the list of struts */
+ 
+   workspace->all_struts = copy_strut_list (workspace->builtin_struts);
+diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c
+index 376d73c78..9b102e589 100644
+--- a/src/x11/window-x11.c
++++ b/src/x11/window-x11.c
+@@ -2032,7 +2032,8 @@ meta_window_move_resize_request (MetaWindow *window,
+       rect.width = width;
+       rect.height = height;
+ 
+-      meta_screen_get_monitor_geometry (window->screen, window->monitor->number, &monitor_rect);
++      if (window->monitor)
++        meta_screen_get_monitor_geometry (window->screen, window->monitor->number, &monitor_rect);
+ 
+       /* Workaround braindead legacy apps that don't know how to
+        * fullscreen themselves properly - don't get fooled by
+-- 
+2.12.0
+
diff --git a/SPECS/mutter.spec b/SPECS/mutter.spec
new file mode 100644
index 0000000..6e09914
--- /dev/null
+++ b/SPECS/mutter.spec
@@ -0,0 +1,785 @@
+%global gtk3_version 3.19.8
+%global gsettings_desktop_schemas_version 3.21.4
+%global json_glib_version 0.12.0
+
+Name:          mutter
+Version:       3.22.3
+Release:       12%{?dist}
+Summary:       Window and compositing manager based on Clutter
+
+License:       GPLv2+
+#VCS:          git:git://git.gnome.org/mutter
+URL:           http://www.gnome.org
+Source0:       http://download.gnome.org/sources/%{name}/3.22/%{name}-%{version}.tar.xz
+
+# https://bugzilla.gnome.org/show_bug.cgi?id=771442
+Patch0:        fall-back-to-xorg-on-hybrid-gpus.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1331382
+Patch1:        0001-Revert-backend-x11-Ensure-the-Xkb-group-index-remain.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1390607
+Patch2:        0001-wayland-xdg-shell-Handle-the-wl_output-on-the-set_fu.patch
+
+Patch3:         startup-notification.patch
+
+Patch4:        deal-more-gracefully-with-oversized-windows.patch
+Patch5:        support-headless-mode.patch
+
+Patch6:        0001-monitor-manager-xrandr-Work-around-spurious-hotplugs.patch
+Patch7:        0001-monitor-manager-xrandr-Force-an-update-when-resuming.patch
+Patch8:        0001-monitor-config-Consider-external-layout-before-defau.patch
+
+Patch9:       Enable-threeaded-swap-wait.patch
+
+Patch10:       0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch
+Patch11:       0001-backends-x11-Support-synaptics-configuration.patch
+
+Patch12:       0001-display-Check-we-have-a-screen-before-freeing-it.patch
+
+Patch13:       0001-cogl-Prefer-swizzling-to-convert-BGRA-buffers.patch
+
+Patch14:       0001-cally-Fix-translation-to-screen-coordinates.patch
+
+Patch15:       0001-window-actor-Special-case-shaped-Java-windows.patch
+
+Patch16:       0001-clutter-clone-Unset-source-when-source-actor-is-dest.patch
+
+Patch17:       0001-stack-tracker-Keep-override-redirect-windows-on-top.patch
+
+Patch18:       0001-screen-Remove-stray-assert.patch
+
+# http://bugzilla.gnome.org/show_bug.cgi?id=733277
+Patch20: 0008-Add-support-for-quad-buffer-stereo.patch
+Patch21: 0001-build-Lower-automake-requirement.patch
+
+Patch22: add-support-for-plain-old-x-device-configuration.patch
+
+BuildRequires: chrpath
+BuildRequires: pango-devel
+BuildRequires: startup-notification-devel
+BuildRequires: gnome-desktop3-devel
+BuildRequires: gtk3-devel >= %{gtk3_version}
+BuildRequires: pkgconfig
+BuildRequires: gobject-introspection-devel >= 1.41.0
+BuildRequires: libSM-devel
+BuildRequires: libX11-devel
+BuildRequires: libXdamage-devel
+BuildRequires: libXext-devel
+BuildRequires: libXfixes-devel
+BuildRequires: libXi-devel
+BuildRequires: libXrandr-devel
+BuildRequires: libXrender-devel
+BuildRequires: libXcursor-devel
+BuildRequires: libXcomposite-devel
+BuildRequires: libxcb-devel
+BuildRequires: libxkbcommon-devel
+BuildRequires: libxkbcommon-x11-devel
+BuildRequires: libxkbfile-devel
+BuildRequires: mesa-libGL-devel
+BuildRequires: mesa-libgbm-devel
+BuildRequires: pam-devel
+BuildRequires: upower-devel
+BuildRequires: xkeyboard-config-devel
+BuildRequires: zenity
+BuildRequires: desktop-file-utils
+# Bootstrap requirements
+BuildRequires: gtk-doc gnome-common gettext-devel
+BuildRequires: libcanberra-devel
+BuildRequires: gsettings-desktop-schemas-devel >= %{gsettings_desktop_schemas_version}
+BuildRequires: automake, autoconf, libtool
+
+BuildRequires: json-glib-devel >= %{json_glib_version}
+BuildRequires: libgudev1-devel
+
+Obsoletes: mutter-wayland < 3.13.0
+Obsoletes: mutter-wayland-devel < 3.13.0
+
+# Make sure yum updates gnome-shell as well; otherwise we might end up with
+# broken gnome-shell installations due to mutter ABI changes.
+Conflicts: gnome-shell < 3.21.1
+
+Requires: control-center-filesystem
+Requires: gsettings-desktop-schemas%{?_isa} >= %{gsettings_desktop_schemas_version}
+Requires: gtk3%{?_isa} >= %{gtk3_version}
+Requires: startup-notification
+Requires: dbus-x11
+Requires: zenity
+
+Requires:      json-glib%{?_isa} >= %{json_glib_version}
+
+%description
+Mutter is a window and compositing manager that displays and manages
+your desktop via OpenGL. Mutter combines a sophisticated display engine
+using the Clutter toolkit with solid window-management logic inherited
+from the Metacity window manager.
+
+While Mutter can be used stand-alone, it is primarily intended to be
+used as the display core of a larger system such as GNOME Shell. For
+this reason, Mutter is very extensible via plugins, which are used both
+to add fancy visual effects and to rework the window management
+behaviors to meet the needs of the environment.
+
+%package devel
+Summary: Development package for %{name}
+Requires: %{name}%{?_isa} = %{version}-%{release}
+
+%description devel
+Header files and libraries for developing Mutter plugins. Also includes
+utilities for testing Metacity/Mutter themes.
+
+%prep
+%setup -q
+%patch0 -p1
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1 -b .deal-with-oversized-windows
+%patch5 -p1 -b .support-headless-mode
+%patch6 -p1 -b .workaround-xvnc-spurious-hotplugs
+%patch7 -p1 -b .force-randr-update-on-resume
+%patch8 -p1 -b .support-external-monitor-layout
+%patch9 -p1 -b .threaded-swap-wait
+%patch10 -p1 -b .dont-move-sloppy-focus-with-button-pressed
+%patch11 -p1 -b .synaptics-touchpad-configuration
+%patch12 -p1 -b .fix-segfault-on-early-exit
+%patch13 -p1 -b .bgra-buffer-swizzling
+%patch14 -p1 -b .fix-cally-screen-coordinates
+%patch15 -p1 -b .special-case-shaped-java-windows
+%patch16 -p1 -b .unset-source-when-actor-is-destroyed
+%patch17 -p1 -b .keep-OR-windows-on-top
+%patch18 -p1 -b .drop-stray-assert
+
+%patch20 -p1 -b .quad-buffer-stereo
+%patch21 -p1 -b .lower-automake-requirement
+
+%patch22 -p1 -b .add-support-for-plain-old-x-device-configuration
+
+%build
+autoreconf
+(if ! test -x configure; then NOCONFIGURE=1 ./autogen.sh; fi;
+ %configure --disable-static --enable-compile-warnings=maximum --disable-wayland-egl-server)
+
+SHOULD_HAVE_DEFINED="HAVE_SM HAVE_RANDR HAVE_STARTUP_NOTIFICATION"
+
+for I in $SHOULD_HAVE_DEFINED; do
+  if ! grep -q "define $I" config.h; then
+    echo "$I was not defined in config.h"
+    grep "$I" config.h
+    exit 1
+  else
+    echo "$I was defined as it should have been"
+    grep "$I" config.h
+  fi
+done
+
+make %{?_smp_mflags} V=1
+
+%install
+%make_install
+
+#Remove libtool archives.
+rm -rf %{buildroot}/%{_libdir}/*.la
+
+%find_lang %{name}
+
+# Mutter contains a .desktop file so we just need to validate it
+desktop-file-validate %{buildroot}/%{_datadir}/applications/%{name}.desktop
+
+%post -p /sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+if [ $1 -eq 0 ]; then
+  glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
+fi
+
+%posttrans
+glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
+
+%files -f %{name}.lang
+%license COPYING
+%doc NEWS
+%{_bindir}/mutter
+%{_datadir}/applications/*.desktop
+%{_libdir}/lib*.so.*
+%{_libdir}/mutter/
+%{_libexecdir}/mutter-restart-helper
+%{_datadir}/GConf/gsettings/mutter-schemas.convert
+%{_datadir}/glib-2.0/schemas/org.gnome.mutter.gschema.xml
+%{_datadir}/glib-2.0/schemas/org.gnome.mutter.wayland.gschema.xml
+%{_datadir}/gnome-control-center/keybindings/50-mutter-*.xml
+%{_mandir}/man1/mutter.1*
+
+%files devel
+%{_includedir}/*
+%{_libdir}/lib*.so
+%{_libdir}/pkgconfig/*
+
+%changelog
+* Tue Oct 10 2017 Rui Matos <rmatos@redhat.com> - 3.22.3-12
+- Add support for plain old X device configuration
+- Resolves: #1515138
+
+* Mon Jun 26 2017 Florian Müllner <fmuellner@redhat.com> - 3.24.3-11
+- Prevent crash when removing workspace with on-all-workspaces windows
+  present (like desktop icons)
+- Resolves: #1453065
+
+* Wed Jun 14 2017 Florian Müllner <fmuellner@redhat.com> - 3.24.3-10
+- Keep OR windows stacked on top
+- Resolves: #1437203
+
+* Thu Jun 08 2017 Florian Müllner <fmuellner@redhat.com> - 3.24.3-9
+- Fix crash when a window closes during Alt+Tab
+- Resolves: #1438722
+
+* Tue May 16 2017 Florian Müllner <fmuellner@redhat.com> - 3.24.3-8
+- Special-case shaped java windows to fix OpenJDK's compliance test
+- Resolves: #1363784
+
+* Fri Apr 28 2017 Florian Müllner <fmuellner@redhat.com> - 3.24.3-7
+- Fix cally translation of screen coordinates
+- Resolves: #1439194
+
+* Fri Mar 17 2017 Florian Müllner <fmuellner@redhat.com> - 3.22.3-6
+- Recreate build files after modifying templates with the last patch
+- Resolves: #1387025
+
+* Thu Mar 16 2017 Owen Taylor <otaylor@redhat.com> - 3.22.3-6
+- Add back quad-buffer stereo patches, rebased to 3.22
+- Resolves: #1387025
+
+* Wed Mar 15 2017 Carlos Garnacho <cgarnach@redhat.com> - 3.22.3-5
+- Swizzle BGRA buffers to avoid pixel conversions
+- Resolves: #1387025
+
+* Tue Mar 14 2017 Florian Müllner <fmuellner@redhat.com> - 3.22.3-4
+- Don't segfault on early exit
+- Resolves: #1369073
+
+* Mon Mar 13 2017 Carlos Garnacho <cgarnach@redhat.com> - 3.22.3-3
+- Handle synaptics settings
+- Resolves: #1387025
+
+* Mon Mar 13 2017 Florian Müllner <fmuellner@redhat.com> - 3.22.3-2
+- Re-add downstream patches
+- Resolves: #1387025
+
+* Thu Feb 16 2017 Kalev Lember <klember@redhat.com> - 3.22.3-1
+- Update to 3.22.3
+- Resolves: #1387025
+
+* Fri Feb 03 2017 Kalev Lember <klember@redhat.com> - 3.22.2-1
+- Update to 3.22.2
+- Resolves: #1387025
+
+* Fri Sep 16 2016 Florian Müllner <fmuellner@redhat.com> - 3.14.4-31
+- Make meta_window_actor_update_visibility() public
+  Related: #1306670
+
+* Mon Aug 29 2016 Owen Taylor <otaylor@redhat.com - 3.14.4-30
+- Make Mutter exit cleanly when opening $DISPLAY fails
+  Resolves: #1346814
+
+* Mon Aug 15 2016 Rui Matos <rmatos@redhat.com> - 3.14.4-29
+- Allow clutter to fallback to the classic gl driver since mesa's
+  software driver doesn't support gl3
+  Related: #1361251
+
+* Thu Aug 11 2016 Rui Matos <rmatos@redhat.com> - 3.14.4-28
+- Add patch to require clutter to use the gl3 driver
+  Resolves: #1361251
+
+* Mon Jul 18 2016 Rui Matos <rmatos@redhat.com> - 3.14.4-27
+- Require a clutter version that provides all the new APIs
+  Related: rhbz#1330488
+
+* Thu Jun 30 2016 Owen Taylor <otaylor@redhat.com> - 3.14.4-26
+- Turn on newly added "threaded swap wait" functionality in Cogl
+  so that on NVIDIA cards, frame completion is handled in a proper
+  non-blocking fashion, fixing bugs with idles not running when
+  they should.
+  Resolves: #1305076
+
+* Wed Jun 29 2016 Rui Matos <rmatos@redhat.com> - 3.14.4-25
+- Handle video memory purge errors
+  Resolves: #1330488
+
+* Tue Jun 28 2016 Florian Müllner <fmuellner@redhat.com> - 3.14.4-24
+- Update translations
+  Resolves: #1304233
+
+* Fri Jun 17 2016 Florian Müllner <fmuellner@redhat.com> - 3.14.4-23
+- Track ignored damage
+  Resolves: #1165840
+
+* Thu May 19 2016 Florian Müllner <fmuellner@redhat.com> - 3.14.4-22
+- Support external monitor layout configuration
+  Related: #1290448
+
+* Thu May 12 2016 Florian Müllner <fmuellner@redhat.com> - 3.14.4-21
+- Ignore window groups for stacking
+  Resolves: #1167889
+
+* Tue May 10 2016 Owen Taylor <otaylor@redhat.com> - 3.14.4-20
+- Rebase and add back stereo support patch that was dropped in
+  update to 3.14.
+- Retain the last active window for seamless restarts.
+  Resolves: #1305076
+
+* Thu Apr 21 2016 Florian Müllner <fmuellner@redhat.com> - 3.14.4-19
+- Make Cogl errors non-fatal
+  Related: #1326372
+
+* Wed Apr 20 2016 Carlos Garnacho <cgarnach@redhat.com> - 3.14.4-18
+- Fix unredirected windows being transparent to input in sloppy focus
+  Resolves: #1299616
+
+* Mon Oct 26 2015 Rui Matos <rmatos@redhat.com> - 3.14.4-17
+- Fix a crash when plugging monitors
+  Resolves: #1275215
+- Avoid a critical message when unplugging monitors
+  Resolves: #1275220
+- Fix monitors remaining undetected on resume from suspend
+  Resolves: #1219476
+
+* Fri Oct 16 2015 Florian Müllner <fmuellner@redhat.com> - 3.14.4-16
+- Fix crash during session saving when saving sticky windows
+  Related: #1272106
+
+* Tue Oct  6 2015 Rui Matos <rmatos@redhat.com> - 3.14.4-15
+- Fix integer sign oversight in the previous patch
+  Related: #1265511
+
+* Tue Oct  6 2015 Rui Matos <rmatos@redhat.com> - 3.14.4-14
+- Add a couple of fixes for Xvnc resolution changes
+  Resolves: #1265511
+
+* Thu Oct 01 2015 Florian Müllner <fmuellner@redhat.com> - 3.14.4-13
+- Fix a couple more errors in headless mode
+  Related: #1212702
+
+* Fri Sep 04 2015 Florian Müllner <fmuellner@redhat.com> - 3.14.4-12
+- Fix maximum potential number of monitors
+  Resolves: #1260082
+
+* Thu Sep 03 2015 Florian Müllner <fmuellner@redhat.com> - 3.14.4-11
+- Fix screen flicking issue with propriertary NVidia drivers
+  Resolves: #1258842
+
+* Thu Jul 30 2015 Florian Müllner <fmuellner@redhat.com> - 3.14.4-10
+- Fix placement of fullscreen windows
+  Resolves: #1247718
+
+* Fri Jul 24 2015 Florian Müllner <fmuellner@redhat.com> - 3.14.4-9
+- Fix some more headless-mode warnings
+  Related: #1212702
+
+* Fri Jul 24 2015 Florian Müllner <fmuellner@redhat.com> - 3.14.4-8
+- Fix focus_serial overflow
+  Resolves: #1236113
+
+* Tue Jul 21 2015 Matthias Clasen <mclasen@redhat.com> - 3.14.4-7
+- Fix coverity spotted bugs
+  Related #1174722
+
+* Fri Jul 17 2015 Florian Müllner <fmuellner@redhat.com> - 3.14.4-6
+- Fix oversight in headless-mode backport
+  Resolves: #1212702
+
+* Thu Jul 16 2015 Florian Müllner <fmuellner@redhat.com> - 3.14.4-5
+- Support headless mode
+  Resolves: #1212702
+
+* Fri Jul 10 2015 Florian Müllner <fmuellner@redhat.com> - 3.14.4-4
+- Don't try to focus hidden windows
+  Related: #1174722
+
+* Thu May 21 2015 Florian Müllner <fmuellner@redhat.com> - 3.14.4-3
+- support suggested output position
+  Resolves: rhbz#1166319
+
+* Wed May 06 2015 Ray Strode <rstrode@redhat.com> 3.14.4-2
+- rebuild against new gnome-desktop3
+  Related: #1174722
+
+* Tue Mar 24 2015 Florian Müllner <fmuellner@redhat.com> - 3.14.4-1
+- Drop obsolete patches, rebase still relevant one
+
+* Mon Mar 23 2015 Richard Hughes <rhughes@redhat.com> - 3.14.3-1
+- Update to 3.14.3
+- Resolves: #1174722
+
+* Wed Jan 14 2015 Florian Müllner <fmuellner@redhat.com> - 3.8.4.16
+- Fix window placement regression
+  Resolves: rhbz#1153641
+
+* Thu Nov 13 2014 Florian Müllner <fmuellner@redhat.com> - 3.8.4-15
+- Fix delayed mouse mode
+  Resolves: rhbz#1149585
+
+* Thu Oct 09 2014 Florian Müllner <fmueller@redhat.com> - 3.8.4-14
+- Preserve window placement on monitor changes
+  Resolves: rhbz#1126754
+
+* Thu Oct 09 2014 Florian Müllner <fmueller@redhat.com> - 3.8.4-13
+- Improve handling of vertical monitor layouts
+  Resolves: rhbz#1108322
+
+* Thu Jul 17 2014 Owen Taylor <otaylor@redhat.com> 3.8.4-13
+- Add patches for quadbuffer stereo suppport
+  Fix a bad performance problem drawing window thumbnails
+  Resolves: rhbz#861507
+
+* Tue Mar 11 2014 Florian Müllner <fmuellner@redhat.com> - 3.8.4-10
+- Fix crash when encountering over-sized windows
+  Resolves: #1027832
+
+* Tue Mar 11 2014 Florian Müllner <fmuellner@redhat.com> - 3.8.4-10
+- Backport another minor memory leak fix
+  Resolves: #1067456
+
+* Tue Mar 11 2014 Debarshi Ray <rishi@fedoraproject.org> - 3.8.4-9
+- Do not save pixbuf in user data
+  Resolves: #1067456
+
+* Wed Feb 12 2014 Carlos Garnacho <cgarnach@redhat.com> - 3.8.4-8
+- Fix window dragging on touchscreens
+  Resolves: #1051006
+
+* Tue Feb 11 2014 Owen Taylor <otaylor@redhat.com> - 3.8.4-7
+- Add an upstream patch that fixes a bug with left-over window
+  shadows that show up when we add patches to Clutter to stop
+  redrawing the entire screen on every window move.
+  Resolves: rhbz#1063984
+
+* Fri Jan 24 2014 Daniel Mach <dmach@redhat.com> - 3.8.4-6
+- Mass rebuild 2014-01-24
+
+* Fri Dec 27 2013 Daniel Mach <dmach@redhat.com> - 3.8.4-5
+- Mass rebuild 2013-12-27
+
+* Thu Nov 28 2013 Florian Müllner <fmuellner@redhat.com> - 3.8.4-4
+- Include translation updates
+  Resolves: rhbz#1030369
+
+* Mon Nov 11 2013 Florian Müllner <fmuellner@redhat.com> - 3.8.4-3
+- Backport allowing sliced textures for large backgrounds
+  Resolves: rhbz#1028586
+
+* Thu Oct 31 2013 Florian Müllner <fmuellner@redhat.com> - 3.8.4-2
+- Backport performance improvements for software rendering from 3.10
+
+* Tue Jul 30 2013 Ray Strode <rstrode@redhat.com> 3.8.4-1
+- Update to 3.8.4
+
+* Tue Jul 02 2013 Florian Müllner <fmuellner@redhat.com> - 3.8.3-2
+- Rebuild with (re-)fixed download URL
+
+* Fri Jun 07 2013 Florian Müllner <fmuellner@redhat.com> - 3.8.3-1
+- Update to 3.8.3
+
+* Tue May 14 2013 Florian Müllner <fmuellner@redhat.com> - 3.8.2-1
+- Update to 3.8.2
+
+* Tue Apr 16 2013 Florian Müllner <fmuellner@redhat.com> - 3.8.1-1
+- Update to 3.8.1
+
+* Tue Mar 26 2013 Florian Müllner <fmuellner@redhat.com> - 3.8.0-1
+- Update to 3.8.0
+
+* Tue Mar 19 2013 Florian Müllner <fmuellner@redhat.com> - 3.7.92-1
+- Update to 3.7.92
+
+* Mon Mar 04 2013 Florian Müllner <fmuellner@redhat.com> - 3.7.91-1
+- Update to 3.7.91
+
+* Wed Feb 20 2013 Florian Müllner <fmuellner@redhat.com> - 3.7.90-1
+- Update to 3.7.90
+
+* Tue Feb 05 2013 Florian Müllner <fmuellner@redhat.com> - 3.7.5-1
+- Update to 3.7.5
+
+* Fri Jan 25 2013 Peter Robinson <pbrobinson@fedoraproject.org> 3.7.4-2
+- Rebuild for new cogl
+
+* Tue Jan 15 2013 Florian Müllner <fmuellner@redhat.com> - 3.7.4-1
+- Update to 3.7.4
+
+* Tue Dec 18 2012 Florian Müllner <fmuellner@redhat.com> - 3.7.3-1
+- Update to 3.7.3
+
+* Mon Nov 19 2012 Florian Müllner <fmuellner@redhat.com> - 3.7.2-1
+- Update to 3.7.2
+
+* Fri Nov 09 2012 Kalev Lember <kalevlember@gmail.com> - 3.7.1-1
+- Update to 3.7.1
+
+* Mon Oct 15 2012 Florian Müllner <fmuellner@redhat.com> - 3.6.1-1
+- Update to 3.6.1
+
+* Tue Sep 25 2012 Florian Müllner <fmuellner@redhat.com> - 3.6.0-1
+- Update to 3.6.0
+
+* Wed Sep 19 2012 Florian Müllner <fmuellner@redhat.com> - 3.5.92-1
+- Update to 3.5.92
+
+* Tue Sep 04 2012 Debarshi Ray <rishi@fedoraproject.org> - 3.5.91-2
+- Rebuild against new cogl
+
+* Tue Sep 04 2012 Debarshi Ray <rishi@fedoraproject.org> - 3.5.91-1
+- Update to 3.5.91
+
+* Tue Aug 28 2012 Matthias Clasen <mclasen@redhat.com> - 3.5.90-2
+- Rebuild against new cogl/clutter
+
+* Tue Aug 21 2012 Richard Hughes <hughsient@gmail.com> - 3.5.90-1
+- Update to 3.5.90
+
+* Tue Aug 07 2012 Richard Hughes <hughsient@gmail.com> - 3.5.5-1
+- Update to 3.5.5
+
+* Fri Jul 27 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 3.5.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Tue Jul 17 2012 Richard Hughes <hughsient@gmail.com> - 3.5.4-1
+- Update to 3.5.4
+
+* Tue Jun 26 2012 Matthias Clasen <mclasen@redhat.com> - 3.5.3-1
+- Update to 3.5.3
+
+* Fri Jun  8 2012 Matthias Clasen <mclasen@redhat.com> - 3.5.2-3
+- Make resize grip area larger
+
+* Thu Jun 07 2012 Matthias Clasen <mclasen@redhat.com> - 3.5.2-2
+- Don't check for Xinerama anymore - it is now mandatory
+
+* Thu Jun 07 2012 Richard Hughes <hughsient@gmail.com> - 3.5.2-1
+- Update to 3.5.2
+- Remove upstreamed patches
+
+* Wed May 09 2012 Adam Jackson <ajax@redhat.com> 3.4.1-3
+- mutter-never-slice-shape-mask.patch, mutter-use-cogl-texrect-api.patch:
+  Fix window texturing on hardware without ARB_texture_non_power_of_two
+  (#813648)
+
+* Wed Apr 18 2012 Kalev Lember <kalevlember@gmail.com> - 3.4.1-2
+- Silence glib-compile-schemas scriplets
+
+* Wed Apr 18 2012 Kalev Lember <kalevlember@gmail.com> - 3.4.1-1
+- Update to 3.4.1
+- Conflict with gnome-shell versions older than 3.4.1
+
+* Tue Mar 27 2012 Richard Hughes <hughsient@gmail.com> - 3.4.0-1
+- Update to 3.4.0
+
+* Wed Mar 21 2012 Kalev Lember <kalevlember@gmail.com> - 3.3.92-1
+- Update to 3.3.92
+
+* Sat Mar 10 2012 Matthias Clasen <mclasen@redhat.com> - 3.3.90-2
+- Rebuild against new cogl
+
+* Sat Feb 25 2012 Matthias Clasen <mclasen@redhat.com> - 3.3.90-1
+- Update to 3.3.90
+
+* Tue Feb  7 2012 Matthias Clasen <mclasen@redhat.com> - 3.3.5-1
+- Update to 3.3.5
+
+* Fri Jan 20 2012 Matthias Clasen <mclasen@redhat.com> - 3.3.4-1
+- Update to 3.3.4
+
+* Thu Jan 19 2012 Matthias Clasen <mclasen@redhat.com> - 3.3.3-2
+- Rebuild against new cogl
+
+* Thu Jan  5 2012 Matthias Clasen <mclasen@redhat.com> - 3.3.3-1
+- Update to 3.3.3
+
+* Wed Nov 23 2011 Matthias Clasen <mclasen@redhat.com> - 3.3.2-2
+- Rebuild against new clutter
+
+* Tue Nov 22 2011 Matthias Clasen <mclasen@redhat.com> - 3.3.2-1
+- Update to 3.3.2
+
+* Wed Oct 26 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 3.2.1-2
+- Rebuilt for glibc bug#747377
+
+* Wed Oct 19 2011 Matthias Clasen <mclasen@redhat.com> - 3.2.1-1
+- Update to 3.2.1
+
+* Mon Sep 26 2011 Owen Taylor <otaylor@redhat.com> - 3.2.0-1
+- Update to 3.2.0
+
+* Tue Sep 20 2011 Matthias Clasen <mclasen@redhat.com> - 3.1.92-1
+- Update to 3.1.92
+
+* Wed Sep 14 2011 Owen Taylor <otaylor@redhat.com> - 3.1.91.1-1
+- Update to 3.1.91.1
+
+* Wed Aug 31 2011 Matthias Clasen <mclasen@redhat.com> - 3.1.90.1-1
+- Update to 3.1.90.1
+
+* Wed Jul 27 2011 Matthias Clasen <mclasen@redhat.com> - 3.1.4-1
+- Update to 3.1.4
+
+* Wed Jul 27 2011 Matthias Clasen <mclasen@redhat.com> - 3.1.3.1-3
+- Rebuild
+
+* Mon Jul  4 2011 Peter Robinson <pbrobinson@gmail.com> - 3.1.3.1-2
+- rebuild against new clutter/cogl
+
+* Mon Jul 04 2011 Adam Williamson <awilliam@redhat.com> - 3.1.3.1-1
+- Update to 3.1.3.1
+
+* Thu Jun 30 2011 Owen Taylor <otaylor@redhat.com> - 3.1.3-1
+- Update to 3.1.3
+
+* Wed May 25 2011 Owen Taylor <otaylor@redhat.com> - 3.0.2.1-1
+- Update to 3.0.2.1
+
+* Fri Apr 29 2011 Matthias Clasen <mclasen@redhat.com> - 3.0.1-3
+- Actually apply the patch for #700276
+
+* Thu Apr 28 2011 Matthias Clasen <mclasen@redhat.com> - 3.0.1-2
+- Make session saving of gnome-shell work
+
+* Mon Apr 25 2011 Owen Taylor <otaylor@redhat.com> - 3.0.1-1
+- Update to 3.0.1
+
+* Mon Apr  4 2011 Owen Taylor <otaylor@redhat.com> - 3.0.0-1
+- Update to 3.0.0
+
+* Mon Mar 28 2011 Matthias Clasen <mclasen@redhat.com> - 2.91.93-1
+- Update to 2.91.93
+
+* Wed Mar 23 2011 Matthias Clasen <mclasen@redhat.com> - 2.91.92-1
+- Update to 2.91.92
+
+* Mon Mar  7 2011 Owen Taylor <otaylor@redhat.com> - 2.91.91-1
+- Update to 2.91.91
+
+* Tue Mar  1 2011 Matthias Clasen <mclasen@redhat.com> - 2.91.90-2
+- Build against libcanberra, to enable AccessX feedback features
+
+* Tue Feb 22 2011 Matthias Clasen <mclasen@redhat.com> - 2.91.90-1
+- Update to 2.91.90
+
+* Thu Feb 10 2011 Matthias Clasen <mclasen@redhat.com> - 2.91.6-4
+- Rebuild against newer gtk
+
+* Tue Feb 08 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.91.6-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Wed Feb  2 2011 Matthias Clasen <mclasen@redhat.com> - 2.91.6-2
+- Rebuild against newer gtk
+
+* Tue Feb  1 2011 Owen Taylor <otaylor@redhat.com> - 2.91.6-1
+- Update to 2.91.6
+
+* Tue Jan 11 2011 Matthias Clasen <mclasen@redhat.com> - 2.91.5-1
+- Update to 2.91.5
+
+* Fri Jan  7 2011 Matthias Clasen <mclasen@redhat.com> - 2.91.4-1
+- Update to 2.91.4
+
+* Fri Dec  3 2010 Matthias Clasen <mclasen@redhat.com> - 2.91.3-2
+- Rebuild against new gtk
+- Drop no longer needed %%clean etc
+
+* Mon Nov 29 2010 Owen Taylor <otaylor@redhat.com> - 2.91.3-1
+- Update to 2.91.3
+
+* Tue Nov  9 2010 Owen Taylor <otaylor@redhat.com> - 2.91.2-1
+- Update to 2.91.2
+
+* Tue Nov  2 2010 Matthias Clasen <mclasen@redhat.com> - 2.91.1-2
+- Rebuild against newer gtk3
+
+* Fri Oct 29 2010 Owen Taylor <otaylor@redhat.com> - 2.91.1-1
+- Update to 2.91.1
+
+* Mon Oct  4 2010 Owen Taylor <otaylor@redhat.com> - 2.91.0-1
+- Update to 2.91.0
+
+* Wed Sep 22 2010 Matthias Clasen <mclasen@redhat.com> - 2.31.5-4
+- Rebuild against newer gobject-introspection
+
+* Wed Jul 14 2010 Colin Walters <walters@verbum.org> - 2.31.5-3
+- Rebuild for new gobject-introspection
+
+* Tue Jul 13 2010 Adel Gadllah <adel.gadllah@gmail.com> - 2.31.5-2
+- Build against gtk3
+
+* Mon Jul 12 2010 Colin Walters <walters@pocket> - 2.31.5-1
+- New upstream version
+
+* Mon Jul 12 2010 Colin Walters <walters@verbum.org> - 2.31.2-5
+- Rebuild against new gobject-introspection
+
+* Tue Jul  6 2010 Colin Walters <walters@verbum.org> - 2.31.2-4
+- Changes to support snapshot builds
+
+* Fri Jun 25 2010 Colin Walters <walters@megatron> - 2.31.2-3
+- drop gir-repository-devel dep
+
+* Wed May 26 2010 Adam Miller <maxamillion@fedoraproject.org> - 2.31.2-2
+- removed "--with-clutter" as configure is claiming it to be an unknown option
+
+* Wed May 26 2010 Adam Miller <maxamillion@fedoraproject.org> - 2.31.2-1
+- New upstream 2.31.2 release
+
+* Thu Mar 25 2010 Peter Robinson <pbrobinson@gmail.com> 2.29.1-1
+- New upstream 2.29.1 release
+
+* Wed Mar 17 2010 Peter Robinson <pbrobinson@gmail.com> 2.29.0-1
+- New upstream 2.29.0 release
+
+* Tue Feb 16 2010 Adam Jackson <ajax@redhat.com> 2.28.1-0.2
+- mutter-2.28.1-add-needed.patch: Fix FTBFS from --no-add-needed
+
+* Thu Feb  4 2010 Peter Robinson <pbrobinson@gmail.com> 2.28.1-0.1
+- Move to git snapshot
+
+* Wed Oct  7 2009 Owen Taylor <otaylor@redhat.com> - 2.28.0-1
+- Update to 2.28.0
+
+* Tue Sep 15 2009 Owen Taylor <otaylor@redhat.com> - 2.27.5-1
+- Update to 2.27.5
+
+* Fri Sep  4 2009 Owen Taylor <otaylor@redhat.com> - 2.27.4-1
+- Remove workaround for #520209
+- Update to 2.27.4
+
+* Sat Aug 29 2009 Owen Taylor <otaylor@redhat.com> - 2.27.3-3
+- Fix %%preun GConf script to properly be for package removal
+
+* Fri Aug 28 2009 Owen Taylor <otaylor@redhat.com> - 2.27.3-2
+- Add a workaround for Red Hat bug #520209
+
+* Fri Aug 28 2009 Owen Taylor <otaylor@redhat.com> - 2.27.3-1
+- Update to 2.27.3, remove mutter-metawindow.patch
+
+* Fri Aug 21 2009 Peter Robinson <pbrobinson@gmail.com> 2.27.2-2
+- Add upstream patch needed by latest mutter-moblin
+
+* Tue Aug 11 2009 Peter Robinson <pbrobinson@gmail.com> 2.27.2-1
+- New upstream 2.27.2 release. Drop upstreamed patches.
+
+* Wed Jul 29 2009 Peter Robinson <pbrobinson@gmail.com> 2.27.1-5
+- Add upstream patches for clutter 1.0
+
+* Wed Jul 29 2009 Peter Robinson <pbrobinson@gmail.com> 2.27.1-4
+- Add patch to fix mutter --replace
+
+* Sat Jul 25 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.27.1-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
+
+* Sat Jul 18 2009 Peter Robinson <pbrobinson@gmail.com> 2.27.1-2
+- Updates from review request
+
+* Fri Jul 17 2009 Peter Robinson <pbrobinson@gmail.com> 2.27.1-1
+- Update to official 2.27.1 and review updates
+
+* Thu Jun 18 2009 Peter Robinson <pbrobinson@gmail.com> 2.27.0-0.2
+- Updates from initial reviews
+
+* Thu Jun 18 2009 Peter Robinson <pbrobinson@gmail.com> 2.27.0-0.1
+- Initial packaging