diff --git a/.gitignore b/.gitignore
index 8f5c56c..f2ae9b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/mutter-3.26.2.tar.xz
+SOURCES/mutter-3.28.3.tar.xz
diff --git a/.mutter.metadata b/.mutter.metadata
index 8d83fd2..6b4e4ce 100644
--- a/.mutter.metadata
+++ b/.mutter.metadata
@@ -1 +1 @@
-8d9dffa9c1ceaf07761b80662828fb7d60e76dd1 SOURCES/mutter-3.26.2.tar.xz
+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
index ec6bf21..e55d8bb 100644
--- a/SOURCES/0001-Revert-build-Require-libgudev-232.patch
+++ b/SOURCES/0001-Revert-build-Require-libgudev-232.patch
@@ -1,19 +1,20 @@
-From 23f4b91105c4fa9fa2231d2e1049728a6383cd65 Mon Sep 17 00:00:00 2001
+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 | 4 ++++
- 2 files changed, 6 insertions(+), 2 deletions(-)
+ 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 805707933..813ca008a 100644
+index e6b2bf8..2fde187 100644
 --- a/configure.ac
 +++ b/configure.ac
-@@ -225,10 +225,10 @@ AC_MSG_CHECKING([gudev])
+@@ -227,10 +227,10 @@ AC_MSG_CHECKING([gudev])
  if test x$with_gudev = xno ; then
    AC_MSG_RESULT([disabled])
  else
@@ -27,20 +28,32 @@ index 805707933..813ca008a 100644
    else
      AC_MSG_RESULT(no)
 diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c
-index eb35f88be..90b4b98ba 100644
+index 8b066c9..22ea2ad 100644
 --- a/src/backends/native/meta-launcher.c
 +++ b/src/backends/native/meta-launcher.c
-@@ -49,6 +49,10 @@
+@@ -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(GUdevClient, g_object_unref)
 +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevEnumerator, g_object_unref)
 +
- struct _MetaLauncher
+ typedef struct
  {
-   Login1Session *session_proxy;
+   GSource source;
 -- 
-2.13.5
+1.8.3.1
 
diff --git a/SOURCES/0001-backends-Monitor-changes-in-active-tools-settings.patch b/SOURCES/0001-backends-Monitor-changes-in-active-tools-settings.patch
deleted file mode 100644
index 444e6ff..0000000
--- a/SOURCES/0001-backends-Monitor-changes-in-active-tools-settings.patch
+++ /dev/null
@@ -1,142 +0,0 @@
-From 62f0fb12b1fa946779f0efa406159a355811fdc5 Mon Sep 17 00:00:00 2001
-From: Carlos Garnacho <carlosg@gnome.org>
-Date: Mon, 19 Feb 2018 16:50:52 +0100
-Subject: [PATCH] backends: Monitor changes in active tools' settings
-
-So the changes can be instantly applied while the tool is in proximity.
-Before we would just do it on proximity-in, which doesn't provide a
-good look&feel while modifying the tool settings in g-c-c.
-
-https://gitlab.gnome.org/GNOME/mutter/issues/38
-
-Closes: #38
----
- src/backends/meta-input-settings.c | 71 ++++++++++++++++++++++++++++++++++++--
- 1 file changed, 68 insertions(+), 3 deletions(-)
-
-diff --git a/src/backends/meta-input-settings.c b/src/backends/meta-input-settings.c
-index 0658755..ec0fc9f 100644
---- a/src/backends/meta-input-settings.c
-+++ b/src/backends/meta-input-settings.c
-@@ -41,6 +41,16 @@ static GQuark quark_tool_settings = 0;
- 
- typedef struct _MetaInputSettingsPrivate MetaInputSettingsPrivate;
- typedef struct _DeviceMappingInfo DeviceMappingInfo;
-+typedef struct _CurrentToolInfo CurrentToolInfo;
-+
-+struct _CurrentToolInfo
-+{
-+  MetaInputSettings *input_settings;
-+  ClutterInputDevice *device;
-+  ClutterInputDeviceTool *tool;
-+  GSettings *settings;
-+  guint changed_id;
-+};
- 
- struct _DeviceMappingInfo
- {
-@@ -68,6 +78,8 @@ struct _MetaInputSettingsPrivate
- 
-   GHashTable *mappable_devices;
- 
-+  GHashTable *current_tools;
-+
-   ClutterVirtualInputDevice *virtual_pad_keyboard;
- 
- #ifdef HAVE_LIBWACOM
-@@ -144,6 +156,7 @@ meta_input_settings_dispose (GObject *object)
-   g_clear_object (&priv->keyboard_settings);
-   g_clear_object (&priv->gsd_settings);
-   g_clear_pointer (&priv->mappable_devices, g_hash_table_unref);
-+  g_clear_pointer (&priv->current_tools, g_hash_table_unref);
- 
-   if (priv->monitors_changed_id && priv->monitor_manager)
-     {
-@@ -1510,22 +1523,71 @@ meta_input_settings_device_removed (ClutterDeviceManager *device_manager,
- 
-   priv = meta_input_settings_get_instance_private (input_settings);
-   g_hash_table_remove (priv->mappable_devices, device);
-+  g_hash_table_remove (priv->current_tools, device);
- 
-   if (g_hash_table_remove (priv->two_finger_devices, device) &&
-       g_hash_table_size (priv->two_finger_devices) == 0)
-     apply_device_settings (input_settings, NULL);
- }
- 
-+static void
-+current_tool_changed_cb (GSettings  *settings,
-+                         const char *key,
-+                         gpointer    user_data)
-+{
-+  CurrentToolInfo *info = user_data;
-+
-+  apply_stylus_settings (info->input_settings, info->device, info->tool);
-+}
-+
-+static CurrentToolInfo *
-+current_tool_info_new (MetaInputSettings      *input_settings,
-+                       ClutterInputDevice     *device,
-+                       ClutterInputDeviceTool *tool)
-+{
-+  CurrentToolInfo *info;
-+
-+  info = g_new0 (CurrentToolInfo, 1);
-+  info->input_settings = input_settings;
-+  info->device = device;
-+  info->tool = tool;
-+  info->settings = lookup_tool_settings (tool, device);
-+  info->changed_id =
-+    g_signal_connect (info->settings, "changed",
-+                      G_CALLBACK (current_tool_changed_cb),
-+                      info);
-+  return info;
-+}
-+
-+static void
-+current_tool_info_free (CurrentToolInfo *info)
-+{
-+  g_signal_handler_disconnect (info->settings, info->changed_id);
-+  g_free (info);
-+}
-+
- static void
- meta_input_settings_tool_changed (ClutterDeviceManager   *device_manager,
-                                   ClutterInputDevice     *device,
-                                   ClutterInputDeviceTool *tool,
-                                   MetaInputSettings      *input_settings)
- {
--  if (!tool)
--    return;
-+  MetaInputSettingsPrivate *priv;
- 
--  apply_stylus_settings (input_settings, device, tool);
-+  priv = meta_input_settings_get_instance_private (input_settings);
-+
-+  if (tool)
-+    {
-+      CurrentToolInfo *current_tool;
-+
-+      current_tool = current_tool_info_new (input_settings, device, tool);
-+      g_hash_table_insert (priv->current_tools, device, current_tool);
-+      apply_stylus_settings (input_settings, device, tool);
-+    }
-+  else
-+    {
-+      g_hash_table_remove (priv->current_tools, device);
-+    }
- }
- 
- static void
-@@ -1616,6 +1678,9 @@ meta_input_settings_init (MetaInputSettings *settings)
-   priv->mappable_devices =
-     g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) device_mapping_info_free);
- 
-+  priv->current_tools =
-+    g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) current_tool_info_free);
-+
-   priv->monitor_manager = g_object_ref (meta_monitor_manager_get ());
-   g_signal_connect (priv->monitor_manager, "monitors-changed-internal",
-                     G_CALLBACK (monitors_changed_cb), settings);
--- 
-2.16.1
-
diff --git a/SOURCES/0001-backends-x11-Fix-time-comparison-bug-causing-hang.patch b/SOURCES/0001-backends-x11-Fix-time-comparison-bug-causing-hang.patch
deleted file mode 100644
index 6a87a0f..0000000
--- a/SOURCES/0001-backends-x11-Fix-time-comparison-bug-causing-hang.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 05bf09ea4aa5a7dc22869075ea2096c4a293d70d Mon Sep 17 00:00:00 2001
-From: Jeff Smith <whydoubt@gmail.com>
-Date: Wed, 31 Jan 2018 23:27:19 -0600
-Subject: [PATCH] backends/x11: Fix time-comparison bug causing hang
-
-A comparison in translate_device_event() does not account for the fact
-that X's clock wraps about every 49.7 days.  When triggered, this causes
-an unresponsive GUI.
-
-Replace simple less-than comparison with XSERVER_TIME_IS_BEFORE macro,
-which accounts for the wrapping of X's clock.
-
-Closes: https://gitlab.gnome.org/GNOME/mutter/issues/12
----
- src/backends/x11/meta-backend-x11.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
-index 233532435..f447f785f 100644
---- a/src/backends/x11/meta-backend-x11.c
-+++ b/src/backends/x11/meta-backend-x11.c
-@@ -112,7 +112,7 @@ translate_device_event (MetaBackendX11 *x11,
- 
-   if (!device_event->send_event && device_event->time != CurrentTime)
-     {
--      if (device_event->time < priv->latest_evtime)
-+      if (XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime))
-         {
-           /* Emulated pointer events received after XIRejectTouch is received
-            * on a passive touch grab will contain older timestamps, update those
--- 
-2.17.1
-
diff --git a/SOURCES/0001-backends-x11-Preserve-XI1-XDevice-throughout-Clutter.patch b/SOURCES/0001-backends-x11-Preserve-XI1-XDevice-throughout-Clutter.patch
deleted file mode 100644
index 0a1fc86..0000000
--- a/SOURCES/0001-backends-x11-Preserve-XI1-XDevice-throughout-Clutter.patch
+++ /dev/null
@@ -1,127 +0,0 @@
-From bc17d94ef058564c1a1adf28a8696164455fea1b Mon Sep 17 00:00:00 2001
-From: Carlos Garnacho <carlosg@gnome.org>
-Date: Tue, 30 Jan 2018 13:07:32 +0100
-Subject: [PATCH] backends/x11: Preserve XI1 XDevice throughout
- ClutterInputDevice lifetime
-
-Opening and closing the device may result into XI2 grabs being cut short,
-resulting into pad buttons being rendered ineffective, and other possible
-misbehaviors. This is an XInput flaw that fell in the gap between XI1 and
-XI2, and has no easy fix. It pays us for mixing both versions, I guess...
-
-Work this around by keeping the XI1 XDevice attached to the
-ClutterInputDevice, this way it will live long enough that this is not
-a concern.
-
-Investigation of this bug was mostly carried by Peter Hutterer, I'm just
-the executing hand.
-
-https://gitlab.gnome.org/GNOME/mutter/issues/7
-
-Closes: #7
----
- src/backends/x11/meta-input-settings-x11.c | 48 ++++++++++++++++++++++++++----
- 1 file changed, 42 insertions(+), 6 deletions(-)
-
-diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c
-index d1ee37a..7a876ef 100644
---- a/src/backends/x11/meta-input-settings-x11.c
-+++ b/src/backends/x11/meta-input-settings-x11.c
-@@ -55,6 +55,46 @@ enum {
-   SCROLL_METHOD_NUM_FIELDS
- };
- 
-+static void
-+device_free_xdevice (gpointer user_data)
-+{
-+  MetaDisplay *display = meta_get_display ();
-+  MetaBackend *backend = meta_get_backend ();
-+  Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
-+  XDevice *xdev = user_data;
-+
-+  meta_error_trap_push (display);
-+  XCloseDevice (xdisplay, xdev);
-+  meta_error_trap_pop (display);
-+}
-+
-+static XDevice *
-+device_ensure_xdevice (ClutterInputDevice *device)
-+{
-+  MetaDisplay *display = meta_get_display ();
-+  MetaBackend *backend = meta_get_backend ();
-+  Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
-+  int device_id = clutter_input_device_get_device_id (device);
-+  XDevice *xdev = NULL;
-+
-+  xdev = g_object_get_data (G_OBJECT (device), "meta-input-settings-xdevice");
-+  if (xdev)
-+    return xdev;
-+
-+  meta_error_trap_push (display);
-+  xdev = XOpenDevice (xdisplay, device_id);
-+  meta_error_trap_pop (display);
-+
-+  if (xdev)
-+    {
-+      g_object_set_data_full (G_OBJECT (device),
-+                              "meta-input-settings-xdevice",
-+                              xdev, (GDestroyNotify) device_free_xdevice);
-+    }
-+
-+  return xdev;
-+}
-+
- static void *
- get_property (ClutterInputDevice *device,
-               const gchar        *property,
-@@ -540,7 +580,6 @@ meta_input_settings_x11_set_tablet_mapping (MetaInputSettings     *settings,
-   MetaDisplay *display = meta_get_display ();
-   MetaBackend *backend = meta_get_backend ();
-   Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
--  int device_id = clutter_input_device_get_device_id (device);
-   XDevice *xdev;
- 
-   if (!display)
-@@ -548,13 +587,12 @@ meta_input_settings_x11_set_tablet_mapping (MetaInputSettings     *settings,
- 
-   /* Grab the puke bucket! */
-   meta_error_trap_push (display);
--  xdev = XOpenDevice (xdisplay, device_id);
-+  xdev = device_ensure_xdevice (device);
-   if (xdev)
-     {
-       XSetDeviceMode (xdisplay, xdev,
-                       mapping == G_DESKTOP_TABLET_MAPPING_ABSOLUTE ?
-                       Absolute : Relative);
--      XCloseDevice (xdisplay, xdev);
-     }
- 
-   if (meta_error_trap_pop_with_return (display))
-@@ -737,7 +775,6 @@ meta_input_settings_x11_set_stylus_button_map (MetaInputSettings          *setti
-   MetaDisplay *display = meta_get_display ();
-   MetaBackend *backend = meta_get_backend ();
-   Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
--  int device_id = clutter_input_device_get_device_id (device);
-   XDevice *xdev;
- 
-   if (!display)
-@@ -745,7 +782,7 @@ meta_input_settings_x11_set_stylus_button_map (MetaInputSettings          *setti
- 
-   /* Grab the puke bucket! */
-   meta_error_trap_push (display);
--  xdev = XOpenDevice (xdisplay, device_id);
-+  xdev = device_ensure_xdevice (device);
-   if (xdev)
-     {
-       guchar map[3] = {
-@@ -755,7 +792,6 @@ meta_input_settings_x11_set_stylus_button_map (MetaInputSettings          *setti
-       };
- 
-       XSetDeviceButtonMapping (xdisplay, xdev, map, G_N_ELEMENTS (map));
--      XCloseDevice (xdisplay, xdev);
-     }
- 
-   if (meta_error_trap_pop_with_return (display))
--- 
-1.8.3.1
-
diff --git a/SOURCES/0001-backends-x11-wacom-pressure-curve-is-a-32-bit-proper.patch b/SOURCES/0001-backends-x11-wacom-pressure-curve-is-a-32-bit-proper.patch
deleted file mode 100644
index f13f593..0000000
--- a/SOURCES/0001-backends-x11-wacom-pressure-curve-is-a-32-bit-proper.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From ac502c921d2e813e6e916a589a07bc58ca4c12e7 Mon Sep 17 00:00:00 2001
-From: Peter Hutterer <peter.hutterer@who-t.net>
-Date: Fri, 9 Feb 2018 11:53:17 +1000
-Subject: [PATCH] backends/x11: wacom pressure curve is a 32-bit property
-
-The property has been 32 bits since around 2011 and has not changed, mutter
-expects it to be 8 bits. The mismatch causes change_property to never
-actually change the property.
-
-https://gitlab.gnome.org/GNOME/mutter/issues/26
-
-Closes: #26
----
- src/backends/x11/meta-input-settings-x11.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c
-index 7d1d360a3..9687fb36f 100644
---- a/src/backends/x11/meta-input-settings-x11.c
-+++ b/src/backends/x11/meta-input-settings-x11.c
-@@ -813,9 +813,9 @@ meta_input_settings_x11_set_stylus_pressure (MetaInputSettings      *settings,
-                                              ClutterInputDeviceTool *tool,
-                                              const gint32            pressure[4])
- {
--  guchar values[4] = { pressure[0], pressure[1], pressure[2], pressure[3] };
-+  guint32 values[4] = { pressure[0], pressure[1], pressure[2], pressure[3] };
- 
--  change_property (device, "Wacom Pressurecurve", XA_INTEGER, 8,
-+  change_property (device, "Wacom Pressurecurve", XA_INTEGER, 32,
-                    &values, G_N_ELEMENTS (values));
- }
- 
--- 
-2.16.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-stage-don-t-use-deprecated-api.patch b/SOURCES/0001-clutter-stage-don-t-use-deprecated-api.patch
deleted file mode 100644
index d3b0103..0000000
--- a/SOURCES/0001-clutter-stage-don-t-use-deprecated-api.patch
+++ /dev/null
@@ -1,217 +0,0 @@
-From e69a6ac0e44e8d5fd72d7bc60f118044b0407e8f Mon Sep 17 00:00:00 2001
-From: rpm-build <rpm-build>
-Date: Thu, 9 Nov 2017 16:18:02 -0500
-Subject: [PATCH] 0001-clutter-stage-don-t-use-deprecated-api.patch
-
----
- clutter/clutter/clutter-stage.c | 21 ++++++++++++---------
- 1 file changed, 12 insertions(+), 9 deletions(-)
-
-diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
-index 02ab07b..e4f9342 100644
---- a/clutter/clutter/clutter-stage.c
-+++ b/clutter/clutter/clutter-stage.c
-@@ -1459,64 +1459,65 @@ _clutter_stage_do_pick_on_view (ClutterStage     *stage,
-   fb_height = view_layout.height * fb_scale;
-   cogl_push_framebuffer (fb);
- 
-   /* needed for when a context switch happens */
-   _clutter_stage_maybe_setup_viewport (stage, view);
- 
-   /* FIXME: For some reason leaving the cogl clip stack empty causes the
-    * picking to not work at all, so setting it the whole framebuffer content
-    * for now. */
-   cogl_framebuffer_push_scissor_clip (fb, 0, 0,
-                                       view_layout.width * fb_scale,
-                                       view_layout.height * fb_scale);
- 
-   _clutter_stage_window_get_dirty_pixel (priv->impl, view, &dirty_x, &dirty_y);
- 
-   if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
-     {
-       CLUTTER_NOTE (PICK, "Pushing pick scissor clip x: %d, y: %d, 1x1",
-                     (int) dirty_x * fb_scale,
-                     (int) dirty_y * fb_scale);
-       cogl_framebuffer_push_scissor_clip (fb, dirty_x * fb_scale, dirty_y * fb_scale, 1, 1);
-     }
- 
-   viewport_offset_x = x * fb_scale - dirty_x * fb_scale;
-   viewport_offset_y = y * fb_scale - dirty_y * fb_scale;
-   CLUTTER_NOTE (PICK, "Setting viewport to %f, %f, %f, %f",
-                 priv->viewport[0] * fb_scale - viewport_offset_x,
-                 priv->viewport[1] * fb_scale - viewport_offset_y,
-                 priv->viewport[2] * fb_scale,
-                 priv->viewport[3] * fb_scale);
--  cogl_set_viewport (priv->viewport[0] * fb_scale - viewport_offset_x,
--                     priv->viewport[1] * fb_scale - viewport_offset_y,
--                     priv->viewport[2] * fb_scale,
--                     priv->viewport[3] * fb_scale);
-+  cogl_framebuffer_set_viewport (fb,
-+                                 priv->viewport[0] * fb_scale - viewport_offset_x,
-+                                 priv->viewport[1] * fb_scale - viewport_offset_y,
-+                                 priv->viewport[2] * fb_scale,
-+                                 priv->viewport[3] * fb_scale);
- 
-   read_x = dirty_x * fb_scale;
-   read_y = dirty_y * fb_scale;
- 
-   CLUTTER_NOTE (PICK, "Performing pick at %i,%i on view %dx%d+%d+%d s: %d",
-                 x, y,
-                 view_layout.width, view_layout.height,
-                 view_layout.x, view_layout.y, fb_scale);
- 
-   cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255);
-   cogl_clear (&stage_pick_id, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH);
- 
-   /* Disable dithering (if any) when doing the painting in pick mode */
-   dither_enabled_save = cogl_framebuffer_get_dither_enabled (fb);
-   cogl_framebuffer_set_dither_enabled (fb, FALSE);
- 
-   /* Render the entire scence in pick mode - just single colored silhouette's
-    * are drawn offscreen (as we never swap buffers)
-   */
-   context->pick_mode = mode;
-   _clutter_stage_paint_view (stage, view, NULL);
-   context->pick_mode = CLUTTER_PICK_NONE;
- 
-   /* Read the color of the screen co-ords pixel. RGBA_8888_PRE is used
-      even though we don't care about the alpha component because under
-      GLES this is the only format that is guaranteed to work so Cogl
-      will end up having to do a conversion if any other format is
-      used. The format is requested as pre-multiplied because Cogl
-      assumes that all pixels in the framebuffer are premultiplied so
-      it avoids a conversion. */
-@@ -3590,123 +3591,125 @@ calculate_z_translation (float z_near)
-    *  z_2d = --------------------------- + z_near
-    *                 sin (0.5°)
-    */
- 
-    /* We expect the compiler should boil this down to z_near * CONSTANT
-     * already, but just in case we use precomputed constants
-     */
- #if 0
- # define A      tanf (_DEG_TO_RAD (30.f))
- # define B      sinf (_DEG_TO_RAD (120.f))
- # define C      cosf (_DEG_TO_RAD (30.5f))
- # define D      sinf (_DEG_TO_RAD (.5f))
- #else
- # define A      0.57735025882720947265625f
- # define B      0.866025388240814208984375f
- # define C      0.86162912845611572265625f
- # define D      0.00872653536498546600341796875f
- #endif
- 
-   return z_near
-        * A * B * C
-        / D
-        + z_near;
- }
- 
- void
- _clutter_stage_maybe_setup_viewport (ClutterStage     *stage,
-                                      ClutterStageView *view)
- {
-   ClutterStagePrivate *priv = stage->priv;
-+  CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
- 
-   if (clutter_stage_view_is_dirty_viewport (view))
-     {
-       cairo_rectangle_int_t view_layout;
-       ClutterPerspective perspective;
-       float fb_scale;
-       float viewport_offset_x;
-       float viewport_offset_y;
-       float z_2d;
- 
-       CLUTTER_NOTE (PAINT,
-                     "Setting up the viewport { w:%f, h:%f }",
-                     priv->viewport[2],
-                     priv->viewport[3]);
- 
-       fb_scale = clutter_stage_view_get_scale (view);
-       clutter_stage_view_get_layout (view, &view_layout);
- 
-       viewport_offset_x = view_layout.x * fb_scale;
-       viewport_offset_y = view_layout.y * fb_scale;
--      cogl_set_viewport (priv->viewport[0] * fb_scale - viewport_offset_x,
--                         priv->viewport[1] * fb_scale - viewport_offset_y,
--                         priv->viewport[2] * fb_scale,
--                         priv->viewport[3] * fb_scale);
-+      cogl_framebuffer_set_viewport (fb,
-+                                     priv->viewport[0] * fb_scale - viewport_offset_x,
-+                                     priv->viewport[1] * fb_scale - viewport_offset_y,
-+                                     priv->viewport[2] * fb_scale,
-+                                     priv->viewport[3] * fb_scale);
- 
-       perspective = priv->perspective;
- 
-       /* Ideally we want to regenerate the perspective matrix whenever
-        * the size changes but if the user has provided a custom matrix
-        * then we don't want to override it */
-       if (!priv->has_custom_perspective)
-         {
-           perspective.aspect = priv->viewport[2] / priv->viewport[3];
-           z_2d = calculate_z_translation (perspective.z_near);
- 
-           /* NB: z_2d is only enough room for 85% of the stage_height between
-            * the stage and the z_near plane. For behind the stage plane we
-            * want a more consistent gap of 10 times the stage_height before
-            * hitting the far plane so we calculate that relative to the final
-            * height of the stage plane at the z_2d_distance we got... */
-           perspective.z_far = z_2d +
-             tanf (_DEG_TO_RAD (perspective.fovy / 2.0f)) * z_2d * 20.0f;
- 
-           clutter_stage_set_perspective_internal (stage, &perspective);
-         }
-       else
-         z_2d = calculate_z_translation (perspective.z_near);
- 
-       cogl_matrix_init_identity (&priv->view);
-       cogl_matrix_view_2d_in_perspective (&priv->view,
-                                           perspective.fovy,
-                                           perspective.aspect,
-                                           perspective.z_near,
-                                           z_2d,
-                                           priv->viewport[2],
-                                           priv->viewport[3]);
- 
-       clutter_stage_view_set_dirty_viewport (view, FALSE);
-     }
- 
-   if (clutter_stage_view_is_dirty_projection (view))
-     {
--      cogl_set_projection_matrix (&priv->projection);
-+      cogl_framebuffer_set_projection_matrix (fb, &priv->projection);
- 
-       clutter_stage_view_set_dirty_projection (view, FALSE);
-     }
- }
- 
- #undef _DEG_TO_RAD
- 
- /**
-  * clutter_stage_ensure_redraw:
-  * @stage: a #ClutterStage
-  *
-  * Ensures that @stage is redrawn
-  *
-  * This function should not be called by applications: it is
-  * used when embedding a #ClutterStage into a toolkit with
-  * another windowing system, like GTK+.
-  *
-  * Since: 1.0
-  */
- void
- clutter_stage_ensure_redraw (ClutterStage *stage)
- {
-   ClutterMasterClock *master_clock;
-   ClutterStagePrivate *priv;
- 
-   g_return_if_fail (CLUTTER_IS_STAGE (stage));
- 
-   priv = stage->priv;
- 
-   if (!priv->relayout_pending && !priv->redraw_pending)
--- 
-2.14.3
-
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-clutter-x11-Implement-missing-ClutterInputDevice-pad.patch b/SOURCES/0001-clutter-x11-Implement-missing-ClutterInputDevice-pad.patch
deleted file mode 100644
index 69ca7a4..0000000
--- a/SOURCES/0001-clutter-x11-Implement-missing-ClutterInputDevice-pad.patch
+++ /dev/null
@@ -1,481 +0,0 @@
-From 1d745a858470b29b44e5b0e308488a477c4526cb Mon Sep 17 00:00:00 2001
-From: Carlos Garnacho <carlosg@gnome.org>
-Date: Thu, 22 Feb 2018 17:48:17 +0100
-Subject: [PATCH 1/2] clutter/x11: Implement missing ClutterInputDevice pad
- vmethods
-
-Use libwacom to be able to find out modes, groups and button roles on
-pad devices.
-
-https://gitlab.gnome.org/GNOME/mutter/issues/48
-
-Closes: #48
----
- clutter/clutter/x11/clutter-device-manager-xi2.c | 11 +++
- clutter/clutter/x11/clutter-device-manager-xi2.h |  8 ++
- clutter/clutter/x11/clutter-input-device-xi2.c   | 97 ++++++++++++++++++++++++
- clutter/clutter/x11/clutter-input-device-xi2.h   | 10 +++
- clutter/configure.ac                             | 32 +++++++-
- 5 files changed, 156 insertions(+), 2 deletions(-)
-
-diff --git a/clutter/clutter/x11/clutter-device-manager-xi2.c b/clutter/clutter/x11/clutter-device-manager-xi2.c
-index d2610cc..dee2604 100644
---- a/clutter/clutter/x11/clutter-device-manager-xi2.c
-+++ b/clutter/clutter/x11/clutter-device-manager-xi2.c
-@@ -495,11 +495,18 @@ create_device (ClutterDeviceManagerXI2 *manager_xi2,
-                          "device-node", node_path,
-                          "n-rings", num_rings,
-                          "n-strips", num_strips,
-+                         "n-mode-groups", MAX (num_rings, num_strips),
-                          NULL);
- 
-   translate_device_classes (backend_x11->xdpy, retval,
-                             info->classes,
-                             info->num_classes);
-+
-+#ifdef HAVE_LIBWACOM
-+  if (source == CLUTTER_PAD_DEVICE)
-+    clutter_input_device_xi2_ensure_wacom_info (retval, manager_xi2->wacom_db);
-+#endif
-+
-   g_free (vendor_id);
-   g_free (product_id);
- 
-@@ -2063,4 +2070,8 @@ clutter_device_manager_xi2_init (ClutterDeviceManagerXI2 *self)
-                                                (GDestroyNotify) g_object_unref);
-   self->tools_by_serial = g_hash_table_new_full (NULL, NULL, NULL,
-                                                  (GDestroyNotify) g_object_unref);
-+
-+#ifdef HAVE_LIBWACOM
-+  self->wacom_db = libwacom_database_new ();
-+#endif
- }
-diff --git a/clutter/clutter/x11/clutter-device-manager-xi2.h b/clutter/clutter/x11/clutter-device-manager-xi2.h
-index c8e66f9..be25759 100644
---- a/clutter/clutter/x11/clutter-device-manager-xi2.h
-+++ b/clutter/clutter/x11/clutter-device-manager-xi2.h
-@@ -26,6 +26,10 @@
- 
- #include <clutter/clutter-device-manager.h>
- 
-+#ifdef HAVE_LIBWACOM
-+#include <libwacom/libwacom.h>
-+#endif
-+
- G_BEGIN_DECLS
- 
- #define CLUTTER_TYPE_DEVICE_MANAGER_XI2            (_clutter_device_manager_xi2_get_type ())
-@@ -51,6 +55,10 @@ struct _ClutterDeviceManagerXI2
-   GList *slave_devices;
- 
-   int opcode;
-+
-+#ifdef HAVE_LIBWACOM
-+  WacomDeviceDatabase *wacom_db;
-+#endif
- };
- 
- struct _ClutterDeviceManagerXI2Class
-diff --git a/clutter/clutter/x11/clutter-input-device-xi2.c b/clutter/clutter/x11/clutter-input-device-xi2.c
-index 7fb0e05..2d9b6d2 100644
---- a/clutter/clutter/x11/clutter-input-device-xi2.c
-+++ b/clutter/clutter/x11/clutter-input-device-xi2.c
-@@ -45,6 +45,10 @@ struct _ClutterInputDeviceXI2
- 
-   gint device_id;
-   ClutterInputDeviceTool *current_tool;
-+
-+#ifdef HAVE_LIBWACOM
-+  WacomDevice *wacom_device;
-+#endif
- };
- 
- #define N_BUTTONS       5
-@@ -88,15 +92,94 @@ clutter_input_device_xi2_is_grouped (ClutterInputDevice *device,
- }
- 
- static void
-+clutter_input_device_xi2_finalize (GObject *object)
-+{
-+#ifdef HAVE_LIBWACOM
-+  ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (object);
-+
-+  if (device_xi2->wacom_device)
-+    libwacom_destroy (device_xi2->wacom_device);
-+#endif
-+
-+  G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->finalize (object);
-+}
-+
-+static gint
-+clutter_input_device_xi2_get_group_n_modes (ClutterInputDevice *device,
-+                                            gint                group)
-+{
-+#ifdef HAVE_LIBWACOM
-+  ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device);
-+
-+  if (device_xi2->wacom_device)
-+    {
-+      if (group == 0)
-+        {
-+          if (libwacom_has_ring (device_xi2->wacom_device))
-+            return libwacom_get_ring_num_modes (device_xi2->wacom_device);
-+          else if (libwacom_get_num_strips (device_xi2->wacom_device) >= 1)
-+            return libwacom_get_strips_num_modes (device_xi2->wacom_device);
-+        }
-+      else if (group == 1)
-+        {
-+          if (libwacom_has_ring2 (device_xi2->wacom_device))
-+            return libwacom_get_ring2_num_modes (device_xi2->wacom_device);
-+          else if (libwacom_get_num_strips (device_xi2->wacom_device) >= 2)
-+            return libwacom_get_strips_num_modes (device_xi2->wacom_device);
-+        }
-+    }
-+#endif
-+
-+  return -1;
-+}
-+
-+#ifdef HAVE_LIBWACOM
-+static int
-+clutter_input_device_xi2_get_button_group (ClutterInputDevice *device,
-+                                           guint               button)
-+{
-+  ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device);
-+
-+  if (device_xi2->wacom_device)
-+    {
-+      if (button >= libwacom_get_num_buttons (device_xi2->wacom_device))
-+        return -1;
-+
-+      return libwacom_get_button_led_group (device_xi2->wacom_device,
-+                                            'A' + button);
-+    }
-+  else
-+    return -1;
-+}
-+#endif
-+
-+static gboolean
-+clutter_input_device_xi2_is_mode_switch_button (ClutterInputDevice *device,
-+                                                guint               group,
-+                                                guint               button)
-+{
-+  int button_group = -1;
-+
-+#ifdef HAVE_LIBWACOM
-+  button_group = clutter_input_device_xi2_get_button_group (device, button);
-+#endif
-+
-+  return button_group == (int) group;
-+}
-+
-+static void
- clutter_input_device_xi2_class_init (ClutterInputDeviceXI2Class *klass)
- {
-   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-   ClutterInputDeviceClass *device_class = CLUTTER_INPUT_DEVICE_CLASS (klass);
- 
-   gobject_class->constructed = clutter_input_device_xi2_constructed;
-+  gobject_class->finalize = clutter_input_device_xi2_finalize;
- 
-   device_class->keycode_to_evdev = clutter_input_device_xi2_keycode_to_evdev;
-   device_class->is_grouped = clutter_input_device_xi2_is_grouped;
-+  device_class->get_group_n_modes = clutter_input_device_xi2_get_group_n_modes;
-+  device_class->is_mode_switch_button = clutter_input_device_xi2_is_mode_switch_button;
- }
- 
- static void
-@@ -196,3 +279,17 @@ clutter_input_device_xi2_get_current_tool (ClutterInputDevice *device)
-   ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device);
-   return device_xi2->current_tool;
- }
-+
-+#ifdef HAVE_LIBWACOM
-+void
-+clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice  *device,
-+                                            WacomDeviceDatabase *wacom_db)
-+{
-+  ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device);
-+  const gchar *node_path;
-+
-+  node_path = clutter_input_device_get_device_node (device);
-+  device_xi2->wacom_device = libwacom_new_from_path (wacom_db, node_path,
-+                                                     WFALLBACK_NONE, NULL);
-+}
-+#endif
-diff --git a/clutter/clutter/x11/clutter-input-device-xi2.h b/clutter/clutter/x11/clutter-input-device-xi2.h
-index b93684f..e30fb4d 100644
---- a/clutter/clutter/x11/clutter-input-device-xi2.h
-+++ b/clutter/clutter/x11/clutter-input-device-xi2.h
-@@ -27,6 +27,10 @@
- #include <clutter/clutter-input-device.h>
- #include <X11/extensions/XInput2.h>
- 
-+#ifdef HAVE_LIBWACOM
-+#include <libwacom/libwacom.h>
-+#endif
-+
- G_BEGIN_DECLS
- 
- #define CLUTTER_TYPE_INPUT_DEVICE_XI2           (_clutter_input_device_xi2_get_type ())
-@@ -45,6 +49,12 @@ void  clutter_input_device_xi2_update_tool      (ClutterInputDevice     *device,
-                                                  ClutterInputDeviceTool *tool);
- ClutterInputDeviceTool * clutter_input_device_xi2_get_current_tool (ClutterInputDevice *device);
- 
-+#ifdef HAVE_LIBWACOM
-+void clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice  *device,
-+                                                 WacomDeviceDatabase *wacom_db);
-+
-+#endif
-+
- G_END_DECLS
- 
- #endif /* __CLUTTER_INPUT_DEVICE_XI2_H__ */
-diff --git a/clutter/configure.ac b/clutter/configure.ac
-index 3c3d0c5..5474fa0 100644
---- a/clutter/configure.ac
-+++ b/clutter/configure.ac
-@@ -121,6 +121,7 @@ m4_define([xcomposite_req_version],     [0.4])
- m4_define([gdk_req_version],            [3.3.18])
- m4_define([libinput_req_version],       [1.4.0])
- m4_define([libudev_req_version],        [136])
-+m4_define([libwacom_req_version],       [0.13])
- 
- AC_SUBST([GLIB_REQ_VERSION],       [glib_req_version])
- AC_SUBST([COGL_REQ_VERSION],       [cogl_req_version])
-@@ -133,6 +134,7 @@ AC_SUBST([XCOMPOSITE_REQ_VERSION], [xcomposite_req_version])
- AC_SUBST([GDK_REQ_VERSION],        [gdk_req_version])
- AC_SUBST([LIBINPUT_REQ_VERSION],   [libinput_req_version])
- AC_SUBST([LIBUDEV_REQ_VERSION],    [libudev_req_version])
-+AC_SUBST([LIBWACOM_REQ_VERSION],   [libwacom_req_version])
- 
- # Checks for typedefs, structures, and compiler characteristics.
- AM_PATH_GLIB_2_0([glib_req_version],
-@@ -508,6 +510,32 @@ X11_EXTS=${X11_EXTS#* }
- 
- AC_CACHE_SAVE
- 
-+dnl === Libwacom support for X11 ===============================================
-+AC_ARG_WITH(libwacom,
-+  AC_HELP_STRING([--without-libwacom],
-+                 [disable the use of libwacom for advanced tablet management]),,
-+  with_libwacom=auto)
-+
-+have_libwacom=no
-+AC_MSG_CHECKING([libwacom])
-+if test x$with_libwacom = xno ; then
-+  AC_MSG_RESULT([disabled])
-+else
-+  if $PKG_CONFIG --exists libwacom '>=' $LIBWACOM_REQ_VERSION; then
-+    have_libwacom=yes
-+    AC_MSG_RESULT(yes)
-+    PKG_CHECK_MODULES([LIBWACOM], [libwacom])
-+    AC_SUBST(LIBWACOM_CFLAGS)
-+    AC_SUBST(LIBWACOM_LIBS)
-+    AC_DEFINE([HAVE_LIBWACOM], 1, [Building with libwacom for advanced tablet management])
-+  else
-+    AC_MSG_RESULT(no)
-+    if test x$with_libwacom = xyes ; then
-+      AC_MSG_ERROR([libwacom forced but not found])
-+    fi
-+  fi
-+fi
-+
- dnl === Enable GDK-Pixbuf in tests ============================================
- 
- m4_define([pixbuf_default], [yes])
-@@ -679,8 +707,8 @@ AS_IF([test "x$CLUTTER_BASE_PC_FILES_PRIVATE" = "x" && test "x$BACKEND_PC_FILES_
- AC_SUBST(CLUTTER_REQUIRES)
- AC_SUBST(CLUTTER_REQUIRES_PRIVATE)
- 
--CLUTTER_CFLAGS="$FLAVOUR_CFLAGS $CLUTTER_DEPS_CFLAGS $CLUTTER_DEPS_PRIVATE_CFLAGS $GLIB_CFLAGS"
--CLUTTER_LIBS="$FLAVOUR_LIBS $CLUTTER_DEPS_LIBS $CLUTTER_DEPS_PRIVATE_LIBS $GLIB_LIBS"
-+CLUTTER_CFLAGS="$FLAVOUR_CFLAGS $CLUTTER_DEPS_CFLAGS $CLUTTER_DEPS_PRIVATE_CFLAGS $GLIB_CFLAGS $LIBWACOM_CFLAGS"
-+CLUTTER_LIBS="$FLAVOUR_LIBS $CLUTTER_DEPS_LIBS $CLUTTER_DEPS_PRIVATE_LIBS $GLIB_LIBS $LIBWACOM_LIBS"
- AC_SUBST(CLUTTER_CFLAGS)
- AC_SUBST(CLUTTER_LIBS)
- 
--- 
-1.8.3.1
-
-
-From f8fa4b8fa13fba9ed484be74fb7fc82499d46261 Mon Sep 17 00:00:00 2001
-From: Carlos Garnacho <carlosg@gnome.org>
-Date: Thu, 22 Feb 2018 17:50:42 +0100
-Subject: [PATCH 2/2] clutter/x11: Communicate proper group/mode on pad events.
-
-So we can trigger actions for the right mode.
-
-https://gitlab.gnome.org/GNOME/mutter/issues/48
-
-Closes: #48
----
- clutter/clutter/x11/clutter-device-manager-xi2.c | 15 +++++-
- clutter/clutter/x11/clutter-input-device-xi2.c   | 61 ++++++++++++++++++++++++
- clutter/clutter/x11/clutter-input-device-xi2.h   |  9 ++++
- 3 files changed, 84 insertions(+), 1 deletion(-)
-
-diff --git a/clutter/clutter/x11/clutter-device-manager-xi2.c b/clutter/clutter/x11/clutter-device-manager-xi2.c
-index dee2604..d269a38 100644
---- a/clutter/clutter/x11/clutter-device-manager-xi2.c
-+++ b/clutter/clutter/x11/clutter-device-manager-xi2.c
-@@ -1133,7 +1133,7 @@ translate_pad_event (ClutterEvent       *event,
-                      ClutterInputDevice *device)
- {
-   gdouble value;
--  guint number;
-+  guint number, mode = 0;
- 
-   if (!translate_pad_axis (device, &xev->valuators,
-                            &event->any.type,
-@@ -1147,15 +1147,21 @@ translate_pad_event (ClutterEvent       *event,
-   if (xev->evtype == XI_Motion)
-     value = -1;
- 
-+#ifdef HAVE_LIBWACOM
-+  mode = clutter_input_device_xi2_get_pad_group_mode (device, number);
-+#endif
-+
-   if (event->any.type == CLUTTER_PAD_RING)
-     {
-       event->pad_ring.ring_number = number;
-       event->pad_ring.angle = value;
-+      event->pad_ring.mode = mode;
-     }
-   else
-     {
-       event->pad_strip.strip_number = number;
-       event->pad_strip.value = value;
-+      event->pad_strip.mode = mode;
-     }
- 
-   event->any.time = xev->time;
-@@ -1382,6 +1388,13 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
- 
-             /* Pad buttons are 0-indexed */
-             event->pad_button.button = xev->detail - 1;
-+#ifdef HAVE_LIBWACOM
-+            clutter_input_device_xi2_update_pad_state (device,
-+                                                       event->pad_button.button,
-+                                                       (xi_event->evtype == XI_ButtonPress),
-+                                                       &event->pad_button.group,
-+                                                       &event->pad_button.mode);
-+#endif
-             clutter_event_set_device (event, device);
-             clutter_event_set_source_device (event, source_device);
- 
-diff --git a/clutter/clutter/x11/clutter-input-device-xi2.c b/clutter/clutter/x11/clutter-input-device-xi2.c
-index 2d9b6d2..f62ba85 100644
---- a/clutter/clutter/x11/clutter-input-device-xi2.c
-+++ b/clutter/clutter/x11/clutter-input-device-xi2.c
-@@ -48,6 +48,7 @@ struct _ClutterInputDeviceXI2
- 
- #ifdef HAVE_LIBWACOM
-   WacomDevice *wacom_device;
-+  GArray *group_modes;
- #endif
- };
- 
-@@ -68,6 +69,15 @@ clutter_input_device_xi2_constructed (GObject *gobject)
- 
-   if (G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->constructed)
-     G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->constructed (gobject);
-+
-+#ifdef HAVE_LIBWACOM
-+  if (clutter_input_device_get_device_type (CLUTTER_INPUT_DEVICE (gobject)) == CLUTTER_PAD_DEVICE)
-+    {
-+      device_xi2->group_modes = g_array_new (FALSE, TRUE, sizeof (guint));
-+      g_array_set_size (device_xi2->group_modes,
-+                        clutter_input_device_get_n_mode_groups (CLUTTER_INPUT_DEVICE (gobject)));
-+    }
-+#endif
- }
- 
- static gboolean
-@@ -99,6 +109,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);
- #endif
- 
-   G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->finalize (object);
-@@ -292,4 +304,53 @@ clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice  *device,
-   device_xi2->wacom_device = libwacom_new_from_path (wacom_db, node_path,
-                                                      WFALLBACK_NONE, NULL);
- }
-+
-+guint
-+clutter_input_device_xi2_get_pad_group_mode (ClutterInputDevice *device,
-+                                             guint               group)
-+{
-+  ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device);
-+
-+  if (group >= device_xi2->group_modes->len)
-+    return 0;
-+
-+  return g_array_index (device_xi2->group_modes, guint, group);
-+}
-+
-+void
-+clutter_input_device_xi2_update_pad_state (ClutterInputDevice *device,
-+                                           guint               button,
-+                                           guint               state,
-+                                           guint              *group,
-+                                           guint              *mode)
-+{
-+  ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device);
-+  guint button_group, *group_mode;
-+  gboolean is_mode_switch = FALSE;
-+
-+  button_group = clutter_input_device_xi2_get_button_group (device, button);
-+  is_mode_switch = button_group >= 0;
-+
-+  /* Assign all non-mode-switch buttons to group 0 so far */
-+  button_group = MAX (0, button_group);
-+
-+  if (button_group >= device_xi2->group_modes->len)
-+    return;
-+
-+  group_mode = &g_array_index (device_xi2->group_modes, guint, button_group);
-+
-+  if (is_mode_switch && state)
-+    {
-+      guint next, n_modes;
-+
-+      n_modes = clutter_input_device_get_group_n_modes (device, button_group);
-+      next = (*group_mode + 1) % n_modes;
-+      *group_mode = next;
-+    }
-+
-+  if (group)
-+    *group = button_group;
-+  if (mode)
-+    *mode = *group_mode;
-+}
- #endif
-diff --git a/clutter/clutter/x11/clutter-input-device-xi2.h b/clutter/clutter/x11/clutter-input-device-xi2.h
-index e30fb4d..2194e1b 100644
---- a/clutter/clutter/x11/clutter-input-device-xi2.h
-+++ b/clutter/clutter/x11/clutter-input-device-xi2.h
-@@ -53,6 +53,15 @@ ClutterInputDeviceTool * clutter_input_device_xi2_get_current_tool (ClutterInput
- void clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice  *device,
-                                                  WacomDeviceDatabase *wacom_db);
- 
-+guint clutter_input_device_xi2_get_pad_group_mode (ClutterInputDevice *device,
-+                                                   guint               group);
-+
-+void clutter_input_device_xi2_update_pad_state (ClutterInputDevice *device,
-+                                                guint               button,
-+                                                guint               state,
-+                                                guint              *group,
-+                                                guint              *mode);
-+
- #endif
- 
- G_END_DECLS
--- 
-1.8.3.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
index 0fffa56..5ef6094 100644
--- a/SOURCES/0001-monitor-manager-Consider-external-layout-before-defa.patch
+++ b/SOURCES/0001-monitor-manager-Consider-external-layout-before-defa.patch
@@ -13,14 +13,14 @@ 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, 95 insertions(+)
+ 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,81 @@ create_preferred_logical_monitor_config (MetaMonitorManager          *monitor_ma
+@@ -559,6 +559,83 @@ create_preferred_logical_monitor_config (MetaMonitorManager          *monitor_ma
    return logical_monitor_config;
  }
  
@@ -31,12 +31,14 @@ index 197892bf2..ae988f64a 100644
 +                                           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,
-+                                                    output->crtc->rect.x,
-+                                                    output->crtc->rect.y,
++                                                    crtc->rect.x,
++                                                    crtc->rect.y,
 +                                                    primary_logical_monitor_config,
 +                                                    layout_mode);
 +}
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
index 127f61d..857ab93 100644
--- a/SOURCES/0001-monitor-manager-xrandr-Force-an-update-when-resuming.patch
+++ b/SOURCES/0001-monitor-manager-xrandr-Force-an-update-when-resuming.patch
@@ -1,107 +1,526 @@
-From ed7cad0561b79e68ddd91f0e12042087199676ea Mon Sep 17 00:00:00 2001
+From 100795c2729305f919ff9611c877ea3e74d528b7 Mon Sep 17 00:00:00 2001
 From: Rui Matos <tiagomatos@gmail.com>
-Date: Sun, 25 Oct 2015 16:14:58 +0100
-Subject: [PATCH 3/8] monitor-manager-xrandr: Force an update when resuming
- from suspend
+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/x11/meta-monitor-manager-xrandr.c | 188 ++++++++++++++++++-------
- 1 file changed, 137 insertions(+), 51 deletions(-)
+ 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/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
-index 8d1bdfb69..d451fcccc 100644
---- a/src/backends/x11/meta-monitor-manager-xrandr.c
-+++ b/src/backends/x11/meta-monitor-manager-xrandr.c
-@@ -61,6 +61,11 @@ struct _MetaMonitorManagerXrandr
-   XRRScreenResources *resources;
-   int rr_event_base;
-   int rr_error_base;
-+
-+  guint logind_watch_id;
-+  guint logind_signal_sub_id;
-+
-+  gboolean need_hardware_poll;
-   gboolean has_randr15;
+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];
  
-   xcb_timestamp_t last_xrandr_set_timestamp;
-@@ -787,8 +792,15 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
-   manager->screen_width = WidthOfScreen (screen);
-   manager->screen_height = HeightOfScreen (screen);
+ typedef struct _MetaGpuPrivate
+ {
+   MetaMonitorManager *monitor_manager;
  
--  resources = XRRGetScreenResourcesCurrent (manager_xrandr->xdisplay,
--					    DefaultRootWindow (manager_xrandr->xdisplay));
-+  if (manager_xrandr->need_hardware_poll)
-+    {
-+      resources = XRRGetScreenResources (manager_xrandr->xdisplay,
-+                                         DefaultRootWindow (manager_xrandr->xdisplay));
-+      manager_xrandr->need_hardware_poll = FALSE;
-+    }
-+  else
-+    resources = XRRGetScreenResourcesCurrent (manager_xrandr->xdisplay,
-+                                              DefaultRootWindow (manager_xrandr->xdisplay));
-   if (!resources)
-     return;
+   GList *outputs;
+   GList *crtcs;
+   GList *modes;
+ } MetaGpuPrivate;
  
-@@ -1910,6 +1922,115 @@ meta_monitor_manager_xrandr_get_default_layout_mode (MetaMonitorManager *manager
-   return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
+ 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;
  }
  
-+static gboolean
-+is_xvnc (MetaMonitorManager *manager)
++void
++meta_gpu_poll_hardware (MetaGpu *gpu)
 +{
-+  unsigned int i;
-+
-+  for (i = 0; i < manager->n_outputs; ++i)
-+    if (g_str_has_prefix (manager->outputs[i].name, "VNC-"))
-+      return TRUE;
-+
-+  return FALSE;
++  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_monitor_manager_xrandr_update (MetaMonitorManagerXrandr *manager_xrandr)
++meta_gpu_xrandr_poll_hardware (MetaGpu *gpu)
 +{
-+  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
-+  gboolean is_hotplug;
-+  gboolean is_our_configuration;
-+  unsigned int timestamp;
-+
-+  meta_monitor_manager_read_current_state (manager);
++  MetaGpuXrandr *gpu_xrandr = META_GPU_XRANDR (gpu);
 +
-+  timestamp = manager_xrandr->resources->timestamp;
-+  if (is_xvnc (manager))
-+    timestamp += 100;
++  gpu_xrandr->need_hardware_poll = TRUE;
++}
 +
-+  is_hotplug = (timestamp < manager_xrandr->resources->configTimestamp);
-+  is_our_configuration = (manager_xrandr->resources->timestamp ==
-+                          manager_xrandr->last_xrandr_set_timestamp);
-+  if (is_hotplug)
+ 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)
 +    {
-+      meta_monitor_manager_on_hotplug (manager);
++      resources = XRRGetScreenResources (xdisplay,
++                                         DefaultRootWindow (xdisplay));
++      gpu_xrandr->need_hardware_poll = FALSE;
 +    }
 +  else
 +    {
-+      MetaMonitorsConfig *config;
++      resources = XRRGetScreenResourcesCurrent (xdisplay,
++                                                DefaultRootWindow (xdisplay));
++    }
 +
-+      if (is_our_configuration)
-+        {
-+          MetaMonitorConfigManager *config_manager =
-+            meta_monitor_manager_get_config_manager (manager);
+   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;
 +
-+          config = meta_monitor_config_manager_get_current (config_manager);
-+        }
-+      else
-+        {
-+          config = NULL;
-+        }
++  guint logind_watch_id;
++  guint logind_signal_sub_id;
 +
-+      meta_monitor_manager_rebuild_derived (manager, config);
-+    }
-+}
+   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,
@@ -120,7 +539,7 @@ index 8d1bdfb69..d451fcccc 100644
 +  g_variant_get (parameters, "(b)", &suspending);
 +  if (!suspending)
 +    {
-+      manager_xrandr->need_hardware_poll = TRUE;
++      meta_gpu_poll_hardware (manager_xrandr->gpu);
 +      meta_monitor_manager_xrandr_update (manager_xrandr);
 +    }
 +}
@@ -159,25 +578,60 @@ index 8d1bdfb69..d451fcccc 100644
 +}
 +
  static void
- meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
+ meta_monitor_manager_xrandr_constructed (GObject *object)
  {
-@@ -1948,6 +2069,15 @@ meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
+   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
      }
-+
-+  manager_xrandr->logind_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
-+                                                      "org.freedesktop.login1",
-+                                                      G_BUS_NAME_WATCHER_FLAGS_NONE,
-+                                                      logind_appeared,
-+                                                      logind_vanished,
-+                                                      manager_xrandr,
-+                                                      NULL);
-+  manager_xrandr->need_hardware_poll = TRUE;
+ 
+   G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->constructed (object);
  }
  
  static void
-@@ -1962,6 +2092,10 @@ meta_monitor_manager_xrandr_finalize (GObject *object)
+ 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);
  
@@ -188,72 +642,135 @@ index 8d1bdfb69..d451fcccc 100644
    G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->finalize (object);
  }
  
-@@ -1996,64 +2130,16 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass)
+ 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)
--{
--  unsigned int i;
--
--  for (i = 0; i < manager->n_outputs; ++i)
--    if (g_str_has_prefix (manager->outputs[i].name, "VNC-"))
--      return TRUE;
--
--  return FALSE;
--}
--
- gboolean
- meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr,
- 					   XEvent                   *event)
+ static gboolean
+ is_xvnc (MetaMonitorManager *manager)
  {
--  MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
--  gboolean is_hotplug;
--  gboolean is_our_configuration;
--  unsigned int timestamp;
--
-   if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
-     return FALSE;
+   MetaMonitorManagerXrandr *manager_xrandr =
+     META_MONITOR_MANAGER_XRANDR (manager);
+   GList *l;
  
-   XRRUpdateConfiguration (event);
+   for (l = meta_gpu_get_outputs (manager_xrandr->gpu); l; l = l->next)
+     {
+       MetaOutput *output = l->data;
  
--  meta_monitor_manager_read_current_state (manager);
--
--
--  timestamp = manager_xrandr->resources->timestamp;
--  if (is_xvnc (manager))
--    timestamp += 100;
--
--  is_hotplug = (timestamp < manager_xrandr->resources->configTimestamp);
--  is_our_configuration = (manager_xrandr->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);
+       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;
 -
--          config = meta_monitor_config_manager_get_current (config_manager);
--        }
--      else
--        {
--          config = NULL;
--        }
+-  XRRUpdateConfiguration (event);
 -
--      meta_monitor_manager_xrandr_rebuild_derived (manager, config);
--    }
+   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.14.2
+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
index 73e1cd5..ff9cd9f 100644
--- a/SOURCES/0001-monitor-manager-xrandr-Work-around-spurious-hotplugs.patch
+++ b/SOURCES/0001-monitor-manager-xrandr-Work-around-spurious-hotplugs.patch
@@ -1,8 +1,7 @@
-From 73cae2c78af65cdfd6fa0c8257b4d3ae593f9f74 Mon Sep 17 00:00:00 2001
+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 2/8] monitor-manager-xrandr: Work around spurious hotplugs on
- Xvnc
+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
@@ -10,25 +9,31 @@ requiring new randr configuration timestamps to be ahead of the last
 set timestamp by at least 100 ms for us to consider them an actual
 hotplug.
 ---
- src/backends/x11/meta-monitor-manager-xrandr.c | 20 ++++++++++++++++++--
- 1 file changed, 18 insertions(+), 2 deletions(-)
+ .../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 c369d4960..8d1bdfb69 100644
+index dbe3e4e3b..90a3952db 100644
 --- a/src/backends/x11/meta-monitor-manager-xrandr.c
 +++ b/src/backends/x11/meta-monitor-manager-xrandr.c
-@@ -1909,6 +1909,18 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass)
+@@ -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)
 +{
-+  unsigned int i;
++  MetaMonitorManagerXrandr *manager_xrandr =
++    META_MONITOR_MANAGER_XRANDR (manager);
++  GList *l;
 +
-+  for (i = 0; i < manager->n_outputs; ++i)
-+    if (g_str_has_prefix (manager->outputs[i].name, "VNC-"))
-+      return TRUE;
++  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;
 +}
@@ -36,28 +41,27 @@ index c369d4960..8d1bdfb69 100644
  gboolean
  meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr,
  					   XEvent                   *event)
-@@ -1916,6 +1928,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
-   MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
+@@ -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;
-@@ -1925,8 +1938,11 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
-   meta_monitor_manager_read_current_state (manager);
- 
+@@ -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 = (manager_xrandr->resources->timestamp <
--                manager_xrandr->resources->configTimestamp);
-+  timestamp = manager_xrandr->resources->timestamp;
+-  is_hotplug = resources->timestamp < resources->configTimestamp;
++  timestamp = resources->timestamp;
 +  if (is_xvnc (manager))
 +    timestamp += 100;
 +
-+  is_hotplug = (timestamp < manager_xrandr->resources->configTimestamp);
-   is_our_configuration = (manager_xrandr->resources->timestamp ==
++  is_hotplug = timestamp < resources->configTimestamp;
+   is_our_configuration = (resources->timestamp ==
                            manager_xrandr->last_xrandr_set_timestamp);
    if (is_hotplug)
 -- 
-2.14.2
+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-renderer-x11-Enable-GPU-memory-purge-error-extension.patch b/SOURCES/0001-renderer-x11-Enable-GPU-memory-purge-error-extension.patch
deleted file mode 100644
index 094910d..0000000
--- a/SOURCES/0001-renderer-x11-Enable-GPU-memory-purge-error-extension.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 4b2d21ff03ed389138fcb9bca778aec02bafcadb Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
-Date: Fri, 2 Feb 2018 14:34:50 +0800
-Subject: [PATCH] renderer/x11: Enable GPU memory purge error extension if
- available
-
-This was done by the clutter X11 backend before prior to introducing
-MetaRenderer, but during that work, enabling of said extension was lost.
-Let's turn it on again.
-
-https://bugzilla.gnome.org/show_bug.cgi?id=739178
----
- src/backends/x11/meta-backend-x11.c  | 2 --
- src/backends/x11/meta-renderer-x11.c | 1 +
- 2 files changed, 1 insertion(+), 2 deletions(-)
-
-diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
-index 233532435..c7602cc70 100644
---- a/src/backends/x11/meta-backend-x11.c
-+++ b/src/backends/x11/meta-backend-x11.c
-@@ -705,8 +705,6 @@ meta_backend_x11_init (MetaBackendX11 *x11)
-    */
-   XInitThreads();
- 
--  clutter_x11_request_reset_on_video_memory_purge ();
--
-   /* We do X11 event retrieval ourselves */
-   clutter_x11_disable_event_retrieval ();
- }
-diff --git a/src/backends/x11/meta-renderer-x11.c b/src/backends/x11/meta-renderer-x11.c
-index 90924e038..003211d85 100644
---- a/src/backends/x11/meta-renderer-x11.c
-+++ b/src/backends/x11/meta-renderer-x11.c
-@@ -73,6 +73,7 @@ meta_renderer_x11_create_cogl_renderer (MetaRenderer *renderer)
-   cogl_renderer = cogl_renderer_new ();
-   cogl_renderer_set_custom_winsys (cogl_renderer, get_x11_cogl_winsys_vtable);
-   cogl_xlib_renderer_set_foreign_display (cogl_renderer, xdisplay);
-+  cogl_xlib_renderer_request_reset_on_video_memory_purge (cogl_renderer, TRUE);
- 
-   /* Set up things so that if the INTEL_swap_event extension is not present,
-    * but the driver is known to have good thread support, we use an extra
--- 
-2.14.3
-
diff --git a/SOURCES/0001-wayland-Do-not-fail-on-stalled-.X11-unix-entries.patch b/SOURCES/0001-wayland-Do-not-fail-on-stalled-.X11-unix-entries.patch
deleted file mode 100644
index d90a588..0000000
--- a/SOURCES/0001-wayland-Do-not-fail-on-stalled-.X11-unix-entries.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 9826eae9f091d461bd117c254ba8e255dd084797 Mon Sep 17 00:00:00 2001
-From: Olivier Fourdan <ofourdan@redhat.com>
-Date: Fri, 2 Feb 2018 16:35:26 +0100
-Subject: [PATCH] wayland: Do not fail on stalled .X11-unix entries
-
-If for whatever reason, there are stalled files in /tmp/.X11-unix/ the
-bind() to the abstract socket will succeed but not the bind() to the
-to the UNIX socket.
-
-This causes gnome-shell/mutter to fail because it cannot start Xwayland
-(while it could actually, by using a different display).
-
-In case of failure to bind to the UNIX socket, try the next display
-instead of failing, to avoid stalled entries in /tmp/.X11-unix.
-
-Closes: https://gitlab.gnome.org/GNOME/mutter/issues/13
----
- src/wayland/meta-xwayland.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
-index 50cfc7c57..ce21fe5ee 100644
---- a/src/wayland/meta-xwayland.c
-+++ b/src/wayland/meta-xwayland.c
-@@ -458,7 +458,8 @@ choose_xdisplay (MetaXWaylandManager *manager)
-         {
-           unlink (lock_file);
-           close (manager->abstract_fd);
--          return FALSE;
-+          display++;
-+          continue;
-         }
- 
-       break;
--- 
-2.14.3
-
diff --git a/SOURCES/0003-window-wayland-Handle-resizing-when-headless.patch b/SOURCES/0003-window-wayland-Handle-resizing-when-headless.patch
deleted file mode 100644
index 32756c0..0000000
--- a/SOURCES/0003-window-wayland-Handle-resizing-when-headless.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From 07e5f7ef29b5567e090221d5da9415e8b84c0ebb Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
-Date: Mon, 16 Oct 2017 17:02:51 +0800
-Subject: [PATCH 3/4] window/wayland: Handle resizing when headless
-
-We tried to get the geometry scale, which may depend on the main
-logical monitor assigned to the window. To avoid dereferencing a NULL
-logical monitor when headless, instead assume the geometry scale is 1.
-
-https://bugzilla.gnome.org/show_bug.cgi?id=788764
----
- src/wayland/meta-window-wayland.c | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c
-index ed6e34b43..f3f0e1688 100644
---- a/src/wayland/meta-window-wayland.c
-+++ b/src/wayland/meta-window-wayland.c
-@@ -67,6 +67,8 @@ G_DEFINE_TYPE (MetaWindowWayland, meta_window_wayland, META_TYPE_WINDOW)
- static int
- get_window_geometry_scale_for_logical_monitor (MetaLogicalMonitor *logical_monitor)
- {
-+  g_assert (logical_monitor);
-+
-   if (meta_is_stage_views_scaled ())
-     return 1;
-   else
-@@ -79,8 +81,7 @@ meta_window_wayland_manage (MetaWindow *window)
-   MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window);
-   MetaDisplay *display = window->display;
- 
--  wl_window->geometry_scale =
--    get_window_geometry_scale_for_logical_monitor (window->monitor);
-+  wl_window->geometry_scale = meta_window_wayland_get_geometry_scale (window);
- 
-   meta_display_register_wayland_window (display, window);
- 
-@@ -634,6 +635,9 @@ should_do_pending_move (MetaWindowWayland *wl_window,
- int
- meta_window_wayland_get_geometry_scale (MetaWindow *window)
- {
-+  if (!window->monitor)
-+    return 1;
-+
-   return get_window_geometry_scale_for_logical_monitor (window->monitor);
- }
- 
--- 
-2.14.2
-
diff --git a/SOURCES/0008-Add-support-for-quad-buffer-stereo.patch b/SOURCES/0008-Add-support-for-quad-buffer-stereo.patch
index 82fe332..e5b861e 100644
--- a/SOURCES/0008-Add-support-for-quad-buffer-stereo.patch
+++ b/SOURCES/0008-Add-support-for-quad-buffer-stereo.patch
@@ -1,7 +1,7 @@
-From 7940ea62307044c056c16f1534e3e8e94cc7a352 Mon Sep 17 00:00:00 2001
+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 7/8] Add support for quad-buffer stereo
+Subject: [PATCH] Add support for quad-buffer stereo
 
 Track the stereo status of windows using the new EXT_stereo_tree
 GLX extension.
@@ -37,10 +37,10 @@ texture_from_pixmap.
  create mode 100644 src/core/stereo.h
 
 diff --git a/src/Makefile.am b/src/Makefile.am
-index 6aef50de8..8c680602c 100644
+index 5bbac70..8b21d2f 100644
 --- a/src/Makefile.am
 +++ b/src/Makefile.am
-@@ -281,6 +281,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES =	\
+@@ -308,6 +308,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES =	\
  	core/stack.h				\
  	core/stack-tracker.c			\
  	core/stack-tracker.h			\
@@ -50,7 +50,7 @@ index 6aef50de8..8c680602c 100644
  	meta/util.h				\
  	core/util-private.h			\
 diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
-index ba58bf175..1c257b5ee 100644
+index 40c0344..25cab92 100644
 --- a/src/compositor/compositor-private.h
 +++ b/src/compositor/compositor-private.h
 @@ -21,6 +21,10 @@ struct _MetaCompositor
@@ -77,11 +77,11 @@ index ba58bf175..1c257b5ee 100644
                                     MetaWindow     *window);
  
 diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
-index 17e8a55dd..a1bf1a8f8 100644
+index 8c924d2..e12fb7b 100644
 --- a/src/compositor/compositor.c
 +++ b/src/compositor/compositor.c
 @@ -70,6 +70,8 @@
- #include "meta-window-group.h"
+ #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"
@@ -89,7 +89,7 @@ index 17e8a55dd..a1bf1a8f8 100644
  #include "util-private.h"
  #include "backends/meta-dnd-private.h"
  #include "frame.h"
-@@ -482,6 +484,97 @@ redirect_windows (MetaScreen *screen)
+@@ -487,6 +489,97 @@ redirect_windows (MetaScreen *screen)
      }
  }
  
@@ -187,7 +187,7 @@ index 17e8a55dd..a1bf1a8f8 100644
  void
  meta_compositor_manage (MetaCompositor *compositor)
  {
-@@ -490,6 +583,8 @@ meta_compositor_manage (MetaCompositor *compositor)
+@@ -495,6 +588,8 @@ meta_compositor_manage (MetaCompositor *compositor)
    MetaScreen *screen = display->screen;
    MetaBackend *backend = meta_get_backend ();
  
@@ -196,7 +196,7 @@ index 17e8a55dd..a1bf1a8f8 100644
    meta_screen_set_cm_selection (display->screen);
  
    compositor->stage = meta_backend_get_stage (backend);
-@@ -757,6 +852,23 @@ meta_compositor_process_event (MetaCompositor *compositor,
+@@ -759,6 +854,23 @@ meta_compositor_process_event (MetaCompositor *compositor,
        if (window)
          process_damage (compositor, (XDamageNotifyEvent *) event, window);
      }
@@ -220,7 +220,7 @@ index 17e8a55dd..a1bf1a8f8 100644
  
    if (compositor->have_x11_sync_object)
      meta_sync_ring_handle_event (event);
-@@ -957,6 +1069,7 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
+@@ -969,6 +1081,7 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
  			    GList	    *stack)
  {
    GList *old_stack;
@@ -228,7 +228,7 @@ index 17e8a55dd..a1bf1a8f8 100644
  
    /* 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
-@@ -1032,6 +1145,8 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
+@@ -1044,6 +1157,8 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
         * near the front of the other.)
         */
        compositor->windows = g_list_prepend (compositor->windows, actor);
@@ -237,16 +237,16 @@ index 17e8a55dd..a1bf1a8f8 100644
  
        stack = g_list_remove (stack, window);
        old_stack = g_list_remove (old_stack, actor);
-@@ -1039,6 +1154,8 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
+@@ -1051,6 +1166,8 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
  
    sync_actor_stacking (compositor);
  
 +  meta_stereo_set_have_stereo_windows (stereo_window_count > 0);
 +
-   compositor->top_window_actor = get_top_visible_window_actor (compositor);
- }
- 
-@@ -1237,6 +1354,17 @@ meta_compositor_new (MetaDisplay *display)
+   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);
@@ -265,7 +265,7 @@ index 17e8a55dd..a1bf1a8f8 100644
  }
  
 diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h
-index 5b3f283c2..189a95312 100644
+index 5b3f283..189a953 100644
 --- a/src/compositor/meta-shaped-texture-private.h
 +++ b/src/compositor/meta-shaped-texture-private.h
 @@ -30,8 +30,9 @@
@@ -281,7 +281,7 @@ index 5b3f283c2..189a95312 100644
                                              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 98346c6ae..b89de03a3 100644
+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];
@@ -550,10 +550,10 @@ index 98346c6ae..b89de03a3 100644
  
  /**
 diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c
-index 551322573..6ca68eb64 100644
+index 7505b7d..9475c20 100644
 --- a/src/compositor/meta-surface-actor-wayland.c
 +++ b/src/compositor/meta-surface-actor-wayland.c
-@@ -403,7 +403,7 @@ meta_surface_actor_wayland_dispose (GObject *object)
+@@ -187,7 +187,7 @@ meta_surface_actor_wayland_dispose (GObject *object)
    MetaShapedTexture *stex =
      meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
  
@@ -562,7 +562,7 @@ index 551322573..6ca68eb64 100644
    if (priv->surface)
      {
        g_object_remove_weak_pointer (G_OBJECT (priv->surface),
-@@ -462,6 +462,14 @@ meta_surface_actor_wayland_new (MetaWaylandSurface *surface)
+@@ -246,6 +246,14 @@ meta_surface_actor_wayland_new (MetaWaylandSurface *surface)
    return META_SURFACE_ACTOR (self);
  }
  
@@ -578,7 +578,7 @@ index 551322573..6ca68eb64 100644
  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 d32aeb68a..52db3808e 100644
+index d32aeb6..52db380 100644
 --- a/src/compositor/meta-surface-actor-x11.c
 +++ b/src/compositor/meta-surface-actor-x11.c
 @@ -31,6 +31,7 @@
@@ -716,7 +716,7 @@ index d32aeb68a..52db3808e 100644
 +  return priv->stereo;
 +}
 diff --git a/src/compositor/meta-surface-actor-x11.h b/src/compositor/meta-surface-actor-x11.h
-index 0e692ee0f..4b2ecccb1 100644
+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);
@@ -732,12 +732,12 @@ index 0e692ee0f..4b2ecccb1 100644
  
  #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 72dcd1451..035d756b2 100644
+index ce5e7ea..5b011ce 100644
 --- a/src/compositor/meta-window-actor-private.h
 +++ b/src/compositor/meta-window-actor-private.h
-@@ -59,4 +59,9 @@ void meta_window_actor_effect_completed (MetaWindowActor  *actor,
- MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self);
+@@ -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);
@@ -746,12 +746,12 @@ index 72dcd1451..035d756b2 100644
 +
  #endif /* META_WINDOW_ACTOR_PRIVATE_H */
 diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
-index 1184cd422..773e6d09d 100644
+index 120b043..b2c7725 100644
 --- a/src/compositor/meta-window-actor.c
 +++ b/src/compositor/meta-window-actor.c
-@@ -2150,3 +2150,25 @@ meta_window_actor_sync_updates_frozen (MetaWindowActor *self)
- 
-   meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (window));
+@@ -2189,3 +2189,25 @@ meta_window_actor_from_window (MetaWindow *window)
+ {
+   return META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
  }
 +
 +void
@@ -776,7 +776,7 @@ index 1184cd422..773e6d09d 100644
 +    return FALSE;
 +}
 diff --git a/src/core/main.c b/src/core/main.c
-index dc1f1c4f6..2c1160711 100644
+index 04a42c7..faa2081 100644
 --- a/src/core/main.c
 +++ b/src/core/main.c
 @@ -47,6 +47,7 @@
@@ -787,7 +787,7 @@ index dc1f1c4f6..2c1160711 100644
  #include <meta/errors.h>
  #include "ui.h"
  #include <meta/prefs.h>
-@@ -566,6 +567,9 @@ meta_init (void)
+@@ -580,6 +581,9 @@ meta_init (void)
  
    meta_init_backend (backend_gtype);
  
@@ -799,7 +799,7 @@ index dc1f1c4f6..2c1160711 100644
  #ifdef HAVE_WAYLAND
 diff --git a/src/core/stereo.c b/src/core/stereo.c
 new file mode 100644
-index 000000000..5a232b67c
+index 0000000..5a232b6
 --- /dev/null
 +++ b/src/core/stereo.c
 @@ -0,0 +1,153 @@
@@ -958,7 +958,7 @@ index 000000000..5a232b67c
 +}
 diff --git a/src/core/stereo.h b/src/core/stereo.h
 new file mode 100644
-index 000000000..ccd1d702a
+index 0000000..ccd1d70
 --- /dev/null
 +++ b/src/core/stereo.h
 @@ -0,0 +1,28 @@
@@ -991,10 +991,10 @@ index 000000000..ccd1d702a
 +
 +#endif
 diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
-index 6f9df37da..d353ae5d0 100644
+index 899f777..f8f7fc5 100644
 --- a/src/wayland/meta-wayland-surface.c
 +++ b/src/wayland/meta-wayland-surface.c
-@@ -789,7 +789,7 @@ apply_pending_state (MetaWaylandSurface      *surface,
+@@ -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);
  
@@ -1004,5 +1004,5 @@ index 6f9df37da..d353ae5d0 100644
                meta_shaped_texture_set_is_y_inverted (stex, is_y_inverted);
                g_clear_pointer (&snippet, cogl_object_unref);
 -- 
-2.14.2
+1.8.3.1
 
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/fix-session-save-crash.patch b/SOURCES/fix-session-save-crash.patch
deleted file mode 100644
index 99534ae..0000000
--- a/SOURCES/fix-session-save-crash.patch
+++ /dev/null
@@ -1,92 +0,0 @@
-From 0c9cb02111908409285991e4b0f44a4fdcf91eed Mon Sep 17 00:00:00 2001
-From: Olivier Fourdan <ofourdan@redhat.com>
-Date: Tue, 23 Jan 2018 11:43:09 +0100
-Subject: [PATCH 1/2] session: use initial workspace if no workspace set
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Having “on_all_workspaces_requested” FALSE on a window does not imply a
-workspace is set.
-
-If the X11 window is placed on a secondary monitor while workspaces
-applies on primary monitor only  (“workspaces-only-on-primary” set) then
-“on_all_workspaces_requested” is FALSE while “on_all_workspaces“ is TRUE
-and the associated workspace is NULL, leading to a crash when saving the
-gnome-shell/mutter session.
-
-So if no workspace is set, use the “initial_workspace” instead to avoid
-a NULL pointer dereference.
-
-https://bugzilla.gnome.org/show_bug.cgi?id=792818
----
- src/x11/session.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/src/x11/session.c b/src/x11/session.c
-index af64270a6..8b2a89f1c 100644
---- a/src/x11/session.c
-+++ b/src/x11/session.c
-@@ -950,7 +950,10 @@ save_state (void)
-               fputs ("    <sticky/>\n", outfile);
-             } else {
-               int n;
--              n = meta_workspace_index (window->workspace);
-+              if (window->workspace)
-+                n = meta_workspace_index (window->workspace);
-+              else
-+                n = window->initial_workspace;
-               fprintf (outfile,
-                        "    <workspace index=\"%d\"/>\n", n);
-             }
--- 
-2.14.3
-
-
-From e2269448dcebd24f23bb8872590204819abc3ac0 Mon Sep 17 00:00:00 2001
-From: Olivier Fourdan <ofourdan@redhat.com>
-Date: Mon, 29 Jan 2018 16:58:46 +0100
-Subject: [PATCH 2/2] =?UTF-8?q?x11/window:=20Mark=20restored=20workspace?=
- =?UTF-8?q?=20as=20=E2=80=9Cset=E2=80=9D?=
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When a window's workspace is not NULL, on_all_workspace should be FALSE.
-Similarly, when on_all_workspace is TRUE, the window workspace should be
-NULL.
-
-This is an assumption in multiple places in the code, including when
-setting the workspace state, the window is either added or removed from
-all workspaces only if the window's workspace is NULL.
-
-This rule is initially enforced at creation in _meta_window_shared_new()
-when a initial workspace is set. However, when the initial workspace is
-set from the session info, the initial workspace is not marked as “set”
-which leads to an assertion failure when unmanaging windows, because the
-window is not removed from all the workspaces.
-
-When applying the session info to a window, mark the workspace as “set”.
-
-https://gitlab.gnome.org/GNOME/mutter/issues/4
-
-Closes: #4
----
- src/x11/window-x11.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c
-index 36a5e70a3..9c8ef5d75 100644
---- a/src/x11/window-x11.c
-+++ b/src/x11/window-x11.c
-@@ -466,6 +466,7 @@ meta_window_apply_session_info (MetaWindow *window,
-           MetaWorkspace *workspace = spaces->data;
- 
-           meta_window_change_workspace (window, workspace);
-+          window->initial_workspace_set = TRUE;
- 
-           meta_topic (META_DEBUG_SM,
-                       "Restoring saved window %s to workspace %d\n",
--- 
-2.14.3
-
diff --git a/SOURCES/fix-transient-close-crash.patch b/SOURCES/fix-transient-close-crash.patch
deleted file mode 100644
index 0d2da5e..0000000
--- a/SOURCES/fix-transient-close-crash.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-From 2e3ae76207d9367fa15a3e759e797a0bea5eea71 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 c2d9869d2..80144cc63 100644
---- a/src/core/window.c
-+++ b/src/core/window.c
-@@ -4601,6 +4601,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 ba49c5298b1ae3a1e1ba52ec16d5a739115e6967 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 80144cc63..0b71744d5 100644
---- a/src/core/window.c
-+++ b/src/core/window.c
-@@ -1466,7 +1466,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/mutter-3.26.0-hybrid-gpus.patch b/SOURCES/mutter-3.26.0-hybrid-gpus.patch
deleted file mode 100644
index e0c314a..0000000
--- a/SOURCES/mutter-3.26.0-hybrid-gpus.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -up mutter-3.26.0/src/backends/native/meta-launcher.c.hybrid mutter-3.26.0/src/backends/native/meta-launcher.c
---- mutter-3.26.0/src/backends/native/meta-launcher.c.hybrid	2017-09-18 15:55:56.673262947 +0100
-+++ mutter-3.26.0/src/backends/native/meta-launcher.c	2017-09-18 15:56:21.383167768 +0100
-@@ -363,7 +363,7 @@ get_primary_gpu_path (const gchar *seat_
-       guint num_devices;
- 
-       num_devices = count_devices_with_connectors (seat_name, devices);
--      if (num_devices != 1)
-+      if (num_devices > 1)
-         goto out;
-     }
- 
diff --git a/SOURCES/remember-saved-multi-monitor-configuration.patch b/SOURCES/remember-saved-multi-monitor-configuration.patch
deleted file mode 100644
index f658b0d..0000000
--- a/SOURCES/remember-saved-multi-monitor-configuration.patch
+++ /dev/null
@@ -1,160 +0,0 @@
-From 702f204a281c6525da6bfcd2286d70b1ab6eab13 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
-Date: Fri, 3 Nov 2017 15:58:02 +0800
-Subject: [PATCH 1/4] monitor-config-manager: Don't include closed laptop panel
- in config key
-
-When deriving the list of disabled monitors when creating new monitors
-configs, don't include the laptop panel if the lid is currently closed,
-as we consider the laptop panel nonexistent when the laptop lid is
-closed when it comes to configuration.
-
-The laptop panel connector(s) will either way be appropriately disabled
-anyway, as the field listing disabled monitors in the configuration do
-not affect actual CRTC/connector assignments.
-
-https://bugzilla.gnome.org/show_bug.cgi?id=788915
----
- src/backends/meta-monitor-config-manager.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
-index 2fe620767..2a7287778 100644
---- a/src/backends/meta-monitor-config-manager.c
-+++ b/src/backends/meta-monitor-config-manager.c
-@@ -1308,6 +1308,10 @@ meta_monitors_config_new (MetaMonitorManager           *monitor_manager,
-       MetaMonitor *monitor = l->data;
-       MetaMonitorSpec *monitor_spec;
- 
-+      if (meta_monitor_manager_is_lid_closed (monitor_manager) &&
-+          meta_monitor_is_laptop_panel (monitor))
-+        continue;
-+
-       monitor_spec = meta_monitor_get_spec (monitor);
-       if (meta_logical_monitor_configs_have_monitor (logical_monitor_configs,
-                                                      monitor_spec))
--- 
-2.14.2
-
-From 584e2b93d9f28557cfe8a6ff720b4c3e45c458ab Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
-Date: Fri, 3 Nov 2017 16:03:23 +0800
-Subject: [PATCH 2/4] monitor-manager: Compare keys when checking whether a
- config is complete
-
-We only counted configured monitors and whether the config was
-applicable (could be assigned), howeverwe didn't include disabled
-monitors when comparing. This could caused incorrect configurations to
-be applied when trying to use the previous configuration.
-
-One scenario where this happened was one a system with one laptop
-screen and one external monitor that was hot plugged some point after
-start up. When the laptop lid was closed, the 'previous configuration'
-being the configuration where only the laptop panel was enabled, passed
-'is-complete' check as the number of configured monitors were correct,
-and the configuration was applicable.
-
-Avoid this issue by simply comparing the configuration key of the
-previous configuration and the configuration key of the current state.
-This correctly identifies a laptop panel with the lid closed as
-inaccessible, thus doesn't incorrectly revert to the previous
-configuration.
-
-https://bugzilla.gnome.org/show_bug.cgi?id=788915
----
- src/backends/meta-monitor-config-manager.c |  7 +++---
- src/backends/meta-monitor-config-manager.h |  2 ++
- src/backends/meta-monitor-manager.c        | 36 +++++++++---------------------
- 3 files changed, 16 insertions(+), 29 deletions(-)
-
-diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
-index 2a7287778..bdf863055 100644
---- a/src/backends/meta-monitor-config-manager.c
-+++ b/src/backends/meta-monitor-config-manager.c
-@@ -326,8 +326,8 @@ meta_monitor_config_manager_assign (MetaMonitorManager *manager,
-   return TRUE;
- }
- 
--static MetaMonitorsConfigKey *
--create_key_for_current_state (MetaMonitorManager *monitor_manager)
-+MetaMonitorsConfigKey *
-+meta_create_monitors_config_key_for_current_state (MetaMonitorManager *monitor_manager)
- {
-   MetaMonitorsConfigKey *config_key;
-   GList *l;
-@@ -369,7 +369,8 @@ meta_monitor_config_manager_get_stored (MetaMonitorConfigManager *config_manager
-   MetaMonitorsConfig *config;
-   GError *error = NULL;
- 
--  config_key = create_key_for_current_state (monitor_manager);
-+  config_key =
-+    meta_create_monitors_config_key_for_current_state (monitor_manager);
-   if (!config_key)
-     return NULL;
- 
-diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h
-index 516909dd7..c36df38e6 100644
---- a/src/backends/meta-monitor-config-manager.h
-+++ b/src/backends/meta-monitor-config-manager.h
-@@ -136,6 +136,8 @@ void meta_logical_monitor_config_free (MetaLogicalMonitorConfig *logical_monitor
- 
- void meta_monitor_config_free (MetaMonitorConfig *monitor_config);
- 
-+MetaMonitorsConfigKey * meta_create_monitors_config_key_for_current_state (MetaMonitorManager *monitor_manager);
-+
- gboolean meta_logical_monitor_configs_have_monitor (GList           *logical_monitor_configs,
-                                                     MetaMonitorSpec *monitor_spec);
- 
-diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c
-index 8b548fd68..eb3612cf0 100644
---- a/src/backends/meta-monitor-manager.c
-+++ b/src/backends/meta-monitor-manager.c
-@@ -1551,35 +1551,19 @@ static gboolean
- meta_monitor_manager_is_config_complete (MetaMonitorManager *manager,
-                                          MetaMonitorsConfig *config)
- {
--  GList *l;
--  unsigned int configured_monitor_count = 0;
--  unsigned int expected_monitor_count = 0;
--
--  for (l = config->logical_monitor_configs; l; l = l->next)
--    {
--      MetaLogicalMonitorConfig *logical_monitor_config = l->data;
--      GList *k;
-+  MetaMonitorsConfigKey *current_state_key;
-+  gboolean is_config_complete;
- 
--      for (k = logical_monitor_config->monitor_configs; k; k = k->next)
--        configured_monitor_count++;
--    }
--
--  for (l = manager->monitors; l; l = l->next)
--    {
--      MetaMonitor *monitor = l->data;
-+  current_state_key =
-+    meta_create_monitors_config_key_for_current_state (manager);
-+  if (!current_state_key)
-+    return FALSE;
- 
--      if (meta_monitor_is_laptop_panel (monitor))
--        {
--          if (!meta_monitor_manager_is_lid_closed (manager))
--            expected_monitor_count++;
--        }
--      else
--        {
--          expected_monitor_count++;
--        }
--    }
-+  is_config_complete = meta_monitors_config_key_equal (current_state_key,
-+                                                       config->key);
-+  meta_monitors_config_key_free (current_state_key);
- 
--  if (configured_monitor_count != expected_monitor_count)
-+  if (!is_config_complete)
-     return FALSE;
- 
-   return meta_monitor_manager_is_config_applicable (manager, config, NULL);
--- 
-2.14.2
-
diff --git a/SOURCES/wacom-pro-pen-3d.patch b/SOURCES/wacom-pro-pen-3d.patch
deleted file mode 100644
index f3d155a..0000000
--- a/SOURCES/wacom-pro-pen-3d.patch
+++ /dev/null
@@ -1,159 +0,0 @@
-From 42a526581d1216d835dbbbeab5a7bdb75b349179 Mon Sep 17 00:00:00 2001
-From: Jason Gerecke <killertofu@gmail.com>
-Date: Tue, 10 Oct 2017 09:18:25 -0700
-Subject: [PATCH 1/2] clutter/evdev: Add support for BTN_STYLUS3
-
-BTN_STYLUS3 is defined by the Linux 4.15 kernel and is sent when the
-third button on a stylus is pressed. At the moment, only Wacom's "Pro
-Pen 3D" has three stylus buttons. Pressing this button triggers a button
-8 event to be sent under X11, so we use the same mapping here.
-
-https://bugzilla.gnome.org/show_bug.cgi?id=790033
----
- clutter/clutter/evdev/clutter-seat-evdev.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/clutter/clutter/evdev/clutter-seat-evdev.c b/clutter/clutter/evdev/clutter-seat-evdev.c
-index e8524da..f98f85a 100644
---- a/clutter/clutter/evdev/clutter-seat-evdev.c
-+++ b/clutter/clutter/evdev/clutter-seat-evdev.c
-@@ -45,6 +45,10 @@
- 
- #define DISCRETE_SCROLL_STEP 10.0
- 
-+#ifndef BTN_STYLUS3
-+#define BTN_STYLUS3 0x149 /* Linux 4.15 */
-+#endif
-+
- void
- clutter_seat_evdev_set_libinput_seat (ClutterSeatEvdev     *seat,
-                                       struct libinput_seat *libinput_seat)
-@@ -492,6 +496,10 @@ clutter_seat_evdev_notify_button (ClutterSeatEvdev   *seat,
-       button_nr = CLUTTER_BUTTON_MIDDLE;
-       break;
- 
-+    case 0x149: /* BTN_STYLUS3 */
-+      button_nr = 8;
-+      break;
-+
-     default:
-       /* For compatibility reasons, all additional buttons go after the old 4-7 scroll ones */
-       if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
--- 
-2.17.0
-
-
-From c42c5294d0ca3d27001f217974cad72a40ffae60 Mon Sep 17 00:00:00 2001
-From: Jason Gerecke <killertofu@gmail.com>
-Date: Tue, 10 Oct 2017 08:55:41 -0700
-Subject: [PATCH 2/2] backends: Add support for Wacom stylus
- tertiary-button-action
-
-The tertiary-button-action (see bug 790028) is a place for g-c-c to store
-the action which should be performed when a stylus' third button is pressed.
-Pressing this button is signaled as a BTN_STYLUS3 event from the kernel or
-X11 button 8.
-
-https://bugzilla.gnome.org/show_bug.cgi?id=790033
----
- src/backends/meta-input-settings-private.h       |  3 ++-
- src/backends/meta-input-settings.c               |  5 +++--
- src/backends/native/meta-input-settings-native.c |  5 ++++-
- src/backends/x11/meta-input-settings-x11.c       | 10 ++++++++--
- 4 files changed, 17 insertions(+), 6 deletions(-)
-
-diff --git a/src/backends/meta-input-settings-private.h b/src/backends/meta-input-settings-private.h
-index 605690e..893d4ec 100644
---- a/src/backends/meta-input-settings-private.h
-+++ b/src/backends/meta-input-settings-private.h
-@@ -111,7 +111,8 @@ struct _MetaInputSettingsClass
-                                   ClutterInputDevice         *device,
-                                   ClutterInputDeviceTool     *tool,
-                                   GDesktopStylusButtonAction  primary,
--                                  GDesktopStylusButtonAction  secondary);
-+                                  GDesktopStylusButtonAction  secondary,
-+                                  GDesktopStylusButtonAction  tertiary);
-   gboolean (* has_two_finger_scroll) (MetaInputSettings  *settings,
-                                       ClutterInputDevice *device);
- };
-diff --git a/src/backends/meta-input-settings.c b/src/backends/meta-input-settings.c
-index ec0fc9f..989f9e3 100644
---- a/src/backends/meta-input-settings.c
-+++ b/src/backends/meta-input-settings.c
-@@ -1453,7 +1453,7 @@ update_stylus_buttonmap (MetaInputSettings      *input_settings,
-                          ClutterInputDeviceTool *tool)
- {
-   MetaInputSettingsClass *input_settings_class;
--  GDesktopStylusButtonAction primary, secondary;
-+  GDesktopStylusButtonAction primary, secondary, tertiary;
-   GSettings *tool_settings;
- 
-   if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE &&
-@@ -1468,10 +1468,11 @@ update_stylus_buttonmap (MetaInputSettings      *input_settings,
- 
-   primary = g_settings_get_enum (tool_settings, "button-action");
-   secondary = g_settings_get_enum (tool_settings, "secondary-button-action");
-+  tertiary = g_settings_get_enum (tool_settings, "tertiary-button-action");
- 
-   input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
-   input_settings_class->set_stylus_button_map (input_settings, device, tool,
--                                               primary, secondary);
-+                                               primary, secondary, tertiary);
- }
- 
- static void
-diff --git a/src/backends/native/meta-input-settings-native.c b/src/backends/native/meta-input-settings-native.c
-index beb7217..7450725 100644
---- a/src/backends/native/meta-input-settings-native.c
-+++ b/src/backends/native/meta-input-settings-native.c
-@@ -547,12 +547,15 @@ meta_input_settings_native_set_stylus_button_map (MetaInputSettings          *se
-                                                   ClutterInputDevice         *device,
-                                                   ClutterInputDeviceTool     *tool,
-                                                   GDesktopStylusButtonAction  primary,
--                                                  GDesktopStylusButtonAction  secondary)
-+                                                  GDesktopStylusButtonAction  secondary,
-+                                                  GDesktopStylusButtonAction  tertiary)
- {
-   clutter_evdev_input_device_tool_set_button_code (tool, CLUTTER_BUTTON_MIDDLE,
-                                                    action_to_evcode (primary));
-   clutter_evdev_input_device_tool_set_button_code (tool, CLUTTER_BUTTON_SECONDARY,
-                                                    action_to_evcode (secondary));
-+  clutter_evdev_input_device_tool_set_button_code (tool, 8, /* Back */
-+                                                   action_to_evcode (tertiary));
- }
- 
- static void
-diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c
-index 4867b6b..7d5239f 100644
---- a/src/backends/x11/meta-input-settings-x11.c
-+++ b/src/backends/x11/meta-input-settings-x11.c
-@@ -1031,7 +1031,8 @@ meta_input_settings_x11_set_stylus_button_map (MetaInputSettings          *setti
-                                                ClutterInputDevice         *device,
-                                                ClutterInputDeviceTool     *tool,
-                                                GDesktopStylusButtonAction  primary,
--                                               GDesktopStylusButtonAction  secondary)
-+                                               GDesktopStylusButtonAction  secondary,
-+                                               GDesktopStylusButtonAction  tertiary)
- {
-   MetaDisplay *display = meta_get_display ();
-   MetaBackend *backend = meta_get_backend ();
-@@ -1046,10 +1047,15 @@ meta_input_settings_x11_set_stylus_button_map (MetaInputSettings          *setti
-   xdev = device_ensure_xdevice (device);
-   if (xdev)
-     {
--      guchar map[3] = {
-+      guchar map[8] = {
-         CLUTTER_BUTTON_PRIMARY,
-         action_to_button (primary, CLUTTER_BUTTON_MIDDLE),
-         action_to_button (secondary, CLUTTER_BUTTON_SECONDARY),
-+        4,
-+        5,
-+        6,
-+        7,
-+        action_to_button (tertiary, 8), /* "Back" */
-       };
- 
-       XSetDeviceButtonMapping (xdisplay, xdev, map, G_N_ELEMENTS (map));
--- 
-2.17.0
-
diff --git a/SPECS/mutter.spec b/SPECS/mutter.spec
index 52c9c6c..0b9d366 100644
--- a/SPECS/mutter.spec
+++ b/SPECS/mutter.spec
@@ -3,27 +3,28 @@
 %global gsettings_desktop_schemas_version 3.21.4
 %global json_glib_version 0.12.0
 %global libinput_version 1.4
-%global wayland_protocols_version 1.9.0
 
 %ifarch s390 s390x
 %global disable_wayland --disable-wayland-egl-server --disable-wayland --disable-native-backend
 %endif
 
 Name:          mutter
-Version:       3.26.2
-Release:       17%{?dist}
+Version:       3.28.3
+Release:       4%{?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.26/%{name}-%{version}.tar.xz
+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
 
@@ -32,35 +33,31 @@ Patch6:  0001-backends-x11-Support-synaptics-configuration.patch
 
 Patch7:  0001-window-actor-Special-case-shaped-Java-windows.patch
 
-Patch8:  0001-backends-x11-Preserve-XI1-XDevice-throughout-Clutter.patch
 Patch9:  0001-clutter-Extend-touchpad-device-property-check-for-Sy.patch
-Patch10: 0001-backends-x11-wacom-pressure-curve-is-a-32-bit-proper.patch
-
-Patch11:  0001-renderer-x11-Enable-GPU-memory-purge-error-extension.patch
-Patch12:  0001-backends-Monitor-changes-in-active-tools-settings.patch
-Patch13:  0001-clutter-x11-Implement-missing-ClutterInputDevice-pad.patch
-Patch14:  wacom-pro-pen-3d.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
 
-Patch23: 0001-backends-x11-Fix-time-comparison-bug-causing-hang.patch
-Patch24: fix-transient-close-crash.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
 
 # el7 patches
 Patch100: 0001-Revert-build-Require-libgudev-232.patch
 Patch101: 0001-rhel7-Fix-build-for-el7.patch
-Patch102: mutter-3.26.0-hybrid-gpus.patch
 Patch103: 0001-wayland-enable-scale-monitor-framebuffer-by-default.patch
 Patch104: add-support-for-plain-old-x-device-configuration.patch
-Patch105: remember-saved-multi-monitor-configuration.patch
-Patch106: 0003-window-wayland-Handle-resizing-when-headless.patch
-Patch107: fix-session-save-crash.patch
-Patch108: 0001-wayland-Do-not-fail-on-stalled-.X11-unix-entries.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
 
-Patch500: 0001-clutter-stage-don-t-use-deprecated-api.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
 
 BuildRequires: chrpath
 BuildRequires: pango-devel
@@ -91,6 +88,7 @@ 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
@@ -110,7 +108,6 @@ BuildRequires: libgudev1-devel
 %ifnarch s390 s390x
 BuildRequires: libwayland-server-devel
 BuildRequires: libinput-devel >= %{libinput_version}
-BuildRequires: wayland-protocols-devel >= %{wayland_protocols_version}
 %endif
 
 Obsoletes: mutter-wayland < 3.13.0
@@ -128,7 +125,6 @@ Requires: dbus-x11
 Requires: zenity
 
 Requires:      json-glib%{?_isa} >= %{json_glib_version}
-
 %ifnarch s390 s390x
 Requires:      libinput%{?_isa} >= %{libinput_version}
 %endif
@@ -218,21 +214,47 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
 %{_libdir}/pkgconfig/*
 
 %changelog
-* Tue Aug 28 2018 Florian Müllner <fmuellner@redhat.com> - 3.26.2-17
-- Fix crash when transient dialog closes during drag operation
-- Resolves: #1622036
+* 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 08 2018 Florian Müllner <fmuellner@redhat.com> - 3.26.2-16
+* 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: #1622000
+- Resolves: #1585230
+
+* Tue Jun 19 2018 Carlos Garnacho <cgarnach@redhat.com> - 3.28.2-2
+- Update scroll axes only in slave devices
+- Resolves: #1423374
 
-* Tue Jul 17 2018 Florian Müllner <fmuellner@redhat.com> - 3.26.2-15
-- Fix time comparison bug causing hang
-  Resolves: #1601948
+* 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: #1568702
+  Resolves: #1564063
 
 * Fri Feb 23 2018 Carlos Garnacho <cgarnach@redhat.com> - 3.26.2-13
 - Fix pad ring/strip modes