diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f2ae9b2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/mutter-3.28.3.tar.xz
diff --git a/.mutter.metadata b/.mutter.metadata
new file mode 100644
index 0000000..6b4e4ce
--- /dev/null
+++ b/.mutter.metadata
@@ -0,0 +1 @@
+a7a01f50c75dc6c1e0fe708656cfce1546624568 SOURCES/mutter-3.28.3.tar.xz
diff --git a/SOURCES/0001-Revert-build-Require-libgudev-232.patch b/SOURCES/0001-Revert-build-Require-libgudev-232.patch
new file mode 100644
index 0000000..e55d8bb
--- /dev/null
+++ b/SOURCES/0001-Revert-build-Require-libgudev-232.patch
@@ -0,0 +1,59 @@
+From 6a807a31b5d762797850948761d66c1ab4fbfd7b Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <ofourdan@redhat.com>
+Date: Fri, 15 Sep 2017 09:39:18 +0200
+Subject: [PATCH] Revert "build: Require libgudev >= 232"
+
+This reverts commit 361bf847af82c7dca097302fe64c575079280c9c.
+---
+ configure.ac                                   | 4 ++--
+ src/backends/native/meta-launcher.c            | 2 ++
+ src/backends/native/meta-monitor-manager-kms.c | 3 +++
+ 3 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index e6b2bf8..2fde187 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -227,10 +227,10 @@ AC_MSG_CHECKING([gudev])
+ if test x$with_gudev = xno ; then
+   AC_MSG_RESULT([disabled])
+ else
+-  if $PKG_CONFIG --exists "gudev-1.0 >= 232"; then
++  if $PKG_CONFIG --exists gudev-1.0; then
+     have_gudev=yes
+     AC_MSG_RESULT(yes)
+-    MUTTER_PC_MODULES="$MUTTER_PC_MODULES gudev-1.0 >= 232"
++    MUTTER_PC_MODULES="$MUTTER_PC_MODULES gudev-1.0"
+     AC_DEFINE([HAVE_LIBGUDEV], 1, [Building with gudev for device type detection])
+   else
+     AC_MSG_RESULT(no)
+diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c
+index 8b066c9..22ea2ad 100644
+--- a/src/backends/native/meta-launcher.c
++++ b/src/backends/native/meta-launcher.c
+@@ -46,6 +46,8 @@
+ #include "meta-cursor-renderer-native.h"
+ #include "meta-renderer-native.h"
+ 
++G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevClient, g_object_unref)
++
+ struct _MetaLauncher
+ {
+   Login1Session *session_proxy;
+diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c
+index 1a2eaec..2a13cdb 100644
+--- a/src/backends/native/meta-monitor-manager-kms.c
++++ b/src/backends/native/meta-monitor-manager-kms.c
+@@ -52,6 +52,9 @@
+ 
+ #define DRM_CARD_UDEV_DEVICE_TYPE "drm_minor"
+ 
++G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevEnumerator, g_object_unref)
++
+ typedef struct
+ {
+   GSource source;
+-- 
+1.8.3.1
+
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..b6f21e1
--- /dev/null
+++ b/SOURCES/0001-backends-x11-Support-synaptics-configuration.patch
@@ -0,0 +1,342 @@
+From 647de5a802627809486fe760c657b05297470683 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 | 261 +++++++++++++++++++++++++++++
+ 1 file changed, 261 insertions(+)
+
+diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c
+index 7a876ef..467a9b7 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>
+@@ -159,6 +160,173 @@ 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 = device_ensure_xdevice (device);
++  if (!xdevice)
++    return;
++
++  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);
++
++  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));
++    }
++}
++
++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 = device_ensure_xdevice (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);
++}
++
+ static void
+ meta_input_settings_x11_set_send_events (MetaInputSettings        *settings,
+                                          ClutterInputDevice       *device,
+@@ -167,6 +335,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)
+@@ -219,6 +394,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);
+@@ -245,6 +426,19 @@ meta_input_settings_x11_set_left_handed (MetaInputSettings  *settings,
+   else
+     {
+       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);
+     }
+@@ -268,6 +462,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);
+ }
+@@ -290,6 +498,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);
+ }
+@@ -303,6 +532,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])
+@@ -332,6 +577,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])
+-- 
+1.8.3.1
+
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-clutter-Do-not-latch-modifiers-on-modifier-keys.patch b/SOURCES/0001-clutter-Do-not-latch-modifiers-on-modifier-keys.patch
new file mode 100644
index 0000000..7a9604e
--- /dev/null
+++ b/SOURCES/0001-clutter-Do-not-latch-modifiers-on-modifier-keys.patch
@@ -0,0 +1,44 @@
+From 67aab7c13812befde061f0d2068b431b04dcbc98 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Wed, 3 Oct 2018 22:43:21 +0200
+Subject: [PATCH] clutter: Do not latch modifiers on modifier keys
+
+If the user maps eg. Alt+F2 to a pad button, the MetaInputSettings will
+send the full Alt press, F2 press, F2 release, Alt release sequence.
+However the keycode corresponding to Alt is found in level 1, so the
+Shift modifier gets unintendedly latched in addition to the Alt key
+press/release pair.
+
+We could probably improve keycode lookup heuristics so level=0 (and
+no modifier latching) is preferred, but we can do without it altogether
+for modifier keys.
+---
+ clutter/clutter/x11/clutter-virtual-input-device-x11.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/clutter/clutter/x11/clutter-virtual-input-device-x11.c b/clutter/clutter/x11/clutter-virtual-input-device-x11.c
+index b86ded0d0..e16ba3fd0 100644
+--- a/clutter/clutter/x11/clutter-virtual-input-device-x11.c
++++ b/clutter/clutter/x11/clutter-virtual-input-device-x11.c
+@@ -147,14 +147,16 @@ clutter_virtual_input_device_x11_notify_keyval (ClutterVirtualInputDevice *virtu
+       return;
+     }
+ 
+-  if (key_state == CLUTTER_KEY_STATE_PRESSED)
++  if (!_clutter_keymap_x11_get_is_modifier (keymap, keycode) &&
++      key_state == CLUTTER_KEY_STATE_PRESSED)
+     clutter_keymap_x11_latch_modifiers (keymap, level, TRUE);
+ 
+   XTestFakeKeyEvent (clutter_x11_get_default_display (),
+                      (KeyCode) keycode,
+                      key_state == CLUTTER_KEY_STATE_PRESSED, 0);
+ 
+-  if (key_state == CLUTTER_KEY_STATE_RELEASED)
++  if (!_clutter_keymap_x11_get_is_modifier (keymap, keycode) &&
++      key_state == CLUTTER_KEY_STATE_RELEASED)
+     clutter_keymap_x11_latch_modifiers (keymap, level, FALSE);
+ }
+ 
+-- 
+2.19.0
+
diff --git a/SOURCES/0001-clutter-Extend-touchpad-device-property-check-for-Sy.patch b/SOURCES/0001-clutter-Extend-touchpad-device-property-check-for-Sy.patch
new file mode 100644
index 0000000..3ae0f20
--- /dev/null
+++ b/SOURCES/0001-clutter-Extend-touchpad-device-property-check-for-Sy.patch
@@ -0,0 +1,61 @@
+From 424e37231a0930594d4363477e7515e006b3dac1 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Tue, 13 Feb 2018 11:44:40 +0100
+Subject: [PATCH] clutter: Extend touchpad device property check for Synaptics
+
+So we reliably get CLUTTER_TOUCHPAD_DEVICE for those. The other heuristics
+to get the device type may fall short.
+---
+ clutter/clutter/x11/clutter-device-manager-xi2.c | 22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/clutter/clutter/x11/clutter-device-manager-xi2.c b/clutter/clutter/x11/clutter-device-manager-xi2.c
+index d2610cc..fcba55c 100644
+--- a/clutter/clutter/x11/clutter-device-manager-xi2.c
++++ b/clutter/clutter/x11/clutter-device-manager-xi2.c
+@@ -267,8 +267,9 @@ is_touch_device (XIAnyClassInfo         **classes,
+ }
+ 
+ static gboolean
+-is_touchpad_device (ClutterBackendX11 *backend_x11,
+-                    XIDeviceInfo      *info)
++query_exists_device_property (ClutterBackendX11 *backend_x11,
++                              XIDeviceInfo      *info,
++                              const gchar       *property)
+ {
+   gulong nitems, bytes_after;
+   guint32 *data = NULL;
+@@ -276,7 +277,7 @@ is_touchpad_device (ClutterBackendX11 *backend_x11,
+   Atom type;
+   Atom prop;
+ 
+-  prop = XInternAtom (backend_x11->xdpy, "libinput Tapping Enabled", True);
++  prop = XInternAtom (backend_x11->xdpy, property, True);
+   if (prop == None)
+     return FALSE;
+ 
+@@ -298,6 +299,21 @@ is_touchpad_device (ClutterBackendX11 *backend_x11,
+ }
+ 
+ static gboolean
++is_touchpad_device (ClutterBackendX11 *backend_x11,
++                    XIDeviceInfo      *info)
++{
++  if (query_exists_device_property (backend_x11, info,
++                                    "libinput Tapping Enabled"))
++    return TRUE;
++
++  if (query_exists_device_property (backend_x11, info,
++                                    "Synaptics Off"))
++    return TRUE;
++
++  return FALSE;
++}
++
++static gboolean
+ get_device_ids (ClutterBackendX11  *backend_x11,
+                 XIDeviceInfo       *info,
+                 gchar             **vendor_id,
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-clutter-Only-reset-scroll-axes-on-slave-devices.patch b/SOURCES/0001-clutter-Only-reset-scroll-axes-on-slave-devices.patch
new file mode 100644
index 0000000..529c05e
--- /dev/null
+++ b/SOURCES/0001-clutter-Only-reset-scroll-axes-on-slave-devices.patch
@@ -0,0 +1,27 @@
+From ee5b766580c702858bb10bab764a39f95a5b6432 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Wed, 13 Jun 2018 13:48:24 +0200
+Subject: [PATCH] clutter: Only reset scroll axes on slave devices
+
+As a plus, unknown source device IDs will just warn instead of crash.
+---
+ clutter/clutter/x11/clutter-device-manager-xi2.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/clutter/clutter/x11/clutter-device-manager-xi2.c b/clutter/clutter/x11/clutter-device-manager-xi2.c
+index 62f558380..ec7268ca8 100644
+--- a/clutter/clutter/x11/clutter-device-manager-xi2.c
++++ b/clutter/clutter/x11/clutter-device-manager-xi2.c
+@@ -1803,7 +1803,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
+             _clutter_input_device_set_stage (device, NULL);
+           }
+ 
+-        _clutter_input_device_reset_scroll_info (source_device);
++        if (clutter_input_device_get_device_mode (source_device) == CLUTTER_INPUT_MODE_SLAVE)
++          _clutter_input_device_reset_scroll_info (source_device);
+ 
+         clutter_event_set_device (event, device);
+         clutter_event_set_source_device (event, source_device);
+-- 
+2.14.3
+
diff --git a/SOURCES/0001-clutter-input-device-xi2-Check-for-null-group_modes-.patch b/SOURCES/0001-clutter-input-device-xi2-Check-for-null-group_modes-.patch
new file mode 100644
index 0000000..5f6473c
--- /dev/null
+++ b/SOURCES/0001-clutter-input-device-xi2-Check-for-null-group_modes-.patch
@@ -0,0 +1,27 @@
+From 2a45b7de7cf5955b81cc1778dbb5085bfabb1c56 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Corentin=20No=C3=ABl?= <corentin@elementary.io>
+Date: Sat, 2 Jun 2018 19:16:32 +0100
+Subject: [PATCH] clutter-input-device-xi2: Check for null group_modes before
+ unref
+
+---
+ clutter/clutter/x11/clutter-input-device-xi2.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/clutter/clutter/x11/clutter-input-device-xi2.c b/clutter/clutter/x11/clutter-input-device-xi2.c
+index f62ba85dcb..1254aca3ae 100644
+--- a/clutter/clutter/x11/clutter-input-device-xi2.c
++++ b/clutter/clutter/x11/clutter-input-device-xi2.c
+@@ -110,7 +110,8 @@ clutter_input_device_xi2_finalize (GObject *object)
+   if (device_xi2->wacom_device)
+     libwacom_destroy (device_xi2->wacom_device);
+ 
+-  g_array_unref (device_xi2->group_modes);
++  if (device_xi2->group_modes)
++    g_array_unref (device_xi2->group_modes);
+ #endif
+ 
+   G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->finalize (object);
+-- 
+2.23.0.rc1
+
diff --git a/SOURCES/0001-clutter-x11-Implement-keycode-lookup-from-keysyms-on.patch b/SOURCES/0001-clutter-x11-Implement-keycode-lookup-from-keysyms-on.patch
new file mode 100644
index 0000000..b577bc8
--- /dev/null
+++ b/SOURCES/0001-clutter-x11-Implement-keycode-lookup-from-keysyms-on.patch
@@ -0,0 +1,317 @@
+From 8dfcfa0607754caab5032532ccc9d97b4393708e Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Fri, 29 Jun 2018 14:31:23 +0200
+Subject: [PATCH] clutter/x11: Implement keycode lookup from keysyms on virtual
+ key devices
+
+Unfortunately XKeysymToKeycode() falls short in that it coalesces keysyms
+into keycodes pertaining to the first level (i.e. lowercase). Add a
+ClutterKeymapX11 method (much alike its GdkKeymap counterpart) to look up
+all matches for the given keysym.
+
+Two other helper methods have been added so the virtual device can fetch
+the current keyboard group, and latch modifiers for key emission. Combining
+all this, the virtual device is now able to handle keycodes in further
+levels.
+
+Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/135
+
+(cherry picked from commit 85284acb000ddc70afcf716b6c198b4b5bf5741e)
+---
+ clutter/clutter/x11/clutter-keymap-x11.c      | 178 +++++++++++++++++-
+ clutter/clutter/x11/clutter-keymap-x11.h      |   8 +
+ .../x11/clutter-virtual-input-device-x11.c    |  22 ++-
+ 3 files changed, 204 insertions(+), 4 deletions(-)
+
+diff --git a/clutter/clutter/x11/clutter-keymap-x11.c b/clutter/clutter/x11/clutter-keymap-x11.c
+index 914e31434..c34e676a4 100644
+--- a/clutter/clutter/x11/clutter-keymap-x11.c
++++ b/clutter/clutter/x11/clutter-keymap-x11.c
+@@ -38,6 +38,14 @@
+ 
+ typedef struct _ClutterKeymapX11Class   ClutterKeymapX11Class;
+ typedef struct _DirectionCacheEntry     DirectionCacheEntry;
++typedef struct _ClutterKeymapKey        ClutterKeymapKey;
++
++struct _ClutterKeymapKey
++{
++  guint keycode;
++  guint group;
++  guint level;
++};
+ 
+ struct _DirectionCacheEntry
+ {
+@@ -59,6 +67,7 @@ struct _ClutterKeymapX11
+ 
+   ClutterModifierType num_lock_mask;
+   ClutterModifierType scroll_lock_mask;
++  ClutterModifierType level3_shift_mask;
+ 
+   PangoDirection current_direction;
+ 
+@@ -69,6 +78,7 @@ struct _ClutterKeymapX11
+   Atom current_group_atom;
+   guint current_cache_serial;
+   DirectionCacheEntry group_direction_cache[4];
++  int current_group;
+ #endif
+ 
+   guint caps_lock_state : 1;
+@@ -198,6 +208,9 @@ get_xkb (ClutterKeymapX11 *keymap_x11)
+   if (keymap_x11->scroll_lock_mask == 0)
+     keymap_x11->scroll_lock_mask = XkbKeysymToModifiers (backend_x11->xdpy,
+                                                          XK_Scroll_Lock);
++  if (keymap_x11->level3_shift_mask == 0)
++    keymap_x11->level3_shift_mask = XkbKeysymToModifiers (backend_x11->xdpy,
++                                                          XK_ISO_Level3_Shift);
+ 
+   return keymap_x11->xkb_desc;
+ }
+@@ -469,6 +482,7 @@ static void
+ clutter_keymap_x11_init (ClutterKeymapX11 *keymap)
+ {
+   keymap->current_direction = PANGO_DIRECTION_NEUTRAL;
++  keymap->current_group = -1;
+ }
+ 
+ static ClutterTranslateReturn
+@@ -498,7 +512,8 @@ clutter_keymap_x11_translate_event (ClutterEventTranslator *translator,
+         {
+         case XkbStateNotify:
+           CLUTTER_NOTE (EVENT, "Updating keyboard state");
+-          update_direction (keymap_x11, XkbStateGroup (&xkb_event->state));
++          keymap_x11->current_group = XkbStateGroup (&xkb_event->state);
++          update_direction (keymap_x11, keymap_x11->current_group);
+           update_locked_mods (keymap_x11, xkb_event->state.locked_mods);
+           retval = CLUTTER_TRANSLATE_REMOVE;
+           break;
+@@ -665,3 +680,164 @@ _clutter_keymap_x11_get_direction (ClutterKeymapX11 *keymap)
+ #endif
+     return PANGO_DIRECTION_NEUTRAL;
+ }
++
++static gboolean
++clutter_keymap_x11_get_entries_for_keyval (ClutterKeymapX11  *keymap_x11,
++                                           guint              keyval,
++                                           ClutterKeymapKey **keys,
++                                           gint              *n_keys)
++{
++#ifdef HAVE_XKB
++  if (CLUTTER_BACKEND_X11 (keymap_x11->backend)->use_xkb)
++    {
++      XkbDescRec *xkb = get_xkb (keymap_x11);
++      GArray *retval;
++      gint keycode;
++
++      keycode = keymap_x11->min_keycode;
++      retval = g_array_new (FALSE, FALSE, sizeof (ClutterKeymapKey));
++
++      while (keycode <= keymap_x11->max_keycode)
++        {
++          gint max_shift_levels = XkbKeyGroupsWidth (xkb, keycode);
++          gint group = 0;
++          gint level = 0;
++          gint total_syms = XkbKeyNumSyms (xkb, keycode);
++          gint i = 0;
++          KeySym *entry;
++
++          /* entry is an array with all syms for group 0, all
++           * syms for group 1, etc. and for each group the
++           * shift level syms are in order
++           */
++          entry = XkbKeySymsPtr (xkb, keycode);
++
++          while (i < total_syms)
++            {
++              g_assert (i == (group * max_shift_levels + level));
++
++              if (entry[i] == keyval)
++                {
++                  ClutterKeymapKey key;
++
++                  key.keycode = keycode;
++                  key.group = group;
++                  key.level = level;
++
++                  g_array_append_val (retval, key);
++
++                  g_assert (XkbKeySymEntry (xkb, keycode, level, group) ==
++                            keyval);
++                }
++
++              ++level;
++
++              if (level == max_shift_levels)
++                {
++                  level = 0;
++                  ++group;
++                }
++
++              ++i;
++            }
++
++          ++keycode;
++        }
++
++      if (retval->len > 0)
++        {
++          *keys = (ClutterKeymapKey*) retval->data;
++          *n_keys = retval->len;
++        }
++      else
++        {
++          *keys = NULL;
++          *n_keys = 0;
++        }
++
++      g_array_free (retval, retval->len > 0 ? FALSE : TRUE);
++
++      return *n_keys > 0;
++    }
++  else
++#endif
++    {
++      return FALSE;
++    }
++}
++
++void
++clutter_keymap_x11_latch_modifiers (ClutterKeymapX11 *keymap_x11,
++                                    uint32_t          level,
++                                    gboolean          enable)
++{
++#ifdef HAVE_XKB
++  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend);
++  uint32_t modifiers[] = {
++    0,
++    ShiftMask,
++    keymap_x11->level3_shift_mask,
++    keymap_x11->level3_shift_mask | ShiftMask,
++  };
++  uint32_t value = 0;
++
++  if (!backend_x11->use_xkb)
++    return;
++
++  level = CLAMP (level, 0, G_N_ELEMENTS (modifiers) - 1);
++
++  if (enable)
++    value = modifiers[level];
++  else
++    value = 0;
++
++  XkbLatchModifiers (clutter_x11_get_default_display (),
++                     XkbUseCoreKbd, modifiers[level],
++                     value);
++#endif
++}
++
++static uint32_t
++clutter_keymap_x11_get_current_group (ClutterKeymapX11 *keymap_x11)
++{
++  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend);
++  XkbStateRec state_rec;
++
++  if (keymap_x11->current_group >= 0)
++    return keymap_x11->current_group;
++
++  XkbGetState (backend_x11->xdpy, XkbUseCoreKbd, &state_rec);
++  return XkbStateGroup (&state_rec);
++}
++
++gboolean
++clutter_keymap_x11_keycode_for_keyval (ClutterKeymapX11 *keymap_x11,
++                                       guint             keyval,
++                                       guint            *keycode_out,
++                                       guint            *level_out)
++{
++  ClutterKeymapKey *keys;
++  gint i, n_keys, group;
++  gboolean found = FALSE;
++
++  g_return_val_if_fail (keycode_out != NULL, FALSE);
++  g_return_val_if_fail (level_out != NULL, FALSE);
++
++  group = clutter_keymap_x11_get_current_group (keymap_x11);
++
++  if (!clutter_keymap_x11_get_entries_for_keyval (keymap_x11, keyval, &keys, &n_keys))
++    return FALSE;
++
++  for (i = 0; i < n_keys && !found; i++)
++    {
++      if (keys[i].group == group)
++        {
++          *keycode_out = keys[i].keycode;
++          *level_out = keys[i].level;
++          found = TRUE;
++        }
++    }
++
++  g_free (keys);
++  return found;
++}
+diff --git a/clutter/clutter/x11/clutter-keymap-x11.h b/clutter/clutter/x11/clutter-keymap-x11.h
+index ad673a2a7..4b5b403c8 100644
+--- a/clutter/clutter/x11/clutter-keymap-x11.h
++++ b/clutter/clutter/x11/clutter-keymap-x11.h
+@@ -51,6 +51,14 @@ gboolean _clutter_keymap_x11_get_is_modifier     (ClutterKeymapX11    *keymap,
+ 
+ PangoDirection _clutter_keymap_x11_get_direction (ClutterKeymapX11    *keymap);
+ 
++gboolean clutter_keymap_x11_keycode_for_keyval (ClutterKeymapX11 *keymap_x11,
++                                                guint             keyval,
++                                                guint            *keycode_out,
++                                                guint            *level_out);
++void     clutter_keymap_x11_latch_modifiers (ClutterKeymapX11 *keymap_x11,
++                                             uint32_t          level,
++                                             gboolean          enable);
++
+ G_END_DECLS
+ 
+ #endif /* __CLUTTER_KEYMAP_X11_H__ */
+diff --git a/clutter/clutter/x11/clutter-virtual-input-device-x11.c b/clutter/clutter/x11/clutter-virtual-input-device-x11.c
+index 416c944b3..b86ded0d0 100644
+--- a/clutter/clutter/x11/clutter-virtual-input-device-x11.c
++++ b/clutter/clutter/x11/clutter-virtual-input-device-x11.c
+@@ -32,6 +32,8 @@
+ 
+ #include "clutter-virtual-input-device.h"
+ #include "x11/clutter-virtual-input-device-x11.h"
++#include "x11/clutter-backend-x11.h"
++#include "x11/clutter-keymap-x11.h"
+ 
+ struct _ClutterVirtualInputDeviceX11
+ {
+@@ -135,11 +137,25 @@ clutter_virtual_input_device_x11_notify_keyval (ClutterVirtualInputDevice *virtu
+ 						uint32_t                   keyval,
+ 						ClutterKeyState            key_state)
+ {
+-  KeyCode keycode;
++  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
++  ClutterKeymapX11 *keymap = backend_x11->keymap;
++  uint32_t keycode, level;
++
++  if (!clutter_keymap_x11_keycode_for_keyval (keymap, keyval, &keycode, &level))
++    {
++      g_warning ("No keycode found for keyval %x in current group", keyval);
++      return;
++    }
++
++  if (key_state == CLUTTER_KEY_STATE_PRESSED)
++    clutter_keymap_x11_latch_modifiers (keymap, level, TRUE);
+ 
+-  keycode = XKeysymToKeycode (clutter_x11_get_default_display (), keyval);
+   XTestFakeKeyEvent (clutter_x11_get_default_display (),
+-                     keycode, key_state == CLUTTER_KEY_STATE_PRESSED, 0);
++                     (KeyCode) keycode,
++                     key_state == CLUTTER_KEY_STATE_PRESSED, 0);
++
++  if (key_state == CLUTTER_KEY_STATE_RELEASED)
++    clutter_keymap_x11_latch_modifiers (keymap, level, FALSE);
+ }
+ 
+ static void
+-- 
+2.19.0.rc0
+
diff --git a/SOURCES/0001-compositor-Don-t-emit-size-changed-when-only-positio.patch b/SOURCES/0001-compositor-Don-t-emit-size-changed-when-only-positio.patch
new file mode 100644
index 0000000..0e04185
--- /dev/null
+++ b/SOURCES/0001-compositor-Don-t-emit-size-changed-when-only-positio.patch
@@ -0,0 +1,140 @@
+From a8d0870c6e9c9d2269c2b856cd2d83949fef4154 Mon Sep 17 00:00:00 2001
+From: Daniel van Vugt <daniel.van.vugt@canonical.com>
+Date: Tue, 7 May 2019 18:08:13 +0800
+Subject: [PATCH 1/2] compositor: Don't emit size-changed when only position
+ changes
+
+Waking up gnome-shell and triggering JavaScript listeners of
+`size-changed` every time a window was only moved was wasting a lot
+of CPU.
+
+This cuts the CPU requirement for dragging windows by around 22%.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/568
+---
+ src/compositor/compositor.c                |  8 +++-
+ src/compositor/meta-window-actor-private.h | 12 +++++-
+ src/compositor/meta-window-actor.c         | 43 ++++++++++++++++++----
+ 3 files changed, 52 insertions(+), 11 deletions(-)
+
+diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
+index 8c924d256..abf7de57d 100644
+--- a/src/compositor/compositor.c
++++ b/src/compositor/compositor.c
+@@ -1070,8 +1070,12 @@ meta_compositor_sync_window_geometry (MetaCompositor *compositor,
+                                       gboolean did_placement)
+ {
+   MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
+-  meta_window_actor_sync_actor_geometry (window_actor, did_placement);
+-  meta_plugin_manager_event_size_changed (compositor->plugin_mgr, window_actor);
++  MetaWindowActorChanges changes;
++
++  changes = meta_window_actor_sync_actor_geometry (window_actor, did_placement);
++
++  if (changes & META_WINDOW_ACTOR_CHANGE_SIZE)
++    meta_plugin_manager_event_size_changed (compositor->plugin_mgr, window_actor);
+ }
+ 
+ static void
+diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
+index ce5e7eadc..acd649d07 100644
+--- a/src/compositor/meta-window-actor-private.h
++++ b/src/compositor/meta-window-actor-private.h
+@@ -12,6 +12,12 @@
+ 
+ MetaWindowActor *meta_window_actor_new (MetaWindow *window);
+ 
++typedef enum
++{
++  META_WINDOW_ACTOR_CHANGE_SIZE     = 1 << 0,
++  META_WINDOW_ACTOR_CHANGE_POSITION = 1 << 1
++} MetaWindowActorChanges;
++
+ void meta_window_actor_queue_destroy   (MetaWindowActor *self);
+ 
+ void meta_window_actor_show (MetaWindowActor *self,
+@@ -43,8 +49,10 @@ void     meta_window_actor_set_unredirected    (MetaWindowActor *self,
+                                                 gboolean         unredirected);
+ 
+ gboolean meta_window_actor_effect_in_progress  (MetaWindowActor *self);
+-void     meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
+-                                                gboolean         did_placement);
++
++MetaWindowActorChanges meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
++                                                              gboolean         did_placement);
++
+ void     meta_window_actor_update_shape        (MetaWindowActor *self);
+ void     meta_window_actor_update_opacity      (MetaWindowActor *self);
+ void     meta_window_actor_mapped              (MetaWindowActor *self);
+diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
+index 120b0432c..afe2bab6e 100644
+--- a/src/compositor/meta-window-actor.c
++++ b/src/compositor/meta-window-actor.c
+@@ -1299,12 +1299,14 @@ meta_window_actor_queue_destroy (MetaWindowActor *self)
+     clutter_actor_destroy (CLUTTER_ACTOR (self));
+ }
+ 
+-void
++MetaWindowActorChanges
+ meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
+                                        gboolean         did_placement)
+ {
+   MetaWindowActorPrivate *priv = self->priv;
+   MetaRectangle window_rect;
++  ClutterActor *actor = CLUTTER_ACTOR (self);
++  MetaWindowActorChanges changes = 0;
+ 
+   meta_window_get_buffer_rect (priv->window, &window_rect);
+ 
+@@ -1322,15 +1324,42 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
+    * updates.
+    */
+   if (is_frozen (self) && !did_placement)
+-    return;
++    return META_WINDOW_ACTOR_CHANGE_POSITION | META_WINDOW_ACTOR_CHANGE_SIZE;
+ 
+   if (meta_window_actor_effect_in_progress (self))
+-    return;
++    return META_WINDOW_ACTOR_CHANGE_POSITION | META_WINDOW_ACTOR_CHANGE_SIZE;
++
++  if (clutter_actor_has_allocation (actor))
++    {
++      ClutterActorBox box;
++      float old_x, old_y;
++      float old_width, old_height;
++
++      clutter_actor_get_allocation_box (actor, &box);
++
++      old_x = box.x1;
++      old_y = box.y1;
++      old_width = box.x2 - box.x1;
++      old_height = box.y2 - box.y1;
++
++      if (old_x != window_rect.x || old_y != window_rect.y)
++        changes |= META_WINDOW_ACTOR_CHANGE_POSITION;
++
++      if (old_width != window_rect.width || old_height != window_rect.height)
++        changes |= META_WINDOW_ACTOR_CHANGE_SIZE;
++    }
++  else
++    {
++      changes = META_WINDOW_ACTOR_CHANGE_POSITION | META_WINDOW_ACTOR_CHANGE_SIZE;
++    }
++
++  if (changes & META_WINDOW_ACTOR_CHANGE_POSITION)
++    clutter_actor_set_position (actor, window_rect.x, window_rect.y);
++
++  if (changes & META_WINDOW_ACTOR_CHANGE_SIZE)
++    clutter_actor_set_size (actor, window_rect.width, window_rect.height);
+ 
+-  clutter_actor_set_position (CLUTTER_ACTOR (self),
+-                              window_rect.x, window_rect.y);
+-  clutter_actor_set_size (CLUTTER_ACTOR (self),
+-                          window_rect.width, window_rect.height);
++  return changes;
+ }
+ 
+ void
+-- 
+2.21.0
+
diff --git a/SOURCES/0001-constraints-Fix-titlebars-going-off-the-bottom.patch b/SOURCES/0001-constraints-Fix-titlebars-going-off-the-bottom.patch
new file mode 100644
index 0000000..bc199e1
--- /dev/null
+++ b/SOURCES/0001-constraints-Fix-titlebars-going-off-the-bottom.patch
@@ -0,0 +1,39 @@
+From 2fd734c349ab00f2f460af97f7c383678407f620 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Wed, 16 Jan 2019 01:09:26 +0100
+Subject: [PATCH] constraints: Fix titlebars going off the bottom
+
+The "current" rect includes the frame, so in order to keep the
+titlebar on screen, window movement must be restricted to at
+most (height - titlebar_height) past the work area bottom.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/391
+---
+ src/core/constraints.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/core/constraints.c b/src/core/constraints.c
+index 3b6203d6b..92b146ce3 100644
+--- a/src/core/constraints.c
++++ b/src/core/constraints.c
+@@ -1570,7 +1570,7 @@ constrain_titlebar_visible (MetaWindow         *window,
+       MetaFrameBorders borders;
+       meta_frame_calc_borders (window->frame, &borders);
+ 
+-      bottom_amount = info->current.height + borders.visible.bottom;
++      bottom_amount = info->current.height - borders.visible.top;
+       vert_amount_onscreen = borders.visible.top;
+     }
+   else
+@@ -1649,7 +1649,7 @@ constrain_partially_onscreen (MetaWindow         *window,
+       MetaFrameBorders borders;
+       meta_frame_calc_borders (window->frame, &borders);
+ 
+-      bottom_amount = info->current.height + borders.visible.bottom;
++      bottom_amount = info->current.height - borders.visible.top;
+       vert_amount_onscreen = borders.visible.top;
+     }
+   else
+-- 
+2.20.1
+
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..4eeb33e
--- /dev/null
+++ b/SOURCES/0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch
@@ -0,0 +1,43 @@
+From 887537360c3c3b0ae5d0ef0222fad4d0a3bc41c9 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 5/8] 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 49f2569f3..ecb4de53d 100644
+--- a/src/x11/events.c
++++ b/src/x11/events.c
+@@ -830,6 +830,16 @@ crossing_serial_is_ignored (MetaDisplay  *display,
+   return FALSE;
+ }
+ 
++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,
+@@ -871,6 +881,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.14.2
+
diff --git a/SOURCES/0001-events-Sync-pending-pointer-events-without-a-window.patch b/SOURCES/0001-events-Sync-pending-pointer-events-without-a-window.patch
new file mode 100644
index 0000000..14878a7
--- /dev/null
+++ b/SOURCES/0001-events-Sync-pending-pointer-events-without-a-window.patch
@@ -0,0 +1,122 @@
+From 3582d1780c9bf3fc93604963a11b9b60d9895178 Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <ofourdan@redhat.com>
+Date: Wed, 2 Oct 2019 16:49:28 +0200
+Subject: [PATCH] events: Sync pending pointer events without a window
+
+Mutter issues a synchronous grab on the pointer for unfocused client
+windows to be able to catch the button events first and raise/focus
+client windows accordingly.
+
+When there is a synchronous grab in effect, all events are queued until
+the grabbing client releases the event queue as it processes the events.
+
+Mutter does release the events in its event handler function but does so
+only if it is able to find the window matching the event. If the window
+is a shell widget, that matching may fail and therefore Mutter will not
+release the events, hence causing a freeze in pointer events delivery.
+
+To avoid the issue, make sure we sync the pointer events in case we
+can't find a matching window.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/821
+---
+ src/core/events.c | 62 ++++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 51 insertions(+), 11 deletions(-)
+
+diff --git a/src/core/events.c b/src/core/events.c
+index 92503a168..9b19065fb 100644
+--- a/src/core/events.c
++++ b/src/core/events.c
+@@ -51,6 +51,12 @@
+ #define IS_KEY_EVENT(e) ((e)->type == CLUTTER_KEY_PRESS || \
+                          (e)->type == CLUTTER_KEY_RELEASE)
+ 
++typedef enum
++{
++  EVENTS_UNFREEZE_SYNC,
++  EVENTS_UNFREEZE_REPLAY,
++} EventsUnfreezeMethod;
++
+ static gboolean
+ stage_has_key_focus (void)
+ {
+@@ -167,6 +173,43 @@ sequence_is_pointer_emulated (MetaDisplay        *display,
+   return FALSE;
+ }
+ 
++static void
++maybe_unfreeze_pointer_events (MetaBackend          *backend,
++                               const ClutterEvent   *event,
++                               EventsUnfreezeMethod  unfreeze_method)
++{
++  Display *xdisplay;
++  int event_mode;
++  int device_id;
++
++  if (event->type != CLUTTER_BUTTON_PRESS)
++    return;
++
++  if (!META_IS_BACKEND_X11 (backend))
++    return;
++
++  device_id = clutter_event_get_device_id (event);
++  switch (unfreeze_method)
++    {
++    case EVENTS_UNFREEZE_SYNC:
++      event_mode = XISyncDevice;
++      meta_verbose ("Syncing events time %u device %i\n",
++                    (unsigned int) event->button.time, device_id);
++      break;
++    case EVENTS_UNFREEZE_REPLAY:
++      event_mode = XIReplayDevice;
++      meta_verbose ("Replaying events time %u device %i\n",
++                    (unsigned int) event->button.time, device_id);
++      break;
++    default:
++      g_assert_not_reached ();
++      return;
++    }
++
++  xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
++  XIAllowEvents (xdisplay, device_id, event_mode, event->button.time);
++}
++
+ static gboolean
+ meta_display_handle_event (MetaDisplay        *display,
+                            const ClutterEvent *event)
+@@ -366,17 +409,7 @@ meta_display_handle_event (MetaDisplay        *display,
+         {
+           /* Only replay button press events, since that's where we
+            * have the synchronous grab. */
+-          if (event->type == CLUTTER_BUTTON_PRESS)
+-            {
+-              if (META_IS_BACKEND_X11 (backend))
+-                {
+-                  Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
+-                  meta_verbose ("Allowing events time %u\n",
+-                                (unsigned int)event->button.time);
+-                  XIAllowEvents (xdisplay, clutter_event_get_device_id (event),
+-                                 XIReplayDevice, event->button.time);
+-                }
+-            }
++          maybe_unfreeze_pointer_events (backend, event, EVENTS_UNFREEZE_REPLAY);
+ 
+           /* If the focus window has an active close dialog let clutter
+            * events go through, so fancy clutter dialogs can get to handle
+@@ -392,6 +425,13 @@ meta_display_handle_event (MetaDisplay        *display,
+ 
+       goto out;
+     }
++  else
++    {
++      /* We could not match the event with a window, make sure we sync
++       * the pointer to discard the sequence and don't keep events frozen.
++       */
++       maybe_unfreeze_pointer_events (backend, event, EVENTS_UNFREEZE_SYNC);
++    }
+ 
+  out:
+   /* If the compositor has a grab, don't pass that through to Wayland */
+-- 
+2.23.0
+
diff --git a/SOURCES/0001-gpu-xrandr-Move-dpms-state-and-screen-size-updating-.patch b/SOURCES/0001-gpu-xrandr-Move-dpms-state-and-screen-size-updating-.patch
new file mode 100644
index 0000000..e448785
--- /dev/null
+++ b/SOURCES/0001-gpu-xrandr-Move-dpms-state-and-screen-size-updating-.patch
@@ -0,0 +1,114 @@
+From 7ce6f10f6966ec6e66549a6878ae333d0fe1e84c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Wed, 3 Oct 2018 10:50:07 +0200
+Subject: [PATCH 1/2] gpu/xrandr: Move dpms state and screen size updating into
+ helpers
+
+To be used by no-Xrandr fallback path.
+---
+ src/backends/x11/meta-gpu-xrandr.c | 70 ++++++++++++++++++++----------
+ 1 file changed, 46 insertions(+), 24 deletions(-)
+
+diff --git a/src/backends/x11/meta-gpu-xrandr.c b/src/backends/x11/meta-gpu-xrandr.c
+index add80c0d2d..a4e187a49a 100644
+--- a/src/backends/x11/meta-gpu-xrandr.c
++++ b/src/backends/x11/meta-gpu-xrandr.c
+@@ -91,31 +91,15 @@ meta_gpu_xrandr_poll_hardware (MetaGpu *gpu)
+   gpu_xrandr->need_hardware_poll = TRUE;
+ }
+ 
+-static gboolean
+-meta_gpu_xrandr_read_current (MetaGpu  *gpu,
+-                              GError  **error)
++static void
++update_dpms_state (MetaMonitorManagerXrandr *monitor_manager_xrandr)
+ {
+-  MetaGpuXrandr *gpu_xrandr = META_GPU_XRANDR (gpu);
+-  MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
+-  MetaMonitorManagerXrandr *monitor_manager_xrandr =
+-    META_MONITOR_MANAGER_XRANDR (monitor_manager);
++  MetaMonitorManager *monitor_manager =
++    META_MONITOR_MANAGER (monitor_manager_xrandr);
+   Display *xdisplay =
+     meta_monitor_manager_xrandr_get_xdisplay (monitor_manager_xrandr);
+-  XRRScreenResources *resources;
+-  RROutput primary_output;
+-  unsigned int i, j;
+-  GList *l;
+-  int min_width, min_height;
+-  Screen *screen;
+   BOOL dpms_capable, dpms_enabled;
+   CARD16 dpms_state;
+-  GList *outputs = NULL;
+-  GList *modes = NULL;
+-  GList *crtcs = NULL;
+-
+-  if (gpu_xrandr->resources)
+-    XRRFreeScreenResources (gpu_xrandr->resources);
+-  gpu_xrandr->resources = NULL;
+ 
+   dpms_capable = DPMSCapable (xdisplay);
+ 
+@@ -146,6 +130,47 @@ meta_gpu_xrandr_read_current (MetaGpu  *gpu,
+     {
+       monitor_manager->power_save_mode = META_POWER_SAVE_UNSUPPORTED;
+     }
++}
++
++static void
++update_screen_size (MetaMonitorManagerXrandr *monitor_manager_xrandr)
++{
++  MetaMonitorManager *monitor_manager =
++    META_MONITOR_MANAGER (monitor_manager_xrandr);
++  Display *xdisplay =
++    meta_monitor_manager_xrandr_get_xdisplay (monitor_manager_xrandr);
++  Screen *screen;
++
++  screen = ScreenOfDisplay (xdisplay, DefaultScreen (xdisplay));
++
++  monitor_manager->screen_width = WidthOfScreen (screen);
++  monitor_manager->screen_height = HeightOfScreen (screen);
++}
++
++static gboolean
++meta_gpu_xrandr_read_current (MetaGpu  *gpu,
++                              GError  **error)
++{
++  MetaGpuXrandr *gpu_xrandr = META_GPU_XRANDR (gpu);
++  MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
++  MetaMonitorManagerXrandr *monitor_manager_xrandr =
++    META_MONITOR_MANAGER_XRANDR (monitor_manager);
++  Display *xdisplay =
++    meta_monitor_manager_xrandr_get_xdisplay (monitor_manager_xrandr);
++  XRRScreenResources *resources;
++  RROutput primary_output;
++  unsigned int i, j;
++  GList *l;
++  int min_width, min_height;
++  GList *outputs = NULL;
++  GList *modes = NULL;
++  GList *crtcs = NULL;
++
++  if (gpu_xrandr->resources)
++    XRRFreeScreenResources (gpu_xrandr->resources);
++  gpu_xrandr->resources = NULL;
++
++  update_dpms_state (monitor_manager_xrandr);
+ 
+   XRRGetScreenSizeRange (xdisplay, DefaultRootWindow (xdisplay),
+                          &min_width,
+@@ -153,10 +178,7 @@ meta_gpu_xrandr_read_current (MetaGpu  *gpu,
+                          &gpu_xrandr->max_screen_width,
+                          &gpu_xrandr->max_screen_height);
+ 
+-  screen = ScreenOfDisplay (xdisplay, DefaultScreen (xdisplay));
+-  /* This is updated because we called XRRUpdateConfiguration. */
+-  monitor_manager->screen_width = WidthOfScreen (screen);
+-  monitor_manager->screen_height = HeightOfScreen (screen);
++  update_screen_size (monitor_manager_xrandr);
+ 
+   if (gpu_xrandr->need_hardware_poll)
+     {
+-- 
+2.17.1
+
diff --git a/SOURCES/0001-idle-monitor-Use-G_SOURCE_CONTINUE-instead-of-TRUE.patch b/SOURCES/0001-idle-monitor-Use-G_SOURCE_CONTINUE-instead-of-TRUE.patch
new file mode 100644
index 0000000..ac3c785
--- /dev/null
+++ b/SOURCES/0001-idle-monitor-Use-G_SOURCE_CONTINUE-instead-of-TRUE.patch
@@ -0,0 +1,28 @@
+From 0ac0bc55cf69579834b28d99729cefd1157624c3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Tue, 16 Apr 2019 18:06:54 +0200
+Subject: [PATCH 1/2] idle-monitor: Use G_SOURCE_CONTINUE instead of TRUE
+
+Returning TRUE is confusing, as it doesn't carry any relevant meaning.
+Use G_SOURCE_CONTINUE to make it clearer that the source is here to
+stay.
+---
+ src/backends/meta-idle-monitor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/backends/meta-idle-monitor.c b/src/backends/meta-idle-monitor.c
+index 46cf8cd76..2b634f59a 100644
+--- a/src/backends/meta-idle-monitor.c
++++ b/src/backends/meta-idle-monitor.c
+@@ -315,7 +315,7 @@ idle_monitor_dispatch_timeout (GSource     *source,
+   _meta_idle_monitor_watch_fire (watch);
+   g_source_set_ready_time (watch->timeout_source, -1);
+ 
+-  return TRUE;
++  return G_SOURCE_CONTINUE;
+ }
+ 
+ static GSourceFuncs idle_monitor_source_funcs = {
+-- 
+2.20.1
+
diff --git a/SOURCES/0001-main-be-more-aggressive-in-assuming-X11-backend.patch b/SOURCES/0001-main-be-more-aggressive-in-assuming-X11-backend.patch
new file mode 100644
index 0000000..8fcef03
--- /dev/null
+++ b/SOURCES/0001-main-be-more-aggressive-in-assuming-X11-backend.patch
@@ -0,0 +1,132 @@
+From 5e3a6efd0e2bbea040e203b996e7d00ab3431cfa Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode@redhat.com>
+Date: Tue, 13 Feb 2018 09:44:50 -0500
+Subject: [PATCH] main: be more aggressive in assuming X11 backend
+
+If the session is started by vncserver right now, the
+XDG_SESSION_TYPE won't be X11.  Ideally that would be
+fixed, but for backward compatibility we should default
+to X11 if the session type isn't set to wayland explicitly.
+---
+ src/core/main.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/src/core/main.c b/src/core/main.c
+index 079f6a9ef..8e8bc3f77 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -304,108 +304,106 @@ meta_finalize (void)
+ 
+ #ifdef HAVE_WAYLAND
+   if (meta_is_wayland_compositor ())
+     meta_wayland_finalize ();
+ #endif
+ }
+ 
+ static gboolean
+ on_sigterm (gpointer user_data)
+ {
+   meta_quit (EXIT_SUCCESS);
+ 
+   return G_SOURCE_REMOVE;
+ }
+ 
+ #if defined(HAVE_WAYLAND) && defined(HAVE_NATIVE_BACKEND)
+ static gboolean
+ session_type_is_supported (const char *session_type)
+ {
+    return (g_strcmp0 (session_type, "x11") == 0) ||
+           (g_strcmp0 (session_type, "wayland") == 0);
+ }
+ 
+ static char *
+ find_session_type (void)
+ {
+   char **sessions = NULL;
+   char *session_id;
+   char *session_type;
+   const char *session_type_env;
+-  gboolean is_tty = FALSE;
+   int ret, i;
+ 
+   ret = sd_pid_get_session (0, &session_id);
+   if (ret == 0 && session_id != NULL)
+     {
+       ret = sd_session_get_type (session_id, &session_type);
+       free (session_id);
+ 
+       if (ret == 0)
+         {
+           if (session_type_is_supported (session_type))
+             goto out;
+-          else
+-            is_tty = g_strcmp0 (session_type, "tty") == 0;
++
+           free (session_type);
+         }
+     }
+   else if (sd_uid_get_sessions (getuid (), 1, &sessions) > 0)
+     {
+       for (i = 0; sessions[i] != NULL; i++)
+         {
+           ret = sd_session_get_type (sessions[i], &session_type);
+ 
+           if (ret < 0)
+             continue;
+ 
+           if (session_type_is_supported (session_type))
+             {
+               g_strfreev (sessions);
+               goto out;
+             }
+ 
+           free (session_type);
+         }
+     }
+   g_strfreev (sessions);
+ 
+   session_type_env = g_getenv ("XDG_SESSION_TYPE");
+   if (session_type_is_supported (session_type_env))
+     {
+       /* The string should be freeable */
+       session_type = strdup (session_type_env);
+       goto out;
+     }
+ 
+-  /* Legacy support for starting through xinit */
+-  if (is_tty && (g_getenv ("MUTTER_DISPLAY") || g_getenv ("DISPLAY")))
++  /* Legacy support for starting through xinit or vncserver */
++  if (g_getenv ("MUTTER_DISPLAY") || g_getenv ("DISPLAY"))
+     {
+       session_type = strdup ("x11");
+       goto out;
+     }
+ 
+   meta_warning ("Unsupported session type\n");
+   meta_exit (META_EXIT_ERROR);
+ 
+ out:
+   return session_type;
+ }
+ 
+ static gboolean
+ check_for_wayland_session_type (void)
+ {
+   char *session_type;
+   gboolean is_wayland;
+ 
+   session_type = find_session_type ();
+   is_wayland = g_strcmp0 (session_type, "wayland") == 0;
+   free (session_type);
+ 
+   return is_wayland;
+ }
+ #endif
+ 
+ /*
+  * Determine the compositor configuration, i.e. whether to run as a Wayland
+  * compositor, as well as what backend to use.
+  *
+-- 
+2.14.3
+
diff --git a/SOURCES/0001-monitor-Use-current-monitor-mode-to-check-whether-ac.patch b/SOURCES/0001-monitor-Use-current-monitor-mode-to-check-whether-ac.patch
new file mode 100644
index 0000000..c5819df
--- /dev/null
+++ b/SOURCES/0001-monitor-Use-current-monitor-mode-to-check-whether-ac.patch
@@ -0,0 +1,85 @@
+From 22d626580cd84136b54ca1154852da6f990c00a2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Tue, 31 Jul 2018 11:18:51 +0000
+Subject: [PATCH 1/2] monitor: Use current monitor mode to check whether active
+
+For historical reasons meta_monitor_is_active() checked whether it is
+active by checking whether the main output have a CRTC assigned and
+whether that CRTC has a current mode. At a later point, the MetaMonitor
+got its own mode abstraction (MetaMonitorMode), but
+meta_monitor_is_active() was never updated to use this.
+
+An issue with checking the main output's CRTC state is that, if there is
+some CRTC mode combination that for some reason isn't properly detected
+by the MetaMonitorMode abstraction (e.g. some tiling configuration not
+yet handled), meta_monitor_is_active() would return TRUE, even though no
+(abstracted) mode was set. This would cause confusion here and there,
+leading to NULL pointer dereferences due to the assumption that if a
+monitor is active, it has an active mode.
+
+Instead, change meta_monitor_is_active() to directly check the current
+monitor mode, and log a warning if the main output still happen to have
+a CRTC with a mode assigned to it. This way, when an not undrestood CRTC
+mode combination is encountered, instead of dereferencing NULL pointers,
+simply assume the monitor is not active, which means that it will not be
+managed or rendered by mutter at all.
+
+https://gitlab.gnome.org/GNOME/mutter/issues/130
+
+
+(cherry picked from commit 4d465eac0806eb1ead375e2852d4a9d6bc24524f)
+---
+ src/backends/meta-monitor.c | 22 ++++++++++++++++------
+ 1 file changed, 16 insertions(+), 6 deletions(-)
+
+diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c
+index 98330661e..9a412a612 100644
+--- a/src/backends/meta-monitor.c
++++ b/src/backends/meta-monitor.c
+@@ -203,13 +203,9 @@ meta_monitor_get_main_output (MetaMonitor *monitor)
+ gboolean
+ meta_monitor_is_active (MetaMonitor *monitor)
+ {
+-  MetaOutput *output;
+-  MetaCrtc *crtc;
+-
+-  output = meta_monitor_get_main_output (monitor);
+-  crtc = meta_output_get_assigned_crtc (output);
++  MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
+ 
+-  return crtc && crtc->current_mode;
++  return !!priv->current_mode;
+ }
+ 
+ gboolean
+@@ -1411,6 +1407,18 @@ meta_monitor_get_current_mode (MetaMonitor *monitor)
+   return priv->current_mode;
+ }
+ 
++static gboolean
++is_current_mode_known (MetaMonitor *monitor)
++{
++  MetaOutput *output;
++  MetaCrtc *crtc;
++
++  output = meta_monitor_get_main_output (monitor);
++  crtc = meta_output_get_assigned_crtc (output);
++
++  return meta_monitor_is_active (monitor) == (crtc && crtc->current_mode);
++}
++
+ void
+ meta_monitor_derive_current_mode (MetaMonitor *monitor)
+ {
+@@ -1430,6 +1438,8 @@ meta_monitor_derive_current_mode (MetaMonitor *monitor)
+     }
+ 
+   priv->current_mode = current_mode;
++
++  g_warn_if_fail (is_current_mode_known (monitor));
+ }
+ 
+ void
+-- 
+2.21.0
+
diff --git a/SOURCES/0001-monitor-config-store-Read-system-wide-config-files.patch b/SOURCES/0001-monitor-config-store-Read-system-wide-config-files.patch
new file mode 100644
index 0000000..4fea4d0
--- /dev/null
+++ b/SOURCES/0001-monitor-config-store-Read-system-wide-config-files.patch
@@ -0,0 +1,186 @@
+From f7de692a87e4bf46bc005567fe0475c1208f0969 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Fri, 5 Oct 2018 18:52:03 +0200
+Subject: [PATCH] monitor-config-store: Read system wide config files
+
+Before introducing the new config store, the old monitor configuration
+system read system wide monitor configuration files. Add back that
+feature.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/253
+---
+ src/backends/meta-monitor-config-manager.h |  1 +
+ src/backends/meta-monitor-config-store.c   | 72 +++++++++++++++++++---
+ 2 files changed, 65 insertions(+), 8 deletions(-)
+
+diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h
+index 29ef8f8ce..16dff6d6a 100644
+--- a/src/backends/meta-monitor-config-manager.h
++++ b/src/backends/meta-monitor-config-manager.h
+@@ -55,6 +55,7 @@ typedef enum _MetaMonitorsConfigFlag
+ {
+   META_MONITORS_CONFIG_FLAG_NONE = 0,
+   META_MONITORS_CONFIG_FLAG_MIGRATED = (1 << 0),
++  META_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG = (1 << 1),
+ } MetaMonitorsConfigFlag;
+ 
+ struct _MetaMonitorsConfig
+diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c
+index ed0ce34f0..770bef734 100644
+--- a/src/backends/meta-monitor-config-store.c
++++ b/src/backends/meta-monitor-config-store.c
+@@ -179,6 +179,8 @@ typedef struct
+   MetaMonitorConfig *current_monitor_config;
+   MetaLogicalMonitorConfig *current_logical_monitor_config;
+   GList *current_disabled_monitor_specs;
++
++  MetaMonitorsConfigFlag extra_config_flags;
+ } ConfigParser;
+ 
+ G_DEFINE_TYPE (MetaMonitorConfigStore, meta_monitor_config_store,
+@@ -766,6 +768,8 @@ handle_end_element (GMarkupParseContext  *context,
+         if (parser->current_was_migrated)
+           config_flags |= META_MONITORS_CONFIG_FLAG_MIGRATED;
+ 
++        config_flags |= parser->extra_config_flags;
++
+         config =
+           meta_monitors_config_new_full (parser->current_logical_monitor_configs,
+                                          parser->current_disabled_monitor_specs,
+@@ -1078,9 +1082,10 @@ static const GMarkupParser config_parser = {
+ };
+ 
+ static gboolean
+-read_config_file (MetaMonitorConfigStore *config_store,
+-                  GFile                  *file,
+-                  GError                **error)
++read_config_file (MetaMonitorConfigStore  *config_store,
++                  GFile                   *file,
++                  MetaMonitorsConfigFlag   extra_config_flags,
++                  GError                 **error)
+ {
+   char *buffer;
+   gsize size;
+@@ -1092,7 +1097,8 @@ read_config_file (MetaMonitorConfigStore *config_store,
+ 
+   parser = (ConfigParser) {
+     .state = STATE_INITIAL,
+-    .config_store = config_store
++    .config_store = config_store,
++    .extra_config_flags = extra_config_flags,
+   };
+ 
+   parse_context = g_markup_parse_context_new (&config_parser,
+@@ -1274,6 +1280,9 @@ generate_config_xml (MetaMonitorConfigStore *config_store)
+     {
+       GList *l;
+ 
++      if (config->flags & META_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG)
++        continue;
++
+       g_string_append (buffer, "  <configuration>\n");
+ 
+       if (config->flags & META_MONITORS_CONFIG_FLAG_MIGRATED)
+@@ -1425,6 +1434,12 @@ maybe_save_configs (MetaMonitorConfigStore *config_store)
+     meta_monitor_config_store_save (config_store);
+ }
+ 
++static gboolean
++is_system_config (MetaMonitorsConfig *config)
++{
++  return !!(config->flags & META_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG);
++}
++
+ void
+ meta_monitor_config_store_add (MetaMonitorConfigStore *config_store,
+                                MetaMonitorsConfig     *config)
+@@ -1432,7 +1447,8 @@ meta_monitor_config_store_add (MetaMonitorConfigStore *config_store,
+   g_hash_table_replace (config_store->configs,
+                         config->key, g_object_ref (config));
+ 
+-  maybe_save_configs (config_store);
++  if (!is_system_config (config))
++    maybe_save_configs (config_store);
+ }
+ 
+ void
+@@ -1441,7 +1457,8 @@ meta_monitor_config_store_remove (MetaMonitorConfigStore *config_store,
+ {
+   g_hash_table_remove (config_store->configs, config->key);
+ 
+-  maybe_save_configs (config_store);
++  if (!is_system_config (config))
++    maybe_save_configs (config_store);
+ }
+ 
+ gboolean
+@@ -1458,7 +1475,10 @@ meta_monitor_config_store_set_custom (MetaMonitorConfigStore *config_store,
+   if (write_path)
+     config_store->custom_write_file = g_file_new_for_path (write_path);
+ 
+-  return read_config_file (config_store, config_store->custom_read_file, error);
++  return read_config_file (config_store,
++                           config_store->custom_read_file,
++                           META_MONITORS_CONFIG_FLAG_NONE,
++                           error);
+ }
+ 
+ int
+@@ -1485,9 +1505,42 @@ static void
+ meta_monitor_config_store_constructed (GObject *object)
+ {
+   MetaMonitorConfigStore *config_store = META_MONITOR_CONFIG_STORE (object);
++  const char * const *system_dirs;
+   char *user_file_path;
+   GError *error = NULL;
+ 
++  for (system_dirs = g_get_system_config_dirs ();
++       system_dirs && *system_dirs;
++       system_dirs++)
++    {
++      g_autofree char *system_file_path = NULL;
++
++      system_file_path = g_build_filename (*system_dirs, "monitors.xml", NULL);
++      if (g_file_test (system_file_path, G_FILE_TEST_EXISTS))
++        {
++          g_autoptr (GFile) system_file = NULL;
++
++          system_file = g_file_new_for_path (system_file_path);
++          if (!read_config_file (config_store,
++                                 system_file,
++                                 META_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG,
++                                 &error))
++            {
++              if (g_error_matches (error,
++                                   META_MONITOR_CONFIG_STORE_ERROR,
++                                   META_MONITOR_CONFIG_STORE_ERROR_NEEDS_MIGRATION))
++                g_warning ("System monitor configuration file (%s) is "
++                           "incompatible; ask your administrator to migrate "
++                           "the system monitor configuation.",
++                           system_file_path);
++              else
++                g_warning ("Failed to read monitors config file '%s': %s",
++                           system_file_path, error->message);
++              g_clear_error (&error);
++            }
++        }
++    }
++
+   user_file_path = g_build_filename (g_get_user_config_dir (),
+                                      "monitors.xml",
+                                      NULL);
+@@ -1495,7 +1548,10 @@ meta_monitor_config_store_constructed (GObject *object)
+ 
+   if (g_file_test (user_file_path, G_FILE_TEST_EXISTS))
+     {
+-      if (!read_config_file (config_store, config_store->user_file, &error))
++      if (!read_config_file (config_store,
++                             config_store->user_file,
++                             META_MONITORS_CONFIG_FLAG_NONE,
++                             &error))
+         {
+           if (error->domain == META_MONITOR_CONFIG_STORE_ERROR &&
+               error->code == META_MONITOR_CONFIG_STORE_ERROR_NEEDS_MIGRATION)
+-- 
+2.20.1
+
diff --git a/SOURCES/0001-monitor-manager-Consider-external-layout-before-defa.patch b/SOURCES/0001-monitor-manager-Consider-external-layout-before-defa.patch
new file mode 100644
index 0000000..5ef6094
--- /dev/null
+++ b/SOURCES/0001-monitor-manager-Consider-external-layout-before-defa.patch
@@ -0,0 +1,151 @@
+From 648f1ce9350fcab0ebaecccb115b5021c632e7b5 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-manager: 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-manager.c | 75 ++++++++++++++++++++++
+ src/backends/meta-monitor-config-manager.h |  1 +
+ src/backends/meta-monitor-manager.c        | 19 ++++++++
+ 3 files changed, 97 insertions(+)
+
+diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
+index 197892bf2..ae988f64a 100644
+--- a/src/backends/meta-monitor-config-manager.c
++++ b/src/backends/meta-monitor-config-manager.c
+@@ -559,6 +559,83 @@ create_preferred_logical_monitor_config (MetaMonitorManager          *monitor_ma
+   return logical_monitor_config;
+ }
+ 
++static MetaLogicalMonitorConfig *
++create_logical_monitor_config_from_output (MetaMonitorManager           *monitor_manager,
++                                           MetaMonitor                  *monitor,
++                                           MetaLogicalMonitorConfig     *primary_logical_monitor_config,
++                                           MetaLogicalMonitorLayoutMode  layout_mode)
++{
++    MetaOutput *output;
++    MetaCrtc *crtc;
++
++    output = meta_monitor_get_main_output (monitor);
++    crtc = meta_output_get_assigned_crtc (output);
++    return create_preferred_logical_monitor_config (monitor_manager,
++                                                    monitor,
++                                                    crtc->rect.x,
++                                                    crtc->rect.y,
++                                                    primary_logical_monitor_config,
++                                                    layout_mode);
++}
++
++MetaMonitorsConfig *
++meta_monitor_config_manager_create_current (MetaMonitorConfigManager *config_manager)
++{
++  MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
++  GList *logical_monitor_configs;
++  MetaMonitor *primary_monitor;
++  MetaLogicalMonitorLayoutMode layout_mode;
++  MetaLogicalMonitorConfig *primary_logical_monitor_config;
++  GList *monitors;
++  GList *l;
++
++  if (meta_monitor_config_store_get_config_count (config_manager->config_store) > 0)
++    return NULL;
++
++  primary_monitor = find_primary_monitor (monitor_manager);
++  if (!primary_monitor || !meta_monitor_is_active (primary_monitor))
++    return NULL;
++
++  layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
++
++  primary_logical_monitor_config =
++    create_logical_monitor_config_from_output (monitor_manager,
++                                               primary_monitor,
++                                               NULL,
++                                               layout_mode);
++
++  primary_logical_monitor_config->is_primary = TRUE;
++  logical_monitor_configs = g_list_append (NULL,
++                                           primary_logical_monitor_config);
++
++  monitors = meta_monitor_manager_get_monitors (monitor_manager);
++  for (l = monitors; l; l = l->next)
++    {
++      MetaMonitor *monitor = l->data;
++      MetaLogicalMonitorConfig *logical_monitor_config;
++
++      if (monitor == primary_monitor)
++        continue;
++
++      if (!meta_monitor_is_active (monitor))
++        continue;
++
++      logical_monitor_config =
++        create_logical_monitor_config_from_output (monitor_manager,
++                                                   monitor,
++                                                   primary_logical_monitor_config,
++                                                   layout_mode);
++
++      logical_monitor_configs = g_list_append (logical_monitor_configs,
++                                               logical_monitor_config);
++    }
++
++  return meta_monitors_config_new (monitor_manager,
++                                   logical_monitor_configs,
++                                   layout_mode,
++                                   META_MONITORS_CONFIG_FLAG_NONE);
++}
++
+ MetaMonitorsConfig *
+ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager)
+ {
+diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h
+index 269d8e1b7..c36df38e6 100644
+--- a/src/backends/meta-monitor-config-manager.h
++++ b/src/backends/meta-monitor-config-manager.h
+@@ -87,6 +87,7 @@ gboolean meta_monitor_config_manager_assign (MetaMonitorManager *manager,
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_get_stored (MetaMonitorConfigManager *config_manager);
+ 
++MetaMonitorsConfig * meta_monitor_config_manager_create_current (MetaMonitorConfigManager *config_manager);
+ MetaMonitorsConfig * meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager);
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_create_fallback (MetaMonitorConfigManager *config_manager);
+diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c
+index 0b5e54c48..263e93941 100644
+--- a/src/backends/meta-monitor-manager.c
++++ b/src/backends/meta-monitor-manager.c
+@@ -576,6 +576,25 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
+       g_clear_object (&config);
+     }
+ 
++  config = meta_monitor_config_manager_create_current (manager->config_manager);
++  if (config)
++    {
++      if (!meta_monitor_manager_apply_monitors_config (manager,
++                                                       config,
++                                                       method,
++                                                       &error))
++        {
++          g_clear_object (&config);
++          g_warning ("Failed to use current monitor configuration: %s",
++                     error->message);
++          g_clear_error (&error);
++        }
++      else
++        {
++          goto done;
++        }
++    }
++
+   config = meta_monitor_config_manager_create_linear (manager->config_manager);
+   if (config)
+     {
+-- 
+2.17.1
+
diff --git a/SOURCES/0001-monitor-manager-only-reuse-initial-config-if-monitor.patch b/SOURCES/0001-monitor-manager-only-reuse-initial-config-if-monitor.patch
new file mode 100644
index 0000000..ede04d7
--- /dev/null
+++ b/SOURCES/0001-monitor-manager-only-reuse-initial-config-if-monitor.patch
@@ -0,0 +1,505 @@
+From 0cc90f343f4caadb5c4279623a0811c378715a09 Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Tue, 11 Sep 2018 10:19:44 -0400
+Subject: [PATCH] monitor-manager: only reuse initial-config if monitor
+ topology matches startup
+
+Right now we try to apply the current monitor config when a new
+monitor is attached.  The current config obviously doesn't include the
+new monitor, so the new monitor isn't lit up.
+
+The only reason we apply the current config at all is to handle the
+startup case:  We want to reuse the config set in Xorg when first
+logging in.
+
+This commit changes the code to look at the *initial config* instead
+of the current config, and only if the new monitor topology matches
+the start up topology.
+---
+ src/backends/meta-monitor-config-manager.c | 20 +++++++++++++++-----
+ src/backends/meta-monitor-config-manager.h |  2 +-
+ src/backends/meta-monitor-manager.c        | 16 +++++++++++++++-
+ 3 files changed, 31 insertions(+), 7 deletions(-)
+
+diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
+index 585ee7034..1ad342a44 100644
+--- a/src/backends/meta-monitor-config-manager.c
++++ b/src/backends/meta-monitor-config-manager.c
+@@ -13,60 +13,61 @@
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+  * 02111-1307, USA.
+  */
+ 
+ #include "config.h"
+ 
+ #include "backends/meta-monitor-config-manager.h"
+ 
+ #include "backends/meta-monitor-config-migration.h"
+ #include "backends/meta-monitor-config-store.h"
+ #include "backends/meta-monitor-manager-private.h"
+ #include "backends/meta-output.h"
+ #include "core/boxes-private.h"
+ 
+ #define CONFIG_HISTORY_MAX_SIZE 3
+ 
+ struct _MetaMonitorConfigManager
+ {
+   GObject parent;
+ 
+   MetaMonitorManager *monitor_manager;
+ 
+   MetaMonitorConfigStore *config_store;
+ 
+   MetaMonitorsConfig *current_config;
++  MetaMonitorsConfig *initial_config;
+   GQueue config_history;
+ };
+ 
+ G_DEFINE_TYPE (MetaMonitorConfigManager, meta_monitor_config_manager,
+                G_TYPE_OBJECT)
+ 
+ G_DEFINE_TYPE (MetaMonitorsConfig, meta_monitors_config,
+                G_TYPE_OBJECT)
+ 
+ static void
+ meta_crtc_info_free (MetaCrtcInfo *info);
+ 
+ static void
+ meta_output_info_free (MetaOutputInfo *info);
+ 
+ MetaMonitorConfigManager *
+ meta_monitor_config_manager_new (MetaMonitorManager *monitor_manager)
+ {
+   MetaMonitorConfigManager *config_manager;
+ 
+   config_manager = g_object_new (META_TYPE_MONITOR_CONFIG_MANAGER, NULL);
+   config_manager->monitor_manager = monitor_manager;
+   config_manager->config_store =
+     meta_monitor_config_store_new (monitor_manager);
+ 
+   return config_manager;
+ }
+ 
+ MetaMonitorConfigStore *
+ meta_monitor_config_manager_get_store (MetaMonitorConfigManager *config_manager)
+@@ -552,115 +553,123 @@ create_preferred_logical_monitor_config (MetaMonitorManager          *monitor_ma
+       .width = width,
+       .height = height
+     },
+     .scale = scale,
+     .monitor_configs = g_list_append (NULL, monitor_config)
+   };
+ 
+   return logical_monitor_config;
+ }
+ 
+ static MetaLogicalMonitorConfig *
+ create_logical_monitor_config_from_output (MetaMonitorManager           *monitor_manager,
+                                            MetaMonitor                  *monitor,
+                                            MetaLogicalMonitorConfig     *primary_logical_monitor_config,
+                                            MetaLogicalMonitorLayoutMode  layout_mode)
+ {
+     MetaOutput *output;
+     MetaCrtc *crtc;
+ 
+     output = meta_monitor_get_main_output (monitor);
+     crtc = meta_output_get_assigned_crtc (output);
+     return create_preferred_logical_monitor_config (monitor_manager,
+                                                     monitor,
+                                                     crtc->rect.x,
+                                                     crtc->rect.y,
+                                                     primary_logical_monitor_config,
+                                                     layout_mode);
+ }
+ 
+ MetaMonitorsConfig *
+-meta_monitor_config_manager_create_current (MetaMonitorConfigManager *config_manager)
++meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_manager)
+ {
+   MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
++  MetaMonitorsConfig *initial_config;
+   GList *logical_monitor_configs;
+   MetaMonitor *primary_monitor;
+   MetaLogicalMonitorLayoutMode layout_mode;
+   MetaLogicalMonitorConfig *primary_logical_monitor_config;
+   GList *monitors;
+   GList *l;
+ 
++  if (config_manager->initial_config != NULL)
++    return g_object_ref (config_manager->initial_config);
++
+   if (meta_monitor_config_store_get_config_count (config_manager->config_store) > 0)
+     return NULL;
+ 
+   primary_monitor = find_primary_monitor (monitor_manager);
+   if (!primary_monitor || !meta_monitor_is_active (primary_monitor))
+     return NULL;
+ 
+   layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
+ 
+   primary_logical_monitor_config =
+     create_logical_monitor_config_from_output (monitor_manager,
+                                                primary_monitor,
+                                                NULL,
+                                                layout_mode);
+ 
+   primary_logical_monitor_config->is_primary = TRUE;
+   logical_monitor_configs = g_list_append (NULL,
+                                            primary_logical_monitor_config);
+ 
+   monitors = meta_monitor_manager_get_monitors (monitor_manager);
+   for (l = monitors; l; l = l->next)
+     {
+       MetaMonitor *monitor = l->data;
+       MetaLogicalMonitorConfig *logical_monitor_config;
+ 
+       if (monitor == primary_monitor)
+         continue;
+ 
+       if (!meta_monitor_is_active (monitor))
+         continue;
+ 
+       logical_monitor_config =
+         create_logical_monitor_config_from_output (monitor_manager,
+                                                    monitor,
+                                                    primary_logical_monitor_config,
+                                                    layout_mode);
+ 
+       logical_monitor_configs = g_list_append (logical_monitor_configs,
+                                                logical_monitor_config);
+     }
+ 
+-  return meta_monitors_config_new (monitor_manager,
+-                                   logical_monitor_configs,
+-                                   layout_mode,
+-                                   META_MONITORS_CONFIG_FLAG_NONE);
++  initial_config = meta_monitors_config_new (monitor_manager,
++                                             logical_monitor_configs,
++                                             layout_mode,
++                                             META_MONITORS_CONFIG_FLAG_NONE);
++
++  config_manager->initial_config = g_object_ref (initial_config);
++
++  return initial_config;
+ }
+ 
+ MetaMonitorsConfig *
+ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager)
+ {
+   MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
+   GList *logical_monitor_configs;
+   MetaMonitor *primary_monitor;
+   MetaLogicalMonitorLayoutMode layout_mode;
+   MetaLogicalMonitorConfig *primary_logical_monitor_config;
+   int x;
+   GList *monitors;
+   GList *l;
+ 
+   primary_monitor = find_primary_monitor (monitor_manager);
+   if (!primary_monitor)
+     return NULL;
+ 
+   layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
+ 
+   primary_logical_monitor_config =
+     create_preferred_logical_monitor_config (monitor_manager,
+                                              primary_monitor,
+                                              0, 0,
+                                              NULL,
+                                              layout_mode);
+   primary_logical_monitor_config->is_primary = TRUE;
+   logical_monitor_configs = g_list_append (NULL,
+                                            primary_logical_monitor_config);
+ 
+@@ -1135,60 +1144,61 @@ meta_monitor_config_manager_get_current (MetaMonitorConfigManager *config_manage
+ {
+   return config_manager->current_config;
+ }
+ 
+ MetaMonitorsConfig *
+ meta_monitor_config_manager_pop_previous (MetaMonitorConfigManager *config_manager)
+ {
+   return g_queue_pop_head (&config_manager->config_history);
+ }
+ 
+ MetaMonitorsConfig *
+ meta_monitor_config_manager_get_previous (MetaMonitorConfigManager *config_manager)
+ {
+   return g_queue_peek_head (&config_manager->config_history);
+ }
+ 
+ void
+ meta_monitor_config_manager_clear_history (MetaMonitorConfigManager *config_manager)
+ {
+   g_queue_foreach (&config_manager->config_history, (GFunc) g_object_unref, NULL);
+   g_queue_clear (&config_manager->config_history);
+ }
+ 
+ static void
+ meta_monitor_config_manager_dispose (GObject *object)
+ {
+   MetaMonitorConfigManager *config_manager =
+     META_MONITOR_CONFIG_MANAGER (object);
+ 
+   g_clear_object (&config_manager->current_config);
++  g_clear_object (&config_manager->initial_config);
+   meta_monitor_config_manager_clear_history (config_manager);
+ 
+   G_OBJECT_CLASS (meta_monitor_config_manager_parent_class)->dispose (object);
+ }
+ 
+ static void
+ meta_monitor_config_manager_init (MetaMonitorConfigManager *config_manager)
+ {
+   g_queue_init (&config_manager->config_history);
+ }
+ 
+ static void
+ meta_monitor_config_manager_class_init (MetaMonitorConfigManagerClass *klass)
+ {
+   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ 
+   object_class->dispose = meta_monitor_config_manager_dispose;
+ }
+ 
+ void
+ meta_monitor_config_free (MetaMonitorConfig *monitor_config)
+ {
+   meta_monitor_spec_free (monitor_config->monitor_spec);
+   g_free (monitor_config->mode_spec);
+   g_free (monitor_config);
+ }
+ 
+ void
+ meta_logical_monitor_config_free (MetaLogicalMonitorConfig *logical_monitor_config)
+ {
+diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h
+index c36df38e6..29ef8f8ce 100644
+--- a/src/backends/meta-monitor-config-manager.h
++++ b/src/backends/meta-monitor-config-manager.h
+@@ -60,61 +60,61 @@ typedef enum _MetaMonitorsConfigFlag
+ struct _MetaMonitorsConfig
+ {
+   GObject parent;
+ 
+   MetaMonitorsConfigKey *key;
+   GList *logical_monitor_configs;
+ 
+   GList *disabled_monitor_specs;
+ 
+   MetaMonitorsConfigFlag flags;
+ 
+   MetaLogicalMonitorLayoutMode layout_mode;
+ };
+ 
+ #define META_TYPE_MONITORS_CONFIG (meta_monitors_config_get_type ())
+ G_DECLARE_FINAL_TYPE (MetaMonitorsConfig, meta_monitors_config,
+                       META, MONITORS_CONFIG, GObject)
+ 
+ MetaMonitorConfigManager * meta_monitor_config_manager_new (MetaMonitorManager *monitor_manager);
+ 
+ MetaMonitorConfigStore * meta_monitor_config_manager_get_store (MetaMonitorConfigManager *config_manager);
+ 
+ gboolean meta_monitor_config_manager_assign (MetaMonitorManager *manager,
+                                              MetaMonitorsConfig *config,
+                                              GPtrArray         **crtc_infos,
+                                              GPtrArray         **output_infos,
+                                              GError            **error);
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_get_stored (MetaMonitorConfigManager *config_manager);
+ 
+-MetaMonitorsConfig * meta_monitor_config_manager_create_current (MetaMonitorConfigManager *config_manager);
++MetaMonitorsConfig * meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_manager);
+ MetaMonitorsConfig * meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager);
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_create_fallback (MetaMonitorConfigManager *config_manager);
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_manager);
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_create_for_orientation (MetaMonitorConfigManager *config_manager,
+                                                                          MetaMonitorTransform      transform);
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_create_for_rotate_monitor (MetaMonitorConfigManager *config_manager);
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_create_for_switch_config (MetaMonitorConfigManager    *config_manager,
+                                                                            MetaMonitorSwitchConfigType  config_type);
+ 
+ void meta_monitor_config_manager_set_current (MetaMonitorConfigManager *config_manager,
+                                               MetaMonitorsConfig       *config);
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_get_current (MetaMonitorConfigManager *config_manager);
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_pop_previous (MetaMonitorConfigManager *config_manager);
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_get_previous (MetaMonitorConfigManager *config_manager);
+ 
+ void meta_monitor_config_manager_clear_history (MetaMonitorConfigManager *config_manager);
+ 
+ void meta_monitor_config_manager_save_current (MetaMonitorConfigManager *config_manager);
+ 
+ MetaMonitorsConfig * meta_monitors_config_new_full (GList                        *logical_monitor_configs,
+                                                     GList                        *disabled_monitors,
+                                                     MetaLogicalMonitorLayoutMode  layout_mode,
+diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c
+index 4503eb841..f7ada0136 100644
+--- a/src/backends/meta-monitor-manager.c
++++ b/src/backends/meta-monitor-manager.c
+@@ -469,73 +469,87 @@ meta_monitor_manager_apply_monitors_config (MetaMonitorManager      *manager,
+ 
+   return TRUE;
+ }
+ 
+ gboolean
+ meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
+ {
+   GList *l;
+ 
+   for (l = manager->gpus; l; l = l->next)
+     {
+       MetaGpu *gpu = l->data;
+ 
+       if (meta_gpu_has_hotplug_mode_update (gpu))
+         return TRUE;
+     }
+ 
+   return FALSE;
+ }
+ 
+ static gboolean
+ should_use_stored_config (MetaMonitorManager *manager)
+ {
+   return (manager->in_init ||
+           !meta_monitor_manager_has_hotplug_mode_update (manager));
+ }
+ 
+ MetaMonitorsConfig *
+ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
+ {
++  g_autoptr (MetaMonitorsConfig) initial_config = NULL;
+   MetaMonitorsConfig *config = NULL;
+   GError *error = NULL;
+   gboolean use_stored_config;
++  MetaMonitorsConfigKey *current_state_key;
+   MetaMonitorsConfigMethod method;
+   MetaMonitorsConfigMethod fallback_method =
+     META_MONITORS_CONFIG_METHOD_TEMPORARY;
+ 
+   use_stored_config = should_use_stored_config (manager);
+   if (use_stored_config)
+     method = META_MONITORS_CONFIG_METHOD_PERSISTENT;
+   else
+     method = META_MONITORS_CONFIG_METHOD_TEMPORARY;
+ 
++  initial_config = meta_monitor_config_manager_create_initial (manager->config_manager);
++
++  if (initial_config)
++    {
++      current_state_key = meta_create_monitors_config_key_for_current_state (manager);
++
++      /* don't ever reuse initial configuration, if the monitor topology changed
++       */
++      if (current_state_key && !meta_monitors_config_key_equal (current_state_key, initial_config->key))
++        g_clear_object (&initial_config);
++    }
++
+   if (use_stored_config)
+     {
+       config = meta_monitor_config_manager_get_stored (manager->config_manager);
+       if (config)
+         {
+           if (!meta_monitor_manager_apply_monitors_config (manager,
+                                                            config,
+                                                            method,
+                                                            &error))
+             {
+               config = NULL;
+               g_warning ("Failed to use stored monitor configuration: %s",
+                          error->message);
+               g_clear_error (&error);
+             }
+           else
+             {
+               g_object_ref (config);
+               goto done;
+             }
+         }
+     }
+ 
+   config = meta_monitor_config_manager_create_suggested (manager->config_manager);
+   if (config)
+     {
+       if (!meta_monitor_manager_apply_monitors_config (manager,
+                                                        config,
+                                                        method,
+                                                        &error))
+@@ -549,61 +563,61 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
+         {
+           goto done;
+         }
+     }
+ 
+   config = meta_monitor_config_manager_get_previous (manager->config_manager);
+   if (config)
+     {
+       config = g_object_ref (config);
+ 
+       if (meta_monitor_manager_is_config_complete (manager, config))
+         {
+           if (!meta_monitor_manager_apply_monitors_config (manager,
+                                                            config,
+                                                            method,
+                                                            &error))
+             {
+               g_warning ("Failed to use suggested monitor configuration: %s",
+                          error->message);
+               g_clear_error (&error);
+             }
+           else
+             {
+               goto done;
+             }
+         }
+ 
+       g_clear_object (&config);
+     }
+ 
+-  config = meta_monitor_config_manager_create_current (manager->config_manager);
++  config = g_steal_pointer (&initial_config);
+   if (config)
+     {
+       if (!meta_monitor_manager_apply_monitors_config (manager,
+                                                        config,
+                                                        method,
+                                                        &error))
+         {
+           g_clear_object (&config);
+           g_warning ("Failed to use current monitor configuration: %s",
+                      error->message);
+           g_clear_error (&error);
+         }
+       else
+         {
+           goto done;
+         }
+     }
+ 
+   config = meta_monitor_config_manager_create_linear (manager->config_manager);
+   if (config)
+     {
+       if (!meta_monitor_manager_apply_monitors_config (manager,
+                                                        config,
+                                                        method,
+                                                        &error))
+         {
+           g_clear_object (&config);
+           g_warning ("Failed to use linear monitor configuration: %s",
+                      error->message);
+           g_clear_error (&error);
+-- 
+2.17.1
+
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..857ab93
--- /dev/null
+++ b/SOURCES/0001-monitor-manager-xrandr-Force-an-update-when-resuming.patch
@@ -0,0 +1,776 @@
+From 100795c2729305f919ff9611c877ea3e74d528b7 Mon Sep 17 00:00:00 2001
+From: Rui Matos <tiagomatos@gmail.com>
+Date: Mon, 4 Jun 2018 16:35:04 -0400
+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/meta-gpu.c                       |  7 ++
+ src/backends/meta-gpu.h                       |  2 +
+ src/backends/x11/meta-gpu-xrandr.c            | 26 ++++-
+ .../x11/meta-monitor-manager-xrandr.c         | 96 +++++++++++++++++--
+ 4 files changed, 121 insertions(+), 10 deletions(-)
+
+diff --git a/src/backends/meta-gpu.c b/src/backends/meta-gpu.c
+index 3577391e5..946f72387 100644
+--- a/src/backends/meta-gpu.c
++++ b/src/backends/meta-gpu.c
+@@ -37,60 +37,67 @@ enum
+ static GParamSpec *obj_props[PROP_LAST];
+ 
+ typedef struct _MetaGpuPrivate
+ {
+   MetaMonitorManager *monitor_manager;
+ 
+   GList *outputs;
+   GList *crtcs;
+   GList *modes;
+ } MetaGpuPrivate;
+ 
+ G_DEFINE_TYPE_WITH_PRIVATE (MetaGpu, meta_gpu, G_TYPE_OBJECT)
+ 
+ gboolean
+ meta_gpu_has_hotplug_mode_update (MetaGpu *gpu)
+ {
+   MetaGpuPrivate *priv = meta_gpu_get_instance_private (gpu);
+   GList *l;
+ 
+   for (l = priv->outputs; l; l = l->next)
+     {
+       MetaOutput *output = l->data;
+ 
+       if (output->hotplug_mode_update)
+         return TRUE;
+     }
+ 
+   return FALSE;
+ }
+ 
++void
++meta_gpu_poll_hardware (MetaGpu *gpu)
++{
++  if (META_GPU_GET_CLASS (gpu)->poll_hardware)
++    META_GPU_GET_CLASS (gpu)->poll_hardware (gpu);
++}
++
+ gboolean
+ meta_gpu_read_current (MetaGpu  *gpu,
+                        GError  **error)
+ {
+   MetaGpuPrivate *priv = meta_gpu_get_instance_private (gpu);
+   gboolean ret;
+   GList *old_outputs;
+   GList *old_crtcs;
+   GList *old_modes;
+ 
+   /* TODO: Get rid of this when objects incref:s what they need instead */
+   old_outputs = priv->outputs;
+   old_crtcs = priv->crtcs;
+   old_modes = priv->modes;
+ 
+   ret = META_GPU_GET_CLASS (gpu)->read_current (gpu, error);
+ 
+   g_list_free_full (old_outputs, g_object_unref);
+   g_list_free_full (old_modes, g_object_unref);
+   g_list_free_full (old_crtcs, g_object_unref);
+ 
+   return ret;
+ }
+ 
+ MetaMonitorManager *
+ meta_gpu_get_monitor_manager (MetaGpu *gpu)
+ {
+   MetaGpuPrivate *priv = meta_gpu_get_instance_private (gpu);
+ 
+   return priv->monitor_manager;
+diff --git a/src/backends/meta-gpu.h b/src/backends/meta-gpu.h
+index 4badcbd26..3cec8e5b0 100644
+--- a/src/backends/meta-gpu.h
++++ b/src/backends/meta-gpu.h
+@@ -8,59 +8,61 @@
+  * published by the Free Software Foundation; either version 2 of the
+  * License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful, but
+  * WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+  * 02111-1307, USA.
+  */
+ 
+ #ifndef META_GPU_H
+ #define META_GPU_H
+ 
+ #include <glib-object.h>
+ 
+ #include "backends/meta-monitor-manager-private.h"
+ 
+ #define META_TYPE_GPU (meta_gpu_get_type ())
+ G_DECLARE_DERIVABLE_TYPE (MetaGpu, meta_gpu, META, GPU, GObject)
+ 
+ struct _MetaGpuClass
+ {
+   GObjectClass parent_class;
+ 
+   gboolean (* read_current) (MetaGpu  *gpu,
+                              GError  **error);
++  void     (* poll_hardware) (MetaGpu *gpu);
+ };
+ 
+ int meta_gpu_get_kms_fd (MetaGpu *gpu);
+ 
+ const char * meta_gpu_get_kms_file_path (MetaGpu *gpu);
+ 
++void meta_gpu_poll_hardware (MetaGpu *gpu);
+ gboolean meta_gpu_read_current (MetaGpu  *gpu,
+                                 GError  **error);
+ 
+ gboolean meta_gpu_has_hotplug_mode_update (MetaGpu *gpu);
+ 
+ MetaMonitorManager * meta_gpu_get_monitor_manager (MetaGpu *gpu);
+ 
+ GList * meta_gpu_get_outputs (MetaGpu *gpu);
+ 
+ GList * meta_gpu_get_crtcs (MetaGpu *gpu);
+ 
+ GList * meta_gpu_get_modes (MetaGpu *gpu);
+ 
+ void meta_gpu_take_outputs (MetaGpu *gpu,
+                             GList   *outputs);
+ 
+ void meta_gpu_take_crtcs (MetaGpu *gpu,
+                           GList   *crtcs);
+ 
+ void meta_gpu_take_modes (MetaGpu *gpu,
+                           GList   *modes);
+ 
+ #endif /* META_GPU_H */
+diff --git a/src/backends/x11/meta-gpu-xrandr.c b/src/backends/x11/meta-gpu-xrandr.c
+index 14b46d530..add80c0d2 100644
+--- a/src/backends/x11/meta-gpu-xrandr.c
++++ b/src/backends/x11/meta-gpu-xrandr.c
+@@ -17,97 +17,107 @@
+  * 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/>.
+  */
+ 
+ #include "config.h"
+ 
+ #include "backends/x11/meta-gpu-xrandr.h"
+ 
+ #include <string.h>
+ #include <X11/extensions/dpms.h>
+ #include <X11/Xlibint.h>
+ 
+ #include "backends/meta-output.h"
+ #include "backends/x11/meta-crtc-xrandr.h"
+ #include "backends/x11/meta-monitor-manager-xrandr.h"
+ #include "backends/x11/meta-output-xrandr.h"
+ 
+ struct _MetaGpuXrandr
+ {
+   MetaGpu parent;
+ 
+   XRRScreenResources *resources;
+ 
+   int max_screen_width;
+   int max_screen_height;
++
++  gboolean need_hardware_poll;
+ };
+ 
+ G_DEFINE_TYPE (MetaGpuXrandr, meta_gpu_xrandr, META_TYPE_GPU)
+ 
+ XRRScreenResources *
+ meta_gpu_xrandr_get_resources (MetaGpuXrandr *gpu_xrandr)
+ {
+   return gpu_xrandr->resources;
+ }
+ 
+ void
+ meta_gpu_xrandr_get_max_screen_size (MetaGpuXrandr *gpu_xrandr,
+                                      int           *max_width,
+                                      int           *max_height)
+ {
+   *max_width = gpu_xrandr->max_screen_width;
+   *max_height = gpu_xrandr->max_screen_height;
+ }
+ 
+ static int
+ compare_outputs (const void *one,
+                  const void *two)
+ {
+   const MetaOutput *o_one = one, *o_two = two;
+ 
+   return strcmp (o_one->name, o_two->name);
+ }
+ 
+ static char *
+ get_xmode_name (XRRModeInfo *xmode)
+ {
+   int width = xmode->width;
+   int height = xmode->height;
+ 
+   return g_strdup_printf ("%dx%d", width, height);
+ }
+ 
++static void
++meta_gpu_xrandr_poll_hardware (MetaGpu *gpu)
++{
++  MetaGpuXrandr *gpu_xrandr = META_GPU_XRANDR (gpu);
++
++  gpu_xrandr->need_hardware_poll = TRUE;
++}
++
+ static gboolean
+ meta_gpu_xrandr_read_current (MetaGpu  *gpu,
+                               GError  **error)
+ {
+   MetaGpuXrandr *gpu_xrandr = META_GPU_XRANDR (gpu);
+   MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
+   MetaMonitorManagerXrandr *monitor_manager_xrandr =
+     META_MONITOR_MANAGER_XRANDR (monitor_manager);
+   Display *xdisplay =
+     meta_monitor_manager_xrandr_get_xdisplay (monitor_manager_xrandr);
+   XRRScreenResources *resources;
+   RROutput primary_output;
+   unsigned int i, j;
+   GList *l;
+   int min_width, min_height;
+   Screen *screen;
+   BOOL dpms_capable, dpms_enabled;
+   CARD16 dpms_state;
+   GList *outputs = NULL;
+   GList *modes = NULL;
+   GList *crtcs = NULL;
+ 
+   if (gpu_xrandr->resources)
+     XRRFreeScreenResources (gpu_xrandr->resources);
+   gpu_xrandr->resources = NULL;
+ 
+   dpms_capable = DPMSCapable (xdisplay);
+ 
+   if (dpms_capable &&
+       DPMSInfo (xdisplay, &dpms_state, &dpms_enabled) &&
+@@ -121,62 +131,72 @@ meta_gpu_xrandr_read_current (MetaGpu  *gpu,
+         case DPMSModeStandby:
+           monitor_manager->power_save_mode = META_POWER_SAVE_STANDBY;
+           break;
+         case DPMSModeSuspend:
+           monitor_manager->power_save_mode = META_POWER_SAVE_SUSPEND;
+           break;
+         case DPMSModeOff:
+           monitor_manager->power_save_mode = META_POWER_SAVE_OFF;
+           break;
+         default:
+           monitor_manager->power_save_mode = META_POWER_SAVE_UNSUPPORTED;
+           break;
+         }
+     }
+   else
+     {
+       monitor_manager->power_save_mode = META_POWER_SAVE_UNSUPPORTED;
+     }
+ 
+   XRRGetScreenSizeRange (xdisplay, DefaultRootWindow (xdisplay),
+                          &min_width,
+                          &min_height,
+                          &gpu_xrandr->max_screen_width,
+                          &gpu_xrandr->max_screen_height);
+ 
+   screen = ScreenOfDisplay (xdisplay, DefaultScreen (xdisplay));
+   /* This is updated because we called XRRUpdateConfiguration. */
+   monitor_manager->screen_width = WidthOfScreen (screen);
+   monitor_manager->screen_height = HeightOfScreen (screen);
+ 
+-  resources = XRRGetScreenResourcesCurrent (xdisplay,
+-                                            DefaultRootWindow (xdisplay));
++  if (gpu_xrandr->need_hardware_poll)
++    {
++      resources = XRRGetScreenResources (xdisplay,
++                                         DefaultRootWindow (xdisplay));
++      gpu_xrandr->need_hardware_poll = FALSE;
++    }
++  else
++    {
++      resources = XRRGetScreenResourcesCurrent (xdisplay,
++                                                DefaultRootWindow (xdisplay));
++    }
++
+   if (!resources)
+     {
+       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                    "Failed to retrieve Xrandr screen resources");
+       return FALSE;
+     }
+ 
+   gpu_xrandr->resources = resources;
+ 
+   outputs = NULL;
+   modes = NULL;
+   crtcs = NULL;
+ 
+   for (i = 0; i < (unsigned)resources->nmode; i++)
+     {
+       XRRModeInfo *xmode = &resources->modes[i];
+       MetaCrtcMode *mode;
+ 
+       mode = g_object_new (META_TYPE_CRTC_MODE, NULL);
+ 
+       mode->mode_id = xmode->id;
+       mode->width = xmode->width;
+       mode->height = xmode->height;
+       mode->refresh_rate = (xmode->dotClock /
+                             ((float)xmode->hTotal * xmode->vTotal));
+       mode->flags = xmode->modeFlags;
+       mode->name = get_xmode_name (xmode);
+ 
+       modes = g_list_append (modes, mode);
+     }
+@@ -255,42 +275,44 @@ meta_gpu_xrandr_read_current (MetaGpu  *gpu,
+                 }
+             }
+         }
+     }
+ 
+   return TRUE;
+ }
+ 
+ MetaGpuXrandr *
+ meta_gpu_xrandr_new (MetaMonitorManagerXrandr *monitor_manager_xrandr)
+ {
+   return g_object_new (META_TYPE_GPU_XRANDR,
+                        "monitor-manager", monitor_manager_xrandr,
+                        NULL);
+ }
+ 
+ static void
+ meta_gpu_xrandr_finalize (GObject *object)
+ {
+   MetaGpuXrandr *gpu_xrandr = META_GPU_XRANDR (object);
+ 
+   g_clear_pointer (&gpu_xrandr->resources,
+                    XRRFreeScreenResources);
+ 
+   G_OBJECT_CLASS (meta_gpu_xrandr_parent_class)->finalize (object);
+ }
+ 
+ static void
+ meta_gpu_xrandr_init (MetaGpuXrandr *gpu_xrandr)
+ {
++  gpu_xrandr->need_hardware_poll = TRUE;
+ }
+ 
+ static void
+ meta_gpu_xrandr_class_init (MetaGpuXrandrClass *klass)
+ {
+   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+   MetaGpuClass *gpu_class = META_GPU_CLASS (klass);
+ 
+   object_class->finalize = meta_gpu_xrandr_finalize;
+ 
+   gpu_class->read_current = meta_gpu_xrandr_read_current;
++  gpu_class->poll_hardware = meta_gpu_xrandr_poll_hardware;
+ }
+diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
+index 90a3952db..2d9a32339 100644
+--- a/src/backends/x11/meta-monitor-manager-xrandr.c
++++ b/src/backends/x11/meta-monitor-manager-xrandr.c
+@@ -33,95 +33,101 @@
+ #include <clutter/clutter.h>
+ 
+ #include <X11/Xlibint.h>
+ #include <X11/extensions/dpms.h>
+ #include <X11/Xlib-xcb.h>
+ #include <xcb/randr.h>
+ 
+ #include "meta-backend-x11.h"
+ #include <meta/main.h>
+ #include <meta/errors.h>
+ #include "backends/meta-crtc.h"
+ #include "backends/meta-monitor-config-manager.h"
+ #include "backends/meta-logical-monitor.h"
+ #include "backends/meta-output.h"
+ #include "backends/x11/meta-crtc-xrandr.h"
+ #include "backends/x11/meta-gpu-xrandr.h"
+ #include "backends/x11/meta-output-xrandr.h"
+ 
+ /* Look for DPI_FALLBACK in:
+  * http://git.gnome.org/browse/gnome-settings-daemon/tree/plugins/xsettings/gsd-xsettings-manager.c
+  * for the reasoning */
+ #define DPI_FALLBACK 96.0
+ 
+ struct _MetaMonitorManagerXrandr
+ {
+   MetaMonitorManager parent_instance;
+ 
+   Display *xdisplay;
+   int rr_event_base;
+   int rr_error_base;
++
++  guint logind_watch_id;
++  guint logind_signal_sub_id;
++
+   gboolean has_randr15;
+ 
+   /*
+    * The X server deals with multiple GPUs for us, soe just see what the X
+    * server gives us as one single GPU, even though it may actually be backed
+    * by multiple.
+    */
+   MetaGpu *gpu;
+ 
+   xcb_timestamp_t last_xrandr_set_timestamp;
+ 
+ #ifdef HAVE_XRANDR15
+   GHashTable *tiled_monitor_atoms;
+ #endif /* HAVE_XRANDR15 */
+ 
+   float *supported_scales;
+   int n_supported_scales;
+ };
+ 
+ struct _MetaMonitorManagerXrandrClass
+ {
+   MetaMonitorManagerClass parent_class;
+ };
+ 
+ G_DEFINE_TYPE (MetaMonitorManagerXrandr, meta_monitor_manager_xrandr, META_TYPE_MONITOR_MANAGER);
+ 
+ #ifdef HAVE_XRANDR15
+ typedef struct _MetaMonitorXrandrData
+ {
+   Atom xrandr_name;
+ } MetaMonitorXrandrData;
+ 
+ GQuark quark_meta_monitor_xrandr_data;
+ #endif /* HAVE_RANDR15 */
+ 
++static void meta_monitor_manager_xrandr_update (MetaMonitorManagerXrandr *manager_xrandr);
++
+ Display *
+ meta_monitor_manager_xrandr_get_xdisplay (MetaMonitorManagerXrandr *manager_xrandr)
+ {
+   return manager_xrandr->xdisplay;
+ }
+ 
+ gboolean
+ meta_monitor_manager_xrandr_has_randr15 (MetaMonitorManagerXrandr *manager_xrandr)
+ {
+   return manager_xrandr->has_randr15;
+ }
+ 
+ static GBytes *
+ meta_monitor_manager_xrandr_read_edid (MetaMonitorManager *manager,
+                                        MetaOutput         *output)
+ {
+   return meta_output_xrandr_read_edid (output);
+ }
+ 
+ static void
+ meta_monitor_manager_xrandr_set_power_save_mode (MetaMonitorManager *manager,
+ 						 MetaPowerSave       mode)
+ {
+   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
+   CARD16 state;
+ 
+   switch (mode) {
+   case META_POWER_SAVE_ON:
+     state = DPMSModeOn;
+     break;
+@@ -934,198 +940,272 @@ meta_monitor_manager_xrandr_calculate_supported_scales (MetaMonitorManager
+                    manager_xrandr->n_supported_scales * sizeof (float));
+ }
+ 
+ static MetaMonitorManagerCapability
+ meta_monitor_manager_xrandr_get_capabilities (MetaMonitorManager *manager)
+ {
+   return (META_MONITOR_MANAGER_CAPABILITY_MIRRORING |
+           META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
+ }
+ 
+ static gboolean
+ meta_monitor_manager_xrandr_get_max_screen_size (MetaMonitorManager *manager,
+                                                  int                *max_width,
+                                                  int                *max_height)
+ {
+   MetaMonitorManagerXrandr *manager_xrandr =
+     META_MONITOR_MANAGER_XRANDR (manager);
+ 
+   meta_gpu_xrandr_get_max_screen_size (META_GPU_XRANDR (manager_xrandr->gpu),
+                                        max_width, max_height);
+ 
+   return TRUE;
+ }
+ 
+ static MetaLogicalMonitorLayoutMode
+ meta_monitor_manager_xrandr_get_default_layout_mode (MetaMonitorManager *manager)
+ {
+   return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
+ }
+ 
++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)
++    {
++      meta_gpu_poll_hardware (manager_xrandr->gpu);
++      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_constructed (GObject *object)
+ {
+   MetaMonitorManagerXrandr *manager_xrandr =
+     META_MONITOR_MANAGER_XRANDR (object);
+   MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
+   MetaBackendX11 *backend =
+     META_BACKEND_X11 (meta_monitor_manager_get_backend (manager));
+ 
+   manager_xrandr->xdisplay = meta_backend_x11_get_xdisplay (backend);
+ 
+   manager_xrandr->gpu = META_GPU (meta_gpu_xrandr_new (manager_xrandr));
+   meta_monitor_manager_add_gpu (manager, manager_xrandr->gpu);
+ 
+   if (!XRRQueryExtension (manager_xrandr->xdisplay,
+ 			  &manager_xrandr->rr_event_base,
+ 			  &manager_xrandr->rr_error_base))
+     {
+       return;
+     }
+   else
+     {
+       int major_version, minor_version;
+       /* We only use ScreenChangeNotify, but GDK uses the others,
+ 	 and we don't want to step on its toes */
+       XRRSelectInput (manager_xrandr->xdisplay,
+ 		      DefaultRootWindow (manager_xrandr->xdisplay),
+ 		      RRScreenChangeNotifyMask
+ 		      | RRCrtcChangeNotifyMask
+ 		      | RROutputPropertyNotifyMask);
+ 
+       manager_xrandr->has_randr15 = FALSE;
+       XRRQueryVersion (manager_xrandr->xdisplay, &major_version,
+                        &minor_version);
+ #ifdef HAVE_XRANDR15
+       if (major_version > 1 ||
+           (major_version == 1 &&
+            minor_version >= 5))
+         {
+           manager_xrandr->has_randr15 = TRUE;
+           manager_xrandr->tiled_monitor_atoms = g_hash_table_new (NULL, NULL);
+         }
+       meta_monitor_manager_xrandr_init_monitors (manager_xrandr);
+ #endif
+     }
+ 
+   G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->constructed (object);
+ }
+ 
+ static void
+ meta_monitor_manager_xrandr_finalize (GObject *object)
+ {
+   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (object);
+ 
+   g_clear_object (&manager_xrandr->gpu);
+   g_hash_table_destroy (manager_xrandr->tiled_monitor_atoms);
+   g_free (manager_xrandr->supported_scales);
+ 
++  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);
+ }
+ 
+ static void
+ meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
+ {
++  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);
+ }
+ 
+ static void
+ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass)
+ {
+   MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
+   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ 
+   object_class->finalize = meta_monitor_manager_xrandr_finalize;
+   object_class->constructed = meta_monitor_manager_xrandr_constructed;
+ 
+   manager_class->read_edid = meta_monitor_manager_xrandr_read_edid;
+   manager_class->ensure_initial_config = meta_monitor_manager_xrandr_ensure_initial_config;
+   manager_class->apply_monitors_config = meta_monitor_manager_xrandr_apply_monitors_config;
+   manager_class->set_power_save_mode = meta_monitor_manager_xrandr_set_power_save_mode;
+   manager_class->change_backlight = meta_monitor_manager_xrandr_change_backlight;
+   manager_class->get_crtc_gamma = meta_monitor_manager_xrandr_get_crtc_gamma;
+   manager_class->set_crtc_gamma = meta_monitor_manager_xrandr_set_crtc_gamma;
+ #ifdef HAVE_XRANDR15
+   manager_class->tiled_monitor_added = meta_monitor_manager_xrandr_tiled_monitor_added;
+   manager_class->tiled_monitor_removed = meta_monitor_manager_xrandr_tiled_monitor_removed;
+ #endif
+   manager_class->is_transform_handled = meta_monitor_manager_xrandr_is_transform_handled;
+   manager_class->calculate_monitor_mode_scale = meta_monitor_manager_xrandr_calculate_monitor_mode_scale;
+   manager_class->calculate_supported_scales = meta_monitor_manager_xrandr_calculate_supported_scales;
+   manager_class->get_capabilities = meta_monitor_manager_xrandr_get_capabilities;
+   manager_class->get_max_screen_size = meta_monitor_manager_xrandr_get_max_screen_size;
+   manager_class->get_default_layout_mode = meta_monitor_manager_xrandr_get_default_layout_mode;
+ 
+   quark_meta_monitor_xrandr_data =
+     g_quark_from_static_string ("-meta-monitor-xrandr-data");
+ }
+ 
+ static gboolean
+ is_xvnc (MetaMonitorManager *manager)
+ {
+   MetaMonitorManagerXrandr *manager_xrandr =
+     META_MONITOR_MANAGER_XRANDR (manager);
+   GList *l;
+ 
+   for (l = meta_gpu_get_outputs (manager_xrandr->gpu); l; l = l->next)
+     {
+       MetaOutput *output = l->data;
+ 
+       if (g_str_has_prefix (output->name, "VNC-"))
+         return TRUE;
+     }
+ 
+   return FALSE;
+ }
+ 
+-gboolean
+-meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr,
+-					   XEvent                   *event)
++static void
++meta_monitor_manager_xrandr_update (MetaMonitorManagerXrandr *manager_xrandr)
+ {
+   MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
+   MetaGpuXrandr *gpu_xrandr;
+   XRRScreenResources *resources;
+   gboolean is_hotplug;
+   gboolean is_our_configuration;
+   unsigned int timestamp;
+ 
+-  if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
+-    return FALSE;
+-
+-  XRRUpdateConfiguration (event);
+-
+   meta_monitor_manager_read_current_state (manager);
+ 
+   gpu_xrandr = META_GPU_XRANDR (manager_xrandr->gpu);
+   resources = meta_gpu_xrandr_get_resources (gpu_xrandr);
+ 
+   timestamp = resources->timestamp;
+   if (is_xvnc (manager))
+     timestamp += 100;
+ 
+   is_hotplug = timestamp < resources->configTimestamp;
+   is_our_configuration = (resources->timestamp ==
+                           manager_xrandr->last_xrandr_set_timestamp);
+   if (is_hotplug)
+     {
+       meta_monitor_manager_on_hotplug (manager);
+     }
+   else
+     {
+       MetaMonitorsConfig *config;
+ 
+       if (is_our_configuration)
+         {
+           MetaMonitorConfigManager *config_manager =
+             meta_monitor_manager_get_config_manager (manager);
+ 
+           config = meta_monitor_config_manager_get_current (config_manager);
+         }
+       else
+         {
+           config = NULL;
+         }
+ 
+       meta_monitor_manager_xrandr_rebuild_derived (manager, config);
+     }
++}
++
++gboolean
++meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr,
++					   XEvent                   *event)
++{
++
++  if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
++    return FALSE;
++
++  XRRUpdateConfiguration (event);
++
++  meta_monitor_manager_xrandr_update (manager_xrandr);
+ 
+   return TRUE;
+ }
+-- 
+2.17.1
+
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..ff9cd9f
--- /dev/null
+++ b/SOURCES/0001-monitor-manager-xrandr-Work-around-spurious-hotplugs.patch
@@ -0,0 +1,67 @@
+From ad61347e9d92380fbbb4effd8a19349777d76715 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.
+---
+ .../x11/meta-monitor-manager-xrandr.c         | 25 ++++++++++++++++++-
+ 1 file changed, 24 insertions(+), 1 deletion(-)
+
+diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
+index dbe3e4e3b..90a3952db 100644
+--- a/src/backends/x11/meta-monitor-manager-xrandr.c
++++ b/src/backends/x11/meta-monitor-manager-xrandr.c
+@@ -1058,6 +1058,24 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass)
+     g_quark_from_static_string ("-meta-monitor-xrandr-data");
+ }
+ 
++static gboolean
++is_xvnc (MetaMonitorManager *manager)
++{
++  MetaMonitorManagerXrandr *manager_xrandr =
++    META_MONITOR_MANAGER_XRANDR (manager);
++  GList *l;
++
++  for (l = meta_gpu_get_outputs (manager_xrandr->gpu); l; l = l->next)
++    {
++      MetaOutput *output = l->data;
++
++      if (g_str_has_prefix (output->name, "VNC-"))
++        return TRUE;
++    }
++
++  return FALSE;
++}
++
+ gboolean
+ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr,
+ 					   XEvent                   *event)
+@@ -1067,6 +1085,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
+   XRRScreenResources *resources;
+   gboolean is_hotplug;
+   gboolean is_our_configuration;
++  unsigned int timestamp;
+ 
+   if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
+     return FALSE;
+@@ -1078,7 +1097,11 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
+   gpu_xrandr = META_GPU_XRANDR (manager_xrandr->gpu);
+   resources = meta_gpu_xrandr_get_resources (gpu_xrandr);
+ 
+-  is_hotplug = resources->timestamp < resources->configTimestamp;
++  timestamp = resources->timestamp;
++  if (is_xvnc (manager))
++    timestamp += 100;
++
++  is_hotplug = timestamp < resources->configTimestamp;
+   is_our_configuration = (resources->timestamp ==
+                           manager_xrandr->last_xrandr_set_timestamp);
+   if (is_hotplug)
+-- 
+2.17.0
+
diff --git a/SOURCES/0001-renderer-native-Check-calculated-transform-when-crea.patch b/SOURCES/0001-renderer-native-Check-calculated-transform-when-crea.patch
new file mode 100644
index 0000000..1079d4c
--- /dev/null
+++ b/SOURCES/0001-renderer-native-Check-calculated-transform-when-crea.patch
@@ -0,0 +1,88 @@
+From 91c5c94434b22895f97b3ae47a889ccb902b86aa Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Mon, 23 Jul 2018 21:36:57 +0200
+Subject: [PATCH] renderer/native: Check calculated transform when creating
+ view
+
+The "backends: Move MetaOutput::crtc field into private struct"
+accidentally changed the view transform calculation code to assume that
+"MetaCrtc::transform" corresponds to the transform of the CRTC; so is
+not the case yet; one must calculate the transform from the logical
+monitor, and check whether it is supported by the CRTC using
+meta_monitor_manager_is_transform_handled(). This commit restores the
+old behaviour that doesn't use MetaCrtc::transform when calculating the
+view transform.
+
+Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/216
+---
+ src/backends/native/meta-renderer-native.c         | 9 +++++++--
+ src/backends/x11/nested/meta-renderer-x11-nested.c | 8 ++++++--
+ 2 files changed, 13 insertions(+), 4 deletions(-)
+
+diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
+index fc6b223026..8dc0da7104 100644
+--- a/src/backends/native/meta-renderer-native.c
++++ b/src/backends/native/meta-renderer-native.c
+@@ -2720,9 +2720,14 @@ calculate_view_transform (MetaMonitorManager *monitor_manager,
+   MetaMonitor *main_monitor;
+   MetaOutput *main_output;
+   MetaCrtc *crtc;
++  MetaMonitorTransform crtc_transform;
++
+   main_monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
+   main_output = meta_monitor_get_main_output (main_monitor);
+   crtc = meta_output_get_assigned_crtc (main_output);
++  crtc_transform =
++    meta_monitor_logical_to_crtc_transform (main_monitor,
++                                            logical_monitor->transform);
+ 
+   /*
+    * Pick any monitor and output and check; all CRTCs of a logical monitor will
+@@ -2731,10 +2736,10 @@ calculate_view_transform (MetaMonitorManager *monitor_manager,
+ 
+   if (meta_monitor_manager_is_transform_handled (monitor_manager,
+                                                  crtc,
+-                                                 crtc->transform))
++                                                 crtc_transform))
+     return META_MONITOR_TRANSFORM_NORMAL;
+   else
+-    return crtc->transform;
++    return crtc_transform;
+ }
+ 
+ static MetaRendererView *
+diff --git a/src/backends/x11/nested/meta-renderer-x11-nested.c b/src/backends/x11/nested/meta-renderer-x11-nested.c
+index 8fdf46b0b5..b29b9c69e2 100644
+--- a/src/backends/x11/nested/meta-renderer-x11-nested.c
++++ b/src/backends/x11/nested/meta-renderer-x11-nested.c
+@@ -51,10 +51,14 @@ calculate_view_transform (MetaMonitorManager *monitor_manager,
+   MetaMonitor *main_monitor;
+   MetaOutput *main_output;
+   MetaCrtc *crtc;
++  MetaMonitorTransform crtc_transform;
+ 
+   main_monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
+   main_output = meta_monitor_get_main_output (main_monitor);
+   crtc = meta_output_get_assigned_crtc (main_output);
++  crtc_transform =
++    meta_monitor_logical_to_crtc_transform (main_monitor,
++                                            logical_monitor->transform);
+   /*
+    * Pick any monitor and output and check; all CRTCs of a logical monitor will
+    * always have the same transform assigned to them.
+@@ -62,10 +66,10 @@ calculate_view_transform (MetaMonitorManager *monitor_manager,
+ 
+   if (meta_monitor_manager_is_transform_handled (monitor_manager,
+                                                  crtc,
+-                                                 crtc->transform))
++                                                 crtc_transform))
+     return META_MONITOR_TRANSFORM_NORMAL;
+   else
+-    return crtc->transform;
++    return crtc_transform;
+ }
+ 
+ static MetaRendererView *
+-- 
+2.17.1
+
diff --git a/SOURCES/0001-rhel7-Fix-build-for-el7.patch b/SOURCES/0001-rhel7-Fix-build-for-el7.patch
new file mode 100644
index 0000000..5b9ac0f
--- /dev/null
+++ b/SOURCES/0001-rhel7-Fix-build-for-el7.patch
@@ -0,0 +1,898 @@
+From 6be34265a67e9ca1e30fe42993d5743b01d3b010 Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Fri, 15 Sep 2017 08:55:44 +0100
+Subject: [PATCH] rhel7: Fix build for el7
+
+---
+ .../evdev/clutter-virtual-input-device-evdev.c     |   1 +
+ clutter/clutter/evdev/linux/input-event-codes.h    | 838 +++++++++++++++++++++
+ src/backends/native/meta-input-settings-native.c   |   2 +-
+ src/wayland/meta-wayland-tablet-tool.c             |   2 +-
+ 4 files changed, 841 insertions(+), 2 deletions(-)
+ create mode 100644 clutter/clutter/evdev/linux/input-event-codes.h
+
+diff --git a/clutter/clutter/evdev/clutter-virtual-input-device-evdev.c b/clutter/clutter/evdev/clutter-virtual-input-device-evdev.c
+index e487708..8443c0a 100644
+--- a/clutter/clutter/evdev/clutter-virtual-input-device-evdev.c
++++ b/clutter/clutter/evdev/clutter-virtual-input-device-evdev.c
+@@ -33,6 +33,7 @@
+ #include "evdev/clutter-input-device-evdev.h"
+ #include "evdev/clutter-seat-evdev.h"
+ #include "evdev/clutter-virtual-input-device-evdev.h"
++#include "evdev/linux/input-event-codes.h"
+ 
+ enum
+ {
+diff --git a/clutter/clutter/evdev/linux/input-event-codes.h b/clutter/clutter/evdev/linux/input-event-codes.h
+new file mode 100644
+index 0000000..e2b5c75
+--- /dev/null
++++ b/clutter/clutter/evdev/linux/input-event-codes.h
+@@ -0,0 +1,838 @@
++/*
++ * Input event codes
++ *
++ *    *** IMPORTANT ***
++ * This file is not only included from C-code but also from devicetree source
++ * files. As such this file MUST only contain comments and defines.
++ *
++ * Copyright (c) 1999-2002 Vojtech Pavlik
++ * Copyright (c) 2015 Hans de Goede <hdegoede@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation.
++ */
++#ifndef _INPUT_EVENT_CODES_H
++#define _INPUT_EVENT_CODES_H
++
++/*
++ * Device properties and quirks
++ */
++
++#define INPUT_PROP_POINTER		0x00	/* needs a pointer */
++#define INPUT_PROP_DIRECT		0x01	/* direct input devices */
++#define INPUT_PROP_BUTTONPAD		0x02	/* has button(s) under pad */
++#define INPUT_PROP_SEMI_MT		0x03	/* touch rectangle only */
++#define INPUT_PROP_TOPBUTTONPAD		0x04	/* softbuttons at top of pad */
++#define INPUT_PROP_POINTING_STICK	0x05	/* is a pointing stick */
++#define INPUT_PROP_ACCELEROMETER	0x06	/* has accelerometer */
++
++#define INPUT_PROP_MAX			0x1f
++#define INPUT_PROP_CNT			(INPUT_PROP_MAX + 1)
++
++/*
++ * Event types
++ */
++
++#define EV_SYN			0x00
++#define EV_KEY			0x01
++#define EV_REL			0x02
++#define EV_ABS			0x03
++#define EV_MSC			0x04
++#define EV_SW			0x05
++#define EV_LED			0x11
++#define EV_SND			0x12
++#define EV_REP			0x14
++#define EV_FF			0x15
++#define EV_PWR			0x16
++#define EV_FF_STATUS		0x17
++#define EV_MAX			0x1f
++#define EV_CNT			(EV_MAX+1)
++
++/*
++ * Synchronization events.
++ */
++
++#define SYN_REPORT		0
++#define SYN_CONFIG		1
++#define SYN_MT_REPORT		2
++#define SYN_DROPPED		3
++#define SYN_MAX			0xf
++#define SYN_CNT			(SYN_MAX+1)
++
++/*
++ * Keys and buttons
++ *
++ * Most of the keys/buttons are modeled after USB HUT 1.12
++ * (see http://www.usb.org/developers/hidpage).
++ * Abbreviations in the comments:
++ * AC - Application Control
++ * AL - Application Launch Button
++ * SC - System Control
++ */
++
++#define KEY_RESERVED		0
++#define KEY_ESC			1
++#define KEY_1			2
++#define KEY_2			3
++#define KEY_3			4
++#define KEY_4			5
++#define KEY_5			6
++#define KEY_6			7
++#define KEY_7			8
++#define KEY_8			9
++#define KEY_9			10
++#define KEY_0			11
++#define KEY_MINUS		12
++#define KEY_EQUAL		13
++#define KEY_BACKSPACE		14
++#define KEY_TAB			15
++#define KEY_Q			16
++#define KEY_W			17
++#define KEY_E			18
++#define KEY_R			19
++#define KEY_T			20
++#define KEY_Y			21
++#define KEY_U			22
++#define KEY_I			23
++#define KEY_O			24
++#define KEY_P			25
++#define KEY_LEFTBRACE		26
++#define KEY_RIGHTBRACE		27
++#define KEY_ENTER		28
++#define KEY_LEFTCTRL		29
++#define KEY_A			30
++#define KEY_S			31
++#define KEY_D			32
++#define KEY_F			33
++#define KEY_G			34
++#define KEY_H			35
++#define KEY_J			36
++#define KEY_K			37
++#define KEY_L			38
++#define KEY_SEMICOLON		39
++#define KEY_APOSTROPHE		40
++#define KEY_GRAVE		41
++#define KEY_LEFTSHIFT		42
++#define KEY_BACKSLASH		43
++#define KEY_Z			44
++#define KEY_X			45
++#define KEY_C			46
++#define KEY_V			47
++#define KEY_B			48
++#define KEY_N			49
++#define KEY_M			50
++#define KEY_COMMA		51
++#define KEY_DOT			52
++#define KEY_SLASH		53
++#define KEY_RIGHTSHIFT		54
++#define KEY_KPASTERISK		55
++#define KEY_LEFTALT		56
++#define KEY_SPACE		57
++#define KEY_CAPSLOCK		58
++#define KEY_F1			59
++#define KEY_F2			60
++#define KEY_F3			61
++#define KEY_F4			62
++#define KEY_F5			63
++#define KEY_F6			64
++#define KEY_F7			65
++#define KEY_F8			66
++#define KEY_F9			67
++#define KEY_F10			68
++#define KEY_NUMLOCK		69
++#define KEY_SCROLLLOCK		70
++#define KEY_KP7			71
++#define KEY_KP8			72
++#define KEY_KP9			73
++#define KEY_KPMINUS		74
++#define KEY_KP4			75
++#define KEY_KP5			76
++#define KEY_KP6			77
++#define KEY_KPPLUS		78
++#define KEY_KP1			79
++#define KEY_KP2			80
++#define KEY_KP3			81
++#define KEY_KP0			82
++#define KEY_KPDOT		83
++
++#define KEY_ZENKAKUHANKAKU	85
++#define KEY_102ND		86
++#define KEY_F11			87
++#define KEY_F12			88
++#define KEY_RO			89
++#define KEY_KATAKANA		90
++#define KEY_HIRAGANA		91
++#define KEY_HENKAN		92
++#define KEY_KATAKANAHIRAGANA	93
++#define KEY_MUHENKAN		94
++#define KEY_KPJPCOMMA		95
++#define KEY_KPENTER		96
++#define KEY_RIGHTCTRL		97
++#define KEY_KPSLASH		98
++#define KEY_SYSRQ		99
++#define KEY_RIGHTALT		100
++#define KEY_LINEFEED		101
++#define KEY_HOME		102
++#define KEY_UP			103
++#define KEY_PAGEUP		104
++#define KEY_LEFT		105
++#define KEY_RIGHT		106
++#define KEY_END			107
++#define KEY_DOWN		108
++#define KEY_PAGEDOWN		109
++#define KEY_INSERT		110
++#define KEY_DELETE		111
++#define KEY_MACRO		112
++#define KEY_MUTE		113
++#define KEY_VOLUMEDOWN		114
++#define KEY_VOLUMEUP		115
++#define KEY_POWER		116	/* SC System Power Down */
++#define KEY_KPEQUAL		117
++#define KEY_KPPLUSMINUS		118
++#define KEY_PAUSE		119
++#define KEY_SCALE		120	/* AL Compiz Scale (Expose) */
++
++#define KEY_KPCOMMA		121
++#define KEY_HANGEUL		122
++#define KEY_HANGUEL		KEY_HANGEUL
++#define KEY_HANJA		123
++#define KEY_YEN			124
++#define KEY_LEFTMETA		125
++#define KEY_RIGHTMETA		126
++#define KEY_COMPOSE		127
++
++#define KEY_STOP		128	/* AC Stop */
++#define KEY_AGAIN		129
++#define KEY_PROPS		130	/* AC Properties */
++#define KEY_UNDO		131	/* AC Undo */
++#define KEY_FRONT		132
++#define KEY_COPY		133	/* AC Copy */
++#define KEY_OPEN		134	/* AC Open */
++#define KEY_PASTE		135	/* AC Paste */
++#define KEY_FIND		136	/* AC Search */
++#define KEY_CUT			137	/* AC Cut */
++#define KEY_HELP		138	/* AL Integrated Help Center */
++#define KEY_MENU		139	/* Menu (show menu) */
++#define KEY_CALC		140	/* AL Calculator */
++#define KEY_SETUP		141
++#define KEY_SLEEP		142	/* SC System Sleep */
++#define KEY_WAKEUP		143	/* System Wake Up */
++#define KEY_FILE		144	/* AL Local Machine Browser */
++#define KEY_SENDFILE		145
++#define KEY_DELETEFILE		146
++#define KEY_XFER		147
++#define KEY_PROG1		148
++#define KEY_PROG2		149
++#define KEY_WWW			150	/* AL Internet Browser */
++#define KEY_MSDOS		151
++#define KEY_COFFEE		152	/* AL Terminal Lock/Screensaver */
++#define KEY_SCREENLOCK		KEY_COFFEE
++#define KEY_ROTATE_DISPLAY	153	/* Display orientation for e.g. tablets */
++#define KEY_DIRECTION		KEY_ROTATE_DISPLAY
++#define KEY_CYCLEWINDOWS	154
++#define KEY_MAIL		155
++#define KEY_BOOKMARKS		156	/* AC Bookmarks */
++#define KEY_COMPUTER		157
++#define KEY_BACK		158	/* AC Back */
++#define KEY_FORWARD		159	/* AC Forward */
++#define KEY_CLOSECD		160
++#define KEY_EJECTCD		161
++#define KEY_EJECTCLOSECD	162
++#define KEY_NEXTSONG		163
++#define KEY_PLAYPAUSE		164
++#define KEY_PREVIOUSSONG	165
++#define KEY_STOPCD		166
++#define KEY_RECORD		167
++#define KEY_REWIND		168
++#define KEY_PHONE		169	/* Media Select Telephone */
++#define KEY_ISO			170
++#define KEY_CONFIG		171	/* AL Consumer Control Configuration */
++#define KEY_HOMEPAGE		172	/* AC Home */
++#define KEY_REFRESH		173	/* AC Refresh */
++#define KEY_EXIT		174	/* AC Exit */
++#define KEY_MOVE		175
++#define KEY_EDIT		176
++#define KEY_SCROLLUP		177
++#define KEY_SCROLLDOWN		178
++#define KEY_KPLEFTPAREN		179
++#define KEY_KPRIGHTPAREN	180
++#define KEY_NEW			181	/* AC New */
++#define KEY_REDO		182	/* AC Redo/Repeat */
++
++#define KEY_F13			183
++#define KEY_F14			184
++#define KEY_F15			185
++#define KEY_F16			186
++#define KEY_F17			187
++#define KEY_F18			188
++#define KEY_F19			189
++#define KEY_F20			190
++#define KEY_F21			191
++#define KEY_F22			192
++#define KEY_F23			193
++#define KEY_F24			194
++
++#define KEY_PLAYCD		200
++#define KEY_PAUSECD		201
++#define KEY_PROG3		202
++#define KEY_PROG4		203
++#define KEY_DASHBOARD		204	/* AL Dashboard */
++#define KEY_SUSPEND		205
++#define KEY_CLOSE		206	/* AC Close */
++#define KEY_PLAY		207
++#define KEY_FASTFORWARD		208
++#define KEY_BASSBOOST		209
++#define KEY_PRINT		210	/* AC Print */
++#define KEY_HP			211
++#define KEY_CAMERA		212
++#define KEY_SOUND		213
++#define KEY_QUESTION		214
++#define KEY_EMAIL		215
++#define KEY_CHAT		216
++#define KEY_SEARCH		217
++#define KEY_CONNECT		218
++#define KEY_FINANCE		219	/* AL Checkbook/Finance */
++#define KEY_SPORT		220
++#define KEY_SHOP		221
++#define KEY_ALTERASE		222
++#define KEY_CANCEL		223	/* AC Cancel */
++#define KEY_BRIGHTNESSDOWN	224
++#define KEY_BRIGHTNESSUP	225
++#define KEY_MEDIA		226
++
++#define KEY_SWITCHVIDEOMODE	227	/* Cycle between available video
++					   outputs (Monitor/LCD/TV-out/etc) */
++#define KEY_KBDILLUMTOGGLE	228
++#define KEY_KBDILLUMDOWN	229
++#define KEY_KBDILLUMUP		230
++
++#define KEY_SEND		231	/* AC Send */
++#define KEY_REPLY		232	/* AC Reply */
++#define KEY_FORWARDMAIL		233	/* AC Forward Msg */
++#define KEY_SAVE		234	/* AC Save */
++#define KEY_DOCUMENTS		235
++
++#define KEY_BATTERY		236
++
++#define KEY_BLUETOOTH		237
++#define KEY_WLAN		238
++#define KEY_UWB			239
++
++#define KEY_UNKNOWN		240
++
++#define KEY_VIDEO_NEXT		241	/* drive next video source */
++#define KEY_VIDEO_PREV		242	/* drive previous video source */
++#define KEY_BRIGHTNESS_CYCLE	243	/* brightness up, after max is min */
++#define KEY_BRIGHTNESS_AUTO	244	/* Set Auto Brightness: manual
++					  brightness control is off,
++					  rely on ambient */
++#define KEY_BRIGHTNESS_ZERO	KEY_BRIGHTNESS_AUTO
++#define KEY_DISPLAY_OFF		245	/* display device to off state */
++
++#define KEY_WWAN		246	/* Wireless WAN (LTE, UMTS, GSM, etc.) */
++#define KEY_WIMAX		KEY_WWAN
++#define KEY_RFKILL		247	/* Key that controls all radios */
++
++#define KEY_MICMUTE		248	/* Mute / unmute the microphone */
++
++/* Code 255 is reserved for special needs of AT keyboard driver */
++
++#define BTN_MISC		0x100
++#define BTN_0			0x100
++#define BTN_1			0x101
++#define BTN_2			0x102
++#define BTN_3			0x103
++#define BTN_4			0x104
++#define BTN_5			0x105
++#define BTN_6			0x106
++#define BTN_7			0x107
++#define BTN_8			0x108
++#define BTN_9			0x109
++
++#define BTN_MOUSE		0x110
++#define BTN_LEFT		0x110
++#define BTN_RIGHT		0x111
++#define BTN_MIDDLE		0x112
++#define BTN_SIDE		0x113
++#define BTN_EXTRA		0x114
++#define BTN_FORWARD		0x115
++#define BTN_BACK		0x116
++#define BTN_TASK		0x117
++
++#define BTN_JOYSTICK		0x120
++#define BTN_TRIGGER		0x120
++#define BTN_THUMB		0x121
++#define BTN_THUMB2		0x122
++#define BTN_TOP			0x123
++#define BTN_TOP2		0x124
++#define BTN_PINKIE		0x125
++#define BTN_BASE		0x126
++#define BTN_BASE2		0x127
++#define BTN_BASE3		0x128
++#define BTN_BASE4		0x129
++#define BTN_BASE5		0x12a
++#define BTN_BASE6		0x12b
++#define BTN_DEAD		0x12f
++
++#define BTN_GAMEPAD		0x130
++#define BTN_SOUTH		0x130
++#define BTN_A			BTN_SOUTH
++#define BTN_EAST		0x131
++#define BTN_B			BTN_EAST
++#define BTN_C			0x132
++#define BTN_NORTH		0x133
++#define BTN_X			BTN_NORTH
++#define BTN_WEST		0x134
++#define BTN_Y			BTN_WEST
++#define BTN_Z			0x135
++#define BTN_TL			0x136
++#define BTN_TR			0x137
++#define BTN_TL2			0x138
++#define BTN_TR2			0x139
++#define BTN_SELECT		0x13a
++#define BTN_START		0x13b
++#define BTN_MODE		0x13c
++#define BTN_THUMBL		0x13d
++#define BTN_THUMBR		0x13e
++
++#define BTN_DIGI		0x140
++#define BTN_TOOL_PEN		0x140
++#define BTN_TOOL_RUBBER		0x141
++#define BTN_TOOL_BRUSH		0x142
++#define BTN_TOOL_PENCIL		0x143
++#define BTN_TOOL_AIRBRUSH	0x144
++#define BTN_TOOL_FINGER		0x145
++#define BTN_TOOL_MOUSE		0x146
++#define BTN_TOOL_LENS		0x147
++#define BTN_TOOL_QUINTTAP	0x148	/* Five fingers on trackpad */
++#define BTN_TOUCH		0x14a
++#define BTN_STYLUS		0x14b
++#define BTN_STYLUS2		0x14c
++#define BTN_TOOL_DOUBLETAP	0x14d
++#define BTN_TOOL_TRIPLETAP	0x14e
++#define BTN_TOOL_QUADTAP	0x14f	/* Four fingers on trackpad */
++
++#define BTN_WHEEL		0x150
++#define BTN_GEAR_DOWN		0x150
++#define BTN_GEAR_UP		0x151
++
++#define KEY_OK			0x160
++#define KEY_SELECT		0x161
++#define KEY_GOTO		0x162
++#define KEY_CLEAR		0x163
++#define KEY_POWER2		0x164
++#define KEY_OPTION		0x165
++#define KEY_INFO		0x166	/* AL OEM Features/Tips/Tutorial */
++#define KEY_TIME		0x167
++#define KEY_VENDOR		0x168
++#define KEY_ARCHIVE		0x169
++#define KEY_PROGRAM		0x16a	/* Media Select Program Guide */
++#define KEY_CHANNEL		0x16b
++#define KEY_FAVORITES		0x16c
++#define KEY_EPG			0x16d
++#define KEY_PVR			0x16e	/* Media Select Home */
++#define KEY_MHP			0x16f
++#define KEY_LANGUAGE		0x170
++#define KEY_TITLE		0x171
++#define KEY_SUBTITLE		0x172
++#define KEY_ANGLE		0x173
++#define KEY_ZOOM		0x174
++#define KEY_MODE		0x175
++#define KEY_KEYBOARD		0x176
++#define KEY_SCREEN		0x177
++#define KEY_PC			0x178	/* Media Select Computer */
++#define KEY_TV			0x179	/* Media Select TV */
++#define KEY_TV2			0x17a	/* Media Select Cable */
++#define KEY_VCR			0x17b	/* Media Select VCR */
++#define KEY_VCR2		0x17c	/* VCR Plus */
++#define KEY_SAT			0x17d	/* Media Select Satellite */
++#define KEY_SAT2		0x17e
++#define KEY_CD			0x17f	/* Media Select CD */
++#define KEY_TAPE		0x180	/* Media Select Tape */
++#define KEY_RADIO		0x181
++#define KEY_TUNER		0x182	/* Media Select Tuner */
++#define KEY_PLAYER		0x183
++#define KEY_TEXT		0x184
++#define KEY_DVD			0x185	/* Media Select DVD */
++#define KEY_AUX			0x186
++#define KEY_MP3			0x187
++#define KEY_AUDIO		0x188	/* AL Audio Browser */
++#define KEY_VIDEO		0x189	/* AL Movie Browser */
++#define KEY_DIRECTORY		0x18a
++#define KEY_LIST		0x18b
++#define KEY_MEMO		0x18c	/* Media Select Messages */
++#define KEY_CALENDAR		0x18d
++#define KEY_RED			0x18e
++#define KEY_GREEN		0x18f
++#define KEY_YELLOW		0x190
++#define KEY_BLUE		0x191
++#define KEY_CHANNELUP		0x192	/* Channel Increment */
++#define KEY_CHANNELDOWN		0x193	/* Channel Decrement */
++#define KEY_FIRST		0x194
++#define KEY_LAST		0x195	/* Recall Last */
++#define KEY_AB			0x196
++#define KEY_NEXT		0x197
++#define KEY_RESTART		0x198
++#define KEY_SLOW		0x199
++#define KEY_SHUFFLE		0x19a
++#define KEY_BREAK		0x19b
++#define KEY_PREVIOUS		0x19c
++#define KEY_DIGITS		0x19d
++#define KEY_TEEN		0x19e
++#define KEY_TWEN		0x19f
++#define KEY_VIDEOPHONE		0x1a0	/* Media Select Video Phone */
++#define KEY_GAMES		0x1a1	/* Media Select Games */
++#define KEY_ZOOMIN		0x1a2	/* AC Zoom In */
++#define KEY_ZOOMOUT		0x1a3	/* AC Zoom Out */
++#define KEY_ZOOMRESET		0x1a4	/* AC Zoom */
++#define KEY_WORDPROCESSOR	0x1a5	/* AL Word Processor */
++#define KEY_EDITOR		0x1a6	/* AL Text Editor */
++#define KEY_SPREADSHEET		0x1a7	/* AL Spreadsheet */
++#define KEY_GRAPHICSEDITOR	0x1a8	/* AL Graphics Editor */
++#define KEY_PRESENTATION	0x1a9	/* AL Presentation App */
++#define KEY_DATABASE		0x1aa	/* AL Database App */
++#define KEY_NEWS		0x1ab	/* AL Newsreader */
++#define KEY_VOICEMAIL		0x1ac	/* AL Voicemail */
++#define KEY_ADDRESSBOOK		0x1ad	/* AL Contacts/Address Book */
++#define KEY_MESSENGER		0x1ae	/* AL Instant Messaging */
++#define KEY_DISPLAYTOGGLE	0x1af	/* Turn display (LCD) on and off */
++#define KEY_BRIGHTNESS_TOGGLE	KEY_DISPLAYTOGGLE
++#define KEY_SPELLCHECK		0x1b0   /* AL Spell Check */
++#define KEY_LOGOFF		0x1b1   /* AL Logoff */
++
++#define KEY_DOLLAR		0x1b2
++#define KEY_EURO		0x1b3
++
++#define KEY_FRAMEBACK		0x1b4	/* Consumer - transport controls */
++#define KEY_FRAMEFORWARD	0x1b5
++#define KEY_CONTEXT_MENU	0x1b6	/* GenDesc - system context menu */
++#define KEY_MEDIA_REPEAT	0x1b7	/* Consumer - transport control */
++#define KEY_10CHANNELSUP	0x1b8	/* 10 channels up (10+) */
++#define KEY_10CHANNELSDOWN	0x1b9	/* 10 channels down (10-) */
++#define KEY_IMAGES		0x1ba	/* AL Image Browser */
++
++#define KEY_DEL_EOL		0x1c0
++#define KEY_DEL_EOS		0x1c1
++#define KEY_INS_LINE		0x1c2
++#define KEY_DEL_LINE		0x1c3
++
++#define KEY_FN			0x1d0
++#define KEY_FN_ESC		0x1d1
++#define KEY_FN_F1		0x1d2
++#define KEY_FN_F2		0x1d3
++#define KEY_FN_F3		0x1d4
++#define KEY_FN_F4		0x1d5
++#define KEY_FN_F5		0x1d6
++#define KEY_FN_F6		0x1d7
++#define KEY_FN_F7		0x1d8
++#define KEY_FN_F8		0x1d9
++#define KEY_FN_F9		0x1da
++#define KEY_FN_F10		0x1db
++#define KEY_FN_F11		0x1dc
++#define KEY_FN_F12		0x1dd
++#define KEY_FN_1		0x1de
++#define KEY_FN_2		0x1df
++#define KEY_FN_D		0x1e0
++#define KEY_FN_E		0x1e1
++#define KEY_FN_F		0x1e2
++#define KEY_FN_S		0x1e3
++#define KEY_FN_B		0x1e4
++
++#define KEY_BRL_DOT1		0x1f1
++#define KEY_BRL_DOT2		0x1f2
++#define KEY_BRL_DOT3		0x1f3
++#define KEY_BRL_DOT4		0x1f4
++#define KEY_BRL_DOT5		0x1f5
++#define KEY_BRL_DOT6		0x1f6
++#define KEY_BRL_DOT7		0x1f7
++#define KEY_BRL_DOT8		0x1f8
++#define KEY_BRL_DOT9		0x1f9
++#define KEY_BRL_DOT10		0x1fa
++
++#define KEY_NUMERIC_0		0x200	/* used by phones, remote controls, */
++#define KEY_NUMERIC_1		0x201	/* and other keypads */
++#define KEY_NUMERIC_2		0x202
++#define KEY_NUMERIC_3		0x203
++#define KEY_NUMERIC_4		0x204
++#define KEY_NUMERIC_5		0x205
++#define KEY_NUMERIC_6		0x206
++#define KEY_NUMERIC_7		0x207
++#define KEY_NUMERIC_8		0x208
++#define KEY_NUMERIC_9		0x209
++#define KEY_NUMERIC_STAR	0x20a
++#define KEY_NUMERIC_POUND	0x20b
++#define KEY_NUMERIC_A		0x20c	/* Phone key A - HUT Telephony 0xb9 */
++#define KEY_NUMERIC_B		0x20d
++#define KEY_NUMERIC_C		0x20e
++#define KEY_NUMERIC_D		0x20f
++
++#define KEY_CAMERA_FOCUS	0x210
++#define KEY_WPS_BUTTON		0x211	/* WiFi Protected Setup key */
++
++#define KEY_TOUCHPAD_TOGGLE	0x212	/* Request switch touchpad on or off */
++#define KEY_TOUCHPAD_ON		0x213
++#define KEY_TOUCHPAD_OFF	0x214
++
++#define KEY_CAMERA_ZOOMIN	0x215
++#define KEY_CAMERA_ZOOMOUT	0x216
++#define KEY_CAMERA_UP		0x217
++#define KEY_CAMERA_DOWN		0x218
++#define KEY_CAMERA_LEFT		0x219
++#define KEY_CAMERA_RIGHT	0x21a
++
++#define KEY_ATTENDANT_ON	0x21b
++#define KEY_ATTENDANT_OFF	0x21c
++#define KEY_ATTENDANT_TOGGLE	0x21d	/* Attendant call on or off */
++#define KEY_LIGHTS_TOGGLE	0x21e	/* Reading light on or off */
++
++#define BTN_DPAD_UP		0x220
++#define BTN_DPAD_DOWN		0x221
++#define BTN_DPAD_LEFT		0x222
++#define BTN_DPAD_RIGHT		0x223
++
++#define KEY_ALS_TOGGLE		0x230	/* Ambient light sensor */
++
++#define KEY_BUTTONCONFIG		0x240	/* AL Button Configuration */
++#define KEY_TASKMANAGER		0x241	/* AL Task/Project Manager */
++#define KEY_JOURNAL		0x242	/* AL Log/Journal/Timecard */
++#define KEY_CONTROLPANEL		0x243	/* AL Control Panel */
++#define KEY_APPSELECT		0x244	/* AL Select Task/Application */
++#define KEY_SCREENSAVER		0x245	/* AL Screen Saver */
++#define KEY_VOICECOMMAND		0x246	/* Listening Voice Command */
++
++#define KEY_BRIGHTNESS_MIN		0x250	/* Set Brightness to Minimum */
++#define KEY_BRIGHTNESS_MAX		0x251	/* Set Brightness to Maximum */
++
++#define KEY_KBDINPUTASSIST_PREV		0x260
++#define KEY_KBDINPUTASSIST_NEXT		0x261
++#define KEY_KBDINPUTASSIST_PREVGROUP		0x262
++#define KEY_KBDINPUTASSIST_NEXTGROUP		0x263
++#define KEY_KBDINPUTASSIST_ACCEPT		0x264
++#define KEY_KBDINPUTASSIST_CANCEL		0x265
++
++/* Diagonal movement keys */
++#define KEY_RIGHT_UP			0x266
++#define KEY_RIGHT_DOWN			0x267
++#define KEY_LEFT_UP			0x268
++#define KEY_LEFT_DOWN			0x269
++
++#define KEY_ROOT_MENU			0x26a /* Show Device's Root Menu */
++/* Show Top Menu of the Media (e.g. DVD) */
++#define KEY_MEDIA_TOP_MENU		0x26b
++#define KEY_NUMERIC_11			0x26c
++#define KEY_NUMERIC_12			0x26d
++/*
++ * Toggle Audio Description: refers to an audio service that helps blind and
++ * visually impaired consumers understand the action in a program. Note: in
++ * some countries this is referred to as "Video Description".
++ */
++#define KEY_AUDIO_DESC			0x26e
++#define KEY_3D_MODE			0x26f
++#define KEY_NEXT_FAVORITE		0x270
++#define KEY_STOP_RECORD			0x271
++#define KEY_PAUSE_RECORD		0x272
++#define KEY_VOD				0x273 /* Video on Demand */
++#define KEY_UNMUTE			0x274
++#define KEY_FASTREVERSE			0x275
++#define KEY_SLOWREVERSE			0x276
++/*
++ * Control a data application associated with the currently viewed channel,
++ * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.)
++ */
++#define KEY_DATA			0x277
++#define KEY_ONSCREEN_KEYBOARD		0x278
++
++#define BTN_TRIGGER_HAPPY		0x2c0
++#define BTN_TRIGGER_HAPPY1		0x2c0
++#define BTN_TRIGGER_HAPPY2		0x2c1
++#define BTN_TRIGGER_HAPPY3		0x2c2
++#define BTN_TRIGGER_HAPPY4		0x2c3
++#define BTN_TRIGGER_HAPPY5		0x2c4
++#define BTN_TRIGGER_HAPPY6		0x2c5
++#define BTN_TRIGGER_HAPPY7		0x2c6
++#define BTN_TRIGGER_HAPPY8		0x2c7
++#define BTN_TRIGGER_HAPPY9		0x2c8
++#define BTN_TRIGGER_HAPPY10		0x2c9
++#define BTN_TRIGGER_HAPPY11		0x2ca
++#define BTN_TRIGGER_HAPPY12		0x2cb
++#define BTN_TRIGGER_HAPPY13		0x2cc
++#define BTN_TRIGGER_HAPPY14		0x2cd
++#define BTN_TRIGGER_HAPPY15		0x2ce
++#define BTN_TRIGGER_HAPPY16		0x2cf
++#define BTN_TRIGGER_HAPPY17		0x2d0
++#define BTN_TRIGGER_HAPPY18		0x2d1
++#define BTN_TRIGGER_HAPPY19		0x2d2
++#define BTN_TRIGGER_HAPPY20		0x2d3
++#define BTN_TRIGGER_HAPPY21		0x2d4
++#define BTN_TRIGGER_HAPPY22		0x2d5
++#define BTN_TRIGGER_HAPPY23		0x2d6
++#define BTN_TRIGGER_HAPPY24		0x2d7
++#define BTN_TRIGGER_HAPPY25		0x2d8
++#define BTN_TRIGGER_HAPPY26		0x2d9
++#define BTN_TRIGGER_HAPPY27		0x2da
++#define BTN_TRIGGER_HAPPY28		0x2db
++#define BTN_TRIGGER_HAPPY29		0x2dc
++#define BTN_TRIGGER_HAPPY30		0x2dd
++#define BTN_TRIGGER_HAPPY31		0x2de
++#define BTN_TRIGGER_HAPPY32		0x2df
++#define BTN_TRIGGER_HAPPY33		0x2e0
++#define BTN_TRIGGER_HAPPY34		0x2e1
++#define BTN_TRIGGER_HAPPY35		0x2e2
++#define BTN_TRIGGER_HAPPY36		0x2e3
++#define BTN_TRIGGER_HAPPY37		0x2e4
++#define BTN_TRIGGER_HAPPY38		0x2e5
++#define BTN_TRIGGER_HAPPY39		0x2e6
++#define BTN_TRIGGER_HAPPY40		0x2e7
++
++/* We avoid low common keys in module aliases so they don't get huge. */
++#define KEY_MIN_INTERESTING	KEY_MUTE
++#define KEY_MAX			0x2ff
++#define KEY_CNT			(KEY_MAX+1)
++
++/*
++ * Relative axes
++ */
++
++#define REL_X			0x00
++#define REL_Y			0x01
++#define REL_Z			0x02
++#define REL_RX			0x03
++#define REL_RY			0x04
++#define REL_RZ			0x05
++#define REL_HWHEEL		0x06
++#define REL_DIAL		0x07
++#define REL_WHEEL		0x08
++#define REL_MISC		0x09
++#define REL_MAX			0x0f
++#define REL_CNT			(REL_MAX+1)
++
++/*
++ * Absolute axes
++ */
++
++#define ABS_X			0x00
++#define ABS_Y			0x01
++#define ABS_Z			0x02
++#define ABS_RX			0x03
++#define ABS_RY			0x04
++#define ABS_RZ			0x05
++#define ABS_THROTTLE		0x06
++#define ABS_RUDDER		0x07
++#define ABS_WHEEL		0x08
++#define ABS_GAS			0x09
++#define ABS_BRAKE		0x0a
++#define ABS_HAT0X		0x10
++#define ABS_HAT0Y		0x11
++#define ABS_HAT1X		0x12
++#define ABS_HAT1Y		0x13
++#define ABS_HAT2X		0x14
++#define ABS_HAT2Y		0x15
++#define ABS_HAT3X		0x16
++#define ABS_HAT3Y		0x17
++#define ABS_PRESSURE		0x18
++#define ABS_DISTANCE		0x19
++#define ABS_TILT_X		0x1a
++#define ABS_TILT_Y		0x1b
++#define ABS_TOOL_WIDTH		0x1c
++
++#define ABS_VOLUME		0x20
++
++#define ABS_MISC		0x28
++
++#define ABS_MT_SLOT		0x2f	/* MT slot being modified */
++#define ABS_MT_TOUCH_MAJOR	0x30	/* Major axis of touching ellipse */
++#define ABS_MT_TOUCH_MINOR	0x31	/* Minor axis (omit if circular) */
++#define ABS_MT_WIDTH_MAJOR	0x32	/* Major axis of approaching ellipse */
++#define ABS_MT_WIDTH_MINOR	0x33	/* Minor axis (omit if circular) */
++#define ABS_MT_ORIENTATION	0x34	/* Ellipse orientation */
++#define ABS_MT_POSITION_X	0x35	/* Center X touch position */
++#define ABS_MT_POSITION_Y	0x36	/* Center Y touch position */
++#define ABS_MT_TOOL_TYPE	0x37	/* Type of touching device */
++#define ABS_MT_BLOB_ID		0x38	/* Group a set of packets as a blob */
++#define ABS_MT_TRACKING_ID	0x39	/* Unique ID of initiated contact */
++#define ABS_MT_PRESSURE		0x3a	/* Pressure on contact area */
++#define ABS_MT_DISTANCE		0x3b	/* Contact hover distance */
++#define ABS_MT_TOOL_X		0x3c	/* Center X tool position */
++#define ABS_MT_TOOL_Y		0x3d	/* Center Y tool position */
++
++
++#define ABS_MAX			0x3f
++#define ABS_CNT			(ABS_MAX+1)
++
++/*
++ * Switch events
++ */
++
++#define SW_LID			0x00  /* set = lid shut */
++#define SW_TABLET_MODE		0x01  /* set = tablet mode */
++#define SW_HEADPHONE_INSERT	0x02  /* set = inserted */
++#define SW_RFKILL_ALL		0x03  /* rfkill master switch, type "any"
++					 set = radio enabled */
++#define SW_RADIO		SW_RFKILL_ALL	/* deprecated */
++#define SW_MICROPHONE_INSERT	0x04  /* set = inserted */
++#define SW_DOCK			0x05  /* set = plugged into dock */
++#define SW_LINEOUT_INSERT	0x06  /* set = inserted */
++#define SW_JACK_PHYSICAL_INSERT 0x07  /* set = mechanical switch set */
++#define SW_VIDEOOUT_INSERT	0x08  /* set = inserted */
++#define SW_CAMERA_LENS_COVER	0x09  /* set = lens covered */
++#define SW_KEYPAD_SLIDE		0x0a  /* set = keypad slide out */
++#define SW_FRONT_PROXIMITY	0x0b  /* set = front proximity sensor active */
++#define SW_ROTATE_LOCK		0x0c  /* set = rotate locked/disabled */
++#define SW_LINEIN_INSERT	0x0d  /* set = inserted */
++#define SW_MUTE_DEVICE		0x0e  /* set = device disabled */
++#define SW_PEN_INSERTED		0x0f  /* set = pen inserted */
++#define SW_MAX			0x0f
++#define SW_CNT			(SW_MAX+1)
++
++/*
++ * Misc events
++ */
++
++#define MSC_SERIAL		0x00
++#define MSC_PULSELED		0x01
++#define MSC_GESTURE		0x02
++#define MSC_RAW			0x03
++#define MSC_SCAN		0x04
++#define MSC_TIMESTAMP		0x05
++#define MSC_MAX			0x07
++#define MSC_CNT			(MSC_MAX+1)
++
++/*
++ * LEDs
++ */
++
++#define LED_NUML		0x00
++#define LED_CAPSL		0x01
++#define LED_SCROLLL		0x02
++#define LED_COMPOSE		0x03
++#define LED_KANA		0x04
++#define LED_SLEEP		0x05
++#define LED_SUSPEND		0x06
++#define LED_MUTE		0x07
++#define LED_MISC		0x08
++#define LED_MAIL		0x09
++#define LED_CHARGING		0x0a
++#define LED_MAX			0x0f
++#define LED_CNT			(LED_MAX+1)
++
++/*
++ * Autorepeat values
++ */
++
++#define REP_DELAY		0x00
++#define REP_PERIOD		0x01
++#define REP_MAX			0x01
++#define REP_CNT			(REP_MAX+1)
++
++/*
++ * Sounds
++ */
++
++#define SND_CLICK		0x00
++#define SND_BELL		0x01
++#define SND_TONE		0x02
++#define SND_MAX			0x07
++#define SND_CNT			(SND_MAX+1)
++
++#endif
+diff --git a/src/backends/native/meta-input-settings-native.c b/src/backends/native/meta-input-settings-native.c
+index 8a62bb3..8a5ff5b 100644
+--- a/src/backends/native/meta-input-settings-native.c
++++ b/src/backends/native/meta-input-settings-native.c
+@@ -24,7 +24,7 @@
+ #include "config.h"
+ 
+ #include <clutter/evdev/clutter-evdev.h>
+-#include <linux/input-event-codes.h>
++#include <clutter/evdev/linux/input-event-codes.h>
+ #include <libinput.h>
+ 
+ #include "meta-backend-native.h"
+diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c
+index 4b57d41..5675f48 100644
+--- a/src/wayland/meta-wayland-tablet-tool.c
++++ b/src/wayland/meta-wayland-tablet-tool.c
+@@ -41,7 +41,7 @@
+ 
+ #ifdef HAVE_NATIVE_BACKEND
+ #include "backends/native/meta-backend-native.h"
+-#include <linux/input-event-codes.h>
++#include <clutter/evdev/linux/input-event-codes.h>
+ #endif
+ 
+ #define TABLET_AXIS_MAX 65535
+-- 
+1.8.3.1
+
diff --git a/SOURCES/0001-screen-Expose-workspace-layout-properties.patch b/SOURCES/0001-screen-Expose-workspace-layout-properties.patch
new file mode 100644
index 0000000..bc7ed96
--- /dev/null
+++ b/SOURCES/0001-screen-Expose-workspace-layout-properties.patch
@@ -0,0 +1,80 @@
+From 6b8e2636911c79d77d95aaac62336dd4f4063f63 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Tue, 4 Jun 2019 21:21:37 +0200
+Subject: [PATCH] screen: Expose workspace layout properties
+
+gnome-shell hardcodes a vertical one-column workspace layout, and
+while not supporting arbitrary grids is very much by design, it
+currently doesn't have a choice: We simply don't expose the workspace
+layout we use.
+
+Change that to allow gnome-shell to be a bit more flexible with the
+workspace layouts it supports.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/618
+---
+ src/core/screen.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/src/core/screen.c b/src/core/screen.c
+index c14bba0cf..4fac02cdb 100644
+--- a/src/core/screen.c
++++ b/src/core/screen.c
+@@ -81,6 +81,9 @@ static void on_monitors_changed          (MetaMonitorManager *manager,
+ enum
+ {
+   PROP_N_WORKSPACES = 1,
++
++  PROP_LAYOUT_COLUMNS,
++  PROP_LAYOUT_ROWS,
+ };
+ 
+ enum
+@@ -138,6 +141,12 @@ meta_screen_get_property (GObject      *object,
+ 
+   switch (prop_id)
+     {
++    case PROP_LAYOUT_COLUMNS:
++      g_value_set_int (value, screen->columns_of_workspaces);
++      break;
++    case PROP_LAYOUT_ROWS:
++      g_value_set_int (value, screen->rows_of_workspaces);
++      break;
+     case PROP_N_WORKSPACES:
+       g_value_set_int (value, meta_screen_get_n_workspaces (screen));
+       break;
+@@ -261,6 +270,22 @@ meta_screen_class_init (MetaScreenClass *klass)
+                   NULL, NULL, NULL,
+ 		  G_TYPE_NONE, 0);
+ 
++  g_object_class_install_property (object_class,
++                                   PROP_LAYOUT_COLUMNS,
++                                   g_param_spec_int ("layout-columns",
++                                                     "Layout columns",
++                                                     "Number of columns in layout",
++                                                     -1, G_MAXINT, 1,
++                                                     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
++
++  g_object_class_install_property (object_class,
++                                   PROP_LAYOUT_ROWS,
++                                   g_param_spec_int ("layout-rows",
++                                                     "Layout rows",
++                                                     "Number of rows in layout",
++                                                     -1, G_MAXINT, 1,
++                                                     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
++
+   g_object_class_install_property (object_class,
+                                    PROP_N_WORKSPACES,
+                                    pspec);
+@@ -1753,6 +1778,8 @@ meta_screen_update_workspace_layout (MetaScreen *screen)
+                 screen->columns_of_workspaces,
+                 screen->vertical_workspaces,
+                 screen->starting_corner);
++  g_object_notify (G_OBJECT (screen), "layout-columns");
++  g_object_notify (G_OBJECT (screen), "layout-rows");
+ }
+ 
+ /**
+-- 
+2.21.0
+
diff --git a/SOURCES/0001-wayland-enable-scale-monitor-framebuffer-by-default.patch b/SOURCES/0001-wayland-enable-scale-monitor-framebuffer-by-default.patch
new file mode 100644
index 0000000..46c940b
--- /dev/null
+++ b/SOURCES/0001-wayland-enable-scale-monitor-framebuffer-by-default.patch
@@ -0,0 +1,25 @@
+From 85968e1d0996b7f3a7453076c88ed6d5e0113369 Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <ofourdan@redhat.com>
+Date: Wed, 20 Sep 2017 12:17:23 +0200
+Subject: [PATCH] wayland: enable scale-monitor-framebuffer by default
+
+---
+ data/org.gnome.mutter.gschema.xml.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/data/org.gnome.mutter.gschema.xml.in b/data/org.gnome.mutter.gschema.xml.in
+index d926312c8..bec5585bd 100644
+--- a/data/org.gnome.mutter.gschema.xml.in
++++ b/data/org.gnome.mutter.gschema.xml.in
+@@ -103,7 +103,7 @@
+     </key>
+ 
+     <key name="experimental-features" type="as">
+-      <default>[]</default>
++      <default>['scale-monitor-framebuffer']</default>
+       <summary>Enable experimental features</summary>
+       <description>
+         To enable experimental features, add the feature keyword to the list.
+-- 
+2.13.5
+
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..f20fc6c
--- /dev/null
+++ b/SOURCES/0001-window-actor-Special-case-shaped-Java-windows.patch
@@ -0,0 +1,35 @@
+From 97f5f9bdc1c5cb1a2e02ec04750b5db9a4b4fdf1 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 8/8] 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 773e6d09d..ac072997c 100644
+--- a/src/compositor/meta-window-actor.c
++++ b/src/compositor/meta-window-actor.c
+@@ -843,6 +843,14 @@ meta_window_actor_has_shadow (MetaWindowActor *self)
+   if (priv->window->has_custom_frame_extents)
+     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.
+    */
+-- 
+2.14.2
+
diff --git a/SOURCES/0001-x11-window-props-Do-not-convert-WM_NAME.patch b/SOURCES/0001-x11-window-props-Do-not-convert-WM_NAME.patch
new file mode 100644
index 0000000..f7ce445
--- /dev/null
+++ b/SOURCES/0001-x11-window-props-Do-not-convert-WM_NAME.patch
@@ -0,0 +1,38 @@
+From ad1a395707f7c37b26ce446f0fd73ac7fbb9d0fd Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Tue, 9 Oct 2018 00:40:33 +0200
+Subject: [PATCH 1/2] x11/window-props: Do not convert WM_NAME
+
+The WM_NAME property is of type TEXT_PROPERTY, which is supposed to be
+returned as UTF-8. Commit 840378ae68 broke that assumption, resulting
+in crashes with non-UTF8 locales; however the "fix" of converting from
+LATIN1 to UTF8 is wrong as well, as the conversion will spit out garbage
+when the input encoding isn't actually LATIN1.
+
+Now that the original issue in text_property_to_utf8() has been fixed,
+we can simply revert the relevant bits of commit d62491f46eba748e.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/227
+---
+ src/x11/window-props.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+diff --git a/src/x11/window-props.c b/src/x11/window-props.c
+index 2f4dfeb31..7c6b25fdb 100644
+--- a/src/x11/window-props.c
++++ b/src/x11/window-props.c
+@@ -645,10 +645,7 @@ reload_wm_name (MetaWindow    *window,
+ 
+   if (value->type != META_PROP_VALUE_INVALID)
+     {
+-      g_autofree gchar *title = g_convert (value->v.str, -1,
+-                                           "UTF-8", "LATIN1",
+-                                           NULL, NULL, NULL);
+-      set_window_title (window, title);
++      set_window_title (window, value->v.str);
+ 
+       meta_verbose ("Using WM_NAME for new title of %s: \"%s\"\n",
+                     window->desc, window->title);
+-- 
+2.21.0
+
diff --git a/SOURCES/0002-clutter-Avoid-relayouts-when-raising-lowering-childr.patch b/SOURCES/0002-clutter-Avoid-relayouts-when-raising-lowering-childr.patch
new file mode 100644
index 0000000..3bdd6e8
--- /dev/null
+++ b/SOURCES/0002-clutter-Avoid-relayouts-when-raising-lowering-childr.patch
@@ -0,0 +1,60 @@
+From dcf0717d7d90ff525c4f87cf633353caabf0eeeb Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Fri, 10 Aug 2018 21:30:58 +0200
+Subject: [PATCH 2/2] clutter: Avoid relayouts when raising/lowering children
+
+These calls don't actually affect the layout, but the paint order.
+It seems safe to skip the full relayout/repaint of the parent actor,
+and redraw only the area occupied by the affected child.
+---
+ clutter/clutter/clutter-actor.c | 20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c
+index 6954f0396..7a9da7257 100644
+--- a/clutter/clutter/clutter-actor.c
++++ b/clutter/clutter/clutter-actor.c
+@@ -1713,6 +1713,22 @@ set_show_on_set_parent (ClutterActor *self,
+     }
+ }
+ 
++static void
++clutter_actor_queue_redraw_on_parent (ClutterActor *self)
++{
++  const ClutterPaintVolume *pv;
++
++  if (!self->priv->parent)
++    return;
++
++  /* A relayout/redraw is underway */
++  if (self->priv->needs_allocation)
++    return;
++
++  pv = clutter_actor_get_transformed_paint_volume (self, self->priv->parent);
++  _clutter_actor_queue_redraw_with_clip (self->priv->parent, 0, pv);
++}
++
+ /**
+  * clutter_actor_show:
+  * @self: A #ClutterActor
+@@ -13618,7 +13634,7 @@ clutter_actor_set_child_above_sibling (ClutterActor *self,
+                                     sibling);
+   g_object_unref(child);
+ 
+-  clutter_actor_queue_relayout (self);
++  clutter_actor_queue_redraw_on_parent (child);
+ }
+ 
+ /**
+@@ -13665,7 +13681,7 @@ clutter_actor_set_child_below_sibling (ClutterActor *self,
+                                     sibling);
+   g_object_unref(child);
+ 
+-  clutter_actor_queue_relayout (self);
++  clutter_actor_queue_redraw_on_parent (child);
+ }
+ 
+ /**
+-- 
+2.21.0
+
diff --git a/SOURCES/0002-idle-monitor-Postpone-dispatching-of-idle-timeout-if.patch b/SOURCES/0002-idle-monitor-Postpone-dispatching-of-idle-timeout-if.patch
new file mode 100644
index 0000000..54879c6
--- /dev/null
+++ b/SOURCES/0002-idle-monitor-Postpone-dispatching-of-idle-timeout-if.patch
@@ -0,0 +1,41 @@
+From 22879378393c21a1a1e5307dc457233bd40ef877 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Tue, 16 Apr 2019 18:07:31 +0200
+Subject: [PATCH 2/2] idle-monitor: Postpone dispatching of idle timeout if not
+ ready
+
+If we update the ready time while the source is already in the
+to-dispatch list, changing the ready time doesn't have any effect, and
+the source will still be dispatched. This could cause incorrect idle
+watch firing causing the power management plugin in
+gnome-settings-daemon to sometimes turn off monitors due to it believing
+the user had been idle for some time, while in fact, they just logged
+back in.
+
+Fix this by not actually dispatching the idle timeout if the ready time
+is in the future when actually dispatching.
+---
+ src/backends/meta-idle-monitor.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/backends/meta-idle-monitor.c b/src/backends/meta-idle-monitor.c
+index 2b634f59a..2c06ee73c 100644
+--- a/src/backends/meta-idle-monitor.c
++++ b/src/backends/meta-idle-monitor.c
+@@ -311,6 +311,13 @@ idle_monitor_dispatch_timeout (GSource     *source,
+                                gpointer     user_data)
+ {
+   MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) user_data;
++  int64_t now;
++  int64_t ready_time;
++
++  now = g_source_get_time (source);
++  ready_time = g_source_get_ready_time (source);
++  if (ready_time > now)
++    return G_SOURCE_CONTINUE;
+ 
+   _meta_idle_monitor_watch_fire (watch);
+   g_source_set_ready_time (watch->timeout_source, -1);
+-- 
+2.20.1
+
diff --git a/SOURCES/0002-monitor-manager-xrandr-Create-dummy-screen-sized-mon.patch b/SOURCES/0002-monitor-manager-xrandr-Create-dummy-screen-sized-mon.patch
new file mode 100644
index 0000000..a676cf6
--- /dev/null
+++ b/SOURCES/0002-monitor-manager-xrandr-Create-dummy-screen-sized-mon.patch
@@ -0,0 +1,171 @@
+From 8950fc632bcf4c3eca2be1c347acaa16b4b8d0c5 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Wed, 3 Oct 2018 10:50:47 +0200
+Subject: [PATCH 2/2] monitor-manager/xrandr: Create dummy screen sized monitor
+ if no RANDR
+
+When there is no RANDR support enabled in the X server, we wont get
+notified of any monitors, resulting in mutter believing we're being
+headless. To get at least something working, although with no way
+configuration ability, lets pretend the whole screen is just a single
+monitor with a single output, crtc and mode.
+---
+ src/backends/x11/meta-gpu-xrandr.c            | 60 +++++++++++++++++++
+ .../x11/meta-monitor-manager-xrandr.c         | 20 +++++++
+ .../x11/meta-monitor-manager-xrandr.h         |  2 +
+ 3 files changed, 82 insertions(+)
+
+diff --git a/src/backends/x11/meta-gpu-xrandr.c b/src/backends/x11/meta-gpu-xrandr.c
+index a4e187a49a..9397c1f64d 100644
+--- a/src/backends/x11/meta-gpu-xrandr.c
++++ b/src/backends/x11/meta-gpu-xrandr.c
+@@ -147,6 +147,63 @@ update_screen_size (MetaMonitorManagerXrandr *monitor_manager_xrandr)
+   monitor_manager->screen_height = HeightOfScreen (screen);
+ }
+ 
++static gboolean
++read_current_fallback (MetaGpuXrandr            *gpu_xrandr,
++                       MetaMonitorManagerXrandr *monitor_manager_xrandr)
++{
++  MetaGpu *gpu = META_GPU (gpu_xrandr);
++  MetaMonitorManager *monitor_manager =
++    META_MONITOR_MANAGER (monitor_manager_xrandr);
++  MetaCrtcMode *mode;
++  MetaCrtc *crtc;
++  MetaOutput *output;
++
++  update_dpms_state (monitor_manager_xrandr);
++  update_screen_size (monitor_manager_xrandr);
++
++  mode = g_object_new (META_TYPE_CRTC_MODE, NULL);
++  mode->mode_id = 0;
++  mode->width = monitor_manager->screen_width;
++  mode->height = monitor_manager->screen_height;
++  mode->refresh_rate = 60.0;
++  mode->name = g_strdup_printf ("%dx%d", mode->width, mode->height);
++
++  meta_gpu_take_modes (gpu, g_list_prepend (NULL, mode));
++
++  crtc = g_object_new (META_TYPE_CRTC, NULL);
++  crtc->gpu = gpu;
++  crtc->crtc_id = 0;
++  crtc->rect = (MetaRectangle) { .width = mode->width, .height = mode->height };
++  crtc->current_mode = mode;
++
++  meta_gpu_take_crtcs (gpu, g_list_prepend (NULL, crtc));
++
++  output = g_object_new (META_TYPE_OUTPUT, NULL);
++  output->gpu = gpu;
++  output->winsys_id = 0;
++  output->name = g_strdup ("X11 Screen");
++  output->vendor = g_strdup ("unknown");
++  output->product = g_strdup ("unknown");
++  output->serial = g_strdup ("unknown");
++  output->hotplug_mode_update = TRUE;
++  output->suggested_x = -1;
++  output->suggested_y = -1;
++  output->connector_type = META_CONNECTOR_TYPE_Unknown;
++  output->modes = g_new0 (MetaCrtcMode *, 1);
++  output->modes[0] = mode;
++  output->n_modes = 1;
++  output->preferred_mode = mode;
++  output->possible_crtcs = g_new0 (MetaCrtc *, 1);
++  output->possible_crtcs[0] = crtc;
++  output->n_possible_crtcs = 1;
++  meta_output_assign_crtc (output, crtc);
++  output->is_primary = TRUE;
++
++  meta_gpu_take_outputs (gpu, g_list_prepend (NULL, output));
++
++  return TRUE;
++}
++
+ static gboolean
+ meta_gpu_xrandr_read_current (MetaGpu  *gpu,
+                               GError  **error)
+@@ -166,6 +223,9 @@ meta_gpu_xrandr_read_current (MetaGpu  *gpu,
+   GList *modes = NULL;
+   GList *crtcs = NULL;
+ 
++  if (!meta_monitor_manager_xrandr_has_randr (monitor_manager_xrandr))
++    return read_current_fallback (gpu_xrandr, monitor_manager_xrandr);
++
+   if (gpu_xrandr->resources)
+     XRRFreeScreenResources (gpu_xrandr->resources);
+   gpu_xrandr->resources = NULL;
+diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
+index d0da2c539e..26b057a559 100644
+--- a/src/backends/x11/meta-monitor-manager-xrandr.c
++++ b/src/backends/x11/meta-monitor-manager-xrandr.c
+@@ -64,6 +64,7 @@ struct _MetaMonitorManagerXrandr
+   guint logind_watch_id;
+   guint logind_signal_sub_id;
+ 
++  gboolean has_randr;
+   gboolean has_randr15;
+ 
+   /*
+@@ -107,6 +108,12 @@ meta_monitor_manager_xrandr_get_xdisplay (MetaMonitorManagerXrandr *manager_xran
+   return manager_xrandr->xdisplay;
+ }
+ 
++gboolean
++meta_monitor_manager_xrandr_has_randr (MetaMonitorManagerXrandr *manager_xrandr)
++{
++  return manager_xrandr->has_randr;
++}
++
+ gboolean
+ meta_monitor_manager_xrandr_has_randr15 (MetaMonitorManagerXrandr *manager_xrandr)
+ {
+@@ -577,9 +584,18 @@ meta_monitor_manager_xrandr_apply_monitors_config (MetaMonitorManager      *mana
+                                                    MetaMonitorsConfigMethod method,
+                                                    GError                 **error)
+ {
++  MetaMonitorManagerXrandr *manager_xrandr =
++    META_MONITOR_MANAGER_XRANDR (manager);
+   GPtrArray *crtc_infos;
+   GPtrArray *output_infos;
+ 
++  if (!manager_xrandr->has_randr)
++    {
++      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++                   "Tried to change configuration without XRANDR support");
++      return FALSE;
++    }
++
+   if (!config)
+     {
+       meta_monitor_manager_xrandr_rebuild_derived (manager, NULL);
+@@ -1046,11 +1062,15 @@ meta_monitor_manager_xrandr_constructed (GObject *object)
+ 			  &manager_xrandr->rr_event_base,
+ 			  &manager_xrandr->rr_error_base))
+     {
++      g_warning ("No RANDR support, monitor configuration disabled");
+       return;
+     }
+   else
+     {
+       int major_version, minor_version;
++
++      manager_xrandr->has_randr = TRUE;
++
+       /* We only use ScreenChangeNotify, but GDK uses the others,
+ 	 and we don't want to step on its toes */
+       XRRSelectInput (manager_xrandr->xdisplay,
+diff --git a/src/backends/x11/meta-monitor-manager-xrandr.h b/src/backends/x11/meta-monitor-manager-xrandr.h
+index f09cbfd83a..343c8131ee 100644
+--- a/src/backends/x11/meta-monitor-manager-xrandr.h
++++ b/src/backends/x11/meta-monitor-manager-xrandr.h
+@@ -33,6 +33,8 @@ G_DECLARE_FINAL_TYPE (MetaMonitorManagerXrandr, meta_monitor_manager_xrandr,
+ 
+ Display * meta_monitor_manager_xrandr_get_xdisplay (MetaMonitorManagerXrandr *manager_xrandr);
+ 
++gboolean meta_monitor_manager_xrandr_has_randr (MetaMonitorManagerXrandr *manager_xrandr);
++
+ gboolean meta_monitor_manager_xrandr_has_randr15 (MetaMonitorManagerXrandr *manager_xrandr);
+ 
+ gboolean meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager,
+-- 
+2.17.1
+
diff --git a/SOURCES/0002-window-Return-1-if-meta_window_get_monitor-is-called.patch b/SOURCES/0002-window-Return-1-if-meta_window_get_monitor-is-called.patch
new file mode 100644
index 0000000..76191d9
--- /dev/null
+++ b/SOURCES/0002-window-Return-1-if-meta_window_get_monitor-is-called.patch
@@ -0,0 +1,38 @@
+From 760e22fd301df35a4bca9e0453a3877f1840a819 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <sam@endlessm.com>
+Date: Wed, 11 Oct 2017 00:39:40 +0800
+Subject: [PATCH 2/2] window: Return -1 if meta_window_get_monitor is called on
+ an unmanaged window
+
+As opposed to crashing. In this case, letting the caller deal with
+it is the best policy, since this is public API.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=788834
+---
+ src/core/window.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/src/core/window.c b/src/core/window.c
+index cc0813ac4..79f0d6bc0 100644
+--- a/src/core/window.c
++++ b/src/core/window.c
+@@ -3752,11 +3752,15 @@ maybe_move_attached_dialog (MetaWindow *window,
+  *
+  * Gets index of the monitor that this window is on.
+  *
+- * Return Value: The index of the monitor in the screens monitor list
++ * Return Value: The index of the monitor in the screens monitor list, or -1
++ * if the window has been recently unmanaged and does not have a monitor.
+  */
+ int
+ meta_window_get_monitor (MetaWindow *window)
+ {
++  if (!window->monitor)
++    return -1;
++
+   return window->monitor->number;
+ }
+ 
+-- 
+2.21.0
+
diff --git a/SOURCES/0002-xprops-Make-sure-text_property_to_utf8-returns-UTF8.patch b/SOURCES/0002-xprops-Make-sure-text_property_to_utf8-returns-UTF8.patch
new file mode 100644
index 0000000..6178049
--- /dev/null
+++ b/SOURCES/0002-xprops-Make-sure-text_property_to_utf8-returns-UTF8.patch
@@ -0,0 +1,44 @@
+From 5881b87be4432ca1c50ee0652634883110b487de Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Tue, 9 Oct 2018 00:29:01 +0200
+Subject: [PATCH 2/2] xprops: Make sure text_property_to_utf8() returns UTF8
+
+Commit 840378ae682 changed the code to use XmbTextPropertyToTextList()
+instead of gdk_text_property_to_utf8_list_for_display(), but didn't
+take into account that the replacement returns text in the current
+locale's encoding, while any callers (rightfully) expect UTF8.
+
+Fix this by converting the text if necessary.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/227
+---
+ src/x11/xprops.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/src/x11/xprops.c b/src/x11/xprops.c
+index cffa5958a..ca686b2fa 100644
+--- a/src/x11/xprops.c
++++ b/src/x11/xprops.c
+@@ -637,6 +637,7 @@ text_property_to_utf8 (Display *xdisplay,
+ {
+   char *ret = NULL;
+   char **local_list = NULL;
++  const char *charset = NULL;
+   int count = 0;
+   int res;
+ 
+@@ -647,7 +648,10 @@ text_property_to_utf8 (Display *xdisplay,
+   if (count == 0)
+     goto out;
+ 
+-  ret = g_strdup (local_list[0]);
++  if (g_get_charset (&charset))
++    ret = g_strdup (local_list[0]);
++  else
++    ret = g_convert (local_list[0], -1, "UTF-8", charset, NULL, NULL, NULL);
+ 
+  out:
+   XFreeStringList (local_list);
+-- 
+2.21.0
+
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..e5b861e
--- /dev/null
+++ b/SOURCES/0008-Add-support-for-quad-buffer-stereo.patch
@@ -0,0 +1,1008 @@
+From 77b95bdac1b3cca4d06480e1d7fe1b6c86a32d2f 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] 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  |  10 +-
+ 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 +++++
+ src/wayland/meta-wayland-surface.c           |   2 +-
+ 14 files changed, 535 insertions(+), 51 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 5bbac70..8b21d2f 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -308,6 +308,8 @@ libmutter_@LIBMUTTER_API_VERSION@_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 40c0344..25cab92 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;
+ 
+@@ -61,6 +65,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 8c924d2..e12fb7b 100644
+--- a/src/compositor/compositor.c
++++ b/src/compositor/compositor.c
+@@ -70,6 +70,8 @@
+ #include "meta-window-group-private.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 "backends/meta-dnd-private.h"
+ #include "frame.h"
+@@ -487,6 +489,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 extensions_string && 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)
+ {
+@@ -495,6 +588,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);
+@@ -759,6 +854,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);
+@@ -969,6 +1081,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
+@@ -1044,6 +1157,8 @@ 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);
+@@ -1051,6 +1166,8 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
+ 
+   sync_actor_stacking (compositor);
+ 
++  meta_stereo_set_have_stereo_windows (stereo_window_count > 0);
++
+   if (compositor->top_window_actor)
+     g_signal_handlers_disconnect_by_func (compositor->top_window_actor,
+                                           on_top_window_actor_destroyed,
+@@ -1259,6 +1376,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 5b3f283..189a953 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_is_y_inverted (MetaShapedTexture *stex,
+                                             gboolean           is_y_inverted);
+ void meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
+diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
+index 98346c6..b89de03 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;
+   CoglSnippet *snippet;
+ 
+@@ -129,8 +131,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;
+   priv->is_y_inverted = TRUE;
+@@ -191,11 +195,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);
+@@ -326,8 +330,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;
+@@ -338,8 +343,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)
+     {
+@@ -353,6 +361,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)
+     {
+@@ -368,52 +379,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;
+ 
+@@ -574,6 +574,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,
+@@ -692,6 +762,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);
++        }
+     }
+ }
+ 
+@@ -757,6 +833,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)
+@@ -789,17 +867,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 7505b7d..9475c20 100644
+--- a/src/compositor/meta-surface-actor-wayland.c
++++ b/src/compositor/meta-surface-actor-wayland.c
+@@ -187,7 +187,7 @@ meta_surface_actor_wayland_dispose (GObject *object)
+   MetaShapedTexture *stex =
+     meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
+ 
+-  meta_shaped_texture_set_texture (stex, NULL);
++  meta_shaped_texture_set_textures (stex, NULL, NULL);
+   if (priv->surface)
+     {
+       g_object_remove_weak_pointer (G_OBJECT (priv->surface),
+@@ -246,6 +246,14 @@ meta_surface_actor_wayland_new (MetaWaylandSurface *surface)
+   return META_SURFACE_ACTOR (self);
+ }
+ 
++void
++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_textures (stex, texture, NULL);
++}
++
+ MetaWaylandSurface *
+ meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self)
+ {
+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 ce5e7ea..5b011ce 100644
+--- a/src/compositor/meta-window-actor-private.h
++++ b/src/compositor/meta-window-actor-private.h
+@@ -60,4 +60,9 @@ MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self);
+ void meta_window_actor_update_surface (MetaWindowActor *self);
+ MetaWindowActor *meta_window_actor_from_window (MetaWindow *window);
+ 
++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 120b043..b2c7725 100644
+--- a/src/compositor/meta-window-actor.c
++++ b/src/compositor/meta-window-actor.c
+@@ -2189,3 +2189,25 @@ meta_window_actor_from_window (MetaWindow *window)
+ {
+   return META_WINDOW_ACTOR (meta_window_get_compositor_private (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 04a42c7..faa2081 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>
+@@ -580,6 +581,9 @@ meta_init (void)
+ 
+   meta_init_backend (backend_gtype);
+ 
++  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
+diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
+index 899f777..f8f7fc5 100644
+--- a/src/wayland/meta-wayland-surface.c
++++ b/src/wayland/meta-wayland-surface.c
+@@ -667,7 +667,7 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface      *surface,
+               snippet = meta_wayland_buffer_create_snippet (pending->buffer);
+               is_y_inverted = meta_wayland_buffer_is_y_inverted (pending->buffer);
+ 
+-              meta_shaped_texture_set_texture (stex, texture);
++              meta_shaped_texture_set_textures (stex, texture, NULL);
+               meta_shaped_texture_set_snippet (stex, snippet);
+               meta_shaped_texture_set_is_y_inverted (stex, is_y_inverted);
+               g_clear_pointer (&snippet, cogl_object_unref);
+-- 
+1.8.3.1
+
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..3198a09
--- /dev/null
+++ b/SOURCES/add-support-for-plain-old-x-device-configuration.patch
@@ -0,0 +1,400 @@
+From 81986e9b3c16efa170b2bb4fe2af05a30b9386b3 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 467a9b7..27995c8 100644
+--- a/src/backends/x11/meta-input-settings-x11.c
++++ b/src/backends/x11/meta-input-settings-x11.c
+@@ -222,6 +222,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))
+     {
+-- 
+1.8.3.1
+
+
+From c3f4dc97cdb4f1b63e43e38daf02e676d207ad37 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 27995c8..4c2709c 100644
+--- a/src/backends/x11/meta-input-settings-x11.c
++++ b/src/backends/x11/meta-input-settings-x11.c
+@@ -621,6 +621,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])
+-- 
+1.8.3.1
+
+
+From fd94f5fd842f0f0f9e4a28e69716a30669e2e848 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 | 112 +++++++++++++++++++++++++++++
+ 1 file changed, 112 insertions(+)
+
+diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c
+index 4c2709c..9a85f94 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>
+ #include "backends/meta-logical-monitor.h"
+@@ -44,6 +47,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,
+@@ -328,6 +333,107 @@ change_synaptics_speed (ClutterInputDevice *device,
+   XFreeFeedbackList (states);
+ }
+ 
++/* 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,
+@@ -452,6 +558,12 @@ meta_input_settings_x11_set_disable_while_typing (MetaInputSettings  *settings,
+ {
+   guchar value = (enabled) ? 1 : 0;
+ 
++  if (is_device_synaptics (device))
++    {
++      set_synaptics_disable_w_typing (settings, enabled);
++      return;
++    }
++
+   change_property (device, "libinput Disable While Typing Enabled",
+                    XA_INTEGER, 8, &value, 1);
+ }
+-- 
+1.8.3.1
+
+
+From f5f9195fe23c0af8a498a13ca6bc5521a0c9e6ce 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 | 96 +++++++++++++++++++++++-------
+ 1 file changed, 74 insertions(+), 22 deletions(-)
+
+diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c
+index 9a85f94..cb4eb00 100644
+--- a/src/backends/x11/meta-input-settings-x11.c
++++ b/src/backends/x11/meta-input-settings-x11.c
+@@ -179,35 +179,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 = device_ensure_xdevice (device);
+   if (!xdevice)
+     return;
+ 
+-  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);
+-
+   if (display)
+     meta_error_trap_push (display);
+   buttons = g_new (guchar, buttons_capacity);
+@@ -231,14 +231,37 @@ 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));
+     }
+ }
+ 
+ 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 ();
+@@ -333,6 +356,23 @@ change_synaptics_speed (ClutterInputDevice *device,
+   XFreeFeedbackList (states);
+ }
+ 
++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
+@@ -501,9 +541,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;
+     }
+ 
+@@ -545,6 +586,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);
+@@ -758,6 +804,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);
+ }
+-- 
+1.8.3.1
+
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..477aded
--- /dev/null
+++ b/SOURCES/deal-more-gracefully-with-oversized-windows.patch
@@ -0,0 +1,85 @@
+From 547af942e6a0586208dbc3f158a7ec2c14611ff8 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 1/8] 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 f5360ef9d..3b6203d6b 100644
+--- a/src/core/constraints.c
++++ b/src/core/constraints.c
+@@ -106,6 +106,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;
+ 
+@@ -196,6 +197,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,
+@@ -231,6 +236,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}
+ };
+ 
+@@ -1674,3 +1680,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.14.2
+
diff --git a/SOURCES/fix-crash-when-modal-closes-during-drag.patch b/SOURCES/fix-crash-when-modal-closes-during-drag.patch
new file mode 100644
index 0000000..598a574
--- /dev/null
+++ b/SOURCES/fix-crash-when-modal-closes-during-drag.patch
@@ -0,0 +1,71 @@
+From 33bf5319baec86e6caef5b94c71db8101fb94343 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Fri, 25 May 2018 20:18:23 +0200
+Subject: [PATCH 1/2] window: Don't refuse to move focus to the grab window
+
+We refuse to move focus while a grab operation is in place. While this
+generally makes sense, there's no reason why the window that owns the
+grab shouldn't be given the regular input focus as well - we pretty
+much assume that the grab window is also the focus window anyway.
+
+In fact there's a strong reason for allowing the focus change here:
+If the grab window isn't the focus window, it probably has a modal
+transient that is focused instead, and a likely reason for the focus
+request is that the transient is being unmanaged and we must move
+the focus elsewhere.
+
+https://gitlab.gnome.org/GNOME/mutter/issues/15
+---
+ src/core/window.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/core/window.c b/src/core/window.c
+index 743326c60..5b1eb5b68 100644
+--- a/src/core/window.c
++++ b/src/core/window.c
+@@ -4620,6 +4620,7 @@ meta_window_focus (MetaWindow  *window,
+               window->desc, window->input, window->take_focus);
+ 
+   if (window->display->grab_window &&
++      window->display->grab_window != window &&
+       window->display->grab_window->all_keys_grabbed &&
+       !window->display->grab_window->unmanaging)
+     {
+-- 
+2.17.1
+
+
+From 149ae05df628480e8226f035044e6020305a8aeb Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Fri, 25 May 2018 21:24:17 +0200
+Subject: [PATCH 2/2] window: Explicitly exclude unmanaging window from focus
+ again
+
+Since commit b3b9d9e16 we no longer have to pass the unmanaging window
+to make sure we don't try to focus it again, however the parameter also
+influences the focus policy by giving ancestors preference over the normal
+stack order.
+
+https://gitlab.gnome.org/GNOME/mutter/issues/15
+---
+ src/core/window.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/core/window.c b/src/core/window.c
+index 5b1eb5b68..cc0813ac4 100644
+--- a/src/core/window.c
++++ b/src/core/window.c
+@@ -1469,7 +1469,9 @@ meta_window_unmanage (MetaWindow  *window,
+       meta_topic (META_DEBUG_FOCUS,
+                   "Focusing default window since we're unmanaging %s\n",
+                   window->desc);
+-      meta_workspace_focus_default_window (window->screen->active_workspace, NULL, timestamp);
++      meta_workspace_focus_default_window (window->screen->active_workspace,
++                                           window,
++                                           timestamp);
+     }
+   else
+     {
+-- 
+2.17.1
+
diff --git a/SOURCES/hw-cursor-on-demand-gnome-3-28.patch b/SOURCES/hw-cursor-on-demand-gnome-3-28.patch
new file mode 100644
index 0000000..ae3db81
--- /dev/null
+++ b/SOURCES/hw-cursor-on-demand-gnome-3-28.patch
@@ -0,0 +1,3006 @@
+diff --git a/src/Makefile.am b/src/Makefile.am
+index bcb3505c7..5bbac70e8 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -114,6 +114,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES =	\
+ 	backends/meta-cursor-tracker-private.h	\
+ 	backends/meta-cursor-renderer.c		\
+ 	backends/meta-cursor-renderer.h		\
++	backends/meta-cursor-sprite-xcursor.c	\
++	backends/meta-cursor-sprite-xcursor.h	\
+ 	backends/meta-dnd-private.h		\
+ 	backends/meta-egl.c			\
+ 	backends/meta-egl.h			\
+@@ -176,6 +178,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES =	\
+ 	backends/x11/meta-gpu-xrandr.h			\
+ 	backends/x11/cm/meta-backend-x11-cm.c		\
+ 	backends/x11/cm/meta-backend-x11-cm.h		\
++	backends/x11/cm/meta-cursor-sprite-xfixes.c	\
++	backends/x11/cm/meta-cursor-sprite-xfixes.h	\
+ 	backends/x11/cm/meta-renderer-x11-cm.c		\
+ 	backends/x11/cm/meta-renderer-x11-cm.h		\
+ 	backends/x11/nested/meta-backend-x11-nested.c	\
+@@ -370,6 +374,8 @@ if HAVE_WAYLAND
+ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES +=	\
+ 	compositor/meta-surface-actor-wayland.c	\
+ 	compositor/meta-surface-actor-wayland.h	\
++	wayland/meta-cursor-sprite-wayland.c	\
++	wayland/meta-cursor-sprite-wayland.h	\
+ 	wayland/meta-wayland.c			\
+ 	wayland/meta-wayland.h			\
+ 	wayland/meta-wayland-private.h		\
+@@ -431,10 +437,10 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES +=	\
+ 	wayland/meta-wayland-touch.h		\
+ 	wayland/meta-wayland-surface.c		\
+ 	wayland/meta-wayland-surface.h		\
+-	wayland/meta-wayland-surface-role-cursor.c	\
+-	wayland/meta-wayland-surface-role-cursor.h	\
+-	wayland/meta-wayland-surface-role-tablet-cursor.c	\
+-	wayland/meta-wayland-surface-role-tablet-cursor.h	\
++	wayland/meta-wayland-cursor-surface.c	\
++	wayland/meta-wayland-cursor-surface.h	\
++	wayland/meta-wayland-tablet-cursor-surface.c	\
++	wayland/meta-wayland-tablet-cursor-surface.h	\
+ 	wayland/meta-wayland-actor-surface.c	\
+ 	wayland/meta-wayland-actor-surface.h	\
+ 	wayland/meta-wayland-subsurface.c	\
+diff --git a/src/backends/meta-cursor-renderer.c b/src/backends/meta-cursor-renderer.c
+index f6470e66a..eb79737f1 100644
+--- a/src/backends/meta-cursor-renderer.c
++++ b/src/backends/meta-cursor-renderer.c
+@@ -193,8 +193,8 @@ meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
+ }
+ 
+ static void
+-update_cursor (MetaCursorRenderer *renderer,
+-               MetaCursorSprite   *cursor_sprite)
++meta_cursor_renderer_update_cursor (MetaCursorRenderer *renderer,
++                                    MetaCursorSprite   *cursor_sprite)
+ {
+   MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
+   gboolean handled_by_backend;
+@@ -237,7 +237,7 @@ meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
+     return;
+   priv->displayed_cursor = cursor_sprite;
+ 
+-  update_cursor (renderer, cursor_sprite);
++  meta_cursor_renderer_update_cursor (renderer, cursor_sprite);
+ }
+ 
+ void
+@@ -246,7 +246,7 @@ meta_cursor_renderer_force_update (MetaCursorRenderer *renderer)
+   MetaCursorRendererPrivate *priv =
+     meta_cursor_renderer_get_instance_private (renderer);
+ 
+-  update_cursor (renderer, priv->displayed_cursor);
++  meta_cursor_renderer_update_cursor (renderer, priv->displayed_cursor);
+ }
+ 
+ void
+@@ -261,7 +261,7 @@ meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
+   priv->current_x = x;
+   priv->current_y = y;
+ 
+-  update_cursor (renderer, priv->displayed_cursor);
++  meta_cursor_renderer_update_cursor (renderer, priv->displayed_cursor);
+ }
+ 
+ ClutterPoint
+@@ -283,28 +283,3 @@ meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
+ 
+   return priv->displayed_cursor;
+ }
+-
+-#ifdef HAVE_WAYLAND
+-void
+-meta_cursor_renderer_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
+-                                                    MetaCursorSprite   *cursor_sprite,
+-                                                    struct wl_resource *buffer)
+-{
+-
+-  MetaCursorRendererClass *renderer_class = META_CURSOR_RENDERER_GET_CLASS (renderer);
+-
+-  if (renderer_class->realize_cursor_from_wl_buffer)
+-    renderer_class->realize_cursor_from_wl_buffer (renderer, cursor_sprite, buffer);
+-}
+-#endif
+-
+-void
+-meta_cursor_renderer_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
+-                                                  MetaCursorSprite   *cursor_sprite,
+-                                                  XcursorImage       *xc_image)
+-{
+-  MetaCursorRendererClass *renderer_class = META_CURSOR_RENDERER_GET_CLASS (renderer);
+-
+-  if (renderer_class->realize_cursor_from_xcursor)
+-    renderer_class->realize_cursor_from_xcursor (renderer, cursor_sprite, xc_image);
+-}
+diff --git a/src/backends/meta-cursor-renderer.h b/src/backends/meta-cursor-renderer.h
+index 1691f4471..830d16ef6 100644
+--- a/src/backends/meta-cursor-renderer.h
++++ b/src/backends/meta-cursor-renderer.h
+@@ -26,10 +26,6 @@
+ #define META_CURSOR_RENDERER_H
+ 
+ #include <glib-object.h>
+-#include <X11/Xcursor/Xcursor.h>
+-#ifdef HAVE_WAYLAND
+-#include <wayland-server.h>
+-#endif
+ 
+ #include <meta/screen.h>
+ #include "meta-cursor.h"
+@@ -44,14 +40,6 @@ struct _MetaCursorRendererClass
+ 
+   gboolean (* update_cursor) (MetaCursorRenderer *renderer,
+                               MetaCursorSprite   *cursor_sprite);
+-#ifdef HAVE_WAYLAND
+-  void (* realize_cursor_from_wl_buffer) (MetaCursorRenderer *renderer,
+-                                          MetaCursorSprite *cursor_sprite,
+-                                          struct wl_resource *buffer);
+-#endif
+-  void (* realize_cursor_from_xcursor) (MetaCursorRenderer *renderer,
+-                                        MetaCursorSprite *cursor_sprite,
+-                                        XcursorImage *xc_image);
+ };
+ 
+ MetaCursorRenderer * meta_cursor_renderer_new (void);
+@@ -70,16 +58,6 @@ MetaCursorSprite * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer
+ ClutterRect meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
+                                                  MetaCursorSprite   *cursor_sprite);
+ 
+-#ifdef HAVE_WAYLAND
+-void meta_cursor_renderer_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
+-                                                         MetaCursorSprite   *cursor_sprite,
+-                                                         struct wl_resource *buffer);
+-#endif
+-
+-void meta_cursor_renderer_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
+-                                                       MetaCursorSprite   *cursor_sprite,
+-                                                       XcursorImage       *xc_image);
+-
+ void meta_cursor_renderer_emit_painted (MetaCursorRenderer *renderer,
+                                         MetaCursorSprite   *cursor_sprite);
+ 
+diff --git a/src/backends/meta-cursor-sprite-xcursor.c b/src/backends/meta-cursor-sprite-xcursor.c
+new file mode 100644
+index 000000000..657c1dae8
+--- /dev/null
++++ b/src/backends/meta-cursor-sprite-xcursor.c
+@@ -0,0 +1,292 @@
++/*
++ * Copyright 2013, 2018 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/>.
++ *
++ */
++
++#include "config.h"
++
++#include "backends/meta-cursor-sprite-xcursor.h"
++
++#include "backends/meta-cursor.h"
++#include "backends/meta-cursor-renderer.h"
++#include "clutter/clutter.h"
++#include "cogl/cogl.h"
++#include "meta/prefs.h"
++
++struct _MetaCursorSpriteXcursor
++{
++  MetaCursorSprite parent;
++
++  MetaCursor cursor;
++
++  int current_frame;
++  XcursorImages *xcursor_images;
++
++  int theme_scale;
++  gboolean theme_dirty;
++};
++
++G_DEFINE_TYPE (MetaCursorSpriteXcursor, meta_cursor_sprite_xcursor,
++               META_TYPE_CURSOR_SPRITE)
++
++static const char *
++translate_meta_cursor (MetaCursor cursor)
++{
++  switch (cursor)
++    {
++    case META_CURSOR_DEFAULT:
++      return "left_ptr";
++    case META_CURSOR_NORTH_RESIZE:
++      return "top_side";
++    case META_CURSOR_SOUTH_RESIZE:
++      return "bottom_side";
++    case META_CURSOR_WEST_RESIZE:
++      return "left_side";
++    case META_CURSOR_EAST_RESIZE:
++      return "right_side";
++    case META_CURSOR_SE_RESIZE:
++      return "bottom_right_corner";
++    case META_CURSOR_SW_RESIZE:
++      return "bottom_left_corner";
++    case META_CURSOR_NE_RESIZE:
++      return "top_right_corner";
++    case META_CURSOR_NW_RESIZE:
++      return "top_left_corner";
++    case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
++      return "fleur";
++    case META_CURSOR_BUSY:
++      return "watch";
++    case META_CURSOR_DND_IN_DRAG:
++      return "dnd-none";
++    case META_CURSOR_DND_MOVE:
++      return "dnd-move";
++    case META_CURSOR_DND_COPY:
++      return "dnd-copy";
++    case META_CURSOR_DND_UNSUPPORTED_TARGET:
++      return "dnd-none";
++    case META_CURSOR_POINTING_HAND:
++      return "hand2";
++    case META_CURSOR_CROSSHAIR:
++      return "crosshair";
++    case META_CURSOR_IBEAM:
++      return "xterm";
++    default:
++      break;
++    }
++
++  g_assert_not_reached ();
++}
++
++MetaCursor
++meta_cursor_sprite_xcursor_get_cursor (MetaCursorSpriteXcursor *sprite_xcursor)
++{
++  return sprite_xcursor->cursor;
++}
++
++Cursor
++meta_create_x_cursor (Display    *xdisplay,
++                      MetaCursor  cursor)
++{
++  return XcursorLibraryLoadCursor (xdisplay, translate_meta_cursor (cursor));
++}
++
++static XcursorImages *
++load_cursor_on_client (MetaCursor cursor, int scale)
++{
++  return XcursorLibraryLoadImages (translate_meta_cursor (cursor),
++                                   meta_prefs_get_cursor_theme (),
++                                   meta_prefs_get_cursor_size () * scale);
++}
++
++static void
++load_from_current_xcursor_image (MetaCursorSpriteXcursor *sprite_xcursor)
++{
++  MetaCursorSprite *sprite = META_CURSOR_SPRITE (sprite_xcursor);
++  XcursorImage *xc_image;
++  int width, height, rowstride;
++  CoglPixelFormat cogl_format;
++  ClutterBackend *clutter_backend;
++  CoglContext *cogl_context;
++  CoglTexture2D *texture;
++  CoglError *error = NULL;
++
++  g_assert (!meta_cursor_sprite_get_cogl_texture (sprite));
++
++  xc_image = meta_cursor_sprite_xcursor_get_current_image (sprite_xcursor);
++  width = (int) xc_image->width;
++  height = (int) xc_image->height;
++  rowstride = width * 4;
++
++#if G_BYTE_ORDER == G_LITTLE_ENDIAN
++  cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
++#else
++  cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
++#endif
++
++  clutter_backend = clutter_get_default_backend ();
++  cogl_context = clutter_backend_get_cogl_context (clutter_backend);
++  texture = cogl_texture_2d_new_from_data (cogl_context,
++                                           width, height,
++                                           cogl_format,
++                                           rowstride,
++                                           (uint8_t *) xc_image->pixels,
++                                           &error);
++  if (!texture)
++    {
++      g_warning ("Failed to allocate cursor texture: %s\n", error->message);
++      cogl_error_free (error);
++    }
++
++  meta_cursor_sprite_set_texture (sprite,
++                                  COGL_TEXTURE (texture),
++                                  xc_image->xhot, xc_image->yhot);
++
++  if (texture)
++    cogl_object_unref (texture);
++}
++
++void
++meta_cursor_sprite_xcursor_set_theme_scale (MetaCursorSpriteXcursor *sprite_xcursor,
++                                            int                      theme_scale)
++{
++  if (sprite_xcursor->theme_scale != theme_scale)
++    sprite_xcursor->theme_dirty = TRUE;
++  sprite_xcursor->theme_scale = theme_scale;
++}
++
++
++static gboolean
++meta_cursor_sprite_xcursor_is_animated (MetaCursorSprite *sprite)
++{
++  MetaCursorSpriteXcursor *sprite_xcursor = META_CURSOR_SPRITE_XCURSOR (sprite);
++
++  return (sprite_xcursor->xcursor_images &&
++          sprite_xcursor->xcursor_images->nimage > 1);
++}
++
++XcursorImage *
++meta_cursor_sprite_xcursor_get_current_image (MetaCursorSpriteXcursor *sprite_xcursor)
++{
++  return sprite_xcursor->xcursor_images->images[sprite_xcursor->current_frame];
++}
++
++static void
++meta_cursor_sprite_xcursor_tick_frame (MetaCursorSprite *sprite)
++{
++  MetaCursorSpriteXcursor *sprite_xcursor = META_CURSOR_SPRITE_XCURSOR (sprite);
++
++  if (!meta_cursor_sprite_is_animated (sprite))
++    return;
++
++  sprite_xcursor->current_frame++;
++
++  if (sprite_xcursor->current_frame >= sprite_xcursor->xcursor_images->nimage)
++    sprite_xcursor->current_frame = 0;
++
++  meta_cursor_sprite_clear_texture (sprite);
++  load_from_current_xcursor_image (sprite_xcursor);
++}
++
++static unsigned int
++meta_cursor_sprite_xcursor_get_current_frame_time (MetaCursorSprite *sprite)
++{
++  MetaCursorSpriteXcursor *sprite_xcursor = META_CURSOR_SPRITE_XCURSOR (sprite);
++  XcursorImages *xcursor_images;
++
++  g_return_val_if_fail (meta_cursor_sprite_is_animated (sprite), 0);
++
++  xcursor_images = sprite_xcursor->xcursor_images;
++  return xcursor_images->images[sprite_xcursor->current_frame]->delay;
++}
++
++static void
++load_cursor_from_theme (MetaCursorSprite *sprite)
++{
++  MetaCursorSpriteXcursor *sprite_xcursor = META_CURSOR_SPRITE_XCURSOR (sprite);
++
++  g_assert (sprite_xcursor->cursor != META_CURSOR_NONE);
++
++  sprite_xcursor->theme_dirty = FALSE;
++
++  /* We might be reloading with a different scale. If so clear the old data. */
++  if (sprite_xcursor->xcursor_images)
++    {
++      meta_cursor_sprite_clear_texture (sprite);
++      XcursorImagesDestroy (sprite_xcursor->xcursor_images);
++    }
++
++  sprite_xcursor->current_frame = 0;
++  sprite_xcursor->xcursor_images =
++    load_cursor_on_client (sprite_xcursor->cursor,
++                           sprite_xcursor->theme_scale);
++  if (!sprite_xcursor->xcursor_images)
++    g_error ("Could not find cursor. Perhaps set XCURSOR_PATH?");
++
++  load_from_current_xcursor_image (sprite_xcursor);
++}
++
++static void
++meta_cursor_sprite_xcursor_realize_texture (MetaCursorSprite *sprite)
++{
++  MetaCursorSpriteXcursor *sprite_xcursor = META_CURSOR_SPRITE_XCURSOR (sprite);
++
++  if (sprite_xcursor->theme_dirty)
++    load_cursor_from_theme (sprite);
++}
++
++MetaCursorSpriteXcursor *
++meta_cursor_sprite_xcursor_new (MetaCursor cursor)
++{
++  MetaCursorSpriteXcursor *sprite_xcursor;
++
++  sprite_xcursor = g_object_new (META_TYPE_CURSOR_SPRITE_XCURSOR, NULL);
++  sprite_xcursor->cursor = cursor;
++
++  return sprite_xcursor;
++}
++
++static void
++meta_cursor_sprite_xcursor_finalize (GObject *object)
++{
++  MetaCursorSpriteXcursor *sprite_xcursor = META_CURSOR_SPRITE_XCURSOR (object);
++
++  g_clear_pointer (&sprite_xcursor->xcursor_images,
++                   XcursorImagesDestroy);
++
++  G_OBJECT_CLASS (meta_cursor_sprite_xcursor_parent_class)->finalize (object);
++}
++
++static void
++meta_cursor_sprite_xcursor_init (MetaCursorSpriteXcursor *sprite_xcursor)
++{
++  sprite_xcursor->theme_dirty = TRUE;
++}
++
++static void
++meta_cursor_sprite_xcursor_class_init (MetaCursorSpriteXcursorClass *klass)
++{
++  GObjectClass *object_class = G_OBJECT_CLASS (klass);
++  MetaCursorSpriteClass *cursor_sprite_class = META_CURSOR_SPRITE_CLASS (klass);
++
++  object_class->finalize = meta_cursor_sprite_xcursor_finalize;
++
++  cursor_sprite_class->realize_texture =
++    meta_cursor_sprite_xcursor_realize_texture;
++  cursor_sprite_class->is_animated = meta_cursor_sprite_xcursor_is_animated;
++  cursor_sprite_class->tick_frame = meta_cursor_sprite_xcursor_tick_frame;
++  cursor_sprite_class->get_current_frame_time =
++    meta_cursor_sprite_xcursor_get_current_frame_time;
++}
+diff --git a/src/backends/meta-cursor-sprite-xcursor.h b/src/backends/meta-cursor-sprite-xcursor.h
+new file mode 100644
+index 000000000..dbc927484
+--- /dev/null
++++ b/src/backends/meta-cursor-sprite-xcursor.h
+@@ -0,0 +1,43 @@
++/*
++ * Copyright 2013, 2018 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_CURSOR_SPRITE_XCURSOR_H
++#define META_CURSOR_SPRITE_XCURSOR_H
++
++#include <glib-object.h>
++#include <X11/Xcursor/Xcursor.h>
++
++#include "backends/meta-cursor.h"
++
++#define META_TYPE_CURSOR_SPRITE_XCURSOR meta_cursor_sprite_xcursor_get_type ()
++G_DECLARE_FINAL_TYPE (MetaCursorSpriteXcursor, meta_cursor_sprite_xcursor,
++                      META, CURSOR_SPRITE_XCURSOR, MetaCursorSprite)
++
++MetaCursorSpriteXcursor * meta_cursor_sprite_xcursor_new (MetaCursor cursor);
++
++void meta_cursor_sprite_xcursor_set_theme_scale (MetaCursorSpriteXcursor *sprite_xcursor,
++                                                 int                      scale);
++
++MetaCursor meta_cursor_sprite_xcursor_get_cursor (MetaCursorSpriteXcursor *sprite_xcusror);
++
++XcursorImage * meta_cursor_sprite_xcursor_get_current_image (MetaCursorSpriteXcursor *sprite_xcursor);
++
++Cursor meta_create_x_cursor (Display    *xdisplay,
++                             MetaCursor  cursor);
++
++#endif /* META_CURSOR_SPRITE_XCURSOR_H */
+diff --git a/src/backends/meta-cursor-tracker-private.h b/src/backends/meta-cursor-tracker-private.h
+index 2ec946847..6f4f84b83 100644
+--- a/src/backends/meta-cursor-tracker-private.h
++++ b/src/backends/meta-cursor-tracker-private.h
+@@ -26,6 +26,7 @@
+ 
+ #include "meta-cursor.h"
+ #include "meta-cursor-renderer.h"
++#include "backends/x11/cm/meta-cursor-sprite-xfixes.h"
+ 
+ struct _MetaCursorTracker {
+   GObject parent_instance;
+@@ -46,7 +47,7 @@ struct _MetaCursorTracker {
+   MetaCursorSprite *root_cursor;
+ 
+   /* The cursor from the X11 server. */
+-  MetaCursorSprite *xfixes_cursor;
++  MetaCursorSpriteXfixes *xfixes_cursor;
+ };
+ 
+ struct _MetaCursorTrackerClass {
+diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c
+index 74fa4351d..6244f11ee 100644
+--- a/src/backends/meta-cursor-tracker.c
++++ b/src/backends/meta-cursor-tracker.c
+@@ -40,9 +40,9 @@
+ 
+ #include <gdk/gdk.h>
+ #include <gdk/gdkx.h>
+-#include <X11/extensions/Xfixes.h>
+ 
+ #include "meta-backend-private.h"
++#include "backends/x11/cm/meta-cursor-sprite-xfixes.h"
+ 
+ G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
+ 
+@@ -218,75 +218,14 @@ static void
+ ensure_xfixes_cursor (MetaCursorTracker *tracker)
+ {
+   MetaDisplay *display = meta_get_display ();
+-  XFixesCursorImage *cursor_image;
+-  CoglTexture2D *sprite;
+-  guint8 *cursor_data;
+-  gboolean free_cursor_data;
+-  CoglContext *ctx;
+-  CoglError *error = NULL;
++  g_autoptr (GError) error = NULL;
+ 
+   if (tracker->xfixes_cursor)
+     return;
+ 
+-  cursor_image = XFixesGetCursorImage (display->xdisplay);
+-  if (!cursor_image)
+-    return;
+-
+-  /* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit
+-   * quantities as arrays of long; we need to convert on 64 bit */
+-  if (sizeof(long) == 4)
+-    {
+-      cursor_data = (guint8 *)cursor_image->pixels;
+-      free_cursor_data = FALSE;
+-    }
+-  else
+-    {
+-      int i, j;
+-      guint32 *cursor_words;
+-      gulong *p;
+-      guint32 *q;
+-
+-      cursor_words = g_new (guint32, cursor_image->width * cursor_image->height);
+-      cursor_data = (guint8 *)cursor_words;
+-
+-      p = cursor_image->pixels;
+-      q = cursor_words;
+-      for (j = 0; j < cursor_image->height; j++)
+-        for (i = 0; i < cursor_image->width; i++)
+-          *(q++) = *(p++);
+-
+-      free_cursor_data = TRUE;
+-    }
+-
+-  ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
+-  sprite = cogl_texture_2d_new_from_data (ctx,
+-                                          cursor_image->width,
+-                                          cursor_image->height,
+-                                          CLUTTER_CAIRO_FORMAT_ARGB32,
+-                                          cursor_image->width * 4, /* stride */
+-                                          cursor_data,
+-                                          &error);
+-
+-  if (free_cursor_data)
+-    g_free (cursor_data);
+-
+-  if (error != NULL)
+-    {
+-      meta_warning ("Failed to allocate cursor sprite texture: %s\n", error->message);
+-      cogl_error_free (error);
+-    }
+-
+-  if (sprite != NULL)
+-    {
+-      MetaCursorSprite *cursor_sprite = meta_cursor_sprite_new ();
+-      meta_cursor_sprite_set_texture (cursor_sprite,
+-                                      COGL_TEXTURE (sprite),
+-                                      cursor_image->xhot,
+-                                      cursor_image->yhot);
+-      cogl_object_unref (sprite);
+-      tracker->xfixes_cursor = cursor_sprite;
+-    }
+-  XFree (cursor_image);
++  tracker->xfixes_cursor = meta_cursor_sprite_xfixes_new (display, &error);
++  if (!tracker->xfixes_cursor)
++    g_warning ("Failed to create XFIXES cursor: %s", error->message);
+ }
+ 
+ /**
+@@ -308,7 +247,7 @@ meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
+   else
+     {
+       ensure_xfixes_cursor (tracker);
+-      cursor_sprite = tracker->xfixes_cursor;
++      cursor_sprite = META_CURSOR_SPRITE (tracker->xfixes_cursor);
+     }
+ 
+   if (cursor_sprite)
+@@ -345,7 +284,7 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
+   else
+     {
+       ensure_xfixes_cursor (tracker);
+-      cursor_sprite = tracker->xfixes_cursor;
++      cursor_sprite = META_CURSOR_SPRITE (tracker->xfixes_cursor);
+     }
+ 
+   if (cursor_sprite)
+diff --git a/src/backends/meta-cursor.c b/src/backends/meta-cursor.c
+index beeee765b..9750dc00b 100644
+--- a/src/backends/meta-cursor.c
++++ b/src/backends/meta-cursor.c
+@@ -23,19 +23,12 @@
+ 
+ #include "meta-cursor.h"
+ 
+-#include <meta/errors.h>
++#include "backends/meta-backend-private.h"
++#include "cogl/cogl.h"
++#include "meta/common.h"
+ 
+-#include "display-private.h"
+-#include "screen-private.h"
+-#include "meta-backend-private.h"
+-
+-#include <string.h>
+-
+-#include <X11/cursorfont.h>
+-#include <X11/extensions/Xfixes.h>
+-#include <X11/Xcursor/Xcursor.h>
+-
+-enum {
++enum
++{
+   PREPARE_AT,
+   TEXTURE_CHANGED,
+ 
+@@ -44,316 +37,148 @@ enum {
+ 
+ static guint signals[LAST_SIGNAL];
+ 
+-struct _MetaCursorSprite
++typedef struct _MetaCursorSpritePrivate
+ {
+   GObject parent;
+ 
+-  MetaCursor cursor;
+-
+   CoglTexture2D *texture;
+   float texture_scale;
+   int hot_x, hot_y;
++} MetaCursorSpritePrivate;
+ 
+-  int current_frame;
+-  XcursorImages *xcursor_images;
+-
+-  int theme_scale;
+-  gboolean theme_dirty;
+-};
+-
+-G_DEFINE_TYPE (MetaCursorSprite, meta_cursor_sprite, G_TYPE_OBJECT)
++G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaCursorSprite,
++                                     meta_cursor_sprite,
++                                     G_TYPE_OBJECT)
+ 
+-static const char *
+-translate_meta_cursor (MetaCursor cursor)
+-{
+-  switch (cursor)
+-    {
+-    case META_CURSOR_DEFAULT:
+-      return "left_ptr";
+-    case META_CURSOR_NORTH_RESIZE:
+-      return "top_side";
+-    case META_CURSOR_SOUTH_RESIZE:
+-      return "bottom_side";
+-    case META_CURSOR_WEST_RESIZE:
+-      return "left_side";
+-    case META_CURSOR_EAST_RESIZE:
+-      return "right_side";
+-    case META_CURSOR_SE_RESIZE:
+-      return "bottom_right_corner";
+-    case META_CURSOR_SW_RESIZE:
+-      return "bottom_left_corner";
+-    case META_CURSOR_NE_RESIZE:
+-      return "top_right_corner";
+-    case META_CURSOR_NW_RESIZE:
+-      return "top_left_corner";
+-    case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
+-      return "fleur";
+-    case META_CURSOR_BUSY:
+-      return "watch";
+-    case META_CURSOR_DND_IN_DRAG:
+-      return "dnd-none";
+-    case META_CURSOR_DND_MOVE:
+-      return "dnd-move";
+-    case META_CURSOR_DND_COPY:
+-      return "dnd-copy";
+-    case META_CURSOR_DND_UNSUPPORTED_TARGET:
+-      return "dnd-none";
+-    case META_CURSOR_POINTING_HAND:
+-      return "hand2";
+-    case META_CURSOR_CROSSHAIR:
+-      return "crosshair";
+-    case META_CURSOR_IBEAM:
+-      return "xterm";
+-    default:
+-      break;
+-    }
+-
+-  g_assert_not_reached ();
+-}
+-
+-Cursor
+-meta_cursor_create_x_cursor (Display    *xdisplay,
+-                             MetaCursor  cursor)
+-{
+-  return XcursorLibraryLoadCursor (xdisplay, translate_meta_cursor (cursor));
+-}
+-
+-static XcursorImages *
+-load_cursor_on_client (MetaCursor cursor, int scale)
+-{
+-  return XcursorLibraryLoadImages (translate_meta_cursor (cursor),
+-                                   meta_prefs_get_cursor_theme (),
+-                                   meta_prefs_get_cursor_size () * scale);
+-}
+-
+-static void
+-meta_cursor_sprite_load_from_xcursor_image (MetaCursorSprite *self,
+-                                            XcursorImage     *xc_image)
++gboolean
++meta_cursor_sprite_is_animated (MetaCursorSprite *sprite)
+ {
+-  MetaBackend *meta_backend = meta_get_backend ();
+-  MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
+-  uint width, height, rowstride;
+-  CoglPixelFormat cogl_format;
+-  ClutterBackend *clutter_backend;
+-  CoglContext *cogl_context;
+-  CoglTexture2D *texture;
+-  CoglError *error = NULL;
+-
+-  g_assert (self->texture == NULL);
+-
+-  width           = xc_image->width;
+-  height          = xc_image->height;
+-  rowstride       = width * 4;
+-
+-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+-  cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
+-#else
+-  cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
+-#endif
+-
+-  clutter_backend = clutter_get_default_backend ();
+-  cogl_context = clutter_backend_get_cogl_context (clutter_backend);
+-  texture = cogl_texture_2d_new_from_data (cogl_context,
+-                                           width, height,
+-                                           cogl_format,
+-                                           rowstride,
+-                                           (uint8_t *) xc_image->pixels,
+-                                           &error);
+-
+-  if (error)
+-    {
+-      meta_warning ("Failed to allocate cursor texture: %s\n", error->message);
+-      cogl_error_free (error);
+-    }
+-
+-  meta_cursor_sprite_set_texture (self, COGL_TEXTURE (texture),
+-                                  xc_image->xhot, xc_image->yhot);
++  MetaCursorSpriteClass *klass = META_CURSOR_SPRITE_GET_CLASS (sprite);
+ 
+-  if (texture)
+-    cogl_object_unref (texture);
+-
+-  meta_cursor_renderer_realize_cursor_from_xcursor (renderer, self, xc_image);
+-}
+-
+-static XcursorImage *
+-meta_cursor_sprite_get_current_frame_image (MetaCursorSprite *self)
+-{
+-  return self->xcursor_images->images[self->current_frame];
++  if (klass->is_animated)
++    return klass->is_animated (sprite);
++  else
++    return FALSE;
+ }
+ 
+ void
+-meta_cursor_sprite_tick_frame (MetaCursorSprite *self)
+-{
+-  XcursorImage *image;
+-
+-  if (!meta_cursor_sprite_is_animated (self))
+-    return;
+-
+-  self->current_frame++;
+-
+-  if (self->current_frame >= self->xcursor_images->nimage)
+-    self->current_frame = 0;
+-
+-  image = meta_cursor_sprite_get_current_frame_image (self);
+-
+-  g_clear_pointer (&self->texture, cogl_object_unref);
+-  meta_cursor_sprite_load_from_xcursor_image (self, image);
+-}
+-
+-guint
+-meta_cursor_sprite_get_current_frame_time (MetaCursorSprite *self)
+-{
+-  if (!meta_cursor_sprite_is_animated (self))
+-    return 0;
+-
+-  return self->xcursor_images->images[self->current_frame]->delay;
+-}
+-
+-gboolean
+-meta_cursor_sprite_is_animated (MetaCursorSprite *self)
++meta_cursor_sprite_tick_frame (MetaCursorSprite *sprite)
+ {
+-  return (self->xcursor_images &&
+-          self->xcursor_images->nimage > 1);
++  return META_CURSOR_SPRITE_GET_CLASS (sprite)->tick_frame (sprite);
+ }
+ 
+-MetaCursorSprite *
+-meta_cursor_sprite_new (void)
++unsigned int
++meta_cursor_sprite_get_current_frame_time (MetaCursorSprite *sprite)
+ {
+-  return g_object_new (META_TYPE_CURSOR_SPRITE, NULL);
++  return META_CURSOR_SPRITE_GET_CLASS (sprite)->get_current_frame_time (sprite);
+ }
+ 
+-static void
+-meta_cursor_sprite_load_from_theme (MetaCursorSprite *self)
+-{
+-  XcursorImage *image;
+-
+-  g_assert (self->cursor != META_CURSOR_NONE);
+-
+-  self->theme_dirty = FALSE;
+-
+-  /* We might be reloading with a different scale. If so clear the old data. */
+-  if (self->xcursor_images)
+-    {
+-      g_clear_pointer (&self->texture, cogl_object_unref);
+-      XcursorImagesDestroy (self->xcursor_images);
+-    }
+-
+-  self->current_frame = 0;
+-  self->xcursor_images = load_cursor_on_client (self->cursor,
+-                                                self->theme_scale);
+-  if (!self->xcursor_images)
+-    meta_fatal ("Could not find cursor. Perhaps set XCURSOR_PATH?");
+-
+-  image = meta_cursor_sprite_get_current_frame_image (self);
+-  meta_cursor_sprite_load_from_xcursor_image (self, image);
+-}
+-
+-MetaCursorSprite *
+-meta_cursor_sprite_from_theme (MetaCursor cursor)
++void
++meta_cursor_sprite_clear_texture (MetaCursorSprite *sprite)
+ {
+-  MetaCursorSprite *self;
+-
+-  self = meta_cursor_sprite_new ();
+-
+-  self->cursor = cursor;
+-  self->theme_dirty = TRUE;
++  MetaCursorSpritePrivate *priv =
++    meta_cursor_sprite_get_instance_private (sprite);
+ 
+-  return self;
++  g_clear_pointer (&priv->texture, cogl_object_unref);
+ }
+ 
+ void
+-meta_cursor_sprite_set_texture (MetaCursorSprite *self,
++meta_cursor_sprite_set_texture (MetaCursorSprite *sprite,
+                                 CoglTexture      *texture,
+                                 int               hot_x,
+                                 int               hot_y)
+ {
+-  if (self->texture == COGL_TEXTURE_2D (texture) &&
+-      self->hot_x == hot_x &&
+-      self->hot_y == hot_y)
++  MetaCursorSpritePrivate *priv =
++    meta_cursor_sprite_get_instance_private (sprite);
++
++  if (priv->texture == COGL_TEXTURE_2D (texture) &&
++      priv->hot_x == hot_x &&
++      priv->hot_y == hot_y)
+     return;
+ 
+-  g_clear_pointer (&self->texture, cogl_object_unref);
++  g_clear_pointer (&priv->texture, cogl_object_unref);
+   if (texture)
+-    self->texture = cogl_object_ref (texture);
+-  self->hot_x = hot_x;
+-  self->hot_y = hot_y;
++    priv->texture = cogl_object_ref (texture);
++  priv->hot_x = hot_x;
++  priv->hot_y = hot_y;
+ 
+-  g_signal_emit (self, signals[TEXTURE_CHANGED], 0);
++  g_signal_emit (sprite, signals[TEXTURE_CHANGED], 0);
+ }
+ 
+ void
+-meta_cursor_sprite_set_texture_scale (MetaCursorSprite *self,
++meta_cursor_sprite_set_texture_scale (MetaCursorSprite *sprite,
+                                       float             scale)
+ {
+-  self->texture_scale = scale;
+-}
++  MetaCursorSpritePrivate *priv =
++    meta_cursor_sprite_get_instance_private (sprite);
+ 
+-void
+-meta_cursor_sprite_set_theme_scale (MetaCursorSprite *self,
+-                                    int               theme_scale)
+-{
+-  if (self->theme_scale != theme_scale)
+-    self->theme_dirty = TRUE;
+-  self->theme_scale = theme_scale;
++  priv->texture_scale = scale;
+ }
+ 
+ CoglTexture *
+-meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self)
++meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *sprite)
+ {
+-  return COGL_TEXTURE (self->texture);
+-}
++  MetaCursorSpritePrivate *priv =
++    meta_cursor_sprite_get_instance_private (sprite);
+ 
+-MetaCursor
+-meta_cursor_sprite_get_meta_cursor (MetaCursorSprite *self)
+-{
+-  return self->cursor;
++  return COGL_TEXTURE (priv->texture);
+ }
+ 
+ void
+-meta_cursor_sprite_get_hotspot (MetaCursorSprite *self,
++meta_cursor_sprite_get_hotspot (MetaCursorSprite *sprite,
+                                 int              *hot_x,
+                                 int              *hot_y)
+ {
+-  *hot_x = self->hot_x;
+-  *hot_y = self->hot_y;
++  MetaCursorSpritePrivate *priv =
++    meta_cursor_sprite_get_instance_private (sprite);
++
++  *hot_x = priv->hot_x;
++  *hot_y = priv->hot_y;
+ }
+ 
+ float
+-meta_cursor_sprite_get_texture_scale (MetaCursorSprite *self)
++meta_cursor_sprite_get_texture_scale (MetaCursorSprite *sprite)
+ {
+-  return self->texture_scale;
++  MetaCursorSpritePrivate *priv =
++    meta_cursor_sprite_get_instance_private (sprite);
++
++  return priv->texture_scale;
+ }
+ 
+ void
+-meta_cursor_sprite_prepare_at (MetaCursorSprite *self,
++meta_cursor_sprite_prepare_at (MetaCursorSprite *sprite,
+                                int               x,
+                                int               y)
+ {
+-  g_signal_emit (self, signals[PREPARE_AT], 0, x, y);
++  g_signal_emit (sprite, signals[PREPARE_AT], 0, x, y);
+ }
+ 
+ void
+-meta_cursor_sprite_realize_texture (MetaCursorSprite *self)
++meta_cursor_sprite_realize_texture (MetaCursorSprite *sprite)
+ {
+-  if (self->theme_dirty)
+-    meta_cursor_sprite_load_from_theme (self);
++  MetaCursorSpriteClass *klass = META_CURSOR_SPRITE_GET_CLASS (sprite);
++
++  if (klass->realize_texture)
++    klass->realize_texture (sprite);
+ }
+ 
+ static void
+-meta_cursor_sprite_init (MetaCursorSprite *self)
++meta_cursor_sprite_init (MetaCursorSprite *sprite)
+ {
+-  self->texture_scale = 1.0f;
++  MetaCursorSpritePrivate *priv =
++    meta_cursor_sprite_get_instance_private (sprite);
++
++  priv->texture_scale = 1.0f;
+ }
+ 
+ static void
+ meta_cursor_sprite_finalize (GObject *object)
+ {
+-  MetaCursorSprite *self = META_CURSOR_SPRITE (object);
+-
+-  if (self->xcursor_images)
+-    XcursorImagesDestroy (self->xcursor_images);
++  MetaCursorSprite *sprite = META_CURSOR_SPRITE (object);
++  MetaCursorSpritePrivate *priv =
++    meta_cursor_sprite_get_instance_private (sprite);
+ 
+-  g_clear_pointer (&self->texture, cogl_object_unref);
++  g_clear_pointer (&priv->texture, cogl_object_unref);
+ 
+   G_OBJECT_CLASS (meta_cursor_sprite_parent_class)->finalize (object);
+ }
+diff --git a/src/backends/meta-cursor.h b/src/backends/meta-cursor.h
+index 6087df69c..3051fdee6 100644
+--- a/src/backends/meta-cursor.h
++++ b/src/backends/meta-cursor.h
+@@ -25,51 +25,50 @@
+ #include <meta/common.h>
+ #include <meta/boxes.h>
+ 
+-typedef struct _MetaCursorSprite MetaCursorSprite;
+-
+ #define META_TYPE_CURSOR_SPRITE (meta_cursor_sprite_get_type ())
+-G_DECLARE_FINAL_TYPE (MetaCursorSprite,
+-                      meta_cursor_sprite,
+-                      META, CURSOR_SPRITE,
+-                      GObject);
+-
+-MetaCursorSprite * meta_cursor_sprite_new (void);
+-
+-MetaCursorSprite * meta_cursor_sprite_from_theme  (MetaCursor cursor);
+-
+-
+-void meta_cursor_sprite_set_theme_scale (MetaCursorSprite *self,
+-                                         int               scale);
+-
+-MetaCursor meta_cursor_sprite_get_meta_cursor (MetaCursorSprite *self);
+-
+-Cursor meta_cursor_create_x_cursor (Display    *xdisplay,
+-                                    MetaCursor  cursor);
+-
+-void meta_cursor_sprite_prepare_at (MetaCursorSprite *self,
++G_DECLARE_DERIVABLE_TYPE (MetaCursorSprite,
++                          meta_cursor_sprite,
++                          META, CURSOR_SPRITE,
++                          GObject)
++
++struct _MetaCursorSpriteClass
++{
++  GObjectClass parent_class;
++
++  void (* realize_texture) (MetaCursorSprite *sprite);
++  gboolean (* is_animated) (MetaCursorSprite *sprite);
++  void (* tick_frame) (MetaCursorSprite *sprite);
++  unsigned int (* get_current_frame_time) (MetaCursorSprite *sprite);
++};
++
++void meta_cursor_sprite_prepare_at (MetaCursorSprite *sprite,
+                                     int               x,
+                                     int               y);
+ 
+-void meta_cursor_sprite_realize_texture (MetaCursorSprite *self);
++void meta_cursor_sprite_realize_texture (MetaCursorSprite *sprite);
++
++void meta_cursor_sprite_clear_texture (MetaCursorSprite *sprite);
+ 
+-void meta_cursor_sprite_set_texture (MetaCursorSprite *self,
++void meta_cursor_sprite_set_texture (MetaCursorSprite *sprite,
+                                      CoglTexture      *texture,
+                                      int               hot_x,
+                                      int               hot_y);
+ 
+-void meta_cursor_sprite_set_texture_scale (MetaCursorSprite *self,
++void meta_cursor_sprite_set_texture_scale (MetaCursorSprite *sprite,
+                                            float             scale);
+ 
+-CoglTexture *meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self);
++CoglTexture *meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *sprite);
+ 
+-void meta_cursor_sprite_get_hotspot (MetaCursorSprite *self,
++void meta_cursor_sprite_get_hotspot (MetaCursorSprite *sprite,
+                                      int              *hot_x,
+                                      int              *hot_y);
+ 
+-float meta_cursor_sprite_get_texture_scale (MetaCursorSprite *self);
++float meta_cursor_sprite_get_texture_scale (MetaCursorSprite *sprite);
++
++gboolean meta_cursor_sprite_is_animated (MetaCursorSprite *sprite);
++
++void meta_cursor_sprite_tick_frame (MetaCursorSprite *sprite);
+ 
+-gboolean meta_cursor_sprite_is_animated            (MetaCursorSprite *self);
+-void     meta_cursor_sprite_tick_frame             (MetaCursorSprite *self);
+-guint    meta_cursor_sprite_get_current_frame_time (MetaCursorSprite *self);
++unsigned int meta_cursor_sprite_get_current_frame_time (MetaCursorSprite *sprite);
+ 
+ #endif /* META_CURSOR_H */
+diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
+index a29f593ea..042d96ec6 100644
+--- a/src/backends/native/meta-backend-native.c
++++ b/src/backends/native/meta-backend-native.c
+@@ -645,8 +645,6 @@ void meta_backend_native_resume (MetaBackendNative *native)
+     meta_backend_get_monitor_manager (backend);
+   MetaMonitorManagerKms *monitor_manager_kms =
+     META_MONITOR_MANAGER_KMS (monitor_manager);
+-  MetaCursorRenderer *cursor_renderer;
+-  MetaCursorRendererNative *cursor_renderer_native;
+   ClutterActor *stage;
+   MetaIdleMonitor *idle_monitor;
+ 
+@@ -658,10 +656,6 @@ void meta_backend_native_resume (MetaBackendNative *native)
+   stage = meta_backend_get_stage (backend);
+   clutter_actor_queue_redraw (stage);
+ 
+-  cursor_renderer = meta_backend_get_cursor_renderer (backend);
+-  cursor_renderer_native = META_CURSOR_RENDERER_NATIVE (cursor_renderer);
+-  meta_cursor_renderer_native_force_update (cursor_renderer_native);
+-
+   idle_monitor = meta_backend_get_idle_monitor (backend, 0);
+   meta_idle_monitor_reset_idletime (idle_monitor);
+ }
+diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c
+index c7326af42..29800953b 100644
+--- a/src/backends/native/meta-cursor-renderer-native.c
++++ b/src/backends/native/meta-cursor-renderer-native.c
+@@ -35,6 +35,7 @@
+ #include <meta/meta-backend.h>
+ 
+ #include "backends/meta-backend-private.h"
++#include "backends/meta-cursor-sprite-xcursor.h"
+ #include "backends/meta-logical-monitor.h"
+ #include "backends/meta-monitor.h"
+ #include "backends/meta-monitor-manager-private.h"
+@@ -43,6 +44,11 @@
+ #include "core/boxes-private.h"
+ #include "meta/boxes.h"
+ 
++#ifdef HAVE_WAYLAND
++#include "wayland/meta-cursor-sprite-wayland.h"
++#include "wayland/meta-wayland-buffer.h"
++#endif
++
+ #ifndef DRM_CAP_CURSOR_WIDTH
+ #define DRM_CAP_CURSOR_WIDTH 0x8
+ #endif
+@@ -113,6 +119,11 @@ static GQuark quark_cursor_renderer_native_gpu_data = 0;
+ 
+ G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererNative, meta_cursor_renderer_native, META_TYPE_CURSOR_RENDERER);
+ 
++static void
++realize_cursor_sprite (MetaCursorRenderer *renderer,
++                       MetaCursorSprite   *cursor_sprite,
++                       GList              *gpus);
++
+ static MetaCursorNativeGpuState *
+ get_cursor_gpu_state (MetaCursorNativePrivate *cursor_priv,
+                       MetaGpuKms              *gpu_kms);
+@@ -152,7 +163,8 @@ static void
+ meta_cursor_renderer_native_finalize (GObject *object)
+ {
+   MetaCursorRendererNative *renderer = META_CURSOR_RENDERER_NATIVE (object);
+-  MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (renderer);
++  MetaCursorRendererNativePrivate *priv =
++    meta_cursor_renderer_native_get_instance_private (renderer);
+ 
+   if (priv->animation_timeout_id)
+     g_source_remove (priv->animation_timeout_id);
+@@ -203,7 +215,8 @@ set_crtc_cursor (MetaCursorRendererNative *native,
+                  MetaCrtc                 *crtc,
+                  MetaCursorSprite         *cursor_sprite)
+ {
+-  MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
++  MetaCursorRendererNativePrivate *priv =
++    meta_cursor_renderer_native_get_instance_private (native);
+   MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
+   MetaGpuKms *gpu_kms;
+   int kms_fd;
+@@ -371,7 +384,8 @@ static void
+ update_hw_cursor (MetaCursorRendererNative *native,
+                   MetaCursorSprite         *cursor_sprite)
+ {
+-  MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
++  MetaCursorRendererNativePrivate *priv =
++    meta_cursor_renderer_native_get_instance_private (native);
+   MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
+   MetaMonitorManager *monitor_manager = priv->monitor_manager;
+   GList *logical_monitors;
+@@ -564,18 +578,15 @@ can_draw_cursor_unscaled (MetaCursorRenderer *renderer,
+ 
+ static gboolean
+ should_have_hw_cursor (MetaCursorRenderer *renderer,
+-                       MetaCursorSprite   *cursor_sprite)
++                       MetaCursorSprite   *cursor_sprite,
++                       GList              *gpus)
+ {
+-  MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
+-  MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
+-  GList *gpus;
+   GList *l;
+   CoglTexture *texture;
+ 
+   if (!cursor_sprite)
+     return FALSE;
+ 
+-  gpus = meta_monitor_manager_get_gpus (priv->monitor_manager);
+   for (l = gpus; l; l = l->next)
+     {
+       MetaGpuKms *gpu_kms = l->data;
+@@ -609,7 +620,8 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
+ static gboolean
+ meta_cursor_renderer_native_update_animation (MetaCursorRendererNative *native)
+ {
+-  MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
++  MetaCursorRendererNativePrivate *priv =
++    meta_cursor_renderer_native_get_instance_private (native);
+   MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
+   MetaCursorSprite *cursor_sprite = meta_cursor_renderer_get_cursor (renderer);
+ 
+@@ -621,10 +633,11 @@ meta_cursor_renderer_native_update_animation (MetaCursorRendererNative *native)
+ }
+ 
+ static void
+-meta_cursor_renderer_native_trigger_frame (MetaCursorRendererNative *native,
+-                                           MetaCursorSprite         *cursor_sprite)
++maybe_schedule_cursor_sprite_animation_frame (MetaCursorRendererNative *native,
++                                              MetaCursorSprite         *cursor_sprite)
+ {
+-  MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
++  MetaCursorRendererNativePrivate *priv =
++    meta_cursor_renderer_native_get_instance_private (native);
+   gboolean cursor_change;
+   guint delay;
+ 
+@@ -656,21 +669,78 @@ meta_cursor_renderer_native_trigger_frame (MetaCursorRendererNative *native,
+     }
+ }
+ 
++static GList *
++calculate_cursor_sprite_gpus (MetaCursorRenderer *renderer,
++                              MetaCursorSprite   *cursor_sprite)
++{
++  MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
++  MetaCursorRendererNativePrivate *priv =
++    meta_cursor_renderer_native_get_instance_private (native);
++  MetaMonitorManager *monitor_manager = priv->monitor_manager;
++  GList *gpus = NULL;
++  GList *logical_monitors;
++  GList *l;
++  ClutterRect cursor_rect;
++
++  cursor_rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
++
++  logical_monitors =
++    meta_monitor_manager_get_logical_monitors (monitor_manager);
++  for (l = logical_monitors; l; l = l->next)
++    {
++      MetaLogicalMonitor *logical_monitor = l->data;
++      MetaRectangle logical_monitor_layout;
++      ClutterRect logical_monitor_rect;
++      GList *monitors, *l_mon;
++
++      logical_monitor_layout =
++        meta_logical_monitor_get_layout (logical_monitor);
++      logical_monitor_rect =
++        meta_rectangle_to_clutter_rect (&logical_monitor_layout);
++
++      if (!clutter_rect_intersection (&cursor_rect, &logical_monitor_rect,
++                                      NULL))
++        continue;
++
++      monitors = meta_logical_monitor_get_monitors (logical_monitor);
++      for (l_mon = monitors; l_mon; l_mon = l_mon->next)
++        {
++          MetaMonitor *monitor = l_mon->data;
++          MetaGpu *gpu;
++
++          gpu = meta_monitor_get_gpu (monitor);
++          if (!g_list_find (gpus, gpu))
++            gpus = g_list_prepend (gpus, gpu);
++        }
++    }
++
++  return gpus;
++}
++
+ static gboolean
+ meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *renderer,
+                                            MetaCursorSprite   *cursor_sprite)
+ {
+   MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
+-  MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
++  MetaCursorRendererNativePrivate *priv =
++    meta_cursor_renderer_native_get_instance_private (native);
++  g_autoptr (GList) gpus = NULL;
+ 
+   if (cursor_sprite)
+-    meta_cursor_sprite_realize_texture (cursor_sprite);
++    {
++      meta_cursor_sprite_realize_texture (cursor_sprite);
++      gpus = calculate_cursor_sprite_gpus (renderer, cursor_sprite);
++      realize_cursor_sprite (renderer, cursor_sprite, gpus);
++    }
+ 
+-  meta_cursor_renderer_native_trigger_frame (native, cursor_sprite);
++  maybe_schedule_cursor_sprite_animation_frame (native, cursor_sprite);
+ 
+-  priv->has_hw_cursor = should_have_hw_cursor (renderer, cursor_sprite);
++  priv->has_hw_cursor = should_have_hw_cursor (renderer, cursor_sprite, gpus);
+   update_hw_cursor (native, cursor_sprite);
+-  return priv->has_hw_cursor;
++
++  return (priv->has_hw_cursor ||
++          !cursor_sprite ||
++          !meta_cursor_sprite_get_cogl_texture (cursor_sprite));
+ }
+ 
+ static void
+@@ -706,6 +776,24 @@ ensure_cursor_gpu_state (MetaCursorNativePrivate *cursor_priv,
+   return cursor_gpu_state;
+ }
+ 
++static void
++on_cursor_sprite_texture_changed (MetaCursorSprite *cursor_sprite)
++{
++  MetaCursorNativePrivate *cursor_priv = get_cursor_priv (cursor_sprite);
++  GHashTableIter iter;
++  MetaCursorNativeGpuState *cursor_gpu_state;
++
++  g_hash_table_iter_init (&iter, cursor_priv->gpu_states);
++  while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cursor_gpu_state))
++    {
++      guint pending_bo;
++      pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_gpu_state);
++      g_clear_pointer (&cursor_gpu_state->bos[pending_bo],
++                       (GDestroyNotify) gbm_bo_destroy);
++      cursor_gpu_state->pending_bo_state = META_CURSOR_GBM_BO_STATE_INVALIDATED;
++    }
++}
++
+ static void
+ cursor_priv_free (MetaCursorNativePrivate *cursor_priv)
+ {
+@@ -738,6 +826,9 @@ ensure_cursor_priv (MetaCursorSprite *cursor_sprite)
+                            cursor_priv,
+                            (GDestroyNotify) cursor_priv_free);
+ 
++  g_signal_connect (cursor_sprite, "texture-changed",
++                    G_CALLBACK (on_cursor_sprite_texture_changed), NULL);
++
+   return cursor_priv;
+ }
+ 
+@@ -805,57 +896,71 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native,
+     }
+ }
+ 
+-static void
+-invalidate_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite,
+-                                         MetaGpuKms       *gpu_kms)
++static gboolean
++is_cursor_hw_state_valid (MetaCursorSprite *cursor_sprite,
++                          MetaGpuKms       *gpu_kms)
+ {
+   MetaCursorNativePrivate *cursor_priv;
+   MetaCursorNativeGpuState *cursor_gpu_state;
+-  guint pending_bo;
+ 
+   cursor_priv = get_cursor_priv (cursor_sprite);
+   if (!cursor_priv)
+-    return;
++    return FALSE;
+ 
+   cursor_gpu_state = get_cursor_gpu_state (cursor_priv, gpu_kms);
+   if (!cursor_gpu_state)
+-    return;
++    return FALSE;
+ 
+-  pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_gpu_state);
+-  g_clear_pointer (&cursor_gpu_state->bos[pending_bo],
+-                   (GDestroyNotify) gbm_bo_destroy);
+-  cursor_gpu_state->pending_bo_state = META_CURSOR_GBM_BO_STATE_INVALIDATED;
++  switch (cursor_gpu_state->pending_bo_state)
++    {
++    case META_CURSOR_GBM_BO_STATE_SET:
++    case META_CURSOR_GBM_BO_STATE_NONE:
++      return TRUE;
++    case META_CURSOR_GBM_BO_STATE_INVALIDATED:
++      return FALSE;
++    }
++
++  g_assert_not_reached ();
+ }
+ 
+ #ifdef HAVE_WAYLAND
+ static void
+-meta_cursor_renderer_native_realize_cursor_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer,
+-                                                                   MetaGpuKms         *gpu_kms,
+-                                                                   MetaCursorSprite   *cursor_sprite,
+-                                                                   struct wl_resource *buffer)
++realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer      *renderer,
++                                              MetaGpuKms              *gpu_kms,
++                                              MetaCursorSpriteWayland *sprite_wayland)
+ {
+   MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
++  MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_wayland);
+   MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
+   uint32_t gbm_format;
+   uint64_t cursor_width, cursor_height;
+   CoglTexture *texture;
+   uint width, height;
++  MetaWaylandBuffer *buffer;
++  struct wl_resource *buffer_resource;
++  struct wl_shm_buffer *shm_buffer;
+ 
+   cursor_renderer_gpu_data =
+     meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
+   if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken)
+     return;
+ 
+-  /* Destroy any previous pending cursor buffer; we'll always either fail (which
+-   * should unset, or succeed, which will set new buffer.
+-   */
+-  invalidate_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms);
++  if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms))
++    return;
+ 
+   texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
+   width = cogl_texture_get_width (texture);
+   height = cogl_texture_get_height (texture);
+ 
+-  struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
++  buffer = meta_cursor_sprite_wayland_get_buffer (sprite_wayland);
++  if (!buffer)
++    return;
++
++  buffer_resource = meta_wayland_buffer_get_resource (buffer);
++  if (!buffer_resource)
++    return;
++
++  shm_buffer = wl_shm_buffer_get (buffer_resource);
+   if (shm_buffer)
+     {
+       int rowstride = wl_shm_buffer_get_stride (shm_buffer);
+@@ -929,47 +1034,27 @@ meta_cursor_renderer_native_realize_cursor_from_wl_buffer_for_gpu (MetaCursorRen
+       set_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms, bo);
+     }
+ }
+-
+-static void
+-meta_cursor_renderer_native_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
+-                                                           MetaCursorSprite *cursor_sprite,
+-                                                           struct wl_resource *buffer)
+-{
+-  MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
+-  MetaCursorRendererNativePrivate *priv =
+-	  meta_cursor_renderer_native_get_instance_private (native);
+-  GList *gpus;
+-  GList *l;
+-
+-  gpus = meta_monitor_manager_get_gpus (priv->monitor_manager);
+-  for (l = gpus; l; l = l->next)
+-    {
+-      MetaGpuKms *gpu_kms = l->data;
+-
+-      meta_cursor_renderer_native_realize_cursor_from_wl_buffer_for_gpu (
+-        renderer,
+-        gpu_kms,
+-        cursor_sprite,
+-        buffer);
+-    }
+-}
+ #endif
+ 
+ static void
+-meta_cursor_renderer_native_realize_cursor_from_xcursor_for_gpu (MetaCursorRenderer *renderer,
+-                                                                 MetaGpuKms         *gpu_kms,
+-                                                                 MetaCursorSprite   *cursor_sprite,
+-                                                                 XcursorImage       *xc_image)
++realize_cursor_sprite_from_xcursor_for_gpu (MetaCursorRenderer      *renderer,
++                                            MetaGpuKms              *gpu_kms,
++                                            MetaCursorSpriteXcursor *sprite_xcursor)
+ {
+   MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
+   MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
++  MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_xcursor);
++  XcursorImage *xc_image;
+ 
+   cursor_renderer_gpu_data =
+     meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
+   if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken)
+     return;
+ 
+-  invalidate_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms);
++  if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms))
++    return;
++
++  xc_image = meta_cursor_sprite_xcursor_get_current_image (sprite_xcursor);
+ 
+   load_cursor_sprite_gbm_buffer_for_gpu (native,
+                                          gpu_kms,
+@@ -982,26 +1067,45 @@ meta_cursor_renderer_native_realize_cursor_from_xcursor_for_gpu (MetaCursorRende
+ }
+ 
+ static void
+-meta_cursor_renderer_native_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
+-                                                         MetaCursorSprite   *cursor_sprite,
+-                                                         XcursorImage       *xc_image)
++realize_cursor_sprite_for_gpu (MetaCursorRenderer *renderer,
++                               MetaGpuKms         *gpu_kms,
++                               MetaCursorSprite   *cursor_sprite)
++{
++#ifdef HAVE_WAYLAND
++  if (META_IS_CURSOR_SPRITE_WAYLAND (cursor_sprite))
++    {
++      MetaCursorSpriteWayland *sprite_wayland =
++        META_CURSOR_SPRITE_WAYLAND (cursor_sprite);
++
++      realize_cursor_sprite_from_wl_buffer_for_gpu (renderer,
++                                                    gpu_kms,
++                                                    sprite_wayland);
++    }
++  else
++#endif
++  if (META_IS_CURSOR_SPRITE_XCURSOR (cursor_sprite))
++    {
++      MetaCursorSpriteXcursor *sprite_xcursor =
++        META_CURSOR_SPRITE_XCURSOR (cursor_sprite);
++
++      realize_cursor_sprite_from_xcursor_for_gpu (renderer,
++                                                  gpu_kms,
++                                                  sprite_xcursor);
++    }
++}
++
++static void
++realize_cursor_sprite (MetaCursorRenderer *renderer,
++                       MetaCursorSprite   *cursor_sprite,
++                       GList              *gpus)
+ {
+-  MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
+-  MetaCursorRendererNativePrivate *priv =
+-	  meta_cursor_renderer_native_get_instance_private (native);
+-  GList *gpus;
+   GList *l;
+ 
+-  gpus = meta_monitor_manager_get_gpus (priv->monitor_manager);
+   for (l = gpus; l; l = l->next)
+     {
+       MetaGpuKms *gpu_kms = l->data;
+ 
+-      meta_cursor_renderer_native_realize_cursor_from_xcursor_for_gpu (
+-        renderer,
+-        gpu_kms,
+-        cursor_sprite,
+-        xc_image);
++      realize_cursor_sprite_for_gpu (renderer, gpu_kms, cursor_sprite);
+     }
+ }
+ 
+@@ -1013,12 +1117,6 @@ meta_cursor_renderer_native_class_init (MetaCursorRendererNativeClass *klass)
+ 
+   object_class->finalize = meta_cursor_renderer_native_finalize;
+   renderer_class->update_cursor = meta_cursor_renderer_native_update_cursor;
+-#ifdef HAVE_WAYLAND
+-  renderer_class->realize_cursor_from_wl_buffer =
+-    meta_cursor_renderer_native_realize_cursor_from_wl_buffer;
+-#endif
+-  renderer_class->realize_cursor_from_xcursor =
+-    meta_cursor_renderer_native_realize_cursor_from_xcursor;
+ 
+   quark_cursor_sprite = g_quark_from_static_string ("-meta-cursor-native");
+   quark_cursor_renderer_native_gpu_data =
+@@ -1033,14 +1131,13 @@ force_update_hw_cursor (MetaCursorRendererNative *native)
+     meta_cursor_renderer_native_get_instance_private (native);
+ 
+   priv->hw_state_invalidated = TRUE;
+-  update_hw_cursor (native, meta_cursor_renderer_get_cursor (renderer));
++  meta_cursor_renderer_force_update (renderer);
+ }
+ 
+ static void
+ on_monitors_changed (MetaMonitorManager       *monitors,
+                      MetaCursorRendererNative *native)
+ {
+-  /* Our tracking is all messed up, so force an update. */
+   force_update_hw_cursor (native);
+ }
+ 
+@@ -1112,9 +1209,3 @@ static void
+ meta_cursor_renderer_native_init (MetaCursorRendererNative *native)
+ {
+ }
+-
+-void
+-meta_cursor_renderer_native_force_update (MetaCursorRendererNative *native)
+-{
+-  force_update_hw_cursor (native);
+-}
+diff --git a/src/backends/native/meta-cursor-renderer-native.h b/src/backends/native/meta-cursor-renderer-native.h
+index 09203a5f7..fb4c8edc7 100644
+--- a/src/backends/native/meta-cursor-renderer-native.h
++++ b/src/backends/native/meta-cursor-renderer-native.h
+@@ -32,8 +32,6 @@ G_DECLARE_FINAL_TYPE (MetaCursorRendererNative, meta_cursor_renderer_native,
+                       META, CURSOR_RENDERER_NATIVE,
+                       MetaCursorRenderer)
+ 
+-void meta_cursor_renderer_native_force_update (MetaCursorRendererNative *renderer);
+-
+ MetaCursorRendererNative * meta_cursor_renderer_native_new (MetaBackend *backend);
+ 
+ #endif /* META_CURSOR_RENDERER_NATIVE_H */
+diff --git a/src/backends/x11/cm/meta-cursor-sprite-xfixes.c b/src/backends/x11/cm/meta-cursor-sprite-xfixes.c
+new file mode 100644
+index 000000000..143ebb791
+--- /dev/null
++++ b/src/backends/x11/cm/meta-cursor-sprite-xfixes.c
+@@ -0,0 +1,226 @@
++/*
++ * Copyright 2013, 2018 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/>.
++ *
++ */
++
++#include "config.h"
++
++#include "backends/x11/cm/meta-cursor-sprite-xfixes.h"
++
++#include <X11/extensions/Xfixes.h>
++
++#include "core/display-private.h"
++
++enum
++{
++  PROP_0,
++
++  PROP_DISPLAY,
++
++  N_PROPS
++};
++
++static GParamSpec *obj_props[N_PROPS];
++
++struct _MetaCursorSpriteXfixes
++{
++  MetaCursorSprite parent;
++
++  MetaDisplay *display;
++};
++
++static void
++meta_screen_cast_xfixes_init_initable_iface (GInitableIface *iface);
++
++G_DEFINE_TYPE_WITH_CODE (MetaCursorSpriteXfixes,
++                         meta_cursor_sprite_xfixes,
++                         META_TYPE_CURSOR_SPRITE,
++                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
++                                                meta_screen_cast_xfixes_init_initable_iface))
++
++static void
++meta_cursor_sprite_xfixes_realize_texture (MetaCursorSprite *sprite)
++{
++}
++
++static gboolean
++meta_cursor_sprite_xfixes_is_animated (MetaCursorSprite *sprite)
++{
++  return FALSE;
++}
++
++static void
++meta_cursor_sprite_xfixes_get_property (GObject    *object,
++                                        guint       prop_id,
++                                        GValue     *value,
++                                        GParamSpec *pspec)
++{
++  MetaCursorSpriteXfixes *sprite_xfixes = META_CURSOR_SPRITE_XFIXES (object);
++
++  switch (prop_id)
++    {
++    case PROP_DISPLAY:
++      g_value_set_object (value, sprite_xfixes->display);
++      break;
++    default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++    }
++}
++
++static void
++meta_cursor_sprite_xfixes_set_property (GObject      *object,
++                                        guint         prop_id,
++                                        const GValue *value,
++                                        GParamSpec   *pspec)
++{
++  MetaCursorSpriteXfixes *sprite_xfixes = META_CURSOR_SPRITE_XFIXES (object);
++
++  switch (prop_id)
++    {
++    case PROP_DISPLAY:
++      sprite_xfixes->display = g_value_get_object (value);
++      break;
++    default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++    }
++}
++
++MetaCursorSpriteXfixes *
++meta_cursor_sprite_xfixes_new (MetaDisplay  *display,
++                               GError      **error)
++{
++  return g_initable_new (META_TYPE_CURSOR_SPRITE_XFIXES,
++                         NULL, error,
++                         "display", display,
++                         NULL);
++}
++
++static gboolean
++meta_cursor_sprite_xfixes_initable_init (GInitable     *initable,
++                                         GCancellable  *cancellable,
++                                         GError       **error)
++{
++  MetaCursorSpriteXfixes *sprite_xfixes =
++    META_CURSOR_SPRITE_XFIXES (initable);
++  MetaCursorSprite *sprite = META_CURSOR_SPRITE (sprite_xfixes);
++  XFixesCursorImage *cursor_image;
++  CoglTexture2D *texture;
++  uint8_t *cursor_data;
++  gboolean free_cursor_data;
++  ClutterBackend *clutter_backend;
++  CoglContext *cogl_context;
++
++  cursor_image = XFixesGetCursorImage (sprite_xfixes->display->xdisplay);
++  if (!cursor_image)
++    {
++      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++                   "Failed to get cursor image");
++      return FALSE;
++    }
++
++  /*
++   * Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit
++   * quantities as arrays of long; we need to convert on 64 bit
++   */
++  if (sizeof (long) == 4)
++    {
++      cursor_data = (uint8_t *) cursor_image->pixels;
++      free_cursor_data = FALSE;
++    }
++  else
++    {
++      int i, j;
++      uint32_t *cursor_words;
++      unsigned long *p;
++      uint32_t *q;
++
++      cursor_words = g_new (uint32_t,
++                            cursor_image->width * cursor_image->height);
++      cursor_data = (uint8_t *) cursor_words;
++
++      p = cursor_image->pixels;
++      q = cursor_words;
++      for (j = 0; j < cursor_image->height; j++)
++        {
++          for (i = 0; i < cursor_image->width; i++)
++            *(q++) = *(p++);
++        }
++
++      free_cursor_data = TRUE;
++    }
++
++  clutter_backend = clutter_get_default_backend ();
++  cogl_context = clutter_backend_get_cogl_context (clutter_backend);
++  texture = cogl_texture_2d_new_from_data (cogl_context,
++                                          cursor_image->width,
++                                          cursor_image->height,
++                                          CLUTTER_CAIRO_FORMAT_ARGB32,
++                                          cursor_image->width * 4, /* stride */
++                                          cursor_data,
++                                          error);
++
++  if (free_cursor_data)
++    g_free (cursor_data);
++
++  if (!sprite)
++    return FALSE;
++
++  meta_cursor_sprite_set_texture (sprite,
++                                  COGL_TEXTURE (texture),
++                                  cursor_image->xhot,
++                                  cursor_image->yhot);
++  cogl_object_unref (texture);
++  XFree (cursor_image);
++
++  return TRUE;
++}
++
++static void
++meta_screen_cast_xfixes_init_initable_iface (GInitableIface *iface)
++{
++  iface->init = meta_cursor_sprite_xfixes_initable_init;
++}
++
++static void
++meta_cursor_sprite_xfixes_init (MetaCursorSpriteXfixes *sprite_xfixes)
++{
++}
++
++static void
++meta_cursor_sprite_xfixes_class_init (MetaCursorSpriteXfixesClass *klass)
++{
++  GObjectClass *object_class = G_OBJECT_CLASS (klass);
++  MetaCursorSpriteClass *cursor_sprite_class = META_CURSOR_SPRITE_CLASS (klass);
++
++  object_class->get_property = meta_cursor_sprite_xfixes_get_property;
++  object_class->set_property = meta_cursor_sprite_xfixes_set_property;
++
++  cursor_sprite_class->realize_texture =
++    meta_cursor_sprite_xfixes_realize_texture;
++  cursor_sprite_class->is_animated = meta_cursor_sprite_xfixes_is_animated;
++
++  obj_props[PROP_DISPLAY] =
++    g_param_spec_object ("display",
++                         "display",
++                         "MetaDisplay",
++                         META_TYPE_DISPLAY,
++                         G_PARAM_READWRITE |
++                         G_PARAM_CONSTRUCT_ONLY |
++                         G_PARAM_STATIC_STRINGS);
++  g_object_class_install_properties (object_class, N_PROPS, obj_props);
++}
+diff --git a/src/backends/x11/cm/meta-cursor-sprite-xfixes.h b/src/backends/x11/cm/meta-cursor-sprite-xfixes.h
+new file mode 100644
+index 000000000..c7073fc2c
+--- /dev/null
++++ b/src/backends/x11/cm/meta-cursor-sprite-xfixes.h
+@@ -0,0 +1,36 @@
++/*
++ * Copyright 2013, 2018 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_CURSOR_SPRITE_XFIXES_H
++#define META_CURSOR_SPRITE_XFIXES_H
++
++#include <glib-object.h>
++
++#include "backends/meta-cursor.h"
++#include "meta/types.h"
++
++#define META_TYPE_CURSOR_SPRITE_XFIXES (meta_cursor_sprite_xfixes_get_type ())
++G_DECLARE_FINAL_TYPE (MetaCursorSpriteXfixes,
++                      meta_cursor_sprite_xfixes,
++                      META, CURSOR_SPRITE_XFIXES,
++                      MetaCursorSprite)
++
++MetaCursorSpriteXfixes * meta_cursor_sprite_xfixes_new (MetaDisplay  *display,
++                                                        GError      **error);
++
++#endif /* META_CURSOR_SPRITE_XFIXES_H */
+diff --git a/src/backends/x11/meta-cursor-renderer-x11.c b/src/backends/x11/meta-cursor-renderer-x11.c
+index 82109f1f3..bb3100a91 100644
+--- a/src/backends/x11/meta-cursor-renderer-x11.c
++++ b/src/backends/x11/meta-cursor-renderer-x11.c
+@@ -30,6 +30,7 @@
+ 
+ #include "meta-backend-x11.h"
+ #include "meta-stage-private.h"
++#include "backends/meta-cursor-sprite-xcursor.h"
+ 
+ struct _MetaCursorRendererX11Private
+ {
+@@ -59,13 +60,18 @@ meta_cursor_renderer_x11_update_cursor (MetaCursorRenderer *renderer,
+ 
+   gboolean has_server_cursor = FALSE;
+ 
+-  if (cursor_sprite)
++  if (cursor_sprite && META_IS_CURSOR_SPRITE_XCURSOR (cursor_sprite))
+     {
+-      MetaCursor cursor = meta_cursor_sprite_get_meta_cursor (cursor_sprite);
++      MetaCursorSpriteXcursor *sprite_xcursor =
++        META_CURSOR_SPRITE_XCURSOR (cursor_sprite);
++      MetaCursor cursor;
+ 
++      cursor = meta_cursor_sprite_xcursor_get_cursor (sprite_xcursor);
+       if (cursor != META_CURSOR_NONE)
+         {
+-          Cursor xcursor = meta_cursor_create_x_cursor (xdisplay, cursor);
++          Cursor xcursor;
++
++          xcursor = meta_create_x_cursor (xdisplay, cursor);
+           XDefineCursor (xdisplay, xwindow, xcursor);
+           XFlush (xdisplay);
+           XFreeCursor (xdisplay, xcursor);
+diff --git a/src/backends/x11/nested/meta-cursor-renderer-x11-nested.c b/src/backends/x11/nested/meta-cursor-renderer-x11-nested.c
+index da1a56038..0daae683c 100644
+--- a/src/backends/x11/nested/meta-cursor-renderer-x11-nested.c
++++ b/src/backends/x11/nested/meta-cursor-renderer-x11-nested.c
+@@ -26,6 +26,8 @@
+ 
+ #include "backends/x11/nested/meta-cursor-renderer-x11-nested.h"
+ 
++#include <X11/Xcursor/Xcursor.h>
++
+ #include "backends/x11/meta-backend-x11.h"
+ 
+ struct _MetaCursorRendererX11Nested
+diff --git a/src/core/display.c b/src/core/display.c
+index d6da84b30..e7dd4534b 100644
+--- a/src/core/display.c
++++ b/src/core/display.c
+@@ -3018,7 +3018,7 @@ Cursor
+ meta_display_create_x_cursor (MetaDisplay *display,
+                               MetaCursor   cursor)
+ {
+-  return meta_cursor_create_x_cursor (display->xdisplay, cursor);
++  return meta_create_x_cursor (display->xdisplay, cursor);
+ }
+ 
+ MetaGestureTracker *
+diff --git a/src/core/screen.c b/src/core/screen.c
+index c14bba0cf..048104150 100644
+--- a/src/core/screen.c
++++ b/src/core/screen.c
+@@ -60,6 +60,7 @@
+ #include "x11/xprops.h"
+ 
+ #include "backends/x11/meta-backend-x11.h"
++#include "backends/meta-cursor-sprite-xcursor.h"
+ 
+ static char* get_screen_name (MetaDisplay *display,
+                               int          number);
+@@ -1323,12 +1324,13 @@ find_highest_logical_monitor_scale (MetaBackend      *backend,
+ }
+ 
+ static void
+-root_cursor_prepare_at (MetaCursorSprite *cursor_sprite,
+-                        int               x,
+-                        int               y,
+-                        MetaScreen       *screen)
++root_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
++                        int                      x,
++                        int                      y,
++                        MetaScreen              *screen)
+ {
+   MetaBackend *backend = meta_get_backend ();
++  MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_xcursor);
+ 
+   if (meta_is_stage_views_scaled ())
+     {
+@@ -1337,7 +1339,7 @@ root_cursor_prepare_at (MetaCursorSprite *cursor_sprite,
+       scale = find_highest_logical_monitor_scale (backend, cursor_sprite);
+       if (scale != 0.0)
+         {
+-          meta_cursor_sprite_set_theme_scale (cursor_sprite, scale);
++          meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor, scale);
+           meta_cursor_sprite_set_texture_scale (cursor_sprite, 1.0 / scale);
+         }
+     }
+@@ -1353,18 +1355,18 @@ root_cursor_prepare_at (MetaCursorSprite *cursor_sprite,
+       /* Reload the cursor texture if the scale has changed. */
+       if (logical_monitor)
+         {
+-          meta_cursor_sprite_set_theme_scale (cursor_sprite,
+-                                              logical_monitor->scale);
++          meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
++                                                      logical_monitor->scale);
+           meta_cursor_sprite_set_texture_scale (cursor_sprite, 1.0);
+         }
+     }
+ }
+ 
+ static void
+-manage_root_cursor_sprite_scale (MetaScreen       *screen,
+-                                 MetaCursorSprite *cursor_sprite)
++manage_root_cursor_sprite_scale (MetaScreen              *screen,
++                                 MetaCursorSpriteXcursor *sprite_xcursor)
+ {
+-  g_signal_connect_object (cursor_sprite,
++  g_signal_connect_object (sprite_xcursor,
+                            "prepare-at",
+                            G_CALLBACK (root_cursor_prepare_at),
+                            screen,
+@@ -1377,17 +1379,18 @@ meta_screen_update_cursor (MetaScreen *screen)
+   MetaDisplay *display = screen->display;
+   MetaCursor cursor = screen->current_cursor;
+   Cursor xcursor;
+-  MetaCursorSprite *cursor_sprite;
++  MetaCursorSpriteXcursor *sprite_xcursor;
+   MetaBackend *backend = meta_get_backend ();
+   MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
+ 
+-  cursor_sprite = meta_cursor_sprite_from_theme (cursor);
++  sprite_xcursor = meta_cursor_sprite_xcursor_new (cursor);
+ 
+   if (meta_is_wayland_compositor ())
+-    manage_root_cursor_sprite_scale (screen, cursor_sprite);
++    manage_root_cursor_sprite_scale (screen, sprite_xcursor);
+ 
+-  meta_cursor_tracker_set_root_cursor (cursor_tracker, cursor_sprite);
+-  g_object_unref (cursor_sprite);
++  meta_cursor_tracker_set_root_cursor (cursor_tracker,
++                                       META_CURSOR_SPRITE (sprite_xcursor));
++  g_object_unref (sprite_xcursor);
+ 
+   /* Set a cursor for X11 applications that don't specify their own */
+   xcursor = meta_display_create_x_cursor (display, cursor);
+diff --git a/src/wayland/meta-cursor-sprite-wayland.c b/src/wayland/meta-cursor-sprite-wayland.c
+new file mode 100644
+index 000000000..7c14960ff
+--- /dev/null
++++ b/src/wayland/meta-cursor-sprite-wayland.c
+@@ -0,0 +1,75 @@
++/*
++ * Copyright 2015, 2018 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/>.
++ *
++ */
++
++#include "config.h"
++
++#include "wayland/meta-cursor-sprite-wayland.h"
++
++struct _MetaCursorSpriteWayland
++{
++  MetaCursorSprite parent;
++
++  MetaWaylandSurface *surface;
++};
++
++G_DEFINE_TYPE (MetaCursorSpriteWayland,
++               meta_cursor_sprite_wayland,
++               META_TYPE_CURSOR_SPRITE)
++
++static void
++meta_cursor_sprite_wayland_realize_texture (MetaCursorSprite *sprite)
++{
++}
++
++static gboolean
++meta_cursor_sprite_wayland_is_animated (MetaCursorSprite *sprite)
++{
++  return FALSE;
++}
++
++MetaCursorSpriteWayland *
++meta_cursor_sprite_wayland_new (MetaWaylandSurface *surface)
++{
++  MetaCursorSpriteWayland *sprite_wayland;
++
++  sprite_wayland = g_object_new (META_TYPE_CURSOR_SPRITE_WAYLAND, NULL);
++  sprite_wayland->surface = surface;
++
++  return sprite_wayland;
++}
++
++MetaWaylandBuffer *
++meta_cursor_sprite_wayland_get_buffer (MetaCursorSpriteWayland *sprite_wayland)
++{
++  return meta_wayland_surface_get_buffer (sprite_wayland->surface);
++}
++
++static void
++meta_cursor_sprite_wayland_init (MetaCursorSpriteWayland *sprite_wayland)
++{
++}
++
++static void
++meta_cursor_sprite_wayland_class_init (MetaCursorSpriteWaylandClass *klass)
++{
++  MetaCursorSpriteClass *cursor_sprite_class = META_CURSOR_SPRITE_CLASS (klass);
++
++  cursor_sprite_class->realize_texture =
++    meta_cursor_sprite_wayland_realize_texture;
++  cursor_sprite_class->is_animated = meta_cursor_sprite_wayland_is_animated;
++}
+diff --git a/src/wayland/meta-cursor-sprite-wayland.h b/src/wayland/meta-cursor-sprite-wayland.h
+new file mode 100644
+index 000000000..107698f3f
+--- /dev/null
++++ b/src/wayland/meta-cursor-sprite-wayland.h
+@@ -0,0 +1,35 @@
++/*
++ * Copyright 2013, 2018 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_CURSOR_SPRITE_WAYLAND_H
++#define META_CURSOR_SPRITE_WAYLAND_H
++
++#include <glib-object.h>
++
++#include "backends/meta-cursor.h"
++#include "wayland/meta-wayland-surface.h"
++
++#define META_TYPE_CURSOR_SPRITE_WAYLAND meta_cursor_sprite_wayland_get_type ()
++G_DECLARE_FINAL_TYPE (MetaCursorSpriteWayland, meta_cursor_sprite_wayland,
++                      META, CURSOR_SPRITE_WAYLAND, MetaCursorSprite)
++
++MetaCursorSpriteWayland * meta_cursor_sprite_wayland_new (MetaWaylandSurface *surface);
++
++MetaWaylandBuffer * meta_cursor_sprite_wayland_get_buffer (MetaCursorSpriteWayland *sprite_wayland);
++
++#endif /* META_CURSOR_SPRITE_WAYLAND_H */
+diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c
+index 55564492a..c759eefc1 100644
+--- a/src/wayland/meta-wayland-buffer.c
++++ b/src/wayland/meta-wayland-buffer.c
+@@ -88,6 +88,12 @@ meta_wayland_buffer_from_resource (struct wl_resource *resource)
+   return buffer;
+ }
+ 
++struct wl_resource *
++meta_wayland_buffer_get_resource (MetaWaylandBuffer *buffer)
++{
++  return buffer->resource;
++}
++
+ static gboolean
+ meta_wayland_buffer_is_realized (MetaWaylandBuffer *buffer)
+ {
+diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h
+index 5345033c2..e00a41e09 100644
+--- a/src/wayland/meta-wayland-buffer.h
++++ b/src/wayland/meta-wayland-buffer.h
+@@ -68,6 +68,7 @@ G_DECLARE_FINAL_TYPE (MetaWaylandBuffer, meta_wayland_buffer,
+                       META, WAYLAND_BUFFER, GObject);
+ 
+ MetaWaylandBuffer *     meta_wayland_buffer_from_resource       (struct wl_resource    *resource);
++struct wl_resource *    meta_wayland_buffer_get_resource        (MetaWaylandBuffer     *buffer);
+ gboolean                meta_wayland_buffer_attach              (MetaWaylandBuffer     *buffer,
+                                                                  GError               **error);
+ CoglTexture *           meta_wayland_buffer_get_texture         (MetaWaylandBuffer     *buffer);
+diff --git a/src/wayland/meta-wayland-surface-role-cursor.c b/src/wayland/meta-wayland-cursor-surface.c
+similarity index 52%
+rename from src/wayland/meta-wayland-surface-role-cursor.c
+rename to src/wayland/meta-wayland-cursor-surface.c
+index d118a8917..d08af9e8c 100644
+--- a/src/wayland/meta-wayland-surface-role-cursor.c
++++ b/src/wayland/meta-wayland-cursor-surface.c
+@@ -23,7 +23,7 @@
+ 
+ #include <cogl/cogl.h>
+ #include <cogl/cogl-wayland-server.h>
+-#include "meta-wayland-surface-role-cursor.h"
++#include "meta-wayland-cursor-surface.h"
+ #include "meta-wayland-buffer.h"
+ #include "meta-xwayland.h"
+ #include "screen-private.h"
+@@ -31,35 +31,38 @@
+ #include "backends/meta-backend-private.h"
+ #include "backends/meta-logical-monitor.h"
+ #include "core/boxes-private.h"
++#include "wayland/meta-cursor-sprite-wayland.h"
+ 
+-typedef struct _MetaWaylandSurfaceRoleCursorPrivate MetaWaylandSurfaceRoleCursorPrivate;
++typedef struct _MetaWaylandCursorSurfacePrivate MetaWaylandCursorSurfacePrivate;
+ 
+-struct _MetaWaylandSurfaceRoleCursorPrivate
++struct _MetaWaylandCursorSurfacePrivate
+ {
+   int hot_x;
+   int hot_y;
+-  MetaCursorSprite *cursor_sprite;
++  MetaCursorSpriteWayland *cursor_sprite;
+   MetaCursorRenderer *cursor_renderer;
+   MetaWaylandBuffer *buffer;
+   struct wl_list frame_callbacks;
+   gulong cursor_painted_handler_id;
+ };
+ 
+-G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandSurfaceRoleCursor,
+-                            meta_wayland_surface_role_cursor,
++G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandCursorSurface,
++                            meta_wayland_cursor_surface,
+                             META_TYPE_WAYLAND_SURFACE_ROLE)
+ 
+ static void
+-update_cursor_sprite_texture (MetaWaylandSurfaceRoleCursor *cursor_role)
++update_cursor_sprite_texture (MetaWaylandCursorSurface *cursor_surface)
+ {
+-  MetaWaylandSurfaceRoleCursorPrivate *priv = meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
+-  MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (cursor_role));
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
++  MetaWaylandSurface *surface =
++    meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (cursor_surface));
+   MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
+-  MetaCursorSprite *cursor_sprite = priv->cursor_sprite;
++  MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (priv->cursor_sprite);
+ 
+   g_return_if_fail (!buffer || buffer->texture);
+ 
+-  if (!priv->cursor_renderer || !cursor_sprite)
++  if (!priv->cursor_renderer)
+     return;
+ 
+   if (buffer)
+@@ -68,20 +71,6 @@ update_cursor_sprite_texture (MetaWaylandSurfaceRoleCursor *cursor_role)
+                                       buffer->texture,
+                                       priv->hot_x * surface->scale,
+                                       priv->hot_y * surface->scale);
+-
+-      if (priv->buffer)
+-        {
+-          struct wl_resource *buffer_resource;
+-
+-          g_assert (priv->buffer == buffer);
+-          buffer_resource = buffer->resource;
+-          meta_cursor_renderer_realize_cursor_from_wl_buffer (priv->cursor_renderer,
+-                                                              cursor_sprite,
+-                                                              buffer_resource);
+-
+-          meta_wayland_surface_unref_buffer_use_count (surface);
+-          g_clear_object (&priv->buffer);
+-        }
+     }
+   else
+     {
+@@ -92,12 +81,12 @@ update_cursor_sprite_texture (MetaWaylandSurfaceRoleCursor *cursor_role)
+ }
+ 
+ static void
+-cursor_sprite_prepare_at (MetaCursorSprite             *cursor_sprite,
+-                          int                           x,
+-                          int                           y,
+-                          MetaWaylandSurfaceRoleCursor *cursor_role)
++cursor_sprite_prepare_at (MetaCursorSprite         *cursor_sprite,
++                          int                       x,
++                          int                       y,
++                          MetaWaylandCursorSurface *cursor_surface)
+ {
+-  MetaWaylandSurfaceRole *role = META_WAYLAND_SURFACE_ROLE (cursor_role);
++  MetaWaylandSurfaceRole *role = META_WAYLAND_SURFACE_ROLE (cursor_surface);
+   MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (role);
+ 
+   if (!meta_xwayland_is_xwayland_surface (surface))
+@@ -126,14 +115,14 @@ cursor_sprite_prepare_at (MetaCursorSprite             *cursor_sprite,
+ }
+ 
+ static void
+-cursor_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
++meta_wayland_cursor_surface_assigned (MetaWaylandSurfaceRole *surface_role)
+ {
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (surface_role);
+-  MetaWaylandSurfaceRoleCursor *cursor_role =
+-    META_WAYLAND_SURFACE_ROLE_CURSOR (surface_role);
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
++  MetaWaylandCursorSurface *cursor_surface =
++    META_WAYLAND_CURSOR_SURFACE (surface_role);
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+ 
+   wl_list_insert_list (&priv->frame_callbacks,
+                        &surface->pending_frame_callback_list);
+@@ -141,13 +130,13 @@ cursor_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
+ }
+ 
+ static void
+-cursor_surface_role_pre_commit (MetaWaylandSurfaceRole  *surface_role,
+-                                MetaWaylandPendingState *pending)
++meta_wayland_cursor_surface_pre_commit (MetaWaylandSurfaceRole  *surface_role,
++                                        MetaWaylandPendingState *pending)
+ {
+-  MetaWaylandSurfaceRoleCursor *cursor_role =
+-    META_WAYLAND_SURFACE_ROLE_CURSOR (surface_role);
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
++  MetaWaylandCursorSurface *cursor_surface =
++    META_WAYLAND_CURSOR_SURFACE (surface_role);
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (surface_role);
+ 
+@@ -159,13 +148,13 @@ cursor_surface_role_pre_commit (MetaWaylandSurfaceRole  *surface_role,
+ }
+ 
+ static void
+-cursor_surface_role_commit (MetaWaylandSurfaceRole  *surface_role,
+-                            MetaWaylandPendingState *pending)
++meta_wayland_cursor_surface_commit (MetaWaylandSurfaceRole  *surface_role,
++                                    MetaWaylandPendingState *pending)
+ {
+-  MetaWaylandSurfaceRoleCursor *cursor_role =
+-    META_WAYLAND_SURFACE_ROLE_CURSOR (surface_role);
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
++  MetaWaylandCursorSurface *cursor_surface =
++    META_WAYLAND_CURSOR_SURFACE (surface_role);
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (surface_role);
+   MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
+@@ -182,19 +171,19 @@ cursor_surface_role_commit (MetaWaylandSurfaceRole  *surface_role,
+   wl_list_init (&pending->frame_callback_list);
+ 
+   if (pending->newly_attached)
+-    update_cursor_sprite_texture (META_WAYLAND_SURFACE_ROLE_CURSOR (surface_role));
++    update_cursor_sprite_texture (META_WAYLAND_CURSOR_SURFACE (surface_role));
+ }
+ 
+ static gboolean
+-cursor_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *role,
+-                                           MetaLogicalMonitor     *logical_monitor)
++meta_wayland_cursor_surface_is_on_logical_monitor (MetaWaylandSurfaceRole *role,
++                                                   MetaLogicalMonitor     *logical_monitor)
+ {
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (role);
+-  MetaWaylandSurfaceRoleCursor *cursor_role =
+-    META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
++  MetaWaylandCursorSurface *cursor_surface =
++    META_WAYLAND_CURSOR_SURFACE (surface->role);
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+   ClutterPoint point;
+   ClutterRect logical_monitor_rect;
+ 
+@@ -207,12 +196,12 @@ cursor_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *role,
+ }
+ 
+ static void
+-cursor_surface_role_dispose (GObject *object)
++meta_wayland_cursor_surface_dispose (GObject *object)
+ {
+-  MetaWaylandSurfaceRoleCursor *cursor_role =
+-    META_WAYLAND_SURFACE_ROLE_CURSOR (object);
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
++  MetaWaylandCursorSurface *cursor_surface =
++    META_WAYLAND_CURSOR_SURFACE (object);
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (object));
+   MetaWaylandFrameCallback *cb, *next;
+@@ -221,7 +210,7 @@ cursor_surface_role_dispose (GObject *object)
+     wl_resource_destroy (cb->resource);
+ 
+   g_signal_handlers_disconnect_by_func (priv->cursor_sprite,
+-                                        cursor_sprite_prepare_at, cursor_role);
++                                        cursor_sprite_prepare_at, cursor_surface);
+ 
+   g_clear_object (&priv->cursor_renderer);
+   g_clear_object (&priv->cursor_sprite);
+@@ -232,18 +221,18 @@ cursor_surface_role_dispose (GObject *object)
+       g_clear_object (&priv->buffer);
+     }
+ 
+-  G_OBJECT_CLASS (meta_wayland_surface_role_cursor_parent_class)->dispose (object);
++  G_OBJECT_CLASS (meta_wayland_cursor_surface_parent_class)->dispose (object);
+ }
+ 
+ static void
+-cursor_surface_role_constructed (GObject *object)
++meta_wayland_cursor_surface_constructed (GObject *object)
+ {
+-  MetaWaylandSurfaceRoleCursor *cursor_role =
+-    META_WAYLAND_SURFACE_ROLE_CURSOR (object);
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
++  MetaWaylandCursorSurface *cursor_surface =
++    META_WAYLAND_CURSOR_SURFACE (object);
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+   MetaWaylandSurfaceRole *surface_role =
+-    META_WAYLAND_SURFACE_ROLE (cursor_role);
++    META_WAYLAND_SURFACE_ROLE (cursor_surface);
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (surface_role);
+   MetaWaylandBuffer *buffer;
+@@ -257,55 +246,57 @@ cursor_surface_role_constructed (GObject *object)
+       g_set_object (&priv->buffer, buffer);
+       meta_wayland_surface_ref_buffer_use_count (surface);
+     }
+-}
+ 
+-static void
+-meta_wayland_surface_role_cursor_init (MetaWaylandSurfaceRoleCursor *role)
+-{
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (role);
+-
+-  priv->cursor_sprite = meta_cursor_sprite_new ();
++  priv->cursor_sprite = meta_cursor_sprite_wayland_new (surface);
+   g_signal_connect_object (priv->cursor_sprite,
+                            "prepare-at",
+                            G_CALLBACK (cursor_sprite_prepare_at),
+-                           role,
++                           cursor_surface,
+                            0);
++}
++
++static void
++meta_wayland_cursor_surface_init (MetaWaylandCursorSurface *role)
++{
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (role);
++
+   wl_list_init (&priv->frame_callbacks);
+ }
+ 
+ static void
+-meta_wayland_surface_role_cursor_class_init (MetaWaylandSurfaceRoleCursorClass *klass)
++meta_wayland_cursor_surface_class_init (MetaWaylandCursorSurfaceClass *klass)
+ {
+   MetaWaylandSurfaceRoleClass *surface_role_class =
+     META_WAYLAND_SURFACE_ROLE_CLASS (klass);
+   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ 
+-  surface_role_class->assigned = cursor_surface_role_assigned;
+-  surface_role_class->pre_commit = cursor_surface_role_pre_commit;
+-  surface_role_class->commit = cursor_surface_role_commit;
+-  surface_role_class->is_on_logical_monitor = cursor_surface_role_is_on_logical_monitor;
++  surface_role_class->assigned = meta_wayland_cursor_surface_assigned;
++  surface_role_class->pre_commit = meta_wayland_cursor_surface_pre_commit;
++  surface_role_class->commit = meta_wayland_cursor_surface_commit;
++  surface_role_class->is_on_logical_monitor =
++    meta_wayland_cursor_surface_is_on_logical_monitor;
+ 
+-  object_class->constructed = cursor_surface_role_constructed;
+-  object_class->dispose = cursor_surface_role_dispose;
++  object_class->constructed = meta_wayland_cursor_surface_constructed;
++  object_class->dispose = meta_wayland_cursor_surface_dispose;
+ }
+ 
+ MetaCursorSprite *
+-meta_wayland_surface_role_cursor_get_sprite (MetaWaylandSurfaceRoleCursor *cursor_role)
++meta_wayland_cursor_surface_get_sprite (MetaWaylandCursorSurface *cursor_surface)
+ {
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+ 
+-  return priv->cursor_sprite;
++  return META_CURSOR_SPRITE (priv->cursor_sprite);
+ }
+ 
+ void
+-meta_wayland_surface_role_cursor_set_hotspot (MetaWaylandSurfaceRoleCursor *cursor_role,
+-                                              gint                          hotspot_x,
+-                                              gint                          hotspot_y)
++meta_wayland_cursor_surface_set_hotspot (MetaWaylandCursorSurface *cursor_surface,
++                                         int                       hotspot_x,
++                                         int                       hotspot_y)
+ {
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+ 
+   if (priv->hot_x == hotspot_x &&
+       priv->hot_y == hotspot_y)
+@@ -313,16 +304,16 @@ meta_wayland_surface_role_cursor_set_hotspot (MetaWaylandSurfaceRoleCursor *curs
+ 
+   priv->hot_x = hotspot_x;
+   priv->hot_y = hotspot_y;
+-  update_cursor_sprite_texture (cursor_role);
++  update_cursor_sprite_texture (cursor_surface);
+ }
+ 
+ void
+-meta_wayland_surface_role_cursor_get_hotspot (MetaWaylandSurfaceRoleCursor *cursor_role,
+-                                              gint                         *hotspot_x,
+-                                              gint                         *hotspot_y)
++meta_wayland_cursor_surface_get_hotspot (MetaWaylandCursorSurface *cursor_surface,
++                                         int                      *hotspot_x,
++                                         int                      *hotspot_y)
+ {
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+ 
+   if (hotspot_x)
+     *hotspot_x = priv->hot_x;
+@@ -331,15 +322,15 @@ meta_wayland_surface_role_cursor_get_hotspot (MetaWaylandSurfaceRoleCursor *curs
+ }
+ 
+ static void
+-on_cursor_painted (MetaCursorRenderer           *renderer,
+-                   MetaCursorSprite             *displayed_sprite,
+-                   MetaWaylandSurfaceRoleCursor *cursor_role)
++on_cursor_painted (MetaCursorRenderer       *renderer,
++                   MetaCursorSprite         *displayed_sprite,
++                   MetaWaylandCursorSurface *cursor_surface)
+ {
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+   guint32 time = (guint32) (g_get_monotonic_time () / 1000);
+ 
+-  if (displayed_sprite != priv->cursor_sprite)
++  if (displayed_sprite != META_CURSOR_SPRITE (priv->cursor_sprite))
+     return;
+ 
+   while (!wl_list_empty (&priv->frame_callbacks))
+@@ -353,11 +344,11 @@ on_cursor_painted (MetaCursorRenderer           *renderer,
+ }
+ 
+ void
+-meta_wayland_surface_role_cursor_set_renderer (MetaWaylandSurfaceRoleCursor *cursor_role,
+-                                               MetaCursorRenderer           *renderer)
++meta_wayland_cursor_surface_set_renderer (MetaWaylandCursorSurface *cursor_surface,
++                                          MetaCursorRenderer       *renderer)
+ {
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+ 
+   if (priv->cursor_renderer == renderer)
+     return;
+@@ -373,19 +364,19 @@ meta_wayland_surface_role_cursor_set_renderer (MetaWaylandSurfaceRoleCursor *cur
+     {
+       priv->cursor_painted_handler_id =
+         g_signal_connect_object (renderer, "cursor-painted",
+-                                 G_CALLBACK (on_cursor_painted), cursor_role, 0);
++                                 G_CALLBACK (on_cursor_painted), cursor_surface, 0);
+       g_object_ref (renderer);
+     }
+ 
+   priv->cursor_renderer = renderer;
+-  update_cursor_sprite_texture (cursor_role);
++  update_cursor_sprite_texture (cursor_surface);
+ }
+ 
+ MetaCursorRenderer *
+-meta_wayland_surface_role_cursor_get_renderer (MetaWaylandSurfaceRoleCursor *cursor_role)
++meta_wayland_cursor_surface_get_renderer (MetaWaylandCursorSurface *cursor_surface)
+ {
+-  MetaWaylandSurfaceRoleCursorPrivate *priv =
+-    meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
++  MetaWaylandCursorSurfacePrivate *priv =
++    meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+ 
+   return priv->cursor_renderer;
+ }
+diff --git a/src/wayland/meta-wayland-cursor-surface.h b/src/wayland/meta-wayland-cursor-surface.h
+new file mode 100644
+index 000000000..2461a85b3
+--- /dev/null
++++ b/src/wayland/meta-wayland-cursor-surface.h
+@@ -0,0 +1,52 @@
++/*
++ * Wayland Support
++ *
++ * Copyright (C) 2015 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, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++ * 02111-1307, USA.
++ */
++
++#ifndef META_WAYLAND_CURSOR_SURFACE_H
++#define META_WAYLAND_CURSOR_SURFACE_H
++
++#include "meta-wayland-surface.h"
++#include "backends/meta-cursor-renderer.h"
++
++struct _MetaWaylandCursorSurfaceClass
++{
++  MetaWaylandSurfaceRoleClass parent_class;
++};
++
++#define META_TYPE_WAYLAND_CURSOR_SURFACE (meta_wayland_cursor_surface_get_type ())
++G_DECLARE_DERIVABLE_TYPE (MetaWaylandCursorSurface,
++                          meta_wayland_cursor_surface,
++                          META, WAYLAND_CURSOR_SURFACE,
++                          MetaWaylandSurfaceRole);
++
++MetaCursorSprite *   meta_wayland_cursor_surface_get_sprite   (MetaWaylandCursorSurface *cursor_surface);
++
++void                 meta_wayland_cursor_surface_set_hotspot  (MetaWaylandCursorSurface *cursor_surface,
++                                                               int                       hotspot_x,
++                                                               int                       hotspot_y);
++void                 meta_wayland_cursor_surface_get_hotspot  (MetaWaylandCursorSurface *cursor_surface,
++                                                               int                       *hotspot_x,
++                                                               int                       *hotspot_y);
++void                 meta_wayland_cursor_surface_set_renderer (MetaWaylandCursorSurface *cursor_surface,
++                                                               MetaCursorRenderer       *renderer);
++MetaCursorRenderer * meta_wayland_cursor_surface_get_renderer (MetaWaylandCursorSurface *cursor_surface);
++
++
++#endif /* META_WAYLAND_CURSOR_SURFACE_H */
+diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c
+index d5c90c169..e8138576e 100644
+--- a/src/wayland/meta-wayland-pointer.c
++++ b/src/wayland/meta-wayland-pointer.c
+@@ -55,7 +55,7 @@
+ #include "meta-wayland-seat.h"
+ #include "meta-wayland-surface.h"
+ #include "meta-wayland-buffer.h"
+-#include "meta-wayland-surface-role-cursor.h"
++#include "meta-wayland-cursor-surface.h"
+ #include "meta-xwayland.h"
+ #include "meta-cursor.h"
+ #include "meta-cursor-tracker-private.h"
+@@ -1025,10 +1025,10 @@ meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer)
+ 
+       if (pointer->cursor_surface)
+         {
+-          MetaWaylandSurfaceRoleCursor *cursor_role =
+-            META_WAYLAND_SURFACE_ROLE_CURSOR (pointer->cursor_surface->role);
++          MetaWaylandCursorSurface *cursor_surface =
++            META_WAYLAND_CURSOR_SURFACE (pointer->cursor_surface->role);
+ 
+-          cursor_sprite = meta_wayland_surface_role_cursor_get_sprite (cursor_role);
++          cursor_sprite = meta_wayland_cursor_surface_get_sprite (cursor_surface);
+         }
+ 
+       meta_cursor_tracker_set_window_cursor (cursor_tracker, cursor_sprite);
+@@ -1102,7 +1102,7 @@ pointer_set_cursor (struct wl_client *client,
+ 
+   if (surface &&
+       !meta_wayland_surface_assign_role (surface,
+-                                         META_TYPE_WAYLAND_SURFACE_ROLE_CURSOR,
++                                         META_TYPE_WAYLAND_CURSOR_SURFACE,
+                                          NULL))
+     {
+       wl_resource_post_error (resource, WL_POINTER_ERROR_ROLE,
+@@ -1115,13 +1115,13 @@ pointer_set_cursor (struct wl_client *client,
+     {
+       MetaCursorRenderer *cursor_renderer =
+         meta_backend_get_cursor_renderer (meta_get_backend ());
+-      MetaWaylandSurfaceRoleCursor *cursor_role;
++      MetaWaylandCursorSurface *cursor_surface;
+ 
+-      cursor_role = META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
+-      meta_wayland_surface_role_cursor_set_renderer (cursor_role,
+-                                                     cursor_renderer);
+-      meta_wayland_surface_role_cursor_set_hotspot (cursor_role,
+-                                                    hot_x, hot_y);
++      cursor_surface = META_WAYLAND_CURSOR_SURFACE (surface->role);
++      meta_wayland_cursor_surface_set_renderer (cursor_surface,
++                                                cursor_renderer);
++      meta_wayland_cursor_surface_set_hotspot (cursor_surface,
++                                               hot_x, hot_y);
+     }
+ 
+   meta_wayland_pointer_set_cursor_surface (pointer, surface);
+diff --git a/src/wayland/meta-wayland-surface-role-cursor.h b/src/wayland/meta-wayland-surface-role-cursor.h
+deleted file mode 100644
+index b6d6d4a6a..000000000
+--- a/src/wayland/meta-wayland-surface-role-cursor.h
++++ /dev/null
+@@ -1,52 +0,0 @@
+-/*
+- * Wayland Support
+- *
+- * Copyright (C) 2015 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, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+- * 02111-1307, USA.
+- */
+-
+-#ifndef META_WAYLAND_SURFACE_ROLE_CURSOR_H
+-#define META_WAYLAND_SURFACE_ROLE_CURSOR_H
+-
+-#include "meta-wayland-surface.h"
+-#include "backends/meta-cursor-renderer.h"
+-
+-struct _MetaWaylandSurfaceRoleCursorClass
+-{
+-  MetaWaylandSurfaceRoleClass parent_class;
+-};
+-
+-#define META_TYPE_WAYLAND_SURFACE_ROLE_CURSOR (meta_wayland_surface_role_cursor_get_type ())
+-G_DECLARE_DERIVABLE_TYPE (MetaWaylandSurfaceRoleCursor,
+-                          meta_wayland_surface_role_cursor,
+-                          META, WAYLAND_SURFACE_ROLE_CURSOR,
+-                          MetaWaylandSurfaceRole);
+-
+-MetaCursorSprite *   meta_wayland_surface_role_cursor_get_sprite   (MetaWaylandSurfaceRoleCursor *cursor_role);
+-
+-void                 meta_wayland_surface_role_cursor_set_hotspot  (MetaWaylandSurfaceRoleCursor *cursor_role,
+-                                                                    gint                          hotspot_x,
+-                                                                    gint                          hotspot_y);
+-void                 meta_wayland_surface_role_cursor_get_hotspot  (MetaWaylandSurfaceRoleCursor *cursor_role,
+-                                                                    gint                         *hotspot_x,
+-                                                                    gint                         *hotspot_y);
+-void                 meta_wayland_surface_role_cursor_set_renderer (MetaWaylandSurfaceRoleCursor *cursor_role,
+-                                                                    MetaCursorRenderer           *renderer);
+-MetaCursorRenderer * meta_wayland_surface_role_cursor_get_renderer (MetaWaylandSurfaceRoleCursor *cursor_role);
+-
+-
+-#endif /* META_WAYLAND_SURFACE_ROLE_CURSOR_H */
+diff --git a/src/wayland/meta-wayland-surface-role-tablet-cursor.c b/src/wayland/meta-wayland-tablet-cursor-surface.c
+similarity index 63%
+rename from src/wayland/meta-wayland-surface-role-tablet-cursor.c
+rename to src/wayland/meta-wayland-tablet-cursor-surface.c
+index 075a5e4f6..808bf2820 100644
+--- a/src/wayland/meta-wayland-surface-role-tablet-cursor.c
++++ b/src/wayland/meta-wayland-tablet-cursor-surface.c
+@@ -20,23 +20,24 @@
+  */
+ 
+ #include "config.h"
+-#include "meta-wayland-surface-role-tablet-cursor.h"
+ 
+-struct _MetaWaylandSurfaceRoleTabletCursor
++#include "meta-wayland-tablet-cursor-surface.h"
++
++struct _MetaWaylandTabletCursorSurface
+ {
+-  MetaWaylandSurfaceRoleCursor parent;
++  MetaWaylandCursorSurface parent;
+ };
+ 
+-G_DEFINE_TYPE (MetaWaylandSurfaceRoleTabletCursor,
+-               meta_wayland_surface_role_tablet_cursor,
+-               META_TYPE_WAYLAND_SURFACE_ROLE_CURSOR)
++G_DEFINE_TYPE (MetaWaylandTabletCursorSurface,
++               meta_wayland_tablet_cursor_surface,
++               META_TYPE_WAYLAND_CURSOR_SURFACE)
+ 
+ static void
+-meta_wayland_surface_role_tablet_cursor_init (MetaWaylandSurfaceRoleTabletCursor *role)
++meta_wayland_tablet_cursor_surface_init (MetaWaylandTabletCursorSurface *role)
+ {
+ }
+ 
+ static void
+-meta_wayland_surface_role_tablet_cursor_class_init (MetaWaylandSurfaceRoleTabletCursorClass *klass)
++meta_wayland_tablet_cursor_surface_class_init (MetaWaylandTabletCursorSurfaceClass *klass)
+ {
+ }
+diff --git a/src/wayland/meta-wayland-surface-role-tablet-cursor.h b/src/wayland/meta-wayland-tablet-cursor-surface.h
+similarity index 59%
+rename from src/wayland/meta-wayland-surface-role-tablet-cursor.h
+rename to src/wayland/meta-wayland-tablet-cursor-surface.h
+index 69fc6cf0f..5c5c198f5 100644
+--- a/src/wayland/meta-wayland-surface-role-tablet-cursor.h
++++ b/src/wayland/meta-wayland-tablet-cursor-surface.h
+@@ -19,15 +19,15 @@
+  * 02111-1307, USA.
+  */
+ 
+-#ifndef META_WAYLAND_SURFACE_ROLE_TABLET_CURSOR_H
+-#define META_WAYLAND_SURFACE_ROLE_TABLET_CURSOR_H
++#ifndef META_WAYLAND_TABLET_CURSOR_SURFACE_H
++#define META_WAYLAND_TABLET_CURSOR_SURFACE_H
+ 
+-#include "meta-wayland-surface-role-cursor.h"
++#include "meta-wayland-cursor-surface.h"
+ 
+-#define META_TYPE_WAYLAND_SURFACE_ROLE_TABLET_CURSOR (meta_wayland_surface_role_tablet_cursor_get_type ())
+-G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleTabletCursor,
+-                      meta_wayland_surface_role_tablet_cursor,
+-                      META, WAYLAND_SURFACE_ROLE_TABLET_CURSOR,
+-                      MetaWaylandSurfaceRoleCursor);
++#define META_TYPE_WAYLAND_TABLET_CURSOR_SURFACE (meta_wayland_tablet_cursor_surface_get_type ())
++G_DECLARE_FINAL_TYPE (MetaWaylandTabletCursorSurface,
++                      meta_wayland_tablet_cursor_surface,
++                      META, WAYLAND_TABLET_CURSOR_SURFACE,
++                      MetaWaylandCursorSurface)
+ 
+-#endif /* META_WAYLAND_SURFACE_ROLE_TABLET_CURSOR_H */
++#endif /* META_WAYLAND_TABLET_CURSOR_SURFACE_H */
+diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c
+index 4b57d4156..d373f8d25 100644
+--- a/src/wayland/meta-wayland-tablet-tool.c
++++ b/src/wayland/meta-wayland-tablet-tool.c
+@@ -31,7 +31,7 @@
+ #include <wayland-server.h>
+ #include "tablet-unstable-v2-server-protocol.h"
+ #include "meta-wayland-private.h"
+-#include "meta-wayland-surface-role-tablet-cursor.h"
++#include "meta-wayland-tablet-cursor-surface.h"
+ #include "meta-surface-actor-wayland.h"
+ #include "meta-wayland-tablet.h"
+ #include "meta-wayland-tablet-seat.h"
+@@ -90,16 +90,16 @@ meta_wayland_tablet_tool_update_cursor_surface (MetaWaylandTabletTool *tool)
+       if (tool->cursor_surface &&
+           meta_wayland_surface_get_buffer (tool->cursor_surface))
+         {
+-          MetaWaylandSurfaceRoleCursor *cursor_role =
+-            META_WAYLAND_SURFACE_ROLE_CURSOR (tool->cursor_surface->role);
++          MetaWaylandCursorSurface *cursor_surface =
++            META_WAYLAND_CURSOR_SURFACE (tool->cursor_surface->role);
+ 
+-          cursor = meta_wayland_surface_role_cursor_get_sprite (cursor_role);
++          cursor = meta_wayland_cursor_surface_get_sprite (cursor_surface);
+         }
+       else
+         cursor = NULL;
+     }
+   else if (tool->current_tablet)
+-    cursor = tool->default_sprite;
++    cursor = META_CURSOR_SPRITE (tool->default_sprite);
+   else
+     cursor = NULL;
+ 
+@@ -382,10 +382,10 @@ tablet_tool_handle_cursor_surface_destroy (struct wl_listener *listener,
+ }
+ 
+ static void
+-tool_cursor_prepare_at (MetaCursorSprite      *cursor_sprite,
+-                        int                    x,
+-                        int                    y,
+-                        MetaWaylandTabletTool *tool)
++tool_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
++                        int                      x,
++                        int                      y,
++                        MetaWaylandTabletTool   *tool)
+ {
+   MetaBackend *backend = meta_get_backend ();
+   MetaMonitorManager *monitor_manager =
+@@ -397,7 +397,8 @@ tool_cursor_prepare_at (MetaCursorSprite      *cursor_sprite,
+ 
+   /* Reload the cursor texture if the scale has changed. */
+   if (logical_monitor)
+-    meta_cursor_sprite_set_theme_scale (cursor_sprite, logical_monitor->scale);
++    meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
++                                                logical_monitor->scale);
+ }
+ 
+ MetaWaylandTabletTool *
+@@ -417,7 +418,7 @@ meta_wayland_tablet_tool_new (MetaWaylandTabletSeat  *seat,
+   tool->focus_surface_destroy_listener.notify = tablet_tool_handle_focus_surface_destroy;
+   tool->cursor_surface_destroy_listener.notify = tablet_tool_handle_cursor_surface_destroy;
+ 
+-  tool->default_sprite = meta_cursor_sprite_from_theme (META_CURSOR_CROSSHAIR);
++  tool->default_sprite = meta_cursor_sprite_xcursor_new (META_CURSOR_CROSSHAIR);
+   tool->prepare_at_signal_id =
+     g_signal_connect (tool->default_sprite, "prepare-at",
+                       G_CALLBACK (tool_cursor_prepare_at), tool);
+@@ -471,7 +472,7 @@ tool_set_cursor (struct wl_client   *client,
+ 
+   if (surface &&
+       !meta_wayland_surface_assign_role (surface,
+-                                         META_TYPE_WAYLAND_SURFACE_ROLE_TABLET_CURSOR,
++                                         META_TYPE_WAYLAND_TABLET_CURSOR_SURFACE,
+                                          NULL))
+     {
+       wl_resource_post_error (resource, WL_POINTER_ERROR_ROLE,
+@@ -482,13 +483,13 @@ tool_set_cursor (struct wl_client   *client,
+ 
+   if (surface)
+     {
+-      MetaWaylandSurfaceRoleCursor *cursor_role;
++      MetaWaylandCursorSurface *cursor_surface;
+ 
+-      cursor_role = META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
+-      meta_wayland_surface_role_cursor_set_renderer (cursor_role,
+-                                                     tool->cursor_renderer);
+-      meta_wayland_surface_role_cursor_set_hotspot (cursor_role,
+-                                                    hotspot_x, hotspot_y);
++      cursor_surface = META_WAYLAND_CURSOR_SURFACE (surface->role);
++      meta_wayland_cursor_surface_set_renderer (cursor_surface,
++                                                tool->cursor_renderer);
++      meta_wayland_cursor_surface_set_hotspot (cursor_surface,
++                                               hotspot_x, hotspot_y);
+     }
+ 
+   meta_wayland_tablet_tool_set_cursor_surface (tool, surface);
+diff --git a/src/wayland/meta-wayland-tablet-tool.h b/src/wayland/meta-wayland-tablet-tool.h
+index 8cd930086..011972fc2 100644
+--- a/src/wayland/meta-wayland-tablet-tool.h
++++ b/src/wayland/meta-wayland-tablet-tool.h
+@@ -28,6 +28,7 @@
+ 
+ #include "meta-wayland-types.h"
+ #include "meta-cursor-renderer.h"
++#include "backends/meta-cursor-sprite-xcursor.h"
+ 
+ struct _MetaWaylandTabletTool
+ {
+@@ -43,7 +44,7 @@ struct _MetaWaylandTabletTool
+   MetaWaylandSurface *cursor_surface;
+   struct wl_listener cursor_surface_destroy_listener;
+   MetaCursorRenderer *cursor_renderer;
+-  MetaCursorSprite *default_sprite;
++  MetaCursorSpriteXcursor *default_sprite;
+   guint prepare_at_signal_id;
+ 
+   MetaWaylandSurface *current;
diff --git a/SOURCES/inherit-xrandr-metamodes.patch b/SOURCES/inherit-xrandr-metamodes.patch
new file mode 100644
index 0000000..55db669
--- /dev/null
+++ b/SOURCES/inherit-xrandr-metamodes.patch
@@ -0,0 +1,365 @@
+From ea252d6e8f0e882ad2868853babcb5de4b9d9a6a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Mon, 18 Mar 2019 17:08:11 +0100
+Subject: [PATCH 1/2] monitor-config-manager: Use current mode when deriving
+ current config
+
+Instead of overriding the existing mode with the preferred mode of the monitor,
+use the one already configured. Also use the MetaMonitor API for deriving the
+position of the monitor in the screen coordinate space.
+---
+ src/backends/meta-monitor-config-manager.c | 77 +++++++++++++---------
+ 1 file changed, 47 insertions(+), 30 deletions(-)
+
+diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
+index 1ad342a44..aa8105edf 100644
+--- a/src/backends/meta-monitor-config-manager.c
++++ b/src/backends/meta-monitor-config-manager.c
+@@ -508,20 +508,19 @@ create_monitor_config (MetaMonitor     *monitor,
+ }
+ 
+ static MetaLogicalMonitorConfig *
+-create_preferred_logical_monitor_config (MetaMonitorManager          *monitor_manager,
+-                                         MetaMonitor                 *monitor,
+-                                         int                          x,
+-                                         int                          y,
+-                                         MetaLogicalMonitorConfig    *primary_logical_monitor_config,
+-                                         MetaLogicalMonitorLayoutMode layout_mode)
++create_logical_monitor_config (MetaMonitorManager           *monitor_manager,
++                               MetaMonitor                  *monitor,
++                               MetaMonitorMode              *mode,
++                               int                           x,
++                               int                           y,
++                               MetaLogicalMonitorConfig     *primary_logical_monitor_config,
++                               MetaLogicalMonitorLayoutMode  layout_mode)
+ {
+-  MetaMonitorMode *mode;
+   int width, height;
+   float scale;
+   MetaMonitorConfig *monitor_config;
+   MetaLogicalMonitorConfig *logical_monitor_config;
+ 
+-  mode = meta_monitor_get_preferred_mode (monitor);
+   meta_monitor_mode_get_resolution (mode, &width, &height);
+ 
+   if ((meta_monitor_manager_get_capabilities (monitor_manager) &
+@@ -561,22 +560,40 @@ create_preferred_logical_monitor_config (MetaMonitorManager          *monitor_ma
+ }
+ 
+ static MetaLogicalMonitorConfig *
+-create_logical_monitor_config_from_output (MetaMonitorManager           *monitor_manager,
+-                                           MetaMonitor                  *monitor,
+-                                           MetaLogicalMonitorConfig     *primary_logical_monitor_config,
+-                                           MetaLogicalMonitorLayoutMode  layout_mode)
++create_preferred_logical_monitor_config (MetaMonitorManager           *monitor_manager,
++                                         MetaMonitor                  *monitor,
++                                         int                           x,
++                                         int                           y,
++                                         MetaLogicalMonitorConfig     *primary_logical_monitor_config,
++                                         MetaLogicalMonitorLayoutMode  layout_mode)
+ {
+-    MetaOutput *output;
+-    MetaCrtc *crtc;
++  return create_logical_monitor_config (monitor_manager,
++                                        monitor,
++                                        meta_monitor_get_preferred_mode (monitor),
++                                        x, y,
++                                        primary_logical_monitor_config,
++                                        layout_mode);
++}
+ 
+-    output = meta_monitor_get_main_output (monitor);
+-    crtc = meta_output_get_assigned_crtc (output);
+-    return create_preferred_logical_monitor_config (monitor_manager,
+-                                                    monitor,
+-                                                    crtc->rect.x,
+-                                                    crtc->rect.y,
+-                                                    primary_logical_monitor_config,
+-                                                    layout_mode);
++static MetaLogicalMonitorConfig *
++create_logical_monitor_config_from_monitor (MetaMonitorManager           *monitor_manager,
++                                            MetaMonitor                  *monitor,
++                                            MetaLogicalMonitorConfig     *primary_logical_monitor_config,
++                                            MetaLogicalMonitorLayoutMode  layout_mode)
++{
++  MetaRectangle monitor_layout;
++  MetaMonitorMode *mode;
++
++  meta_monitor_derive_layout (monitor, &monitor_layout);
++  mode = meta_monitor_get_current_mode (monitor);
++
++  return create_logical_monitor_config (monitor_manager,
++                                        monitor,
++                                        mode,
++                                        monitor_layout.x,
++                                        monitor_layout.y,
++                                        primary_logical_monitor_config,
++                                        layout_mode);
+ }
+ 
+ MetaMonitorsConfig *
+@@ -604,10 +621,10 @@ meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_man
+   layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
+ 
+   primary_logical_monitor_config =
+-    create_logical_monitor_config_from_output (monitor_manager,
+-                                               primary_monitor,
+-                                               NULL,
+-                                               layout_mode);
++    create_logical_monitor_config_from_monitor (monitor_manager,
++                                                primary_monitor,
++                                                NULL,
++                                                layout_mode);
+ 
+   primary_logical_monitor_config->is_primary = TRUE;
+   logical_monitor_configs = g_list_append (NULL,
+@@ -626,10 +643,10 @@ meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_man
+         continue;
+ 
+       logical_monitor_config =
+-        create_logical_monitor_config_from_output (monitor_manager,
+-                                                   monitor,
+-                                                   primary_logical_monitor_config,
+-                                                   layout_mode);
++        create_logical_monitor_config_from_monitor (monitor_manager,
++                                                    monitor,
++                                                    primary_logical_monitor_config,
++                                                    layout_mode);
+ 
+       logical_monitor_configs = g_list_append (logical_monitor_configs,
+                                                logical_monitor_config);
+-- 
+2.20.1
+
+
+From 77c07e77ad233b763c82928c1db6003114b0a479 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Mon, 18 Mar 2019 17:10:37 +0100
+Subject: [PATCH 2/2] monitor-manager: Don't try to derive current config on
+ non-X11
+
+This commit also reworks the initial config state reading some. Appart from
+avoiding trying to inherit from backends where it doesn't make sense, it does
+the following changes:
+
+ * Replace the name "initial" with "inherited", as the initial config in the
+   context of monitor management is the one used initialization. E.g. if there is
+   a applicable configuration in monitors.xml, the initial config is taken from
+   there.
+
+ * Don't make "_create_()" functions have side effects. Previously
+   meta_monitor_config_manager_create_initial() also set state on the config
+   manager object. Instead, add a meta_monitor_config_manager_ensure_inherited()
+   and meta_monitor_manager_get_inherited_config() function to make things more
+   explicit.
+
+ * Don't recreate "is-applicable" logic, just use the existing helper.
+---
+ src/backends/meta-monitor-config-manager.c    | 39 +++++++++++--------
+ src/backends/meta-monitor-config-manager.h    |  5 ++-
+ src/backends/meta-monitor-manager-private.h   |  4 +-
+ src/backends/meta-monitor-manager.c           | 32 ++++++++-------
+ .../x11/meta-monitor-manager-xrandr.c         |  3 +-
+ 5 files changed, 48 insertions(+), 35 deletions(-)
+
+diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
+index aa8105edf..cb67e11e7 100644
+--- a/src/backends/meta-monitor-config-manager.c
++++ b/src/backends/meta-monitor-config-manager.c
+@@ -40,7 +40,7 @@ struct _MetaMonitorConfigManager
+   MetaMonitorConfigStore *config_store;
+ 
+   MetaMonitorsConfig *current_config;
+-  MetaMonitorsConfig *initial_config;
++  MetaMonitorsConfig *inherited_config;
+   GQueue config_history;
+ };
+ 
+@@ -596,11 +596,10 @@ create_logical_monitor_config_from_monitor (MetaMonitorManager           *monito
+                                         layout_mode);
+ }
+ 
+-MetaMonitorsConfig *
+-meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_manager)
++static MetaMonitorsConfig *
++meta_monitor_config_manager_derive_current (MetaMonitorConfigManager *config_manager)
+ {
+   MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
+-  MetaMonitorsConfig *initial_config;
+   GList *logical_monitor_configs;
+   MetaMonitor *primary_monitor;
+   MetaLogicalMonitorLayoutMode layout_mode;
+@@ -608,12 +607,6 @@ meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_man
+   GList *monitors;
+   GList *l;
+ 
+-  if (config_manager->initial_config != NULL)
+-    return g_object_ref (config_manager->initial_config);
+-
+-  if (meta_monitor_config_store_get_config_count (config_manager->config_store) > 0)
+-    return NULL;
+-
+   primary_monitor = find_primary_monitor (monitor_manager);
+   if (!primary_monitor || !meta_monitor_is_active (primary_monitor))
+     return NULL;
+@@ -652,14 +645,26 @@ meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_man
+                                                logical_monitor_config);
+     }
+ 
+-  initial_config = meta_monitors_config_new (monitor_manager,
+-                                             logical_monitor_configs,
+-                                             layout_mode,
+-                                             META_MONITORS_CONFIG_FLAG_NONE);
++  return meta_monitors_config_new (monitor_manager,
++                                   logical_monitor_configs,
++                                   layout_mode,
++                                   META_MONITORS_CONFIG_FLAG_NONE);
++}
++
++void
++meta_monitor_config_manager_ensure_inherited_config (MetaMonitorConfigManager *config_manager)
++{
++  if (config_manager->inherited_config)
++    return;
+ 
+-  config_manager->initial_config = g_object_ref (initial_config);
++  config_manager->inherited_config =
++    meta_monitor_config_manager_derive_current (config_manager);
++}
+ 
+-  return initial_config;
++MetaMonitorsConfig *
++meta_monitor_config_manager_get_inherited_config (MetaMonitorConfigManager *config_manager)
++{
++  return config_manager->inherited_config;
+ }
+ 
+ MetaMonitorsConfig *
+@@ -1188,7 +1193,7 @@ meta_monitor_config_manager_dispose (GObject *object)
+     META_MONITOR_CONFIG_MANAGER (object);
+ 
+   g_clear_object (&config_manager->current_config);
+-  g_clear_object (&config_manager->initial_config);
++  g_clear_object (&config_manager->inherited_config);
+   meta_monitor_config_manager_clear_history (config_manager);
+ 
+   G_OBJECT_CLASS (meta_monitor_config_manager_parent_class)->dispose (object);
+diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h
+index 16dff6d6a..25dcabcdc 100644
+--- a/src/backends/meta-monitor-config-manager.h
++++ b/src/backends/meta-monitor-config-manager.h
+@@ -88,7 +88,10 @@ gboolean meta_monitor_config_manager_assign (MetaMonitorManager *manager,
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_get_stored (MetaMonitorConfigManager *config_manager);
+ 
+-MetaMonitorsConfig * meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_manager);
++void meta_monitor_config_manager_ensure_inherited_config (MetaMonitorConfigManager *config_manager);
++
++MetaMonitorsConfig * meta_monitor_config_manager_get_inherited_config (MetaMonitorConfigManager *config_manager);
++
+ MetaMonitorsConfig * meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager);
+ 
+ MetaMonitorsConfig * meta_monitor_config_manager_create_fallback (MetaMonitorConfigManager *config_manager);
+diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h
+index a7a0671ae..0d3ed6830 100644
+--- a/src/backends/meta-monitor-manager-private.h
++++ b/src/backends/meta-monitor-manager-private.h
+@@ -77,7 +77,8 @@ typedef enum _MetaMonitorManagerCapability
+   META_MONITOR_MANAGER_CAPABILITY_NONE = 0,
+   META_MONITOR_MANAGER_CAPABILITY_MIRRORING = (1 << 0),
+   META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE = (1 << 1),
+-  META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED = (1 << 2)
++  META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED = (1 << 2),
++  META_MONITOR_MANAGER_CAPABILITY_CAN_DERIVE_CURRENT = (1 << 3),
+ } MetaMonitorManagerCapability;
+ 
+ /* Equivalent to the 'method' enum in org.gnome.Mutter.DisplayConfig */
+@@ -178,6 +179,7 @@ struct _MetaMonitorManager
+   int persistent_timeout_id;
+ 
+   MetaMonitorConfigManager *config_manager;
++  MetaMonitorsConfig *initial_config;
+ 
+   GnomePnpIds *pnp_ids;
+   UpClient *up_client;
+diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c
+index f7ada0136..68af15e76 100644
+--- a/src/backends/meta-monitor-manager.c
++++ b/src/backends/meta-monitor-manager.c
+@@ -493,14 +493,21 @@ should_use_stored_config (MetaMonitorManager *manager)
+           !meta_monitor_manager_has_hotplug_mode_update (manager));
+ }
+ 
++static gboolean
++can_derive_current_config (MetaMonitorManager *manager)
++{
++  MetaMonitorManagerCapability capabilities;
++
++  capabilities = meta_monitor_manager_get_capabilities (manager);
++  return !!(capabilities & META_MONITOR_MANAGER_CAPABILITY_CAN_DERIVE_CURRENT);
++}
++
+ MetaMonitorsConfig *
+ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
+ {
+-  g_autoptr (MetaMonitorsConfig) initial_config = NULL;
+   MetaMonitorsConfig *config = NULL;
+   GError *error = NULL;
+   gboolean use_stored_config;
+-  MetaMonitorsConfigKey *current_state_key;
+   MetaMonitorsConfigMethod method;
+   MetaMonitorsConfigMethod fallback_method =
+     META_MONITORS_CONFIG_METHOD_TEMPORARY;
+@@ -511,17 +518,8 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
+   else
+     method = META_MONITORS_CONFIG_METHOD_TEMPORARY;
+ 
+-  initial_config = meta_monitor_config_manager_create_initial (manager->config_manager);
+-
+-  if (initial_config)
+-    {
+-      current_state_key = meta_create_monitors_config_key_for_current_state (manager);
+-
+-      /* don't ever reuse initial configuration, if the monitor topology changed
+-       */
+-      if (current_state_key && !meta_monitors_config_key_equal (current_state_key, initial_config->key))
+-        g_clear_object (&initial_config);
+-    }
++  if (can_derive_current_config (manager))
++    meta_monitor_config_manager_ensure_inherited_config (manager->config_manager);
+ 
+   if (use_stored_config)
+     {
+@@ -590,9 +588,13 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
+       g_clear_object (&config);
+     }
+ 
+-  config = g_steal_pointer (&initial_config);
+-  if (config)
++  config =
++    meta_monitor_config_manager_get_inherited_config (manager->config_manager);
++  if (config &&
++      meta_monitor_manager_is_config_complete (manager, config))
+     {
++      config = g_object_ref (config);
++
+       if (!meta_monitor_manager_apply_monitors_config (manager,
+                                                        config,
+                                                        method,
+diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
+index d0da2c539..2c14983e2 100644
+--- a/src/backends/x11/meta-monitor-manager-xrandr.c
++++ b/src/backends/x11/meta-monitor-manager-xrandr.c
+@@ -949,7 +949,8 @@ static MetaMonitorManagerCapability
+ meta_monitor_manager_xrandr_get_capabilities (MetaMonitorManager *manager)
+ {
+   return (META_MONITOR_MANAGER_CAPABILITY_MIRRORING |
+-          META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
++          META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED |
++          META_MONITOR_MANAGER_CAPABILITY_CAN_DERIVE_CURRENT);
+ }
+ 
+ static gboolean
+-- 
+2.20.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/SPECS/mutter.spec b/SPECS/mutter.spec
new file mode 100644
index 0000000..cea0b73
--- /dev/null
+++ b/SPECS/mutter.spec
@@ -0,0 +1,971 @@
+%global gtk3_version 3.19.8
+%global glib_version 2.53.2
+%global gsettings_desktop_schemas_version 3.21.4
+%global json_glib_version 0.12.0
+%global libinput_version 1.4
+
+%ifarch s390 s390x
+%global disable_wayland --disable-wayland-egl-server --disable-wayland --disable-native-backend
+%endif
+
+Name:          mutter
+Version:       3.28.3
+Release:       16%{?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.28/%{name}-%{version}.tar.xz
+
+Patch0:  startup-notification.patch
+
+Patch1:  deal-more-gracefully-with-oversized-windows.patch
+
+# Work-around for Xvnc resizing (#1265511)
+Patch2:  0001-monitor-manager-xrandr-Work-around-spurious-hotplugs.patch
+
+Patch3:  0001-monitor-manager-xrandr-Force-an-update-when-resuming.patch
+Patch4:  0001-monitor-manager-Consider-external-layout-before-defa.patch
+
+Patch5:  0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch
+Patch6:  0001-backends-x11-Support-synaptics-configuration.patch
+
+Patch7:  0001-window-actor-Special-case-shaped-Java-windows.patch
+
+Patch9:  0001-clutter-Extend-touchpad-device-property-check-for-Sy.patch
+Patch10: 0001-clutter-x11-Implement-keycode-lookup-from-keysyms-on.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
+
+# https://bugzilla.redhat.com/show_bug.cgi?id=1618632
+# https://bugzilla.redhat.com/show_bug.cgi?id=1497303
+Patch31: 0001-monitor-manager-only-reuse-initial-config-if-monitor.patch
+
+Patch32: 0001-clutter-Do-not-latch-modifiers-on-modifier-keys.patch
+
+# Prevent titlebar from going off-screen (rhbz#1664407)
+Patch33: 0001-constraints-Fix-titlebars-going-off-the-bottom.patch
+
+# Classic classic mode support
+Patch34: 0001-screen-Expose-workspace-layout-properties.patch
+
+# el7 patches
+Patch100: 0001-Revert-build-Require-libgudev-232.patch
+Patch101: 0001-rhel7-Fix-build-for-el7.patch
+Patch103: 0001-wayland-enable-scale-monitor-framebuffer-by-default.patch
+Patch104: add-support-for-plain-old-x-device-configuration.patch
+Patch109: 0001-main-be-more-aggressive-in-assuming-X11-backend.patch
+Patch110: 0001-clutter-Only-reset-scroll-axes-on-slave-devices.patch
+Patch111: fix-crash-when-modal-closes-during-drag.patch
+
+# Fedora patches:
+# Upload HW cursor on demand, avoiding stuttering on hybrid GPU laptops
+Patch201: hw-cursor-on-demand-gnome-3-28.patch
+# Check hw support for calculated view transform
+Patch202: 0001-renderer-native-Check-calculated-transform-when-crea.patch
+
+# System wide monitor configuration (#1583825)
+Patch250: 0001-monitor-config-store-Read-system-wide-config-files.patch
+
+# Don't ignore 'MetaModes' (#1581806)
+Patch260: inherit-xrandr-metamodes.patch
+
+# Handle lack of RANDR (#1579257)
+Patch261: 0001-gpu-xrandr-Move-dpms-state-and-screen-size-updating-.patch
+Patch262: 0002-monitor-manager-xrandr-Create-dummy-screen-sized-mon.patch
+
+# Queue stage redraw on reactivate (#1636460)
+Patch270: 0001-idle-monitor-Use-G_SOURCE_CONTINUE-instead-of-TRUE.patch
+Patch271: 0002-idle-monitor-Postpone-dispatching-of-idle-timeout-if.patch
+
+# Fix crash in meta_monitor_mode_get_resolution() (#1638727)
+Patch272: 0001-monitor-Use-current-monitor-mode-to-check-whether-ac.patch
+Patch273: 0002-window-Return-1-if-meta_window_get_monitor-is-called.patch
+
+# Fix crash on device removal (#1578186)
+Patch274: 0001-clutter-input-device-xi2-Check-for-null-group_modes-.patch
+
+# Backport two performance improvement patches (#1737515)
+Patch275: 0001-compositor-Don-t-emit-size-changed-when-only-positio.patch
+Patch276: 0002-clutter-Avoid-relayouts-when-raising-lowering-childr.patch
+
+# Backport window title encoding bug fixes (#1630686)
+Patch277: 0001-x11-window-props-Do-not-convert-WM_NAME.patch
+Patch278: 0002-xprops-Make-sure-text_property_to_utf8-returns-UTF8.patch
+
+# Don't loose pointer button grabs (#1657887)
+Patch279: 0001-events-Sync-pending-pointer-events-without-a-window.patch
+
+BuildRequires: chrpath
+BuildRequires: pango-devel
+BuildRequires: startup-notification-devel
+BuildRequires: gnome-desktop3-devel
+BuildRequires: glib2-devel >= %{glib_version}
+BuildRequires: gtk3-devel >= %{gtk3_version}
+BuildRequires: pkgconfig
+BuildRequires: gobject-introspection-devel >= 1.41.0
+BuildRequires: libSM-devel
+BuildRequires: libwacom-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: libXtst-devel
+BuildRequires: mesa-libEGL-devel
+BuildRequires: mesa-libGLES-devel
+BuildRequires: mesa-libGL-devel
+BuildRequires: mesa-libgbm-devel
+BuildRequires: pam-devel
+BuildRequires: systemd-devel
+BuildRequires: upower-devel
+BuildRequires: xkeyboard-config-devel
+BuildRequires: zenity
+BuildRequires: desktop-file-utils
+# Bootstrap requirements
+BuildRequires: gtk-doc gnome-common gettext-devel git
+BuildRequires: libcanberra-devel
+BuildRequires: gsettings-desktop-schemas-devel >= %{gsettings_desktop_schemas_version}
+BuildRequires: automake, autoconf, libtool
+BuildRequires: pkgconfig(gudev-1.0)
+BuildRequires: pkgconfig(libdrm)
+BuildRequires: pkgconfig(gbm)
+BuildRequires: pkgconfig(wayland-server)
+
+BuildRequires: json-glib-devel >= %{json_glib_version}
+BuildRequires: libgudev1-devel
+%ifnarch s390 s390x
+BuildRequires: libwayland-server-devel
+BuildRequires: libinput-devel >= %{libinput_version}
+%endif
+
+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}
+%ifnarch s390 s390x
+Requires:      libinput%{?_isa} >= %{libinput_version}
+%endif
+
+%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
+%autosetup -S git
+
+%build
+autoreconf -f -i
+(if ! test -x configure; then NOCONFIGURE=1 ./autogen.sh; fi;
+ %configure --disable-static %{?disable_wayland} --enable-compile-warnings=maximum --with-libwacom)
+
+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
+* Wed Oct 02 2019 Jonas Ådahl <jadahl@redhat.com>) - 3.28.3-16
+- Don't loose pointer button grabs
+  Resolves: #1657887
+
+* Sun Aug 25 2019 Florian MÜllner <fmuellner@redhat.com> - 3.28.3-15
+- Expose workspace layout as properties
+  Related: #1720286
+
+* Thu Aug 15 2019 Jonas Ådahl <jadahl@redhat.com> - 3.28.3-14
+- Backport window title encoding bug fixes
+  Resolves: #1630686
+
+* Mon Aug 12 2019 Jonas Ådahl <jadahl@redhat.com> - 3.28.3-13
+- Backport two performance improvement patches.
+  Resolves #1737515
+
+* Wed Aug 07 2019 Carlos garnacho <cgarnach@redhat.com> - 3.28.3-12
+- Fix crash on input device removal
+  Resolves: #1578186
+
+* Mon Aug 05 2019 Jonas Ådahl <jadahl@redhat.com> - 3.28.3-11
+- Fix crash in meta_monitor_mode_get_resolution()
+  Resolves #1638727
+
+* Wed Apr 17 2019 Jonas Ådahl <jadahl@redhat.com> - 3.28.3-10
+- Fix idle monitor race condition
+  Resolves: #1636460
+
+* Thu Mar 28 2019 Jonas Ådahl <jadahl@redhat.com> - 3.28.3-9
+- Handle lack of RANDR
+  Resolves: #1579257
+
+* Mon Mar 18 2019 Jonas Ådahl <jadahl@redhat.com> - 3.28.3-8
+- Don't ignore current mode when deriving current config (#1581806)
+
+* Tue Mar 12 2019 Jonas Ådahl <jadahl@redhat.com> - 3.28.3-7
+- Backport read system wide monitor configuration patch (#1583825)
+
+* Wed Jan 16 2019 Florian Müllner <fmuellner@redhat.com> - 3.28.3-6
+- Prevent titlebars going off-screen (rhbz#1664407)
+
+* Wed Oct 10 2018 Carlos Garnacho <cgarnach@redhat.com> - 3.28.3-5
+- Do not latch modifiers on modifier keys
+  Resolves: #1637822
+
+* Fri Sep 21 2018 Ray Strode <rstrode@redhat.com> - 3.28.3-4
+- Fix crasher introduced in the previous build
+  Related: #1497303 1618632
+
+* Wed Sep 19 2018 Ray Strode <rstrode@redhat.com> - 3.28.3-3
+- ensure monitor hotplugged after start up is activated
+  Resolves: #1497303 1618632
+
+* Tue Sep 04 2018 Florian Müllner <fmuellner@redhat.com> - 3.28.3-2
+- Fix non-lowercase letters on virtual key devices
+- Resolves: #1521077
+
+* Wed Aug 01 2018 Kalev Lember <klember@redhat.com> - 3.28.3-1
+- Update to 3.28.3
+- Apply HW cursor on-demand patches
+- Apply monitor transform regression patch
+- Resolves: #1569736
+
+* Thu Jul 26 2018 Florian Müllner <fmuellner@redhat.com> - 3.28.2-5
+- Fix crash when modal closes during drag
+  Resolves: #1581454
+
+* Wed Jul 18 2018 Ray Strode <rstrode@redhat.com> - 3.28.2-4
+- rebuild against correct gnome-desktop
+  Related: #1593782
+
+* Fri Jun 22 2018 Florian Müllner <fmuellner@redhat.com> - 3.28.2-3
+- Fix support for external monitor configurations
+- Resolves: #1585230
+
+* Tue Jun 19 2018 Carlos Garnacho <cgarnach@redhat.com> - 3.28.2-2
+- Update scroll axes only in slave devices
+- Resolves: #1423374
+
+* Mon May 07 2018 Florian Müllner <fmuellner@redhat.com> - 3.28.2-1
+- Update to 3.28.2
+- Resolves: #1569736
+
+* Tue Apr 17 2018 Carlos Garnacho <cgarnach@redhat.com> - 3.26.2-14
+- Add support for Wacom Pro Pen 3D styli
+  Resolves: #1564063
+
+* Fri Feb 23 2018 Carlos Garnacho <cgarnach@redhat.com> - 3.26.2-13
+- Fix pad ring/strip modes
+  Resolves: #1543633
+
+* Mon Feb 19 2018 Carlos Garnacho <cgarnach@redhat.com> - 3.26.2-12
+- Apply settings on current stylus tools instantly
+  Resolves: #1543693
+
+* Wed Feb 14 2018 Jonas Ådahl <jadahl@redhat.com> - 3.26.2-11
+- Fix GPU memory purge error handling
+  Resolves: #1542375
+
+* Tue Feb 13 2018 Carlos Garnacho <cgarnach@redhat.com> - 3.26.2-10
+- Detect CLUTTER_TOUCHPAD_DEVICE on all Synaptics devices
+  Resolves: #1499788
+- Fix tablet pressure curve configuration not being applied
+  Resolves: #1543693
+
+* Tue Feb 13 2018 Ray Strode <rstrode@redhat.com> - 3.26.2-9
+- Fix VNC sessions
+  Resolves: #1543073
+
+* Wed Feb 07 2018 Carlos Garnacho <cgarnach@redhat.com> - 3.26.2-8
+- Avoid XCloseDevice on active XI2 devices
+  Resolves: #1540790
+
+* Wed Feb 07 2018 Florian Müllner <fmuellner@redhat.com> - 3.26.2-7
+- Fix crash during session saving
+  Resolves: #1535080
+- Fix XWayland prevented from starting
+  Resolves: #1540986
+
+* Wed Nov 29 2017 Rui Matos <rmatos@redhat.com> - 3.26.2-6
+- Fix a crash resizing windows while headless
+  Resolves: #1516408
+
+* Wed Nov 29 2017 Rui Matos <rmatos@redhat.com> - 3.26.2-5
+- Fix for certain multi-monitor configurations not being remembered
+  Resolves: #1516404
+
+* Wed Nov 08 2017 Ray Strode <rstrode@redhat.com> - 3.26.2-4
+- Fix crash with screen recorder
+  Resolves: #1508903
+
+* Tue Nov  7 2017 Rui Matos <rmatos@redhat.com> - 3.26.2-3
+- Fix external monitor layout patch to avoid a crash
+- Resolves: #1481386
+
+* Mon Nov  6 2017 Rui Matos <rmatos@redhat.com> - 3.26.2-2
+- Fix stereo patch to fail gracefully on Xwayland
+- Resolves: #1481386
+
+* Fri Nov 03 2017 Kalev Lember <klember@redhat.com> - 3.26.2-1
+- Update to 3.26.2
+- Resolves: #1481386
+
+* Thu Oct 26 2017 Rui Matos <rmatos@redhat.com> - 3.26.1-2
+- Add support for plain old X device configuration
+  Resolves: #1478397
+
+* Fri Oct 06 2017 Florian Müllner <fmuellner@redhat.com> - 3.26.1-1
+- Update to 3.26.1
+  Resolves: #1481386
+
+* 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