diff --git a/SOURCES/0001-cally-Fix-state-set-leak.patch b/SOURCES/0001-cally-Fix-state-set-leak.patch
new file mode 100644
index 0000000..44673bf
--- /dev/null
+++ b/SOURCES/0001-cally-Fix-state-set-leak.patch
@@ -0,0 +1,125 @@
+From f5c5f62d9f820b56e81f8b3829aae8195841c755 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode@redhat.com>
+Date: Thu, 30 Apr 2020 10:23:09 -0400
+Subject: [PATCH 1/4] cally: Fix state set leak
+
+cally_actor_action_do_action leaks a state set object in the
+case where the actor is defunct, insensitive, or hidden.
+
+This commit plugs the leak.
+
+https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1225
+---
+ clutter/clutter/cally/cally-actor.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+diff --git a/clutter/clutter/cally/cally-actor.c b/clutter/clutter/cally/cally-actor.c
+index 77195c0b0..ff6dba14e 100644
+--- a/clutter/clutter/cally/cally-actor.c
++++ b/clutter/clutter/cally/cally-actor.c
+@@ -797,92 +797,95 @@ _cally_actor_get_top_level_origin (ClutterActor *actor,
+ 
+   if (xp)
+     *xp = x;
+ 
+   if (yp)
+     *yp = y;
+ }
+ 
+ /* AtkAction implementation */
+ static void
+ cally_actor_action_interface_init (AtkActionIface *iface)
+ {
+   g_return_if_fail (iface != NULL);
+ 
+   iface->do_action       = cally_actor_action_do_action;
+   iface->get_n_actions   = cally_actor_action_get_n_actions;
+   iface->get_description = cally_actor_action_get_description;
+   iface->get_keybinding  = cally_actor_action_get_keybinding;
+   iface->get_name        = cally_actor_action_get_name;
+   iface->set_description = cally_actor_action_set_description;
+ }
+ 
+ static gboolean
+ cally_actor_action_do_action (AtkAction *action,
+                              gint       index)
+ {
+   CallyActor           *cally_actor = NULL;
+   AtkStateSet          *set         = NULL;
+   CallyActorPrivate    *priv        = NULL;
+   CallyActorActionInfo *info        = NULL;
++  gboolean              did_action  = FALSE;
+ 
+   cally_actor = CALLY_ACTOR (action);
+   priv = cally_actor->priv;
+ 
+   set = atk_object_ref_state_set (ATK_OBJECT (cally_actor));
+ 
+   if (atk_state_set_contains_state (set, ATK_STATE_DEFUNCT))
+-    return FALSE;
++    goto out;
+ 
+   if (!atk_state_set_contains_state (set, ATK_STATE_SENSITIVE) ||
+       !atk_state_set_contains_state (set, ATK_STATE_SHOWING))
+-    return FALSE;
+-
+-  g_object_unref (set);
++    goto out;
+ 
+   info = _cally_actor_get_action_info (cally_actor, index);
+ 
+   if (info == NULL)
+-    return FALSE;
++    goto out;
+ 
+   if (info->do_action_func == NULL)
+-    return FALSE;
++    goto out;
+ 
+   if (!priv->action_queue)
+     priv->action_queue = g_queue_new ();
+ 
+   g_queue_push_head (priv->action_queue, info);
+ 
+   if (!priv->action_idle_handler)
+     priv->action_idle_handler = g_idle_add (idle_do_action, cally_actor);
+ 
+-  return TRUE;
++  did_action = TRUE;
++
++out:
++  g_clear_object (&set);
++  return did_action;
+ }
+ 
+ static gboolean
+ idle_do_action (gpointer data)
+ {
+   CallyActor        *cally_actor = NULL;
+   CallyActorPrivate *priv       = NULL;
+   ClutterActor     *actor      = NULL;
+ 
+   cally_actor = CALLY_ACTOR (data);
+   priv = cally_actor->priv;
+   actor = CALLY_GET_CLUTTER_ACTOR (cally_actor);
+   priv->action_idle_handler = 0;
+ 
+   if (actor == NULL) /* state is defunct*/
+     return FALSE;
+ 
+   while (!g_queue_is_empty (priv->action_queue))
+     {
+       CallyActorActionInfo *info = NULL;
+ 
+       info = (CallyActorActionInfo *) g_queue_pop_head (priv->action_queue);
+ 
+       info->do_action_func (cally_actor, info->user_data);
+     }
+ 
+   return FALSE;
+ }
+ 
+ static gint
+-- 
+2.26.2
+
diff --git a/SOURCES/0001-cogl-Use-autopointers-to-free-structs-on-return.patch b/SOURCES/0001-cogl-Use-autopointers-to-free-structs-on-return.patch
new file mode 100644
index 0000000..2a4aa6d
--- /dev/null
+++ b/SOURCES/0001-cogl-Use-autopointers-to-free-structs-on-return.patch
@@ -0,0 +1,267 @@
+From a5fa286732b08b832ea642347963cb0456c1e19f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Tue, 9 Jul 2019 11:13:09 +0200
+Subject: [PATCH 01/28] cogl: Use autopointers to free structs on return
+
+This is a potential leak discovered by static analysis, in fact if
+_COGL_GET_CONTEXT returns, the newly allocated struct isn't released.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ cogl/cogl-pango/cogl-pango-fontmap.c | 4 ++--
+ cogl/cogl/cogl-onscreen.c            | 4 +++-
+ cogl/cogl/cogl-pipeline-cache.c      | 4 ++--
+ 3 files changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/cogl/cogl-pango/cogl-pango-fontmap.c b/cogl/cogl-pango/cogl-pango-fontmap.c
+index 145f3b9e8..3ec64eee6 100644
+--- a/cogl/cogl-pango/cogl-pango-fontmap.c
++++ b/cogl/cogl-pango/cogl-pango-fontmap.c
+@@ -49,72 +49,72 @@
+ #include <pango/pango-renderer.h>
+ 
+ #include "cogl-pango.h"
+ #include "cogl-pango-private.h"
+ #include "cogl-util.h"
+ #include "cogl/cogl-context-private.h"
+ 
+ static GQuark cogl_pango_font_map_get_priv_key (void) G_GNUC_CONST;
+ 
+ typedef struct _CoglPangoFontMapPriv
+ {
+   CoglContext *ctx;
+   PangoRenderer *renderer;
+ } CoglPangoFontMapPriv;
+ 
+ static void
+ free_priv (gpointer data)
+ {
+   CoglPangoFontMapPriv *priv = data;
+ 
+   cogl_object_unref (priv->ctx);
+   cogl_object_unref (priv->renderer);
+ 
+   g_free (priv);
+ }
+ 
+ PangoFontMap *
+ cogl_pango_font_map_new (void)
+ {
+   PangoFontMap *fm = pango_cairo_font_map_new ();
+-  CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1);
++  g_autofree CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1);
+ 
+   _COGL_GET_CONTEXT (context, NULL);
+ 
+   priv->ctx = cogl_object_ref (context);
+ 
+   /* XXX: The public pango api doesn't let us sub-class
+    * PangoCairoFontMap so we attach our own private data using qdata
+    * for now. */
+   g_object_set_qdata_full (G_OBJECT (fm),
+                            cogl_pango_font_map_get_priv_key (),
+-                           priv,
++                           g_steal_pointer (&priv),
+                            free_priv);
+ 
+   return fm;
+ }
+ 
+ PangoContext *
+ cogl_pango_font_map_create_context (CoglPangoFontMap *fm)
+ {
+   _COGL_RETURN_VAL_IF_FAIL (COGL_PANGO_IS_FONT_MAP (fm), NULL);
+ 
+ #if PANGO_VERSION_CHECK (1, 22, 0)
+   /* We can just directly use the pango context from the Cairo font
+      map */
+   return pango_font_map_create_context (PANGO_FONT_MAP (fm));
+ #else
+   return pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fm));
+ #endif
+ }
+ 
+ static CoglPangoFontMapPriv *
+ _cogl_pango_font_map_get_priv (CoglPangoFontMap *fm)
+ {
+   return g_object_get_qdata (G_OBJECT (fm),
+ 			     cogl_pango_font_map_get_priv_key ());
+ }
+ 
+ PangoRenderer *
+ _cogl_pango_font_map_get_renderer (CoglPangoFontMap *fm)
+ {
+   CoglPangoFontMapPriv *priv = _cogl_pango_font_map_get_priv (fm);
+diff --git a/cogl/cogl/cogl-onscreen.c b/cogl/cogl/cogl-onscreen.c
+index e766e59d0..fcf7f4168 100644
+--- a/cogl/cogl/cogl-onscreen.c
++++ b/cogl/cogl/cogl-onscreen.c
+@@ -72,64 +72,66 @@ COGL_GTYPE_DEFINE_BOXED (FrameClosure, frame_closure,
+                          cogl_dummy_free);
+ COGL_GTYPE_DEFINE_BOXED (OnscreenResizeClosure,
+                          onscreen_resize_closure,
+                          cogl_dummy_copy,
+                          cogl_dummy_free);
+ COGL_GTYPE_DEFINE_BOXED (OnscreenDirtyClosure,
+                          onscreen_dirty_closure,
+                          cogl_dummy_copy,
+                          cogl_dummy_free);
+ 
+ static void
+ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
+                                    CoglOnscreenTemplate *onscreen_template)
+ {
+   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+ 
+   _cogl_list_init (&onscreen->frame_closures);
+   _cogl_list_init (&onscreen->resize_closures);
+   _cogl_list_init (&onscreen->dirty_closures);
+ 
+   framebuffer->config = onscreen_template->config;
+   cogl_object_ref (framebuffer->config.swap_chain);
+ }
+ 
+ /* XXX: While we still have backend in Clutter we need a dummy object
+  * to represent the CoglOnscreen framebuffer that the backend
+  * creates... */
+ CoglOnscreen *
+ _cogl_onscreen_new (void)
+ {
+-  CoglOnscreen *onscreen = g_new0 (CoglOnscreen, 1);
++  g_autofree CoglOnscreen *onscreen_ptr = g_new0 (CoglOnscreen, 1);
++  CoglOnscreen *onscreen;
+ 
+   _COGL_GET_CONTEXT (ctx, NULL);
+ 
++  onscreen = g_steal_pointer (&onscreen_ptr);
+   _cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen),
+                           ctx,
+                           COGL_FRAMEBUFFER_TYPE_ONSCREEN,
+                           0x1eadbeef, /* width */
+                           0x1eadbeef); /* height */
+   /* NB: make sure to pass positive width/height numbers here
+    * because otherwise we'll hit input validation assertions!*/
+ 
+   _cogl_onscreen_init_from_template (onscreen, ctx->display->onscreen_template);
+ 
+   COGL_FRAMEBUFFER (onscreen)->allocated = TRUE;
+ 
+   /* XXX: Note we don't initialize onscreen->winsys in this case. */
+ 
+   return _cogl_onscreen_object_new (onscreen);
+ }
+ 
+ CoglOnscreen *
+ cogl_onscreen_new (CoglContext *ctx, int width, int height)
+ {
+   CoglOnscreen *onscreen;
+ 
+   /* FIXME: We are assuming onscreen buffers will always be
+      premultiplied so we'll set the premult flag on the bitmap
+      format. This will usually be correct because the result of the
+      default blending operations for Cogl ends up with premultiplied
+      data in the framebuffer. However it is possible for the
+      framebuffer to be in whatever format depending on what
+      CoglPipeline is used to render to it. Eventually we may want to
+      add a way for an application to inform Cogl that the framebuffer
+diff --git a/cogl/cogl/cogl-pipeline-cache.c b/cogl/cogl/cogl-pipeline-cache.c
+index 62b372406..4267d2ccb 100644
+--- a/cogl/cogl/cogl-pipeline-cache.c
++++ b/cogl/cogl/cogl-pipeline-cache.c
+@@ -25,91 +25,91 @@
+  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  * SOFTWARE.
+  *
+  *
+  * Authors:
+  *   Neil Roberts <neil@linux.intel.com>
+  *   Robert Bragg <robert@linux.intel.com>
+  */
+ 
+ #ifdef HAVE_CONFIG_H
+ #include "cogl-config.h"
+ #endif
+ 
+ #include <test-fixtures/test-unit.h>
+ 
+ #include "cogl-context-private.h"
+ #include "cogl-pipeline-private.h"
+ #include "cogl-pipeline-cache.h"
+ #include "cogl-pipeline-hash-table.h"
+ 
+ struct _CoglPipelineCache
+ {
+   CoglPipelineHashTable fragment_hash;
+   CoglPipelineHashTable vertex_hash;
+   CoglPipelineHashTable combined_hash;
+ };
+ 
+ CoglPipelineCache *
+ _cogl_pipeline_cache_new (void)
+ {
+-  CoglPipelineCache *cache = g_new (CoglPipelineCache, 1);
++  g_autofree CoglPipelineCache *cache = g_new (CoglPipelineCache, 1);
+   unsigned long vertex_state;
+   unsigned long layer_vertex_state;
+   unsigned int fragment_state;
+   unsigned int layer_fragment_state;
+ 
+   _COGL_GET_CONTEXT (ctx, 0);
+ 
+   vertex_state =
+     _cogl_pipeline_get_state_for_vertex_codegen (ctx);
+   layer_vertex_state =
+     COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN;
+   fragment_state =
+     _cogl_pipeline_get_state_for_fragment_codegen (ctx);
+   layer_fragment_state =
+     _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx);
+ 
+   _cogl_pipeline_hash_table_init (&cache->vertex_hash,
+                                   vertex_state,
+                                   layer_vertex_state,
+                                   "vertex shaders");
+   _cogl_pipeline_hash_table_init (&cache->fragment_hash,
+                                   fragment_state,
+                                   layer_fragment_state,
+                                   "fragment shaders");
+   _cogl_pipeline_hash_table_init (&cache->combined_hash,
+                                   vertex_state | fragment_state,
+                                   layer_vertex_state | layer_fragment_state,
+                                   "programs");
+ 
+-  return cache;
++  return g_steal_pointer (&cache);
+ }
+ 
+ void
+ _cogl_pipeline_cache_free (CoglPipelineCache *cache)
+ {
+   _cogl_pipeline_hash_table_destroy (&cache->fragment_hash);
+   _cogl_pipeline_hash_table_destroy (&cache->vertex_hash);
+   _cogl_pipeline_hash_table_destroy (&cache->combined_hash);
+   g_free (cache);
+ }
+ 
+ CoglPipelineCacheEntry *
+ _cogl_pipeline_cache_get_fragment_template (CoglPipelineCache *cache,
+                                             CoglPipeline *key_pipeline)
+ {
+   return _cogl_pipeline_hash_table_get (&cache->fragment_hash,
+                                         key_pipeline);
+ }
+ 
+ CoglPipelineCacheEntry *
+ _cogl_pipeline_cache_get_vertex_template (CoglPipelineCache *cache,
+                                           CoglPipeline *key_pipeline)
+ {
+   return _cogl_pipeline_hash_table_get (&cache->vertex_hash,
+                                         key_pipeline);
+ }
+ 
+ CoglPipelineCacheEntry *
+ _cogl_pipeline_cache_get_combined_template (CoglPipelineCache *cache,
+                                             CoglPipeline *key_pipeline)
+-- 
+2.26.2
+
diff --git a/SOURCES/0001-stack-tracker-Fix-coding-style-of-meta_stack_op_appl.patch b/SOURCES/0001-stack-tracker-Fix-coding-style-of-meta_stack_op_appl.patch
new file mode 100644
index 0000000..d2f2c55
--- /dev/null
+++ b/SOURCES/0001-stack-tracker-Fix-coding-style-of-meta_stack_op_appl.patch
@@ -0,0 +1,199 @@
+From 599d5241c927ecc716dd5c45f3bf447701161980 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Tue, 9 Jun 2020 19:07:47 +0200
+Subject: [PATCH 1/2] stack-tracker: Fix coding style of meta_stack_op_apply()
+
+Change tabs to spaces, clean up variable declarations.
+
+https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1300
+---
+ src/core/stack-tracker.c | 142 +++++++++++++++++++++------------------
+ 1 file changed, 76 insertions(+), 66 deletions(-)
+
+diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c
+index 82afd644a5..8f0164692f 100644
+--- a/src/core/stack-tracker.c
++++ b/src/core/stack-tracker.c
+@@ -356,103 +356,113 @@ move_window_above (GArray    *stack,
+ static gboolean
+ meta_stack_op_apply (MetaStackTracker *tracker,
+                      MetaStackOp      *op,
+-		     GArray           *stack,
++                     GArray           *stack,
+                      ApplyFlags        apply_flags)
+ {
+   switch (op->any.type)
+     {
+     case STACK_OP_ADD:
+       {
++        int old_pos;
++
+         if (META_STACK_ID_IS_X11 (op->add.window) &&
+             (apply_flags & NO_RESTACK_X_WINDOWS) != 0)
+           return FALSE;
+ 
+-	int old_pos = find_window (stack, op->add.window);
+-	if (old_pos >= 0)
+-	  {
+-	    g_warning ("STACK_OP_ADD: window %s already in stack",
+-		       get_window_desc (tracker, op->add.window));
+-	    return FALSE;
+-	  }
++        old_pos = find_window (stack, op->add.window);
++        if (old_pos >= 0)
++          {
++            g_warning ("STACK_OP_ADD: window %s already in stack",
++                       get_window_desc (tracker, op->add.window));
++            return FALSE;
++          }
+ 
+-	g_array_append_val (stack, op->add.window);
+-	return TRUE;
++        g_array_append_val (stack, op->add.window);
++        return TRUE;
+       }
+     case STACK_OP_REMOVE:
+       {
++        int old_pos;
++
+         if (META_STACK_ID_IS_X11 (op->remove.window) &&
+             (apply_flags & NO_RESTACK_X_WINDOWS) != 0)
+           return FALSE;
+ 
+-	int old_pos = find_window (stack, op->remove.window);
+-	if (old_pos < 0)
+-	  {
+-	    g_warning ("STACK_OP_REMOVE: window %s not in stack",
+-		       get_window_desc (tracker, op->remove.window));
+-	    return FALSE;
+-	  }
++        old_pos = find_window (stack, op->remove.window);
++        if (old_pos < 0)
++          {
++            g_warning ("STACK_OP_REMOVE: window %s not in stack",
++                       get_window_desc (tracker, op->remove.window));
++            return FALSE;
++          }
+ 
+-	g_array_remove_index (stack, old_pos);
+-	return TRUE;
++        g_array_remove_index (stack, old_pos);
++        return TRUE;
+       }
+     case STACK_OP_RAISE_ABOVE:
+       {
+-	int old_pos = find_window (stack, op->raise_above.window);
+-	int above_pos;
+-	if (old_pos < 0)
+-	  {
+-	    g_warning ("STACK_OP_RAISE_ABOVE: window %s not in stack",
+-		       get_window_desc (tracker, op->raise_above.window));
+-	    return FALSE;
+-	  }
++        int old_pos;
++        int above_pos;
++
++        old_pos = find_window (stack, op->raise_above.window);
++        if (old_pos < 0)
++          {
++            g_warning ("STACK_OP_RAISE_ABOVE: window %s not in stack",
++                       get_window_desc (tracker, op->raise_above.window));
++            return FALSE;
++          }
+ 
+         if (op->raise_above.sibling)
+-	  {
+-	    above_pos = find_window (stack, op->raise_above.sibling);
+-	    if (above_pos < 0)
+-	      {
+-		g_warning ("STACK_OP_RAISE_ABOVE: sibling window %s not in stack",
++          {
++            above_pos = find_window (stack, op->raise_above.sibling);
++            if (above_pos < 0)
++              {
++                g_warning ("STACK_OP_RAISE_ABOVE: sibling window %s not in stack",
+                            get_window_desc (tracker, op->raise_above.sibling));
+-		return FALSE;
+-	      }
+-	  }
+-	else
+-	  {
+-	    above_pos = -1;
+-	  }
+-
+-	return move_window_above (stack, op->raise_above.window, old_pos, above_pos,
++                return FALSE;
++              }
++          }
++        else
++          {
++            above_pos = -1;
++          }
++
++        return move_window_above (stack, op->raise_above.window, old_pos, above_pos,
+                                   apply_flags);
+       }
+     case STACK_OP_LOWER_BELOW:
+       {
+-	int old_pos = find_window (stack, op->lower_below.window);
+-	int above_pos;
+-	if (old_pos < 0)
+-	  {
+-	    g_warning ("STACK_OP_LOWER_BELOW: window %s not in stack",
+-		       get_window_desc (tracker, op->lower_below.window));
+-	    return FALSE;
+-	  }
++        int old_pos;
++        int above_pos;
++
++        old_pos = find_window (stack, op->raise_above.window);
++        if (old_pos < 0)
++          {
++            g_warning ("STACK_OP_LOWER_BELOW: window %s not in stack",
++                       get_window_desc (tracker, op->lower_below.window));
++            return FALSE;
++          }
+ 
+         if (op->lower_below.sibling)
+-	  {
+-	    int below_pos = find_window (stack, op->lower_below.sibling);
+-	    if (below_pos < 0)
+-	      {
+-		g_warning ("STACK_OP_LOWER_BELOW: sibling window %s not in stack",
+-			   get_window_desc (tracker, op->lower_below.sibling));
+-		return FALSE;
+-	      }
+-
+-	    above_pos = below_pos - 1;
+-	  }
+-	else
+-	  {
+-	    above_pos = stack->len - 1;
+-	  }
+-
+-	return move_window_above (stack, op->lower_below.window, old_pos, above_pos,
++          {
++            int below_pos;
++
++            below_pos = find_window (stack, op->lower_below.sibling);
++            if (below_pos < 0)
++              {
++                g_warning ("STACK_OP_LOWER_BELOW: sibling window %s not in stack",
++                           get_window_desc (tracker, op->lower_below.sibling));
++                return FALSE;
++              }
++
++            above_pos = below_pos - 1;
++          }
++        else
++          {
++            above_pos = stack->len - 1;
++          }
++
++        return move_window_above (stack, op->lower_below.window, old_pos, above_pos,
+                                   apply_flags);
+       }
+     }
+-- 
+2.26.2
+
diff --git a/SOURCES/0002-barriers-Fix-leak-in-meta_barrier_destroy.patch b/SOURCES/0002-barriers-Fix-leak-in-meta_barrier_destroy.patch
new file mode 100644
index 0000000..af09d5c
--- /dev/null
+++ b/SOURCES/0002-barriers-Fix-leak-in-meta_barrier_destroy.patch
@@ -0,0 +1,86 @@
+From 574e832f20c8c3f278709531083a03b190f1adfa Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode@redhat.com>
+Date: Fri, 25 Sep 2020 14:04:31 -0400
+Subject: [PATCH 2/4] barriers: Fix leak in meta_barrier_destroy
+
+meta_barrier_destroy is responsible for removing the extra
+reference added in meta_barrier_constructed.
+
+Unfortunately, it fails to do this because of a misplaced early
+return statement.
+
+This commit removes the spurious return.
+---
+ src/backends/meta-barrier.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/backends/meta-barrier.c b/src/backends/meta-barrier.c
+index a1e1180fe..2353ef150 100644
+--- a/src/backends/meta-barrier.c
++++ b/src/backends/meta-barrier.c
+@@ -264,61 +264,61 @@ meta_barrier_class_init (MetaBarrierClass *klass)
+                   G_TYPE_NONE, 1,
+                   META_TYPE_BARRIER_EVENT);
+ 
+   /**
+    * MetaBarrier::left:
+    * @barrier: The #MetaBarrier that was left
+    * @event: A #MetaBarrierEvent that has the details of how
+    * the barrier was left.
+    *
+    * When a pointer barrier hitbox was left, this will trigger.
+    * This requires an XI2-enabled server.
+    */
+   obj_signals[LEFT] =
+     g_signal_new ("left",
+                   G_TYPE_FROM_CLASS (object_class),
+                   G_SIGNAL_RUN_FIRST,
+                   0,
+                   NULL, NULL, NULL,
+                   G_TYPE_NONE, 1,
+                   META_TYPE_BARRIER_EVENT);
+ 
+   g_type_class_add_private (object_class, sizeof(MetaBarrierPrivate));
+ }
+ 
+ void
+ meta_barrier_destroy (MetaBarrier *barrier)
+ {
+   MetaBarrierImpl *impl = barrier->priv->impl;
+ 
+   if (impl)
+-    return META_BARRIER_IMPL_GET_CLASS (impl)->destroy (impl);
++    META_BARRIER_IMPL_GET_CLASS (impl)->destroy (impl);
+ 
+   g_object_unref (barrier);
+ }
+ 
+ static void
+ meta_barrier_init (MetaBarrier *barrier)
+ {
+   barrier->priv = G_TYPE_INSTANCE_GET_PRIVATE (barrier, META_TYPE_BARRIER, MetaBarrierPrivate);
+ }
+ 
+ void
+ _meta_barrier_emit_hit_signal (MetaBarrier      *barrier,
+                                MetaBarrierEvent *event)
+ {
+   g_signal_emit (barrier, obj_signals[HIT], 0, event);
+ }
+ 
+ void
+ _meta_barrier_emit_left_signal (MetaBarrier      *barrier,
+                                 MetaBarrierEvent *event)
+ {
+   g_signal_emit (barrier, obj_signals[LEFT], 0, event);
+ }
+ 
+ static void
+ meta_barrier_impl_class_init (MetaBarrierImplClass *klass)
+ {
+   klass->is_active = NULL;
+   klass->release = NULL;
+   klass->destroy = NULL;
+-- 
+2.26.2
+
diff --git a/SOURCES/0002-cogl-Define-autoptr-cleanup-functions-for-Cogl-types.patch b/SOURCES/0002-cogl-Define-autoptr-cleanup-functions-for-Cogl-types.patch
new file mode 100644
index 0000000..7fa1cf4
--- /dev/null
+++ b/SOURCES/0002-cogl-Define-autoptr-cleanup-functions-for-Cogl-types.patch
@@ -0,0 +1,215 @@
+From 758ede11d0967b38eba75241fb5dadb395f29617 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Tue, 9 Jul 2019 14:45:48 +0200
+Subject: [PATCH 02/28] cogl: Define autoptr cleanup functions for Cogl types
+
+Make possible to use g_autoptr () with Cogl types
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ cogl/cogl/Makefile.am         |  1 +
+ cogl/cogl/cogl-autocleanups.h | 67 +++++++++++++++++++++++++++++++++++
+ cogl/cogl/cogl.h              |  2 ++
+ 3 files changed, 70 insertions(+)
+ create mode 100644 cogl/cogl/cogl-autocleanups.h
+
+diff --git a/cogl/cogl/Makefile.am b/cogl/cogl/Makefile.am
+index 66accf709..ecb5e8b59 100644
+--- a/cogl/cogl/Makefile.am
++++ b/cogl/cogl/Makefile.am
+@@ -38,60 +38,61 @@ endif
+ AM_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS)
+ 
+ BUILT_SOURCES += cogl-defines.h cogl-egl-defines.h cogl-gl-header.h
+ DISTCLEANFILES += cogl-defines.h cogl-egl-defines.h cogl-gl-header.h
+ EXTRA_DIST += cogl-defines.h.in cogl-egl-defines.h.in cogl-gl-header.h.in
+ 
+ pc_files = mutter-cogl-$(LIBMUTTER_API_VERSION).pc
+ 
+ pkgconfigdir = $(libdir)/pkgconfig
+ pkgconfig_DATA = $(pc_files)
+ 
+ DISTCLEANFILES += $(pc_files)
+ 
+ cogl_deprecated_h = \
+ 	deprecated/cogl-material-compat.h 	\
+ 	deprecated/cogl-vertex-buffer.h 	\
+ 	deprecated/cogl-shader.h 		\
+ 	deprecated/cogl-clutter.h       	\
+ 	deprecated/cogl-type-casts.h       	\
+ 	deprecated/cogl-auto-texture.h	\
+ 	$(NULL)
+ 
+ cogl_deprecated_nonintrospected_h = \
+ 	deprecated/cogl-framebuffer-deprecated.h \
+ 	$(NULL)
+ 
+ # public 1.x api headers
+ cogl_1_public_h = \
+ 	$(cogl_deprecated_h)			\
+ 	cogl1-context.h 		\
++	cogl-autocleanups.h		\
+ 	cogl-bitmap.h 		\
+ 	cogl-color.h 			\
+ 	cogl-matrix.h 		\
+ 	cogl-offscreen.h 		\
+ 	cogl-primitives.h 		\
+ 	cogl-texture.h 		\
+ 	cogl-types.h 			\
+ 	cogl.h			\
+ 	$(NULL)
+ 
+ cogl_nonintrospected_h = \
+ 	cogl-object.h 		\
+ 	cogl-renderer.h 		\
+ 	cogl-swap-chain.h 		\
+ 	cogl-onscreen-template.h 	\
+ 	cogl-display.h 		\
+ 	cogl-context.h 		\
+ 	cogl-pipeline.h 		\
+ 	cogl-pipeline-state.h 	\
+ 	cogl-pipeline-layer-state.h 	\
+ 	cogl-snippet.h		\
+ 	cogl-gles2.h			\
+ 	cogl-gles2-types.h		\
+ 	cogl-index-buffer.h 		\
+ 	cogl-attribute-buffer.h 	\
+ 	cogl-indices.h 		\
+ 	cogl-attribute.h 		\
+ 	cogl-primitive.h 		\
+ 	cogl-framebuffer.h		\
+ 	cogl-onscreen.h		\
+diff --git a/cogl/cogl/cogl-autocleanups.h b/cogl/cogl/cogl-autocleanups.h
+new file mode 100644
+index 000000000..f18002418
+--- /dev/null
++++ b/cogl/cogl/cogl-autocleanups.h
+@@ -0,0 +1,67 @@
++/*
++ * Cogl
++ *
++ * A Low Level GPU Graphics and Utilities API
++ *
++ * Copyright (C) 2009  Intel Corporation.
++ * Copyright (C) 2019  Canonical Ltd.
++ *
++ * Permission is hereby granted, free of charge, to any person
++ * obtaining a copy of this software and associated documentation
++ * files (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy,
++ * modify, merge, publish, distribute, sublicense, and/or sell copies
++ * of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be
++ * included in all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ *
++ */
++
++#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
++#error "Only <cogl/cogl.h> can be included directly."
++#endif
++
++#ifndef __COGL_AUTOCLEANUPS_H__
++#define __COGL_AUTOCLEANUPS_H__
++
++#ifndef __GI_SCANNER__
++
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglAtlasTexture, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglAttribute, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglAttributeBuffer, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglBitmap, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglColor, cogl_color_free)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglDisplay, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglEuler, cogl_euler_free)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglFramebuffer, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglIndices, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglHandle, cogl_handle_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglMatrix, cogl_matrix_free)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglMatrixEntry, cogl_matrix_entry_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglMatrixStack, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglObject, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglOffscreen, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglOnscreenTemplate, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglPath, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglPipeline, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglQuaternion, cogl_quaternion_free)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglRenderer, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglSnippet, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglTexture, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglTexture2D, cogl_object_unref)
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglTexture2DSliced, cogl_object_unref)
++
++#endif /* __GI_SCANNER__ */
++
++#endif /* __COGL_AUTOCLEANUPS_H__ */
+diff --git a/cogl/cogl/cogl.h b/cogl/cogl/cogl.h
+index 5210e3c59..c7cf7e6a8 100644
+--- a/cogl/cogl/cogl.h
++++ b/cogl/cogl/cogl.h
+@@ -127,51 +127,53 @@
+ #include <cogl/cogl-frame-info.h>
+ #include <cogl/cogl-poll.h>
+ #include <cogl/cogl-fence.h>
+ #include <cogl/cogl-glib-source.h>
+ /* XXX: This will definitly go away once all the Clutter winsys
+  * code has been migrated down into Cogl! */
+ #include <cogl/deprecated/cogl-clutter.h>
+ 
+ /*
+  * API deprecations
+  */
+ #include <cogl/cogl-deprecated.h>
+ 
+ /*
+  * Cogl Path api compatability
+  *
+  * The cogl_path_ api used to be part of the core Cogl api so for
+  * compatability we include cogl-path.h via cogl.h
+  *
+  * Note: we have to make sure not to include cogl-path.h while
+  * building core cogl or generating the Cogl .gir data because
+  * cogl-path now gets built after cogl and some cogl-path headers are
+  * only generated at build time...
+  */
+ #if defined (COGL_HAS_COGL_PATH_SUPPORT) && \
+   !defined (COGL_COMPILATION) && \
+   !defined (COGL_GIR_SCANNING)
+ #include <cogl-path/cogl-path.h>
+ #endif
+ 
++#include <cogl/cogl-autocleanups.h>
++
+ /**
+  * SECTION:cogl
+  * @short_description: General purpose API
+  *
+  * General utility functions for COGL.
+  */
+ 
+ /* The gobject introspection scanner seems to parse public headers in
+  * isolation which means we need to be extra careful about how we
+  * define and undefine __COGL_H_INSIDE__ used to detect when internal
+  * headers are incorrectly included by developers. In the gobject
+  * introspection case we have to manually define __COGL_H_INSIDE__ as
+  * a commandline argument for the scanner which means we must be
+  * careful not to undefine it in a header...
+  */
+ #ifdef __COGL_MUST_UNDEF_COGL_H_INSIDE__
+ #undef __COGL_H_INSIDE__
+ #undef __COGL_MUST_UNDEF_COGL_H_INSIDE__
+ #endif
+ 
+ #endif /* __COGL_H__ */
+-- 
+2.26.2
+
diff --git a/SOURCES/0002-stack-tracker-Don-t-log-warnings-on-race-conditions.patch b/SOURCES/0002-stack-tracker-Don-t-log-warnings-on-race-conditions.patch
new file mode 100644
index 0000000..a550cce
--- /dev/null
+++ b/SOURCES/0002-stack-tracker-Don-t-log-warnings-on-race-conditions.patch
@@ -0,0 +1,98 @@
+From 58ff94c8d008ff2df35f014df24a1937cdc962ae Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Tue, 9 Jun 2020 19:09:00 +0200
+Subject: [PATCH 2/2] stack-tracker: Don't log warnings on race conditions
+
+X11 window stacking operations are by nature prone to race conditions.
+For example, we might queue a "raise above" operation, but before it
+actually takes place, the sibling the window was to be rased above, is
+withdrawn.
+
+In these cases we'd log warnings even though they are expected to
+happen. Downgrade these warnings to debug messages, only printed when
+MUTTER_VERBOSE is set.
+
+https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1300
+---
+ src/core/stack-tracker.c | 30 ++++++++++++++++++------------
+ 1 file changed, 18 insertions(+), 12 deletions(-)
+
+diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c
+index 8f0164692f..37fd20fc59 100644
+--- a/src/core/stack-tracker.c
++++ b/src/core/stack-tracker.c
+@@ -372,8 +372,9 @@ meta_stack_op_apply (MetaStackTracker *tracker,
+         old_pos = find_window (stack, op->add.window);
+         if (old_pos >= 0)
+           {
+-            g_warning ("STACK_OP_ADD: window %s already in stack",
+-                       get_window_desc (tracker, op->add.window));
++            meta_topic (META_DEBUG_STACK,
++                        "STACK_OP_ADD: window %s already in stack",
++                        get_window_desc (tracker, op->add.window));
+             return FALSE;
+           }
+ 
+@@ -391,8 +392,9 @@ meta_stack_op_apply (MetaStackTracker *tracker,
+         old_pos = find_window (stack, op->remove.window);
+         if (old_pos < 0)
+           {
+-            g_warning ("STACK_OP_REMOVE: window %s not in stack",
+-                       get_window_desc (tracker, op->remove.window));
++            meta_topic (META_DEBUG_STACK,
++                        "STACK_OP_REMOVE: window %s not in stack",
++                        get_window_desc (tracker, op->remove.window));
+             return FALSE;
+           }
+ 
+@@ -407,8 +409,9 @@ meta_stack_op_apply (MetaStackTracker *tracker,
+         old_pos = find_window (stack, op->raise_above.window);
+         if (old_pos < 0)
+           {
+-            g_warning ("STACK_OP_RAISE_ABOVE: window %s not in stack",
+-                       get_window_desc (tracker, op->raise_above.window));
++            meta_topic (META_DEBUG_STACK,
++                        "STACK_OP_RAISE_ABOVE: window %s not in stack",
++                        get_window_desc (tracker, op->raise_above.window));
+             return FALSE;
+           }
+ 
+@@ -417,8 +420,9 @@ meta_stack_op_apply (MetaStackTracker *tracker,
+             above_pos = find_window (stack, op->raise_above.sibling);
+             if (above_pos < 0)
+               {
+-                g_warning ("STACK_OP_RAISE_ABOVE: sibling window %s not in stack",
+-                           get_window_desc (tracker, op->raise_above.sibling));
++                meta_topic (META_DEBUG_STACK,
++                            "STACK_OP_RAISE_ABOVE: sibling window %s not in stack",
++                            get_window_desc (tracker, op->raise_above.sibling));
+                 return FALSE;
+               }
+           }
+@@ -438,8 +442,9 @@ meta_stack_op_apply (MetaStackTracker *tracker,
+         old_pos = find_window (stack, op->raise_above.window);
+         if (old_pos < 0)
+           {
+-            g_warning ("STACK_OP_LOWER_BELOW: window %s not in stack",
+-                       get_window_desc (tracker, op->lower_below.window));
++            meta_topic (META_DEBUG_STACK,
++                        "STACK_OP_LOWER_BELOW: window %s not in stack",
++                        get_window_desc (tracker, op->lower_below.window));
+             return FALSE;
+           }
+ 
+@@ -450,8 +455,9 @@ meta_stack_op_apply (MetaStackTracker *tracker,
+             below_pos = find_window (stack, op->lower_below.sibling);
+             if (below_pos < 0)
+               {
+-                g_warning ("STACK_OP_LOWER_BELOW: sibling window %s not in stack",
+-                           get_window_desc (tracker, op->lower_below.sibling));
++                meta_topic (META_DEBUG_STACK,
++                            "STACK_OP_LOWER_BELOW: sibling window %s not in stack",
++                            get_window_desc (tracker, op->lower_below.sibling));
+                 return FALSE;
+               }
+ 
+-- 
+2.26.2
+
diff --git a/SOURCES/0003-barriers-Free-backend-implementation-at-dispose-time.patch b/SOURCES/0003-barriers-Free-backend-implementation-at-dispose-time.patch
new file mode 100644
index 0000000..cdf21de
--- /dev/null
+++ b/SOURCES/0003-barriers-Free-backend-implementation-at-dispose-time.patch
@@ -0,0 +1,96 @@
+From ba76ed7d519a45b7f9b331a28e0617b919c9805e Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode@redhat.com>
+Date: Fri, 25 Sep 2020 14:04:31 -0400
+Subject: [PATCH 3/4] barriers: Free backend implementation at dispose time
+
+When a MetaBarrier is first created it allocates a backend
+impl object which does the actual heavy lifting.
+
+Unfortunately, that backend object is never freed.
+
+This commit ensures the implementation gets freed when
+the barrier object is freed.
+
+https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1451
+---
+ src/backends/meta-barrier.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/backends/meta-barrier.c b/src/backends/meta-barrier.c
+index 2353ef150..65abf7cab 100644
+--- a/src/backends/meta-barrier.c
++++ b/src/backends/meta-barrier.c
+@@ -94,67 +94,70 @@ meta_barrier_set_property (GObject      *object,
+     {
+     case PROP_DISPLAY:
+       priv->display = g_value_get_object (value);
+       break;
+     case PROP_X1:
+       priv->border.line.a.x = g_value_get_int (value);
+       break;
+     case PROP_Y1:
+       priv->border.line.a.y = g_value_get_int (value);
+       break;
+     case PROP_X2:
+       priv->border.line.b.x = g_value_get_int (value);
+       break;
+     case PROP_Y2:
+       priv->border.line.b.y = g_value_get_int (value);
+       break;
+     case PROP_DIRECTIONS:
+       meta_border_set_allows_directions (&priv->border,
+                                          g_value_get_flags (value));
+       break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       break;
+     }
+ }
+ 
+ static void
+ meta_barrier_dispose (GObject *object)
+ {
+   MetaBarrier *barrier = META_BARRIER (object);
++  MetaBarrierPrivate *priv = barrier->priv;
+ 
+   if (meta_barrier_is_active (barrier))
+     {
+       meta_bug ("MetaBarrier %p was destroyed while it was still active.",
+                 barrier);
+     }
+ 
++  g_clear_object (&priv->impl);
++
+   G_OBJECT_CLASS (meta_barrier_parent_class)->dispose (object);
+ }
+ 
+ gboolean
+ meta_barrier_is_active (MetaBarrier *barrier)
+ {
+   MetaBarrierImpl *impl = barrier->priv->impl;
+ 
+   if (impl)
+     return META_BARRIER_IMPL_GET_CLASS (impl)->is_active (impl);
+   else
+     return FALSE;
+ }
+ 
+ /**
+  * meta_barrier_release:
+  * @barrier: The barrier to release
+  * @event: The event to release the pointer for
+  *
+  * In XI2.3, pointer barriers provide a feature where they can
+  * be temporarily released so that the pointer goes through
+  * them. Pass a #MetaBarrierEvent to release the barrier for
+  * this event sequence.
+  */
+ void
+ meta_barrier_release (MetaBarrier      *barrier,
+                       MetaBarrierEvent *event)
+ {
+   MetaBarrierImpl *impl = barrier->priv->impl;
+ 
+-- 
+2.26.2
+
diff --git a/SOURCES/0003-cogl-vertex-buffer-Don-t-try-to-use-free-d-data.patch b/SOURCES/0003-cogl-vertex-buffer-Don-t-try-to-use-free-d-data.patch
new file mode 100644
index 0000000..f71de9a
--- /dev/null
+++ b/SOURCES/0003-cogl-vertex-buffer-Don-t-try-to-use-free-d-data.patch
@@ -0,0 +1,91 @@
+From 7e516f6348505c28c48aed8d21e6194cd1d5cee1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Tue, 9 Jul 2019 16:12:33 +0200
+Subject: [PATCH 03/28] cogl/vertex-buffer: Don't try to use free'd data
+
+set_attribute_enable might try to warn using cogl_attribute_name after that has
+been free'd.
+
+Avoid this using an auto-pointer.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ cogl/cogl/deprecated/cogl-vertex-buffer.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/cogl/cogl/deprecated/cogl-vertex-buffer.c b/cogl/cogl/deprecated/cogl-vertex-buffer.c
+index cf6e51ea2..59381dc56 100644
+--- a/cogl/cogl/deprecated/cogl-vertex-buffer.c
++++ b/cogl/cogl/deprecated/cogl-vertex-buffer.c
+@@ -590,66 +590,65 @@ cogl_vertex_buffer_delete (CoglHandle handle,
+ 
+   /* The submit function works by diffing between submitted_attributes
+    * and new_attributes to minimize the upload bandwidth + cost of
+    * allocating new VBOs, so if there isn't already a list of new_attributes
+    * we create one: */
+   if (!buffer->new_attributes)
+     buffer->new_attributes = copy_submitted_attributes_list (buffer);
+ 
+   for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next)
+     {
+       CoglVertexBufferAttrib *submitted_attribute = tmp->data;
+       if (submitted_attribute->name == name)
+ 	{
+ 	  buffer->new_attributes =
+ 	    g_list_delete_link (buffer->new_attributes, tmp);
+           _cogl_vertex_buffer_attrib_free (submitted_attribute);
+ 	  return;
+ 	}
+     }
+ 
+   g_warning ("Failed to find an attribute named %s to delete\n",
+ 	     attribute_name);
+ }
+ 
+ static void
+ set_attribute_enable (CoglHandle handle,
+ 		      const char *attribute_name,
+ 		      CoglBool state)
+ {
+   CoglVertexBuffer *buffer;
+-  char *cogl_attribute_name = canonize_attribute_name (attribute_name);
++  g_autofree char *cogl_attribute_name =
++    canonize_attribute_name (attribute_name);
+   GQuark name_quark = g_quark_from_string (cogl_attribute_name);
+   GList *tmp;
+ 
+-  g_free (cogl_attribute_name);
+-
+   if (!cogl_is_vertex_buffer (handle))
+     return;
+ 
+   buffer = handle;
+   buffer->dirty_attributes = TRUE;
+ 
+   /* NB: If a buffer is currently being edited, then there can be two seperate
+    * lists of attributes; those that are currently submitted and a new list yet
+    * to be submitted, we need to modify both. */
+ 
+   for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next)
+     {
+       CoglVertexBufferAttrib *attribute = tmp->data;
+       if (attribute->name == name_quark)
+ 	{
+ 	  if (state)
+ 	    attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED;
+ 	  else
+ 	    attribute->flags &= ~COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED;
+ 	  break;
+ 	}
+     }
+ 
+   for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next)
+     {
+       CoglVertexBufferVBO *cogl_vbo = tmp->data;
+       GList *tmp2;
+ 
+       for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next)
+ 	{
+-- 
+2.26.2
+
diff --git a/SOURCES/0004-cogl-onscreen-template-Unref-the-swap-chain.patch b/SOURCES/0004-cogl-onscreen-template-Unref-the-swap-chain.patch
new file mode 100644
index 0000000..0e2b381
--- /dev/null
+++ b/SOURCES/0004-cogl-onscreen-template-Unref-the-swap-chain.patch
@@ -0,0 +1,83 @@
+From bc80ae3c807287597da8c673447311807ae4ce15 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Wed, 10 Jul 2019 15:38:56 +0200
+Subject: [PATCH 04/28] cogl/onscreen-template: Unref the swap chain
+
+Each onscreen template owns a swap chain, but this is not released once on free
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ cogl/cogl/cogl-onscreen-template.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/cogl/cogl/cogl-onscreen-template.c b/cogl/cogl/cogl-onscreen-template.c
+index 1adbf4128..6ca176755 100644
+--- a/cogl/cogl/cogl-onscreen-template.c
++++ b/cogl/cogl/cogl-onscreen-template.c
+@@ -22,60 +22,63 @@
+  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  * SOFTWARE.
+  *
+  * Authors:
+  *   Robert Bragg <robert@linux.intel.com>
+  */
+ 
+ #ifdef HAVE_CONFIG_H
+ #include "cogl-config.h"
+ #endif
+ 
+ #include "cogl-object.h"
+ 
+ #include "cogl-framebuffer-private.h"
+ #include "cogl-onscreen-template-private.h"
+ #include "cogl-gtype-private.h"
+ 
+ #include <stdlib.h>
+ 
+ static void _cogl_onscreen_template_free (CoglOnscreenTemplate *onscreen_template);
+ 
+ COGL_OBJECT_DEFINE (OnscreenTemplate, onscreen_template);
+ COGL_GTYPE_DEFINE_CLASS (OnscreenTemplate, onscreen_template);
+ 
+ static void
+ _cogl_onscreen_template_free (CoglOnscreenTemplate *onscreen_template)
+ {
++  if (onscreen_template->config.swap_chain)
++    cogl_object_unref (onscreen_template->config.swap_chain);
++
+   g_slice_free (CoglOnscreenTemplate, onscreen_template);
+ }
+ 
+ CoglOnscreenTemplate *
+ cogl_onscreen_template_new (CoglSwapChain *swap_chain)
+ {
+   CoglOnscreenTemplate *onscreen_template = g_slice_new0 (CoglOnscreenTemplate);
+   char *user_config;
+ 
+   onscreen_template->config.swap_chain = swap_chain;
+   if (swap_chain)
+     cogl_object_ref (swap_chain);
+   else
+     onscreen_template->config.swap_chain = cogl_swap_chain_new ();
+ 
+   onscreen_template->config.swap_throttled = TRUE;
+   onscreen_template->config.need_stencil = TRUE;
+   onscreen_template->config.samples_per_pixel = 0;
+ 
+   user_config = getenv ("COGL_POINT_SAMPLES_PER_PIXEL");
+   if (user_config)
+     {
+       unsigned long samples_per_pixel = strtoul (user_config, NULL, 10);
+       if (samples_per_pixel != ULONG_MAX)
+         onscreen_template->config.samples_per_pixel =
+           samples_per_pixel;
+     }
+ 
+   return _cogl_onscreen_template_object_new (onscreen_template);
+ }
+-- 
+2.26.2
+
diff --git a/SOURCES/0004-src-Export-MetaWaylandX11-to-introspection.patch b/SOURCES/0004-src-Export-MetaWaylandX11-to-introspection.patch
new file mode 100644
index 0000000..773b02c
--- /dev/null
+++ b/SOURCES/0004-src-Export-MetaWaylandX11-to-introspection.patch
@@ -0,0 +1,79 @@
+From a2e8cf329ba80ea43864829f8d95f3e2b751e579 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode@redhat.com>
+Date: Wed, 14 Oct 2020 14:20:33 -0400
+Subject: [PATCH 4/4] src: Export MetaWaylandX11 to introspection
+
+This avoids a harmless warning at startup for gnome-shell
+---
+ src/Makefile.am | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 8b21d2f6c..56761727e 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -535,60 +535,61 @@ libmutterinclude_headers =			\
+ 	meta/errors.h				\
+ 	meta/group.h				\
+ 	meta/keybindings.h			\
+ 	meta/main.h				\
+ 	meta/meta-backend.h			\
+ 	meta/meta-background.h			\
+ 	meta/meta-background-actor.h		\
+ 	meta/meta-background-image.h		\
+ 	meta/meta-background-group.h		\
+ 	meta/meta-close-dialog.h		\
+ 	meta/meta-inhibit-shortcuts-dialog.h	\
+ 	meta/meta-cursor-tracker.h		\
+ 	meta/meta-dnd.h			\
+ 	meta/meta-idle-monitor.h		\
+ 	meta/meta-plugin.h			\
+ 	meta/meta-monitor-manager.h		\
+ 	meta/meta-settings.h			\
+ 	meta/meta-shaped-texture.h		\
+ 	meta/meta-shadow-factory.h		\
+ 	meta/meta-stage.h			\
+ 	meta/meta-window-actor.h		\
+ 	meta/meta-window-group.h		\
+ 	meta/meta-window-shape.h		\
+ 	meta/prefs.h				\
+ 	meta/screen.h				\
+ 	meta/theme.h				\
+ 	meta/types.h				\
+ 	meta/util.h				\
+ 	meta/window.h				\
+ 	meta/workspace.h			\
++	x11/window-x11.h                        \
+ 	$(NULL)
+ 
+ libmutterinclude_built_headers =		\
+ 	meta/meta-version.h			\
+ 	meta/meta-enum-types.h			\
+ 	$(NULL)
+ 
+ libmutterinclude_base_headers =			\
+ 	$(libmutterinclude_headers)		\
+ 	$(libmutterinclude_built_headers)
+ 
+ libmutterincludedir = $(includedir)/mutter/meta
+ 
+ libmutterinclude_HEADERS =			\
+ 	$(libmutterinclude_headers)
+ 
+ nodist_libmutterinclude_HEADERS =		\
+ 	$(libmutterinclude_built_headers)
+ 
+ bin_PROGRAMS=mutter
+ noinst_PROGRAMS=
+ 
+ mutter_SOURCES = core/mutter.c
+ mutter_LDADD = $(MUTTER_LIBS) libmutter-@LIBMUTTER_API_VERSION@.la
+ 
+ libexec_PROGRAMS = mutter-restart-helper
+ mutter_restart_helper_SOURCES = core/restart-helper.c
+ mutter_restart_helper_LDADD = $(MUTTER_LIBS)
+ 
+ include Makefile-tests.am
+-- 
+2.26.2
+
diff --git a/SOURCES/0005-cogl-framebuffer-Unref-the-config-swap-chain-if-set.patch b/SOURCES/0005-cogl-framebuffer-Unref-the-config-swap-chain-if-set.patch
new file mode 100644
index 0000000..7891953
--- /dev/null
+++ b/SOURCES/0005-cogl-framebuffer-Unref-the-config-swap-chain-if-set.patch
@@ -0,0 +1,87 @@
+From cec68590283dd7f9905695c8f52dc7d93d8f2350 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Wed, 24 Jul 2019 16:45:15 +0200
+Subject: [PATCH 05/28] cogl/framebuffer: Unref the config swap chain if set
+
+When initializing an onscreen through _cogl_onscreen_init_from_template, we set
+the framebuffer config swap_chain and ref it.
+However we don't unref it on destruction.
+
+So, unref it if set when freeing the framebuffer
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ cogl/cogl/cogl-framebuffer.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/cogl/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c
+index 6b105087d..3a107a2e2 100644
+--- a/cogl/cogl/cogl-framebuffer.c
++++ b/cogl/cogl/cogl-framebuffer.c
+@@ -168,60 +168,63 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
+   ctx->framebuffers = g_list_prepend (ctx->framebuffers, framebuffer);
+ }
+ 
+ void
+ _cogl_framebuffer_set_internal_format (CoglFramebuffer *framebuffer,
+                                        CoglPixelFormat internal_format)
+ {
+   framebuffer->internal_format = internal_format;
+ }
+ 
+ void
+ _cogl_framebuffer_free (CoglFramebuffer *framebuffer)
+ {
+   CoglContext *ctx = framebuffer->context;
+ 
+   _cogl_fence_cancel_fences_for_framebuffer (framebuffer);
+ 
+   _cogl_clip_stack_unref (framebuffer->clip_stack);
+ 
+   cogl_object_unref (framebuffer->modelview_stack);
+   framebuffer->modelview_stack = NULL;
+ 
+   cogl_object_unref (framebuffer->projection_stack);
+   framebuffer->projection_stack = NULL;
+ 
+   cogl_object_unref (framebuffer->journal);
+ 
+   if (ctx->viewport_scissor_workaround_framebuffer == framebuffer)
+     ctx->viewport_scissor_workaround_framebuffer = NULL;
+ 
++  if (framebuffer->config.swap_chain)
++    cogl_object_unref (framebuffer->config.swap_chain);
++
+   ctx->framebuffers = g_list_remove (ctx->framebuffers, framebuffer);
+ 
+   if (ctx->current_draw_buffer == framebuffer)
+     ctx->current_draw_buffer = NULL;
+   if (ctx->current_read_buffer == framebuffer)
+     ctx->current_read_buffer = NULL;
+ }
+ 
+ const CoglWinsysVtable *
+ _cogl_framebuffer_get_winsys (CoglFramebuffer *framebuffer)
+ {
+   return framebuffer->context->display->renderer->winsys_vtable;
+ }
+ 
+ /* This version of cogl_clear can be used internally as an alternative
+  * to avoid flushing the journal or the framebuffer state. This is
+  * needed when doing operations that may be called whiling flushing
+  * the journal */
+ void
+ _cogl_framebuffer_clear_without_flush4f (CoglFramebuffer *framebuffer,
+                                          unsigned long buffers,
+                                          float red,
+                                          float green,
+                                          float blue,
+                                          float alpha)
+ {
+   CoglContext *ctx = framebuffer->context;
+ 
+   if (!buffers)
+     {
+-- 
+2.26.2
+
diff --git a/SOURCES/0006-clutter-backend-Use-an-auto-pointer-to-handle-the-te.patch b/SOURCES/0006-clutter-backend-Use-an-auto-pointer-to-handle-the-te.patch
new file mode 100644
index 0000000..e3e0a64
--- /dev/null
+++ b/SOURCES/0006-clutter-backend-Use-an-auto-pointer-to-handle-the-te.patch
@@ -0,0 +1,105 @@
+From bfd1c16e87cf9f90e8fe039b4bab400c68fb68a2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Wed, 24 Jul 2019 16:49:38 +0200
+Subject: [PATCH 06/28] clutter/backend: Use an auto-pointer to handle the
+ template on creation
+
+We allocate a CoglOnscreenTemplate but this is not unreffed if we have an error,
+so let's just use an auto-pointer to manage its lifecycle.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ clutter/clutter/clutter-backend.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/clutter/clutter/clutter-backend.c b/clutter/clutter/clutter-backend.c
+index 30ebe5ef1..69aeec5eb 100644
+--- a/clutter/clutter/clutter-backend.c
++++ b/clutter/clutter/clutter-backend.c
+@@ -234,81 +234,79 @@ clutter_backend_do_real_create_context (ClutterBackend  *backend,
+ 
+   klass = CLUTTER_BACKEND_GET_CLASS (backend);
+ 
+   swap_chain = NULL;
+   internal_error = NULL;
+ 
+   CLUTTER_NOTE (BACKEND, "Creating Cogl renderer");
+   backend->cogl_renderer = klass->get_renderer (backend, &internal_error);
+ 
+   if (backend->cogl_renderer == NULL)
+     goto error;
+ 
+   CLUTTER_NOTE (BACKEND, "Connecting the renderer");
+   cogl_renderer_set_driver (backend->cogl_renderer, driver_id);
+   if (!cogl_renderer_connect (backend->cogl_renderer, &internal_error))
+     goto error;
+ 
+   CLUTTER_NOTE (BACKEND, "Creating Cogl swap chain");
+   swap_chain = cogl_swap_chain_new ();
+ 
+   CLUTTER_NOTE (BACKEND, "Creating Cogl display");
+   if (klass->get_display != NULL)
+     {
+       backend->cogl_display = klass->get_display (backend,
+                                                   backend->cogl_renderer,
+                                                   swap_chain,
+                                                   &internal_error);
+     }
+   else
+     {
+-      CoglOnscreenTemplate *tmpl;
++      g_autoptr (CoglOnscreenTemplate) tmpl = NULL;
+       gboolean res;
+ 
+       tmpl = cogl_onscreen_template_new (swap_chain);
+ 
+       /* XXX: I have some doubts that this is a good design.
+        *
+        * Conceptually should we be able to check an onscreen_template
+        * without more details about the CoglDisplay configuration?
+        */
+       res = cogl_renderer_check_onscreen_template (backend->cogl_renderer,
+                                                    tmpl,
+                                                    &internal_error);
+ 
+       if (!res)
+         goto error;
+ 
+-      backend->cogl_display = cogl_display_new (backend->cogl_renderer, tmpl);
+-
+       /* the display owns the template */
+-      cogl_object_unref (tmpl);
++      backend->cogl_display = cogl_display_new (backend->cogl_renderer, tmpl);
+     }
+ 
+   if (backend->cogl_display == NULL)
+     goto error;
+ 
+ #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
+   cogl_wayland_display_set_compositor_display (backend->cogl_display,
+                                                _wayland_compositor_display);
+ #endif
+ 
+   CLUTTER_NOTE (BACKEND, "Setting up the display");
+   if (!cogl_display_setup (backend->cogl_display, &internal_error))
+     goto error;
+ 
+   CLUTTER_NOTE (BACKEND, "Creating the Cogl context");
+   backend->cogl_context = cogl_context_new (backend->cogl_display, &internal_error);
+   if (backend->cogl_context == NULL)
+     goto error;
+ 
+   /* the display owns the renderer and the swap chain */
+   cogl_object_unref (backend->cogl_renderer);
+   cogl_object_unref (swap_chain);
+ 
+   return TRUE;
+ 
+ error:
+   if (backend->cogl_display != NULL)
+     {
+       cogl_object_unref (backend->cogl_display);
+       backend->cogl_display = NULL;
+-- 
+2.26.2
+
diff --git a/SOURCES/0007-clutter-Keep-a-device-reference-with-events.patch b/SOURCES/0007-clutter-Keep-a-device-reference-with-events.patch
new file mode 100644
index 0000000..3905c2a
--- /dev/null
+++ b/SOURCES/0007-clutter-Keep-a-device-reference-with-events.patch
@@ -0,0 +1,284 @@
+From dfd79cf19dcebf283bd884dded8efc83e449016d Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <ofourdan@redhat.com>
+Date: Mon, 19 Nov 2018 11:25:57 +0100
+Subject: [PATCH 07/28] clutter: Keep a device reference with events
+
+If a device (virtual or real) is removed while there are remaining
+events queued for that device, the event loop may try to access the
+event freed memory.
+
+To avoid the issue, add a reference to the device when the event is
+created or copied, and remove the reference once the device is freed.
+
+Closes: https://gitlab.gnome.org/GNOME/mutter/issues/393
+---
+ clutter/clutter/clutter-event.c | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/clutter/clutter/clutter-event.c b/clutter/clutter/clutter-event.c
+index 10b6c0082..1b21b6a97 100644
+--- a/clutter/clutter/clutter-event.c
++++ b/clutter/clutter/clutter-event.c
+@@ -1068,61 +1068,61 @@ clutter_event_get_device_type (const ClutterEvent *event)
+ 
+   g_return_val_if_fail (event != NULL, CLUTTER_POINTER_DEVICE);
+ 
+   device = clutter_event_get_device (event);
+   if (device != NULL)
+     return clutter_input_device_get_device_type (device);
+ 
+   return CLUTTER_POINTER_DEVICE;
+ }
+ 
+ /**
+  * clutter_event_set_device:
+  * @event: a #ClutterEvent
+  * @device: (allow-none): a #ClutterInputDevice, or %NULL
+  *
+  * Sets the device for @event.
+  *
+  * Since: 1.6
+  */
+ void
+ clutter_event_set_device (ClutterEvent       *event,
+                           ClutterInputDevice *device)
+ {
+   g_return_if_fail (event != NULL);
+   g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device));
+ 
+   if (is_event_allocated (event))
+     {
+       ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
+ 
+-      real_event->device = device;
++      g_set_object (&real_event->device, device);
+     }
+ 
+   switch (event->type)
+     {
+     case CLUTTER_NOTHING:
+     case CLUTTER_STAGE_STATE:
+     case CLUTTER_DESTROY_NOTIFY:
+     case CLUTTER_CLIENT_MESSAGE:
+     case CLUTTER_DELETE:
+     case CLUTTER_EVENT_LAST:
+       break;
+ 
+     case CLUTTER_ENTER:
+     case CLUTTER_LEAVE:
+       event->crossing.device = device;
+       break;
+ 
+     case CLUTTER_BUTTON_PRESS:
+     case CLUTTER_BUTTON_RELEASE:
+       event->button.device = device;
+       break;
+ 
+     case CLUTTER_MOTION:
+       event->motion.device = device;
+       break;
+ 
+     case CLUTTER_SCROLL:
+       event->scroll.device = device;
+       break;
+ 
+@@ -1337,62 +1337,62 @@ clutter_event_new (ClutterEventType type)
+   return new_event;
+ }
+ 
+ /**
+  * clutter_event_copy:
+  * @event: A #ClutterEvent.
+  *
+  * Copies @event.
+  *
+  * Return value: (transfer full): A newly allocated #ClutterEvent
+  */
+ ClutterEvent *
+ clutter_event_copy (const ClutterEvent *event)
+ {
+   ClutterEvent *new_event;
+   ClutterEventPrivate *new_real_event;
+   ClutterInputDevice *device;
+   gint n_axes = 0;
+ 
+   g_return_val_if_fail (event != NULL, NULL);
+ 
+   new_event = clutter_event_new (CLUTTER_NOTHING);
+   new_real_event = (ClutterEventPrivate *) new_event;
+ 
+   *new_event = *event;
+ 
+   if (is_event_allocated (event))
+     {
+       ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
+ 
+-      new_real_event->device = real_event->device;
+-      new_real_event->source_device = real_event->source_device;
++      g_set_object (&new_real_event->device, real_event->device);
++      g_set_object (&new_real_event->source_device, real_event->source_device);
+       new_real_event->delta_x = real_event->delta_x;
+       new_real_event->delta_y = real_event->delta_y;
+       new_real_event->is_pointer_emulated = real_event->is_pointer_emulated;
+       new_real_event->base_state = real_event->base_state;
+       new_real_event->button_state = real_event->button_state;
+       new_real_event->latched_state = real_event->latched_state;
+       new_real_event->locked_state = real_event->locked_state;
+       new_real_event->tool = real_event->tool;
+     }
+ 
+   device = clutter_event_get_device (event);
+   if (device != NULL)
+     n_axes = clutter_input_device_get_n_axes (device);
+ 
+   switch (event->type)
+     {
+     case CLUTTER_BUTTON_PRESS:
+     case CLUTTER_BUTTON_RELEASE:
+       if (event->button.axes != NULL)
+         new_event->button.axes = g_memdup (event->button.axes,
+                                            sizeof (gdouble) * n_axes);
+       break;
+ 
+     case CLUTTER_SCROLL:
+       if (event->scroll.axes != NULL)
+         new_event->scroll.axes = g_memdup (event->scroll.axes,
+                                            sizeof (gdouble) * n_axes);
+       break;
+ 
+     case CLUTTER_MOTION:
+@@ -1408,60 +1408,68 @@ clutter_event_copy (const ClutterEvent *event)
+       if (event->touch.axes != NULL)
+         new_event->touch.axes = g_memdup (event->touch.axes,
+                                           sizeof (gdouble) * n_axes);
+       break;
+ 
+     default:
+       break;
+     }
+ 
+   if (is_event_allocated (event))
+     _clutter_backend_copy_event_data (clutter_get_default_backend (),
+                                       event,
+                                       new_event);
+ 
+   return new_event;
+ }
+ 
+ /**
+  * clutter_event_free:
+  * @event: A #ClutterEvent.
+  *
+  * Frees all resources used by @event.
+  */
+ void
+ clutter_event_free (ClutterEvent *event)
+ {
+   if (G_LIKELY (event != NULL))
+     {
+       _clutter_backend_free_event_data (clutter_get_default_backend (), event);
+ 
++      if (is_event_allocated (event))
++        {
++          ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
++
++          g_clear_object (&real_event->device);
++          g_clear_object (&real_event->source_device);
++        }
++
+       switch (event->type)
+         {
+         case CLUTTER_BUTTON_PRESS:
+         case CLUTTER_BUTTON_RELEASE:
+           g_free (event->button.axes);
+           break;
+ 
+         case CLUTTER_MOTION:
+           g_free (event->motion.axes);
+           break;
+ 
+         case CLUTTER_SCROLL:
+           g_free (event->scroll.axes);
+           break;
+ 
+         case CLUTTER_TOUCH_BEGIN:
+         case CLUTTER_TOUCH_UPDATE:
+         case CLUTTER_TOUCH_END:
+         case CLUTTER_TOUCH_CANCEL:
+           g_free (event->touch.axes);
+           break;
+ 
+         default:
+           break;
+         }
+ 
+       g_hash_table_remove (all_events, event);
+       g_slice_free (ClutterEventPrivate, (ClutterEventPrivate *) event);
+     }
+ }
+@@ -1662,61 +1670,61 @@ clutter_event_get_source_device (const ClutterEvent *event)
+   if (real_event->source_device != NULL)
+     return real_event->source_device;
+ 
+   return clutter_event_get_device (event);
+ }
+ 
+ /**
+  * clutter_event_set_source_device:
+  * @event: a #ClutterEvent
+  * @device: (allow-none): a #ClutterInputDevice
+  *
+  * Sets the source #ClutterInputDevice for @event.
+  *
+  * The #ClutterEvent must have been created using clutter_event_new().
+  *
+  * Since: 1.8
+  */
+ void
+ clutter_event_set_source_device (ClutterEvent       *event,
+                                  ClutterInputDevice *device)
+ {
+   ClutterEventPrivate *real_event;
+ 
+   g_return_if_fail (event != NULL);
+   g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device));
+ 
+   if (!is_event_allocated (event))
+     return;
+ 
+   real_event = (ClutterEventPrivate *) event;
+-  real_event->source_device = device;
++  g_set_object (&real_event->source_device, device);
+ }
+ 
+ /**
+  * clutter_event_get_axes:
+  * @event: a #ClutterEvent
+  * @n_axes: (out): return location for the number of axes returned
+  *
+  * Retrieves the array of axes values attached to the event.
+  *
+  * Return value: (transfer none): an array of axis values
+  *
+  * Since: 1.6
+  */
+ gdouble *
+ clutter_event_get_axes (const ClutterEvent *event,
+                         guint              *n_axes)
+ {
+   gdouble *retval = NULL;
+   guint len = 0;
+ 
+   switch (event->type)
+     {
+     case CLUTTER_NOTHING:
+     case CLUTTER_STAGE_STATE:
+     case CLUTTER_DESTROY_NOTIFY:
+     case CLUTTER_CLIENT_MESSAGE:
+     case CLUTTER_DELETE:
+     case CLUTTER_ENTER:
+     case CLUTTER_LEAVE:
+     case CLUTTER_KEY_PRESS:
+-- 
+2.26.2
+
diff --git a/SOURCES/0008-clutter-event-Use-all-events-Hash-table-as-a-Set-wit.patch b/SOURCES/0008-clutter-event-Use-all-events-Hash-table-as-a-Set-wit.patch
new file mode 100644
index 0000000..aef85ec
--- /dev/null
+++ b/SOURCES/0008-clutter-event-Use-all-events-Hash-table-as-a-Set-wit.patch
@@ -0,0 +1,801 @@
+From 1a5275cdb099e3b15f82cabdd55d2eb6c5196c39 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Thu, 11 Jul 2019 13:32:01 +0200
+Subject: [PATCH 08/28] clutter/event: Use all-events Hash table as a Set with
+ auto deletion
+
+Avoid allocating memory for the value, since we don't use it, just add the key
+to the table, and check for its presence.
+
+Use a custom free function to free the event data and unref the GOBjects, so
+that in clutter_event_free we don't have to both check for the event presence
+in the set, clear the data and eventually remove it from the table, but we
+can just rely on a single g_hash_table_remove() call.
+
+This required to change the event data free/copy functions signatures so that
+we can pass to them the platform data directly, otherwise we might try to call
+get_platform_data on an even that has already been removed from the table, and
+thus that is not considered allocated anymore, causing a leak.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ clutter/clutter/clutter-backend-private.h     | 16 +++----
+ clutter/clutter/clutter-backend.c             | 21 ++++-----
+ .../clutter/clutter-device-manager-private.h  |  7 ++-
+ clutter/clutter/clutter-event.c               | 45 +++++++++++--------
+ .../evdev/clutter-device-manager-evdev.c      | 15 +++----
+ .../clutter/x11/clutter-device-manager-xi2.c  | 17 +++----
+ 6 files changed, 60 insertions(+), 61 deletions(-)
+
+diff --git a/clutter/clutter/clutter-backend-private.h b/clutter/clutter/clutter-backend-private.h
+index 864d896a3..2438f83e1 100644
+--- a/clutter/clutter/clutter-backend-private.h
++++ b/clutter/clutter/clutter-backend-private.h
+@@ -63,100 +63,98 @@ struct _ClutterBackend
+ };
+ 
+ struct _ClutterBackendClass
+ {
+   /*< private >*/
+   GObjectClass parent_class;
+ 
+   /* vfuncs */
+   gboolean              (* pre_parse)          (ClutterBackend  *backend,
+                                                 GError         **error);
+   gboolean              (* post_parse)         (ClutterBackend  *backend,
+                                                 GError         **error);
+   ClutterStageWindow *  (* create_stage)       (ClutterBackend  *backend,
+                                                 ClutterStage    *wrapper,
+                                                 GError         **error);
+   void                  (* init_events)        (ClutterBackend  *backend);
+   void                  (* init_features)      (ClutterBackend  *backend);
+   void                  (* add_options)        (ClutterBackend  *backend,
+                                                 GOptionGroup    *group);
+   ClutterFeatureFlags   (* get_features)       (ClutterBackend  *backend);
+   CoglRenderer *        (* get_renderer)       (ClutterBackend  *backend,
+                                                 GError         **error);
+   CoglDisplay *         (* get_display)        (ClutterBackend  *backend,
+                                                 CoglRenderer    *renderer,
+                                                 CoglSwapChain   *swap_chain,
+                                                 GError         **error);
+   gboolean              (* create_context)     (ClutterBackend  *backend,
+                                                 GError         **error);
+   ClutterDeviceManager *(* get_device_manager) (ClutterBackend  *backend);
+ 
+-  void                  (* copy_event_data)    (ClutterBackend     *backend,
+-                                                const ClutterEvent *src,
+-                                                ClutterEvent       *dest);
+-  void                  (* free_event_data)    (ClutterBackend     *backend,
+-                                                ClutterEvent       *event);
++  gpointer              (* copy_event_data)    (ClutterBackend *backend,
++                                                gpointer        data);
++  void                  (* free_event_data)    (ClutterBackend *backend,
++                                                gpointer        data);
+ 
+   gboolean              (* translate_event)    (ClutterBackend     *backend,
+                                                 gpointer            native,
+                                                 ClutterEvent       *event);
+ 
+   PangoDirection        (* get_keymap_direction) (ClutterBackend   *backend);
+ 
+   void                  (* bell_notify)          (ClutterBackend   *backend);
+ 
+   /* signals */
+   void (* resolution_changed) (ClutterBackend *backend);
+   void (* font_changed)       (ClutterBackend *backend);
+   void (* settings_changed)   (ClutterBackend *backend);
+ };
+ 
+ ClutterBackend *        _clutter_create_backend                         (void);
+ 
+ ClutterStageWindow *    _clutter_backend_create_stage                   (ClutterBackend         *backend,
+                                                                          ClutterStage           *wrapper,
+                                                                          GError                **error);
+ gboolean                _clutter_backend_create_context                 (ClutterBackend         *backend,
+                                                                          GError                **error);
+ 
+ void                    _clutter_backend_add_options                    (ClutterBackend         *backend,
+                                                                          GOptionGroup           *group);
+ gboolean                _clutter_backend_pre_parse                      (ClutterBackend         *backend,
+                                                                          GError                **error);
+ gboolean                _clutter_backend_post_parse                     (ClutterBackend         *backend,
+                                                                          GError                **error);
+ 
+ void                    _clutter_backend_init_events                    (ClutterBackend         *backend);
+-void                    _clutter_backend_copy_event_data                (ClutterBackend         *backend,
+-                                                                         const ClutterEvent     *src,
+-                                                                         ClutterEvent           *dest);
++gpointer                _clutter_backend_copy_event_data                (ClutterBackend         *backend,
++                                                                         const gpointer          data);
+ void                    _clutter_backend_free_event_data                (ClutterBackend         *backend,
+-                                                                         ClutterEvent           *event);
++                                                                         gpointer                data);
+ gboolean                _clutter_backend_translate_event                (ClutterBackend         *backend,
+                                                                          gpointer                native,
+                                                                          ClutterEvent           *event);
+ 
+ CLUTTER_AVAILABLE_IN_MUTTER
+ void                    _clutter_backend_add_event_translator           (ClutterBackend         *backend,
+                                                                          ClutterEventTranslator *translator);
+ 
+ void                    _clutter_backend_remove_event_translator        (ClutterBackend         *backend,
+                                                                          ClutterEventTranslator *translator);
+ 
+ ClutterFeatureFlags     _clutter_backend_get_features                   (ClutterBackend         *backend);
+ 
+ gfloat                  _clutter_backend_get_units_per_em               (ClutterBackend         *backend,
+                                                                          PangoFontDescription   *font_desc);
+ gint32                  _clutter_backend_get_units_serial               (ClutterBackend         *backend);
+ 
+ PangoDirection          _clutter_backend_get_keymap_direction           (ClutterBackend         *backend);
+ 
+ CLUTTER_AVAILABLE_IN_MUTTER
+ void                    _clutter_backend_reset_cogl_framebuffer         (ClutterBackend         *backend);
+ 
+ void                    clutter_set_allowed_drivers                     (const char             *drivers);
+ 
+ void                    clutter_try_set_windowing_backend               (const char             *drivers);
+ 
+ G_END_DECLS
+ 
+ #endif /* __CLUTTER_BACKEND_PRIVATE_H__ */
+diff --git a/clutter/clutter/clutter-backend.c b/clutter/clutter/clutter-backend.c
+index 69aeec5eb..41ea3daed 100644
+--- a/clutter/clutter/clutter-backend.c
++++ b/clutter/clutter/clutter-backend.c
+@@ -804,96 +804,97 @@ _clutter_backend_get_features (ClutterBackend *backend)
+     return klass->get_features (backend);
+   
+   return 0;
+ }
+ 
+ void
+ _clutter_backend_init_events (ClutterBackend *backend)
+ {
+   ClutterBackendClass *klass;
+ 
+   g_assert (CLUTTER_IS_BACKEND (backend));
+ 
+   klass = CLUTTER_BACKEND_GET_CLASS (backend);
+   klass->init_events (backend);
+ }
+ 
+ gfloat
+ _clutter_backend_get_units_per_em (ClutterBackend       *backend,
+                                    PangoFontDescription *font_desc)
+ {
+   /* recompute for the font description, but do not cache the result */
+   if (font_desc != NULL)
+     return get_units_per_em (backend, font_desc);
+ 
+   if (backend->units_per_em < 0)
+     backend->units_per_em = get_units_per_em (backend, NULL);
+ 
+   return backend->units_per_em;
+ }
+ 
+-void
+-_clutter_backend_copy_event_data (ClutterBackend     *backend,
+-                                  const ClutterEvent *src,
+-                                  ClutterEvent       *dest)
++gpointer
++_clutter_backend_copy_event_data (ClutterBackend *backend,
++                                  gpointer        data)
+ {
+   ClutterEventExtenderInterface *iface;
+   ClutterBackendClass *klass;
+ 
+   klass = CLUTTER_BACKEND_GET_CLASS (backend);
+   if (CLUTTER_IS_EVENT_EXTENDER (backend->device_manager))
+     {
+       iface = CLUTTER_EVENT_EXTENDER_GET_IFACE (backend->device_manager);
+-      iface->copy_event_data (CLUTTER_EVENT_EXTENDER (backend->device_manager),
+-                              src, dest);
++      return iface->copy_event_data (CLUTTER_EVENT_EXTENDER (backend->device_manager),
++                                     data);
+     }
+   else if (klass->copy_event_data != NULL)
+-    klass->copy_event_data (backend, src, dest);
++    return klass->copy_event_data (backend, data);
++
++  return NULL;
+ }
+ 
+ void
+ _clutter_backend_free_event_data (ClutterBackend *backend,
+-                                  ClutterEvent   *event)
++                                  gpointer        data)
+ {
+   ClutterEventExtenderInterface *iface;
+   ClutterBackendClass *klass;
+ 
+   klass = CLUTTER_BACKEND_GET_CLASS (backend);
+ 
+   if (CLUTTER_IS_EVENT_EXTENDER (backend->device_manager))
+     {
+       iface = CLUTTER_EVENT_EXTENDER_GET_IFACE (backend->device_manager);
+       iface->free_event_data (CLUTTER_EVENT_EXTENDER (backend->device_manager),
+-                              event);
++                              data);
+     }
+   else if (klass->free_event_data != NULL)
+-    klass->free_event_data (backend, event);
++    klass->free_event_data (backend, data);
+ }
+ 
+ /**
+  * clutter_get_default_backend:
+  *
+  * Retrieves the default #ClutterBackend used by Clutter. The
+  * #ClutterBackend holds backend-specific configuration options.
+  *
+  * Return value: (transfer none): the default backend. You should
+  *   not ref or unref the returned object. Applications should rarely
+  *   need to use this.
+  *
+  * Since: 0.4
+  */
+ ClutterBackend *
+ clutter_get_default_backend (void)
+ {
+   ClutterMainContext *clutter_context;
+ 
+   clutter_context = _clutter_context_get_default ();
+ 
+   return clutter_context->backend;
+ }
+ 
+ /**
+  * clutter_backend_set_double_click_time:
+  * @backend: a #ClutterBackend
+  * @msec: milliseconds between two button press events
+  *
+  * Sets the maximum time between two button press events, used to
+diff --git a/clutter/clutter/clutter-device-manager-private.h b/clutter/clutter/clutter-device-manager-private.h
+index 2364fd27c..6b2c20c72 100644
+--- a/clutter/clutter/clutter-device-manager-private.h
++++ b/clutter/clutter/clutter-device-manager-private.h
+@@ -159,65 +159,64 @@ struct _ClutterInputDeviceClass
+                              ClutterInputDeviceTool *tool);
+ 
+   gboolean (* is_mode_switch_button) (ClutterInputDevice *device,
+                                       guint               group,
+                                       guint               button);
+   gint (* get_group_n_modes) (ClutterInputDevice *device,
+                               gint                group);
+ 
+   gboolean (* is_grouped) (ClutterInputDevice *device,
+                            ClutterInputDevice *other_device);
+ 
+   /* Keyboard accessbility */
+   void (* process_kbd_a11y_event) (ClutterEvent               *event,
+                                    ClutterInputDevice         *device,
+                                    ClutterEmitInputDeviceEvent emit_event_func);
+ };
+ 
+ /* Platform-dependent interface */
+ typedef struct _ClutterEventExtender ClutterEventExtender;
+ typedef struct _ClutterEventExtenderInterface ClutterEventExtenderInterface;
+ 
+ #define CLUTTER_TYPE_EVENT_EXTENDER         (clutter_event_extender_get_type ())
+ #define CLUTTER_EVENT_EXTENDER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), CLUTTER_TYPE_EVENT_EXTENDER, ClutterEventExtender))
+ #define CLUTTER_IS_EVENT_EXTENDER(o)	     (G_TYPE_CHECK_INSTANCE_TYPE ((o), CLUTTER_TYPE_EVENT_EXTENDER))
+ #define CLUTTER_EVENT_EXTENDER_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), CLUTTER_TYPE_EVENT_EXTENDER, ClutterEventExtenderInterface))
+ 
+ struct _ClutterEventExtenderInterface
+ {
+   GTypeInterface g_iface;
+ 
+-  void (* copy_event_data) (ClutterEventExtender *event_extender,
+-                            const ClutterEvent   *src,
+-                            ClutterEvent         *dest);
++  gpointer (* copy_event_data) (ClutterEventExtender *event_extender,
++                                gpointer              data);
+   void (* free_event_data) (ClutterEventExtender *event_extender,
+-                            ClutterEvent         *event);
++                            gpointer              data);
+ };
+ 
+ GType           clutter_event_extender_get_type        (void) G_GNUC_CONST;
+ 
+ /* device manager */
+ void            _clutter_device_manager_add_device              (ClutterDeviceManager *device_manager,
+                                                                  ClutterInputDevice   *device);
+ void            _clutter_device_manager_remove_device           (ClutterDeviceManager *device_manager,
+                                                                  ClutterInputDevice   *device);
+ void            _clutter_device_manager_update_devices          (ClutterDeviceManager *device_manager);
+ void            _clutter_device_manager_select_stage_events     (ClutterDeviceManager *device_manager,
+                                                                  ClutterStage         *stage);
+ ClutterBackend *_clutter_device_manager_get_backend             (ClutterDeviceManager *device_manager);
+ 
+ void            _clutter_device_manager_compress_motion         (ClutterDeviceManager *device_manger,
+                                                                  ClutterEvent         *event,
+                                                                  const ClutterEvent   *to_discard);
+ 
+ /* input device */
+ gboolean        _clutter_input_device_has_sequence              (ClutterInputDevice   *device,
+                                                                  ClutterEventSequence *sequence);
+ void            _clutter_input_device_add_event_sequence        (ClutterInputDevice   *device,
+                                                                  ClutterEvent         *event);
+ void            _clutter_input_device_remove_event_sequence     (ClutterInputDevice   *device,
+                                                                  ClutterEvent         *event);
+ void            _clutter_input_device_set_coords                (ClutterInputDevice   *device,
+                                                                  ClutterEventSequence *sequence,
+                                                                  gfloat                x,
+                                                                  gfloat                y,
+                                                                  ClutterStage         *stage);
+diff --git a/clutter/clutter/clutter-event.c b/clutter/clutter/clutter-event.c
+index 1b21b6a97..60bdd325c 100644
+--- a/clutter/clutter/clutter-event.c
++++ b/clutter/clutter/clutter-event.c
+@@ -77,61 +77,73 @@ typedef struct _ClutterEventFilter {
+ 
+ static GHashTable *all_events = NULL;
+ 
+ G_DEFINE_BOXED_TYPE (ClutterEvent, clutter_event,
+                      clutter_event_copy,
+                      clutter_event_free);
+ 
+ static ClutterEventSequence *
+ clutter_event_sequence_copy (ClutterEventSequence *sequence)
+ {
+   /* Nothing to copy here */
+   return sequence;
+ }
+ 
+ static void
+ clutter_event_sequence_free (ClutterEventSequence *sequence)
+ {
+   /* Nothing to free here */
+ }
+ 
+ G_DEFINE_BOXED_TYPE (ClutterEventSequence, clutter_event_sequence,
+                      clutter_event_sequence_copy,
+                      clutter_event_sequence_free);
+ 
+ static gboolean
+ is_event_allocated (const ClutterEvent *event)
+ {
+   if (all_events == NULL)
+     return FALSE;
+ 
+-  return g_hash_table_lookup (all_events, event) != NULL;
++  return g_hash_table_contains (all_events, event);
++}
++
++static void
++clutter_event_private_data_free (ClutterEvent *event)
++{
++  ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
++
++  _clutter_backend_free_event_data (clutter_get_default_backend (),
++                                    real_event->platform_data);
++
++  g_clear_object (&real_event->device);
++  g_clear_object (&real_event->source_device);
+ }
+ 
+ /*
+  * _clutter_event_get_platform_data:
+  * @event: a #ClutterEvent
+  *
+  * Retrieves the pointer to platform-specific data inside an event
+  *
+  * Return value: a pointer to platform-specific data
+  *
+  * Since: 1.4
+  */
+ gpointer
+ _clutter_event_get_platform_data (const ClutterEvent *event)
+ {
+   if (!is_event_allocated (event))
+     return NULL;
+ 
+   return ((ClutterEventPrivate *) event)->platform_data;
+ }
+ 
+ /*< private >
+  * _clutter_event_set_platform_data:
+  * @event: a #ClutterEvent
+  * @data: a pointer to platform-specific data
+  *
+  * Sets the pointer to platform-specific data inside an event
+  *
+  * Since: 1.4
+  */
+@@ -1303,200 +1315,195 @@ clutter_event_get_device_tool (const ClutterEvent *event)
+   if (is_event_allocated (event))
+     {
+       ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
+ 
+       return real_event->tool;
+     }
+ 
+   return NULL;
+ }
+ 
+ /**
+  * clutter_event_new:
+  * @type: The type of event.
+  *
+  * Creates a new #ClutterEvent of the specified type.
+  *
+  * Return value: (transfer full): A newly allocated #ClutterEvent.
+  */
+ ClutterEvent *
+ clutter_event_new (ClutterEventType type)
+ {
+   ClutterEvent *new_event;
+   ClutterEventPrivate *priv;
+ 
+   priv = g_slice_new0 (ClutterEventPrivate);
+ 
+   new_event = (ClutterEvent *) priv;
+   new_event->type = new_event->any.type = type;
+ 
+   if (G_UNLIKELY (all_events == NULL))
+-    all_events = g_hash_table_new (NULL, NULL);
++    {
++      all_events =
++        g_hash_table_new_full (NULL, NULL,
++                               (GDestroyNotify) clutter_event_private_data_free,
++                               NULL);
++    }
+ 
+-  g_hash_table_replace (all_events, priv, GUINT_TO_POINTER (1));
++  g_hash_table_add (all_events, priv);
+ 
+   return new_event;
+ }
+ 
+ /**
+  * clutter_event_copy:
+  * @event: A #ClutterEvent.
+  *
+  * Copies @event.
+  *
+  * Return value: (transfer full): A newly allocated #ClutterEvent
+  */
+ ClutterEvent *
+ clutter_event_copy (const ClutterEvent *event)
+ {
+   ClutterEvent *new_event;
+   ClutterEventPrivate *new_real_event;
+   ClutterInputDevice *device;
+   gint n_axes = 0;
+ 
+   g_return_val_if_fail (event != NULL, NULL);
+ 
+   new_event = clutter_event_new (CLUTTER_NOTHING);
+   new_real_event = (ClutterEventPrivate *) new_event;
+ 
+   *new_event = *event;
+ 
+   if (is_event_allocated (event))
+     {
+       ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
+ 
+       g_set_object (&new_real_event->device, real_event->device);
+       g_set_object (&new_real_event->source_device, real_event->source_device);
+       new_real_event->delta_x = real_event->delta_x;
+       new_real_event->delta_y = real_event->delta_y;
+       new_real_event->is_pointer_emulated = real_event->is_pointer_emulated;
+       new_real_event->base_state = real_event->base_state;
+       new_real_event->button_state = real_event->button_state;
+       new_real_event->latched_state = real_event->latched_state;
+       new_real_event->locked_state = real_event->locked_state;
+       new_real_event->tool = real_event->tool;
++      new_real_event->platform_data =
++        _clutter_backend_copy_event_data (clutter_get_default_backend (),
++                                          real_event->platform_data);
+     }
+ 
+   device = clutter_event_get_device (event);
+   if (device != NULL)
+     n_axes = clutter_input_device_get_n_axes (device);
+ 
+   switch (event->type)
+     {
+     case CLUTTER_BUTTON_PRESS:
+     case CLUTTER_BUTTON_RELEASE:
+       if (event->button.axes != NULL)
+         new_event->button.axes = g_memdup (event->button.axes,
+                                            sizeof (gdouble) * n_axes);
+       break;
+ 
+     case CLUTTER_SCROLL:
+       if (event->scroll.axes != NULL)
+         new_event->scroll.axes = g_memdup (event->scroll.axes,
+                                            sizeof (gdouble) * n_axes);
+       break;
+ 
+     case CLUTTER_MOTION:
+       if (event->motion.axes != NULL)
+         new_event->motion.axes = g_memdup (event->motion.axes,
+                                            sizeof (gdouble) * n_axes);
+       break;
+ 
+     case CLUTTER_TOUCH_BEGIN:
+     case CLUTTER_TOUCH_UPDATE:
+     case CLUTTER_TOUCH_END:
+     case CLUTTER_TOUCH_CANCEL:
+       if (event->touch.axes != NULL)
+         new_event->touch.axes = g_memdup (event->touch.axes,
+                                           sizeof (gdouble) * n_axes);
+       break;
+ 
+     default:
+       break;
+     }
+ 
+-  if (is_event_allocated (event))
+-    _clutter_backend_copy_event_data (clutter_get_default_backend (),
+-                                      event,
+-                                      new_event);
+-
+   return new_event;
+ }
+ 
+ /**
+  * clutter_event_free:
+  * @event: A #ClutterEvent.
+  *
+  * Frees all resources used by @event.
+  */
+ void
+ clutter_event_free (ClutterEvent *event)
+ {
+   if (G_LIKELY (event != NULL))
+     {
+-      _clutter_backend_free_event_data (clutter_get_default_backend (), event);
+-
+-      if (is_event_allocated (event))
+-        {
+-          ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
+-
+-          g_clear_object (&real_event->device);
+-          g_clear_object (&real_event->source_device);
+-        }
+-
+       switch (event->type)
+         {
+         case CLUTTER_BUTTON_PRESS:
+         case CLUTTER_BUTTON_RELEASE:
+           g_free (event->button.axes);
+           break;
+ 
+         case CLUTTER_MOTION:
+           g_free (event->motion.axes);
+           break;
+ 
+         case CLUTTER_SCROLL:
+           g_free (event->scroll.axes);
+           break;
+ 
+         case CLUTTER_TOUCH_BEGIN:
+         case CLUTTER_TOUCH_UPDATE:
+         case CLUTTER_TOUCH_END:
+         case CLUTTER_TOUCH_CANCEL:
+           g_free (event->touch.axes);
+           break;
+ 
+         default:
+           break;
+         }
+ 
+-      g_hash_table_remove (all_events, event);
++      if (G_LIKELY (all_events))
++        g_hash_table_remove (all_events, event);
++
+       g_slice_free (ClutterEventPrivate, (ClutterEventPrivate *) event);
+     }
+ }
+ 
+ /**
+  * clutter_event_get:
+  *
+  * Pops an event off the event queue. Applications should not need to call 
+  * this.
+  *
+  * Return value: A #ClutterEvent or NULL if queue empty
+  *
+  * Since: 0.4
+  */
+ ClutterEvent *
+ clutter_event_get (void)
+ {
+   ClutterMainContext *context = _clutter_context_get_default ();
+ 
+   if (context->events_queue == NULL)
+     return NULL;
+ 
+   if (g_queue_is_empty (context->events_queue))
+     return NULL;
+ 
+   return g_queue_pop_tail (context->events_queue);
+ }
+ 
+ /**
+  * clutter_event_peek:
+diff --git a/clutter/clutter/evdev/clutter-device-manager-evdev.c b/clutter/clutter/evdev/clutter-device-manager-evdev.c
+index f2aeda696..11cb4781a 100644
+--- a/clutter/clutter/evdev/clutter-device-manager-evdev.c
++++ b/clutter/clutter/evdev/clutter-device-manager-evdev.c
+@@ -128,77 +128,76 @@ static gchar *                    evdev_seat_id;
+ 
+ #ifdef CLUTTER_ENABLE_DEBUG
+ static const char *device_type_str[] = {
+   "pointer",            /* CLUTTER_POINTER_DEVICE */
+   "keyboard",           /* CLUTTER_KEYBOARD_DEVICE */
+   "extension",          /* CLUTTER_EXTENSION_DEVICE */
+   "joystick",           /* CLUTTER_JOYSTICK_DEVICE */
+   "tablet",             /* CLUTTER_TABLET_DEVICE */
+   "touchpad",           /* CLUTTER_TOUCHPAD_DEVICE */
+   "touchscreen",        /* CLUTTER_TOUCHSCREEN_DEVICE */
+   "pen",                /* CLUTTER_PEN_DEVICE */
+   "eraser",             /* CLUTTER_ERASER_DEVICE */
+   "cursor",             /* CLUTTER_CURSOR_DEVICE */
+   "pad",                /* CLUTTER_PAD_DEVICE */
+ };
+ #endif /* CLUTTER_ENABLE_DEBUG */
+ 
+ /*
+  * ClutterEventSource management
+  *
+  * The device manager is responsible for managing the GSource when devices
+  * appear and disappear from the system.
+  */
+ 
+ static const char *option_xkb_layout = "us";
+ static const char *option_xkb_variant = "";
+ static const char *option_xkb_options = "";
+ 
+ static void
+ clutter_device_manager_evdev_copy_event_data (ClutterEventExtender *event_extender,
+-                                              const ClutterEvent   *src,
+-                                              ClutterEvent         *dest)
++                                              gpointer              data)
+ {
+-  ClutterEventEvdev *event_evdev;
++  ClutterEventEvdev *event_evdev = data;
+ 
+-  event_evdev = _clutter_event_get_platform_data (src);
+   if (event_evdev != NULL)
+-    _clutter_event_set_platform_data (dest, _clutter_event_evdev_copy (event_evdev));
++    return _clutter_event_evdev_copy (event_evdev);
++
++  return NULL;
+ }
+ 
+ static void
+ clutter_device_manager_evdev_free_event_data (ClutterEventExtender *event_extender,
+-                                              ClutterEvent         *event)
++                                              gpointer              data)
+ {
+-  ClutterEventEvdev *event_evdev;
++  ClutterEventEvdev *event_evdev = data;
+ 
+-  event_evdev = _clutter_event_get_platform_data (event);
+   if (event_evdev != NULL)
+     _clutter_event_evdev_free (event_evdev);
+ }
+ 
+ static void
+ clutter_device_manager_evdev_event_extender_init (ClutterEventExtenderInterface *iface)
+ {
+   iface->copy_event_data = clutter_device_manager_evdev_copy_event_data;
+   iface->free_event_data = clutter_device_manager_evdev_free_event_data;
+ }
+ 
+ /*
+  * ClutterEventSource for reading input devices
+  */
+ 
+ struct _ClutterEventSource
+ {
+   GSource source;
+ 
+   ClutterDeviceManagerEvdev *manager_evdev;
+   GPollFD event_poll_fd;
+ };
+ 
+ static void
+ process_events (ClutterDeviceManagerEvdev *manager_evdev);
+ 
+ static gboolean
+ clutter_event_prepare (GSource *source,
+                        gint    *timeout)
+ {
+diff --git a/clutter/clutter/x11/clutter-device-manager-xi2.c b/clutter/clutter/x11/clutter-device-manager-xi2.c
+index 0718cd975..35e3808e7 100644
+--- a/clutter/clutter/x11/clutter-device-manager-xi2.c
++++ b/clutter/clutter/x11/clutter-device-manager-xi2.c
+@@ -63,79 +63,74 @@ static const char *clutter_input_axis_atom_names[] = {
+   "Abs Tilt Y",         /* CLUTTER_INPUT_AXIS_YTILT */
+   "Abs Wheel",          /* CLUTTER_INPUT_AXIS_WHEEL */
+   "Abs Distance",       /* CLUTTER_INPUT_AXIS_DISTANCE */
+ };
+ 
+ #define N_AXIS_ATOMS    G_N_ELEMENTS (clutter_input_axis_atom_names)
+ 
+ enum {
+   PAD_AXIS_FIRST  = 3, /* First axes are always x/y/pressure, ignored in pads */
+   PAD_AXIS_STRIP1 = PAD_AXIS_FIRST,
+   PAD_AXIS_STRIP2,
+   PAD_AXIS_RING1,
+   PAD_AXIS_RING2,
+ };
+ 
+ static Atom clutter_input_axis_atoms[N_AXIS_ATOMS] = { 0, };
+ 
+ static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface);
+ static void clutter_event_extender_iface_init   (ClutterEventExtenderInterface *iface);
+ 
+ #define clutter_device_manager_xi2_get_type     _clutter_device_manager_xi2_get_type
+ 
+ G_DEFINE_TYPE_WITH_CODE (ClutterDeviceManagerXI2,
+                          clutter_device_manager_xi2,
+                          CLUTTER_TYPE_DEVICE_MANAGER,
+                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR,
+                                                 clutter_event_translator_iface_init)
+                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_EXTENDER,
+                                                 clutter_event_extender_iface_init))
+ 
+-static void
++static gpointer
+ clutter_device_manager_x11_copy_event_data (ClutterEventExtender *event_extender,
+-                                            const ClutterEvent   *src,
+-                                            ClutterEvent         *dest)
++                                            gpointer              event_x11)
+ {
+-  gpointer event_x11;
+-
+-  event_x11 = _clutter_event_get_platform_data (src);
+   if (event_x11 != NULL)
+-    _clutter_event_set_platform_data (dest, _clutter_event_x11_copy (event_x11));
++    return _clutter_event_x11_copy (event_x11);
++
++  return NULL;
+ }
+ 
+ static void
+ clutter_device_manager_x11_free_event_data (ClutterEventExtender *event_extender,
+-                                            ClutterEvent         *event)
++                                            gpointer              event_x11)
+ {
+-  gpointer event_x11;
+-
+-  event_x11 = _clutter_event_get_platform_data (event);
+   if (event_x11 != NULL)
+     _clutter_event_x11_free (event_x11);
+ }
+ 
+ static void
+ clutter_event_extender_iface_init (ClutterEventExtenderInterface *iface)
+ {
+   iface->copy_event_data = clutter_device_manager_x11_copy_event_data;
+   iface->free_event_data = clutter_device_manager_x11_free_event_data;
+ }
+ 
+ static void
+ translate_valuator_class (Display             *xdisplay,
+                           ClutterInputDevice  *device,
+                           XIValuatorClassInfo *class)
+ {
+   static gboolean atoms_initialized = FALSE;
+   ClutterInputAxis i, axis = CLUTTER_INPUT_AXIS_IGNORE;
+ 
+   if (G_UNLIKELY (!atoms_initialized))
+     {
+       XInternAtoms (xdisplay,
+                     (char **) clutter_input_axis_atom_names, N_AXIS_ATOMS,
+                     False,
+                     clutter_input_axis_atoms);
+ 
+       atoms_initialized = TRUE;
+     }
+ 
+   for (i = 0;
+-- 
+2.26.2
+
diff --git a/SOURCES/0009-clutter-actor-Take-the-marging-boxed-type-if-valid.patch b/SOURCES/0009-clutter-actor-Take-the-marging-boxed-type-if-valid.patch
new file mode 100644
index 0000000..101d0b5
--- /dev/null
+++ b/SOURCES/0009-clutter-actor-Take-the-marging-boxed-type-if-valid.patch
@@ -0,0 +1,83 @@
+From 80949841b030d5272ae625bc3cca82d2affd09e7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Wed, 10 Jul 2019 12:29:26 +0200
+Subject: [PATCH 09/28] clutter/actor: Take the marging boxed type if valid
+
+We were using a clutter margin boxed type, copying it instead of passing the
+ownership, causing a memory leak.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ clutter/clutter/clutter-actor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c
+index 7111d824d..f7b7be0ab 100644
+--- a/clutter/clutter/clutter-actor.c
++++ b/clutter/clutter/clutter-actor.c
+@@ -14695,61 +14695,61 @@ clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
+                                      "written ClutterScript definitions.");
+ #endif
+ 
+       l = parse_behaviours (script, actor, node);
+ 
+       g_value_init (value, G_TYPE_POINTER);
+       g_value_set_pointer (value, l);
+ 
+       retval = TRUE;
+     }
+   else if (strcmp (name, "actions") == 0 ||
+            strcmp (name, "constraints") == 0 ||
+            strcmp (name, "effects") == 0)
+     {
+       GSList *l;
+ 
+       l = parse_actor_metas (script, actor, node);
+ 
+       g_value_init (value, G_TYPE_POINTER);
+       g_value_set_pointer (value, l);
+ 
+       retval = TRUE;
+     }
+   else if (strcmp (name, "margin") == 0)
+     {
+       ClutterMargin *margin = parse_margin (actor, node);
+ 
+       if (margin)
+         {
+           g_value_init (value, CLUTTER_TYPE_MARGIN);
+-          g_value_set_boxed (value, margin);
++          g_value_take_boxed (value, margin);
+           retval = TRUE;
+         }
+     }
+ 
+   return retval;
+ }
+ 
+ static void
+ clutter_actor_set_custom_property (ClutterScriptable *scriptable,
+                                    ClutterScript     *script,
+                                    const gchar       *name,
+                                    const GValue      *value)
+ {
+   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
+ 
+ #ifdef CLUTTER_ENABLE_DEBUG
+   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
+     {
+       gchar *tmp = g_strdup_value_contents (value);
+ 
+       CLUTTER_NOTE (SCRIPT,
+                     "in ClutterActor::set_custom_property('%s') = %s",
+                     name,
+                     tmp);
+ 
+       g_free (tmp);
+     }
+ #endif /* CLUTTER_ENABLE_DEBUG */
+ 
+   if (strcmp (name, "rotation") == 0)
+-- 
+2.26.2
+
diff --git a/SOURCES/0010-clutter-actor-meta-Notify-when-actor-property-change.patch b/SOURCES/0010-clutter-actor-meta-Notify-when-actor-property-change.patch
new file mode 100644
index 0000000..72f0f6a
--- /dev/null
+++ b/SOURCES/0010-clutter-actor-meta-Notify-when-actor-property-change.patch
@@ -0,0 +1,86 @@
+From d4b6d9e3190e2cae30fb5bbc41a76286bbed0214 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Sat, 27 Jul 2019 00:20:55 +0200
+Subject: [PATCH 10/28] clutter/actor-meta: Notify when actor property changed
+
+The ActorMeta contains an actor property holding the parent actor, however when
+it changes no notification is emitted.
+
+Other tham this, since the set_actor vfunc is called on meta destruction, it
+could be a problem if the virtual function is implemented by a Javascript object
+since the JS context will try to use it during its disposition.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ clutter/clutter/clutter-actor-meta.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/clutter/clutter/clutter-actor-meta.c b/clutter/clutter/clutter-actor-meta.c
+index 085f2f65d..2843ea222 100644
+--- a/clutter/clutter/clutter-actor-meta.c
++++ b/clutter/clutter/clutter-actor-meta.c
+@@ -73,60 +73,61 @@ enum
+   PROP_LAST
+ };
+ 
+ static GParamSpec *obj_props[PROP_LAST];
+ 
+ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterActorMeta,
+                                      clutter_actor_meta,
+                                      G_TYPE_INITIALLY_UNOWNED)
+ 
+ static void
+ on_actor_destroy (ClutterActor     *actor,
+                   ClutterActorMeta *meta)
+ {
+   meta->priv->actor = NULL;
+ }
+ 
+ static void
+ clutter_actor_meta_real_set_actor (ClutterActorMeta *meta,
+                                    ClutterActor     *actor)
+ {
+   if (meta->priv->actor == actor)
+     return;
+ 
+   if (meta->priv->destroy_id != 0)
+     {
+       g_signal_handler_disconnect (meta->priv->actor, meta->priv->destroy_id);
+       meta->priv->destroy_id = 0;
+     }
+ 
+   meta->priv->actor = actor;
++  g_object_notify_by_pspec (G_OBJECT (meta), obj_props[PROP_ACTOR]);
+ 
+   if (meta->priv->actor != NULL)
+     meta->priv->destroy_id = g_signal_connect (meta->priv->actor, "destroy",
+                                                G_CALLBACK (on_actor_destroy),
+                                                meta);
+ }
+ 
+ static void
+ clutter_actor_meta_set_property (GObject      *gobject,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+ {
+   ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
+ 
+   switch (prop_id)
+     {
+     case PROP_NAME:
+       clutter_actor_meta_set_name (meta, g_value_get_string (value));
+       break;
+ 
+     case PROP_ENABLED:
+       clutter_actor_meta_set_enabled (meta, g_value_get_boolean (value));
+       break;
+ 
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+       break;
+     }
+ }
+-- 
+2.26.2
+
diff --git a/SOURCES/0011-clutter-actor-meta-Unset-the-actor-if-disposed-calli.patch b/SOURCES/0011-clutter-actor-meta-Unset-the-actor-if-disposed-calli.patch
new file mode 100644
index 0000000..b8ac9b7
--- /dev/null
+++ b/SOURCES/0011-clutter-actor-meta-Unset-the-actor-if-disposed-calli.patch
@@ -0,0 +1,90 @@
+From 7a5c4a68c4c80b61566e6c9eeb0e854d5c344dd1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Sat, 27 Jul 2019 00:28:46 +0200
+Subject: [PATCH 11/28] clutter/actor-meta: Unset the actor if disposed,
+ calling the vfunc
+
+If the actor owned by an ActorMeta is destroyed we unset its pointer, however
+many implementations of this class keep a reference on the pointer, so we should
+notify them about the invalid pointer or they might try to reference an invalid
+memory location.
+
+Fix this by changing the destroy callback, unsetting the destroy connection id
+and calling _clutter_actor_meta_set_actor()
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ clutter/clutter/clutter-actor-meta.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/clutter/clutter/clutter-actor-meta.c b/clutter/clutter/clutter-actor-meta.c
+index 2843ea222..157c1d67e 100644
+--- a/clutter/clutter/clutter-actor-meta.c
++++ b/clutter/clutter/clutter-actor-meta.c
+@@ -56,61 +56,62 @@ struct _ClutterActorMetaPrivate
+   guint destroy_id;
+ 
+   gchar *name;
+ 
+   guint is_enabled : 1;
+ 
+   gint priority;
+ };
+ 
+ enum
+ {
+   PROP_0,
+ 
+   PROP_ACTOR,
+   PROP_NAME,
+   PROP_ENABLED,
+ 
+   PROP_LAST
+ };
+ 
+ static GParamSpec *obj_props[PROP_LAST];
+ 
+ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterActorMeta,
+                                      clutter_actor_meta,
+                                      G_TYPE_INITIALLY_UNOWNED)
+ 
+ static void
+ on_actor_destroy (ClutterActor     *actor,
+                   ClutterActorMeta *meta)
+ {
+-  meta->priv->actor = NULL;
++  meta->priv->destroy_id = 0;
++  _clutter_actor_meta_set_actor (meta, NULL);
+ }
+ 
+ static void
+ clutter_actor_meta_real_set_actor (ClutterActorMeta *meta,
+                                    ClutterActor     *actor)
+ {
+   if (meta->priv->actor == actor)
+     return;
+ 
+   if (meta->priv->destroy_id != 0)
+     {
+       g_signal_handler_disconnect (meta->priv->actor, meta->priv->destroy_id);
+       meta->priv->destroy_id = 0;
+     }
+ 
+   meta->priv->actor = actor;
+   g_object_notify_by_pspec (G_OBJECT (meta), obj_props[PROP_ACTOR]);
+ 
+   if (meta->priv->actor != NULL)
+     meta->priv->destroy_id = g_signal_connect (meta->priv->actor, "destroy",
+                                                G_CALLBACK (on_actor_destroy),
+                                                meta);
+ }
+ 
+ static void
+ clutter_actor_meta_set_property (GObject      *gobject,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+ {
+-- 
+2.26.2
+
diff --git a/SOURCES/0012-clutter-stage-manager-Pause-the-master-clock-when-al.patch b/SOURCES/0012-clutter-stage-manager-Pause-the-master-clock-when-al.patch
new file mode 100644
index 0000000..580d4a7
--- /dev/null
+++ b/SOURCES/0012-clutter-stage-manager-Pause-the-master-clock-when-al.patch
@@ -0,0 +1,91 @@
+From 8f2044e41222e2f5360f7ee7386d4ce0903ed786 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Thu, 25 Jul 2019 01:14:37 +0200
+Subject: [PATCH 12/28] clutter/stage-manager: Pause the master clock when all
+ stages have been removed
+
+The clutter master clock is used by the stage during redraws, but never
+stopped when the last stage is destroyed, potentially causing calls to dead
+objects.
+
+So, set it paused (destroying the underlying GSource) when the last stage is
+disposed.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ clutter/clutter/clutter-stage-manager.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/clutter/clutter/clutter-stage-manager.c b/clutter/clutter/clutter-stage-manager.c
+index 3a44c8209..185e3e2ce 100644
+--- a/clutter/clutter/clutter-stage-manager.c
++++ b/clutter/clutter/clutter-stage-manager.c
+@@ -267,57 +267,65 @@ clutter_stage_manager_list_stages (ClutterStageManager *stage_manager)
+ /**
+  * clutter_stage_manager_peek_stages:
+  * @stage_manager: a #ClutterStageManager
+  *
+  * Lists all currently used stages.
+  *
+  * Return value: (transfer none) (element-type Clutter.Stage): a pointer
+  *   to the internal list of #ClutterStage objects. The returned list
+  *   is owned by the #ClutterStageManager and should never be modified
+  *   or freed
+  *
+  * Since: 1.0
+  */
+ const GSList *
+ clutter_stage_manager_peek_stages (ClutterStageManager *stage_manager)
+ {
+   return stage_manager->stages;
+ }
+ 
+ void
+ _clutter_stage_manager_add_stage (ClutterStageManager *stage_manager,
+                                   ClutterStage        *stage)
+ {
+   if (g_slist_find (stage_manager->stages, stage))
+     {
+       g_warning ("Trying to add a stage to the list of managed stages, "
+                  "but it is already in it, aborting.");
+       return;
+     }
+ 
++  _clutter_master_clock_set_paused (_clutter_master_clock_get_default (), FALSE);
++
+   g_object_ref_sink (stage);
+ 
+   stage_manager->stages = g_slist_append (stage_manager->stages, stage);
+ 
+   g_signal_emit (stage_manager, manager_signals[STAGE_ADDED], 0, stage);
+ }
+ 
+ void
+ _clutter_stage_manager_remove_stage (ClutterStageManager *stage_manager,
+                                      ClutterStage        *stage)
+ {
+   /* this might be called multiple times from a ::dispose, so it
+    * needs to just return without warning
+    */
+   if (!g_slist_find (stage_manager->stages, stage))
+     return;
+ 
+   stage_manager->stages = g_slist_remove (stage_manager->stages, stage);
+ 
+   /* if the default stage is being destroyed then we unset the pointer */
+   if (default_stage == stage)
+     default_stage = NULL;
+ 
+   g_signal_emit (stage_manager, manager_signals[STAGE_REMOVED], 0, stage);
+ 
+   g_object_unref (stage);
++
++  if (!stage_manager->stages)
++    {
++      ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
++      _clutter_master_clock_set_paused (master_clock, TRUE);
++    }
+ }
+-- 
+2.26.2
+
diff --git a/SOURCES/0013-cally-stage-Set-the-keyfocus-to-NULL-if-the-stage-is.patch b/SOURCES/0013-cally-stage-Set-the-keyfocus-to-NULL-if-the-stage-is.patch
new file mode 100644
index 0000000..72bb350
--- /dev/null
+++ b/SOURCES/0013-cally-stage-Set-the-keyfocus-to-NULL-if-the-stage-is.patch
@@ -0,0 +1,87 @@
+From 19a03c1c2df7e510d3fa1b25eec7840cc5816dfe Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Thu, 25 Jul 2019 01:02:34 +0200
+Subject: [PATCH 13/28] cally/stage: Set the keyfocus to NULL if the stage is
+ focused
+
+By definition when the key focus is set to NULL we assume that the stage has it,
+so in such case avoid keeping track of the stage pointer and setting a weak ref
+on it, as it might only cause double-free errors during the stage disposition,
+that would lead (via atk) to a cally stage disposition as well.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ clutter/clutter/cally/cally-stage.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/clutter/clutter/cally/cally-stage.c b/clutter/clutter/cally/cally-stage.c
+index 7c100aabf..5638c1bb1 100644
+--- a/clutter/clutter/cally/cally-stage.c
++++ b/clutter/clutter/cally/cally-stage.c
+@@ -101,60 +101,63 @@ cally_stage_init (CallyStage *cally_stage)
+  */
+ AtkObject*
+ cally_stage_new (ClutterActor *actor)
+ {
+   GObject   *object     = NULL;
+   AtkObject *accessible = NULL;
+ 
+   g_return_val_if_fail (CLUTTER_IS_STAGE (actor), NULL);
+ 
+   object = g_object_new (CALLY_TYPE_STAGE, NULL);
+ 
+   accessible = ATK_OBJECT (object);
+   atk_object_initialize (accessible, actor);
+ 
+   return accessible;
+ }
+ 
+ static void
+ cally_stage_notify_key_focus_cb (ClutterStage *stage,
+                                  GParamSpec   *pspec,
+                                  CallyStage   *self)
+ {
+   ClutterActor *key_focus = NULL;
+   AtkObject *new = NULL;
+ 
+   if (self->priv->active == FALSE)
+     return;
+ 
+   key_focus = clutter_stage_get_key_focus (stage);
+ 
++  if (key_focus == CLUTTER_ACTOR (stage))
++    key_focus = NULL;
++
+   if (key_focus != self->priv->key_focus)
+     {
+       AtkObject *old = NULL;
+ 
+       if (self->priv->key_focus != NULL)
+         {
+           g_object_remove_weak_pointer (G_OBJECT (self->priv->key_focus),
+                                         (gpointer *) &self->priv->key_focus);
+           old = clutter_actor_get_accessible (self->priv->key_focus);
+         }
+       else
+         old = clutter_actor_get_accessible (CLUTTER_ACTOR (stage));
+ 
+       atk_object_notify_state_change (old,
+                                       ATK_STATE_FOCUSED,
+                                       FALSE);
+     }
+ 
+   /* we keep notifying the focus gain without checking previous
+    * key-focus to avoid some missing events due timing
+    */
+   self->priv->key_focus = key_focus;
+ 
+   if (key_focus != NULL)
+     {
+       /* ensure that if the key focus goes away, the field inside
+        * CallyStage is reset. see bug:
+        *
+        * https://bugzilla.gnome.org/show_bug.cgi?id=692706
+        *
+-- 
+2.26.2
+
diff --git a/SOURCES/0014-cally-stage-Monitor-key-focus-actor-via-destroyed-si.patch b/SOURCES/0014-cally-stage-Monitor-key-focus-actor-via-destroyed-si.patch
new file mode 100644
index 0000000..620ec8b
--- /dev/null
+++ b/SOURCES/0014-cally-stage-Monitor-key-focus-actor-via-destroyed-si.patch
@@ -0,0 +1,243 @@
+From 14c2a8eba29647336ca80ce4ed0afe8352fa8818 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Thu, 25 Jul 2019 01:10:02 +0200
+Subject: [PATCH 14/28] cally/stage: Monitor key-focus actor via "destroyed"
+ signal
+
+We use a weak pointer for monitoring the state of the key-focused actor, however
+actors are considered dead once we get a "destroyed" signal instead (that
+happens) before actual GObject disposition.
+Also the weak pointer was set twice if the same actor was signaled as
+key-focused twice in a row.
+
+So instead of using weak pointers, connect to the "destroy" signal to nullify
+the key_focus actor pointer, and don't connect to the signal multiple times.
+Also use a signal handler to manage the connection, that implies less operations
+on disconnection.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ clutter/clutter/cally/cally-stage.c | 53 ++++++++++++++++++++++-------
+ 1 file changed, 40 insertions(+), 13 deletions(-)
+
+diff --git a/clutter/clutter/cally/cally-stage.c b/clutter/clutter/cally/cally-stage.c
+index 5638c1bb1..147ec72e6 100644
+--- a/clutter/clutter/cally/cally-stage.c
++++ b/clutter/clutter/cally/cally-stage.c
+@@ -30,173 +30,200 @@
+  *
+  * Some implementation details: at this moment #CallyStage is used as
+  * the most similar Window object in this toolkit (ie: emitting window
+  * related signals), although the real purpose of #ClutterStage is
+  * being a canvas. Anyway, this is required for applications using
+  * just clutter, or directly #ClutterStage
+  */
+ #include "clutter-build-config.h"
+ 
+ #include "cally-stage.h"
+ #include "cally-actor-private.h"
+ 
+ /* AtkObject.h */
+ static void                  cally_stage_real_initialize (AtkObject *obj,
+                                                           gpointer   data);
+ static AtkStateSet*          cally_stage_ref_state_set   (AtkObject *obj);
+ 
+ /* AtkWindow */
+ static void                  cally_stage_window_interface_init (AtkWindowIface *iface);
+ 
+ /* Auxiliar */
+ static void                  cally_stage_activate_cb     (ClutterStage *stage,
+                                                           gpointer      data);
+ static void                  cally_stage_deactivate_cb   (ClutterStage *stage,
+                                                           gpointer      data);
+ 
+ struct _CallyStagePrivate
+ {
+   /* NULL means that the stage will receive the focus */
+   ClutterActor *key_focus;
++  gulong key_focus_destroyed_id;
+ 
+   gboolean active;
+ };
+ 
+ G_DEFINE_TYPE_WITH_CODE (CallyStage,
+                          cally_stage,
+                          CALLY_TYPE_GROUP,
+                          G_ADD_PRIVATE (CallyStage)
+                          G_IMPLEMENT_INTERFACE (ATK_TYPE_WINDOW,
+                                                 cally_stage_window_interface_init));
+ 
++static void
++cally_stage_dispose (GObject *object)
++{
++  CallyStage *self = CALLY_STAGE (object);
++
++  if (self->priv->key_focus)
++    {
++      if (self->priv->key_focus_destroyed_id)
++        {
++          g_signal_handler_disconnect (self->priv->key_focus,
++                                       self->priv->key_focus_destroyed_id);
++          self->priv->key_focus_destroyed_id = 0;
++        }
++
++      self->priv->key_focus = NULL;
++    }
++
++  G_OBJECT_CLASS (cally_stage_parent_class)->dispose (object);
++}
++
+ static void
+ cally_stage_class_init (CallyStageClass *klass)
+ {
++  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+ 
+   /* AtkObject */
+   class->initialize = cally_stage_real_initialize;
+   class->ref_state_set = cally_stage_ref_state_set;
++
++  gobject_class->dispose = cally_stage_dispose;
+ }
+ 
+ static void
+ cally_stage_init (CallyStage *cally_stage)
+ {
+   CallyStagePrivate *priv = cally_stage_get_instance_private (cally_stage);
+ 
+   cally_stage->priv = priv;
+ 
+   priv->active = FALSE;
+ }
+ 
+ /**
+  * cally_stage_new:
+  * @actor: a #ClutterActor
+  *
+  * Creates a new #CallyStage for the given @actor. @actor should be a
+  * #ClutterStage.
+  *
+  * Return value: the newly created #AtkObject
+  *
+  * Since: 1.4
+  */
+ AtkObject*
+ cally_stage_new (ClutterActor *actor)
+ {
+   GObject   *object     = NULL;
+   AtkObject *accessible = NULL;
+ 
+   g_return_val_if_fail (CLUTTER_IS_STAGE (actor), NULL);
+ 
+   object = g_object_new (CALLY_TYPE_STAGE, NULL);
+ 
+   accessible = ATK_OBJECT (object);
+   atk_object_initialize (accessible, actor);
+ 
+   return accessible;
+ }
+ 
+ static void
+ cally_stage_notify_key_focus_cb (ClutterStage *stage,
+                                  GParamSpec   *pspec,
+                                  CallyStage   *self)
+ {
+   ClutterActor *key_focus = NULL;
+   AtkObject *new = NULL;
+ 
+   if (self->priv->active == FALSE)
+     return;
+ 
+   key_focus = clutter_stage_get_key_focus (stage);
+ 
+   if (key_focus == CLUTTER_ACTOR (stage))
+     key_focus = NULL;
+ 
+   if (key_focus != self->priv->key_focus)
+     {
+       AtkObject *old = NULL;
+ 
+-      if (self->priv->key_focus != NULL)
++      if (self->priv->key_focus != NULL && self->priv->key_focus_destroyed_id)
+         {
+-          g_object_remove_weak_pointer (G_OBJECT (self->priv->key_focus),
+-                                        (gpointer *) &self->priv->key_focus);
+-          old = clutter_actor_get_accessible (self->priv->key_focus);
++          g_signal_handler_disconnect (self->priv->key_focus,
++                                       self->priv->key_focus_destroyed_id);
++          self->priv->key_focus_destroyed_id = 0;
+         }
+-      else
+-        old = clutter_actor_get_accessible (CLUTTER_ACTOR (stage));
++
++      old = clutter_actor_get_accessible (self->priv->key_focus ?
++                                          self->priv->key_focus :
++                                          CLUTTER_ACTOR (stage));
+ 
+       atk_object_notify_state_change (old,
+                                       ATK_STATE_FOCUSED,
+                                       FALSE);
+     }
+ 
+   /* we keep notifying the focus gain without checking previous
+    * key-focus to avoid some missing events due timing
+    */
+   self->priv->key_focus = key_focus;
+ 
+-  if (key_focus != NULL)
++  if (key_focus != NULL && !self->priv->key_focus_destroyed_id)
+     {
+       /* ensure that if the key focus goes away, the field inside
+        * CallyStage is reset. see bug:
+        *
+        * https://bugzilla.gnome.org/show_bug.cgi?id=692706
+        *
+        * we remove the weak pointer above.
+        */
+-      g_object_add_weak_pointer (G_OBJECT (self->priv->key_focus),
+-                                 (gpointer *) &self->priv->key_focus);
+-
+-      new = clutter_actor_get_accessible (key_focus);
++      self->priv->key_focus_destroyed_id =
++        g_signal_connect_swapped (self->priv->key_focus, "destroy",
++                                  G_CALLBACK (g_nullify_pointer),
++                                  &self->priv->key_focus);
+     }
+-  else
+-    new = clutter_actor_get_accessible (CLUTTER_ACTOR (stage));
++
++  new = clutter_actor_get_accessible (key_focus ?
++                                      key_focus : CLUTTER_ACTOR (stage));
+ 
+   atk_object_notify_state_change (new,
+                                   ATK_STATE_FOCUSED,
+                                   TRUE);
+ }
+ 
+ static void
+ cally_stage_real_initialize (AtkObject *obj,
+                              gpointer  data)
+ {
+   ClutterStage *stage = NULL;
+ 
+   g_return_if_fail (CALLY_IS_STAGE (obj));
+ 
+   ATK_OBJECT_CLASS (cally_stage_parent_class)->initialize (obj, data);
+ 
+   stage = CLUTTER_STAGE (CALLY_GET_CLUTTER_ACTOR (obj));
+ 
+   g_signal_connect (stage, "activate", G_CALLBACK (cally_stage_activate_cb), obj);
+   g_signal_connect (stage, "deactivate", G_CALLBACK (cally_stage_deactivate_cb), obj);
+   g_signal_connect (stage, "notify::key-focus",
+                     G_CALLBACK (cally_stage_notify_key_focus_cb), obj);
+ 
+   atk_object_set_role (obj, ATK_ROLE_WINDOW);
+ }
+ 
+ static AtkStateSet*
+ cally_stage_ref_state_set   (AtkObject *obj)
+ {
+   CallyStage   *cally_stage = NULL;
+-- 
+2.26.2
+
diff --git a/SOURCES/0015-group-Free-group-if-returning-early.patch b/SOURCES/0015-group-Free-group-if-returning-early.patch
new file mode 100644
index 0000000..d7a0c9e
--- /dev/null
+++ b/SOURCES/0015-group-Free-group-if-returning-early.patch
@@ -0,0 +1,134 @@
+From 12eefc7a5346ef9132afe1a3e929308f70cd5121 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Tue, 9 Jul 2019 11:17:18 +0200
+Subject: [PATCH 15/28] group: Free group if returning early
+
+If we get an error when fetching the window attributes, the group isn't ever
+free'd, so use an autopointer instead, releasing the stolen one.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/x11/group.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/x11/group.c b/src/x11/group.c
+index 123b9e153..4fafa28eb 100644
+--- a/src/x11/group.c
++++ b/src/x11/group.c
+@@ -10,111 +10,111 @@
+  * License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful, but
+  * WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+ /**
+  * SECTION:group
+  * @title: MetaGroup
+  * @short_description: Mutter window groups
+  *
+  */
+ 
+ #include <config.h>
+ #include <meta/util.h>
+ #include "group-private.h"
+ #include "group-props.h"
+ #include "window-private.h"
+ #include <meta/window.h>
+ #include <X11/Xlib-xcb.h>
+ 
+ static MetaGroup*
+ meta_group_new (MetaDisplay *display,
+                 Window       group_leader)
+ {
+-  MetaGroup *group;
++  g_autofree MetaGroup *group = NULL;
+ #define N_INITIAL_PROPS 3
+   Atom initial_props[N_INITIAL_PROPS];
+   int i;
+ 
+   g_assert (N_INITIAL_PROPS == (int) G_N_ELEMENTS (initial_props));
+ 
+   group = g_new0 (MetaGroup, 1);
+ 
+   group->display = display;
+   group->windows = NULL;
+   group->group_leader = group_leader;
+   group->refcount = 1; /* owned by caller, hash table has only weak ref */
+ 
+   xcb_connection_t *xcb_conn = XGetXCBConnection (display->xdisplay);
+   xcb_generic_error_t *e;
+   g_autofree xcb_get_window_attributes_reply_t *attrs =
+     xcb_get_window_attributes_reply (xcb_conn,
+                                      xcb_get_window_attributes (xcb_conn, group_leader),
+                                      &e);
+   if (e)
+     return NULL;
+ 
+   const uint32_t events[] = { attrs->your_event_mask | XCB_EVENT_MASK_PROPERTY_CHANGE };
+   xcb_change_window_attributes (xcb_conn, group_leader,
+                                 XCB_CW_EVENT_MASK, events);
+ 
+   if (display->groups_by_leader == NULL)
+     display->groups_by_leader = g_hash_table_new (meta_unsigned_long_hash,
+                                                   meta_unsigned_long_equal);
+ 
+   g_assert (g_hash_table_lookup (display->groups_by_leader, &group_leader) == NULL);
+ 
+   g_hash_table_insert (display->groups_by_leader,
+                        &group->group_leader,
+                        group);
+ 
+   /* Fill these in the order we want them to be gotten */
+   i = 0;
+   initial_props[i++] = display->atom_WM_CLIENT_MACHINE;
+   initial_props[i++] = display->atom__NET_WM_PID;
+   initial_props[i++] = display->atom__NET_STARTUP_ID;
+   g_assert (N_INITIAL_PROPS == i);
+ 
+   meta_group_reload_properties (group, initial_props, N_INITIAL_PROPS);
+ 
+   meta_topic (META_DEBUG_GROUPS,
+               "Created new group with leader 0x%lx\n",
+               group->group_leader);
+ 
+-  return group;
++  return g_steal_pointer (&group);
+ }
+ 
+ static void
+ meta_group_unref (MetaGroup *group)
+ {
+   g_return_if_fail (group->refcount > 0);
+ 
+   group->refcount -= 1;
+   if (group->refcount == 0)
+     {
+       meta_topic (META_DEBUG_GROUPS,
+                   "Destroying group with leader 0x%lx\n",
+                   group->group_leader);
+ 
+       g_assert (group->display->groups_by_leader != NULL);
+ 
+       g_hash_table_remove (group->display->groups_by_leader,
+                            &group->group_leader);
+ 
+       /* mop up hash table, this is how it gets freed on display close */
+       if (g_hash_table_size (group->display->groups_by_leader) == 0)
+         {
+           g_hash_table_destroy (group->display->groups_by_leader);
+           group->display->groups_by_leader = NULL;
+         }
+ 
+       g_free (group->wm_client_machine);
+       g_free (group->startup_id);
+ 
+       g_free (group);
+-- 
+2.26.2
+
diff --git a/SOURCES/0016-surface-actor-Destroy-the-pending-damage-region-on-d.patch b/SOURCES/0016-surface-actor-Destroy-the-pending-damage-region-on-d.patch
new file mode 100644
index 0000000..646ac2b
--- /dev/null
+++ b/SOURCES/0016-surface-actor-Destroy-the-pending-damage-region-on-d.patch
@@ -0,0 +1,82 @@
+From e4221a10d0c7e84d141765948489f264a2ff3105 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Wed, 10 Jul 2019 16:06:57 +0200
+Subject: [PATCH 16/28] surface-actor: Destroy the pending damage region on
+ dispose
+
+As the region isn't going to be used anymore, we can safely remove it on dispose
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/compositor/meta-surface-actor.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c
+index bf8c76f39..6996658ed 100644
+--- a/src/compositor/meta-surface-actor.c
++++ b/src/compositor/meta-surface-actor.c
+@@ -80,60 +80,61 @@ meta_surface_actor_pick (ClutterActor       *actor,
+ 
+           rectangles[pos + 0] = rect.x;
+           rectangles[pos + 1] = rect.y;
+           rectangles[pos + 2] = rect.x + rect.width;
+           rectangles[pos + 3] = rect.y + rect.height;
+         }
+ 
+       ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
+       fb = cogl_get_draw_framebuffer ();
+ 
+       cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
+ 
+       pipeline = cogl_pipeline_new (ctx);
+       cogl_pipeline_set_color (pipeline, &cogl_color);
+       cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects);
+       cogl_object_unref (pipeline);
+     }
+ 
+   clutter_actor_iter_init (&iter, actor);
+ 
+   while (clutter_actor_iter_next (&iter, &child))
+     clutter_actor_paint (child);
+ }
+ 
+ static void
+ meta_surface_actor_dispose (GObject *object)
+ {
+   MetaSurfaceActor *self = META_SURFACE_ACTOR (object);
+   MetaSurfaceActorPrivate *priv = self->priv;
+ 
++  g_clear_pointer (&priv->pending_damage, cairo_region_destroy);
+   g_clear_pointer (&priv->input_region, cairo_region_destroy);
+ 
+   G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object);
+ }
+ 
+ static void
+ meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
+ {
+   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+ 
+   object_class->dispose = meta_surface_actor_dispose;
+   actor_class->pick = meta_surface_actor_pick;
+ 
+   signals[REPAINT_SCHEDULED] = g_signal_new ("repaint-scheduled",
+                                              G_TYPE_FROM_CLASS (object_class),
+                                              G_SIGNAL_RUN_LAST,
+                                              0,
+                                              NULL, NULL, NULL,
+                                              G_TYPE_NONE, 0);
+ 
+   signals[SIZE_CHANGED] = g_signal_new ("size-changed",
+                                         G_TYPE_FROM_CLASS (object_class),
+                                         G_SIGNAL_RUN_LAST,
+                                         0,
+                                         NULL, NULL, NULL,
+                                         G_TYPE_NONE, 0);
+ 
+   g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate));
+ }
+-- 
+2.26.2
+
diff --git a/SOURCES/0017-CrtcMode-Free-the-mode-name-on-finalize.patch b/SOURCES/0017-CrtcMode-Free-the-mode-name-on-finalize.patch
new file mode 100644
index 0000000..3d4a28e
--- /dev/null
+++ b/SOURCES/0017-CrtcMode-Free-the-mode-name-on-finalize.patch
@@ -0,0 +1,65 @@
+From 172906f150a15658e2b375340307e3d48b640d42 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Mon, 22 Jul 2019 00:04:33 +0200
+Subject: [PATCH 17/28] CrtcMode: Free the mode name on finalize
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/backends/meta-crtc.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/backends/meta-crtc.c b/src/backends/meta-crtc.c
+index 7ca31ba39..e4da25c5a 100644
+--- a/src/backends/meta-crtc.c
++++ b/src/backends/meta-crtc.c
+@@ -36,45 +36,47 @@ meta_crtc_finalize (GObject *object)
+ {
+   MetaCrtc *crtc = META_CRTC (object);
+ 
+   if (crtc->driver_notify)
+     crtc->driver_notify (crtc);
+ 
+   G_OBJECT_CLASS (meta_crtc_parent_class)->finalize (object);
+ }
+ 
+ static void
+ meta_crtc_init (MetaCrtc *crtc)
+ {
+ }
+ 
+ static void
+ meta_crtc_class_init (MetaCrtcClass *klass)
+ {
+   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ 
+   object_class->finalize = meta_crtc_finalize;
+ }
+ 
+ static void
+ meta_crtc_mode_finalize (GObject *object)
+ {
+   MetaCrtcMode *crtc_mode = META_CRTC_MODE (object);
+ 
+   if (crtc_mode->driver_notify)
+     crtc_mode->driver_notify (crtc_mode);
+ 
++  g_free (crtc_mode->name);
++
+   G_OBJECT_CLASS (meta_crtc_mode_parent_class)->finalize (object);
+ }
+ 
+ static void
+ meta_crtc_mode_init (MetaCrtcMode *crtc_mode)
+ {
+ }
+ 
+ static void
+ meta_crtc_mode_class_init (MetaCrtcModeClass *klass)
+ {
+   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ 
+   object_class->finalize = meta_crtc_mode_finalize;
+ }
+-- 
+2.26.2
+
diff --git a/SOURCES/0018-monitor-config-manager-Always-free-temporary-region-.patch b/SOURCES/0018-monitor-config-manager-Always-free-temporary-region-.patch
new file mode 100644
index 0000000..3b5de4c
--- /dev/null
+++ b/SOURCES/0018-monitor-config-manager-Always-free-temporary-region-.patch
@@ -0,0 +1,162 @@
+From f70261f80302d9f4ffd62f9dbae3d515b5778467 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Sun, 21 Jul 2019 18:18:14 +0200
+Subject: [PATCH 18/28] monitor-config-manager: Always free temporary region on
+ error
+
+During the config parsing we are allocating a temporary rectangles region
+however in case that we find an error we return prematurely but in some cases
+(when not using identical global scale, or when not using adjacent neighbors)
+we didn't free the region list before.
+
+Instead of caring of doing this manually everytime, let's just use an
+auto-pointer to manage the region lifecycle.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/backends/meta-monitor-config-manager.c | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
+index cb67e11e7..59a20d449 100644
+--- a/src/backends/meta-monitor-config-manager.c
++++ b/src/backends/meta-monitor-config-manager.c
+@@ -1578,134 +1578,129 @@ meta_logical_monitor_configs_have_monitor (GList           *logical_monitor_conf
+     {
+       MetaLogicalMonitorConfig *logical_monitor_config = l->data;
+       GList *k;
+ 
+       for (k = logical_monitor_config->monitor_configs; k; k = k->next)
+         {
+           MetaMonitorConfig *monitor_config = k->data;
+ 
+           if (meta_monitor_spec_equals (monitor_spec,
+                                         monitor_config->monitor_spec))
+             return TRUE;
+         }
+     }
+ 
+   return FALSE;
+ }
+ 
+ static gboolean
+ meta_monitors_config_is_monitor_enabled (MetaMonitorsConfig *config,
+                                          MetaMonitorSpec    *monitor_spec)
+ {
+   return meta_logical_monitor_configs_have_monitor (config->logical_monitor_configs,
+                                                     monitor_spec);
+ }
+ 
+ gboolean
+ meta_verify_monitors_config (MetaMonitorsConfig *config,
+                              MetaMonitorManager *monitor_manager,
+                              GError            **error)
+ {
++  g_autoptr (GList) region = NULL;
+   int min_x, min_y;
+   gboolean has_primary;
+-  GList *region;
+   GList *l;
+   gboolean global_scale_required;
+ 
+   if (!config->logical_monitor_configs)
+     {
+       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                    "Monitors config incomplete");
+       return FALSE;
+     }
+ 
+   global_scale_required =
+     !!(meta_monitor_manager_get_capabilities (monitor_manager) &
+        META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
+ 
+   min_x = INT_MAX;
+   min_y = INT_MAX;
+-  region = NULL;
+   has_primary = FALSE;
+   for (l = config->logical_monitor_configs; l; l = l->next)
+     {
+       MetaLogicalMonitorConfig *logical_monitor_config = l->data;
+ 
+       if (global_scale_required)
+         {
+           MetaLogicalMonitorConfig *prev_logical_monitor_config =
+             l->prev ? l->prev->data : NULL;
+ 
+           if (prev_logical_monitor_config &&
+               (prev_logical_monitor_config->scale !=
+                logical_monitor_config->scale))
+             {
+               g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                            "Logical monitor scales must be identical");
+               return FALSE;
+             }
+         }
+ 
+       if (meta_rectangle_overlaps_with_region (region,
+                                                &logical_monitor_config->layout))
+         {
+-          g_list_free (region);
+           g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                        "Logical monitors overlap");
+           return FALSE;
+         }
+ 
+       if (has_primary && logical_monitor_config->is_primary)
+         {
+-          g_list_free (region);
+           g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                        "Config contains multiple primary logical monitors");
+           return FALSE;
+         }
+       else if (logical_monitor_config->is_primary)
+         {
+           has_primary = TRUE;
+         }
+ 
+       if (!has_adjecent_neighbour (config, logical_monitor_config))
+         {
+           g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                        "Logical monitors not adjecent");
+           return FALSE;
+         }
+ 
+       min_x = MIN (logical_monitor_config->layout.x, min_x);
+       min_y = MIN (logical_monitor_config->layout.y, min_y);
+ 
+       region = g_list_prepend (region, &logical_monitor_config->layout);
+     }
+ 
+-  g_list_free (region);
+-
+   for (l = config->disabled_monitor_specs; l; l = l->next)
+     {
+       MetaMonitorSpec *monitor_spec = l->data;
+ 
+       if (meta_monitors_config_is_monitor_enabled (config, monitor_spec))
+         {
+           g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                        "Assigned monitor explicitly disabled");
+           return FALSE;
+         }
+     }
+ 
+   if (min_x != 0 || min_y != 0)
+     {
+       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                    "Logical monitors positions are offset");
+       return FALSE;
+     }
+ 
+   if (!has_primary)
+     {
+       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                    "Config is missing primary logical");
+       return FALSE;
+     }
+ 
+   return TRUE;
+ }
+-- 
+2.26.2
+
diff --git a/SOURCES/0019-monitor-config-store-Use-autopointers-to-cleanup-par.patch b/SOURCES/0019-monitor-config-store-Use-autopointers-to-cleanup-par.patch
new file mode 100644
index 0000000..1b0410d
--- /dev/null
+++ b/SOURCES/0019-monitor-config-store-Use-autopointers-to-cleanup-par.patch
@@ -0,0 +1,116 @@
+From 9de0b3df99d1c2fabe03d06c0e9fdec040aafca8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Mon, 22 Jul 2019 00:05:05 +0200
+Subject: [PATCH 19/28] monitor-config-store: Use autopointers to cleanup parse
+ context and buffer
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/backends/meta-monitor-config-store.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c
+index 770bef734..e24ce707a 100644
+--- a/src/backends/meta-monitor-config-store.c
++++ b/src/backends/meta-monitor-config-store.c
+@@ -1060,95 +1060,92 @@ handle_text (GMarkupParseContext *context,
+           {
+             g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+                          "Invalid mode flag %.*s", (int) text_len, text);
+           }
+ 
+         return;
+       }
+ 
+     case STATE_MONITOR_UNDERSCANNING:
+       {
+         read_bool (text, text_len,
+                    &parser->current_monitor_config->enable_underscanning,
+                    error);
+         return;
+       }
+     }
+ }
+ 
+ static const GMarkupParser config_parser = {
+   .start_element = handle_start_element,
+   .end_element = handle_end_element,
+   .text = handle_text
+ };
+ 
+ static gboolean
+ read_config_file (MetaMonitorConfigStore  *config_store,
+                   GFile                   *file,
+                   MetaMonitorsConfigFlag   extra_config_flags,
+                   GError                 **error)
+ {
+-  char *buffer;
++  g_autoptr (GMarkupParseContext) parse_context = NULL;
++  g_autofree char *buffer = NULL;
+   gsize size;
+   ConfigParser parser;
+-  GMarkupParseContext *parse_context;
+ 
+   if (!g_file_load_contents (file, NULL, &buffer, &size, NULL, error))
+     return FALSE;
+ 
+   parser = (ConfigParser) {
+     .state = STATE_INITIAL,
+     .config_store = config_store,
+     .extra_config_flags = extra_config_flags,
+   };
+ 
+   parse_context = g_markup_parse_context_new (&config_parser,
+                                               G_MARKUP_TREAT_CDATA_AS_TEXT |
+                                               G_MARKUP_PREFIX_ERROR_POSITION,
+                                               &parser, NULL);
+   if (!g_markup_parse_context_parse (parse_context, buffer, size, error))
+     {
+       g_list_free_full (parser.current_logical_monitor_configs,
+                         (GDestroyNotify) meta_logical_monitor_config_free);
+       g_clear_pointer (&parser.current_monitor_spec,
+                        meta_monitor_spec_free);
+       g_free (parser.current_monitor_mode_spec);
+       g_clear_pointer (&parser.current_monitor_config,
+                       meta_monitor_config_free);
+       g_clear_pointer (&parser.current_logical_monitor_config,
+                        meta_logical_monitor_config_free);
+       return FALSE;
+     }
+ 
+-  g_markup_parse_context_free (parse_context);
+-  g_free (buffer);
+-
+   return TRUE;
+ }
+ 
+ MetaMonitorsConfig *
+ meta_monitor_config_store_lookup (MetaMonitorConfigStore *config_store,
+                                   MetaMonitorsConfigKey  *key)
+ {
+   return META_MONITORS_CONFIG (g_hash_table_lookup (config_store->configs,
+                                                     key));
+ }
+ 
+ static void
+ append_monitor_spec (GString         *buffer,
+                      MetaMonitorSpec *monitor_spec,
+                      const char      *indentation)
+ {
+   g_string_append_printf (buffer, "%s<monitorspec>\n", indentation);
+   g_string_append_printf (buffer, "%s  <connector>%s</connector>\n",
+                           indentation,
+                           monitor_spec->connector);
+   g_string_append_printf (buffer, "%s  <vendor>%s</vendor>\n",
+                           indentation,
+                           monitor_spec->vendor);
+   g_string_append_printf (buffer, "%s  <product>%s</product>\n",
+                           indentation,
+                           monitor_spec->product);
+   g_string_append_printf (buffer, "%s  <serial>%s</serial>\n",
+                           indentation,
+                           monitor_spec->serial);
+   g_string_append_printf (buffer, "%s</monitorspec>\n", indentation);
+-- 
+2.26.2
+
diff --git a/SOURCES/0020-monitor-Free-the-existing-mode-if-replacing-it.patch b/SOURCES/0020-monitor-Free-the-existing-mode-if-replacing-it.patch
new file mode 100644
index 0000000..7b3bbd6
--- /dev/null
+++ b/SOURCES/0020-monitor-Free-the-existing-mode-if-replacing-it.patch
@@ -0,0 +1,85 @@
+From 4020cddaf71e8868c03f0136964a6429af313b54 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Wed, 24 Jul 2019 15:40:06 +0200
+Subject: [PATCH 20/28] monitor: Free the existing mode if replacing it
+
+When adding a mode and replacing it, we need to free it after that we've added
+it to the table. Since the mode_ids table has not ownership on the mode id or
+on the mode itself, we need to free it once replaced.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/backends/meta-monitor.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c
+index 9a412a612..ec583aa13 100644
+--- a/src/backends/meta-monitor.c
++++ b/src/backends/meta-monitor.c
+@@ -437,60 +437,63 @@ generate_mode_id (MetaMonitorModeSpec *monitor_mode_spec)
+   is_interlaced = !!(monitor_mode_spec->flags & META_CRTC_MODE_FLAG_INTERLACE);
+   g_ascii_dtostr (refresh_rate_str, G_ASCII_DTOSTR_BUF_SIZE,
+                   monitor_mode_spec->refresh_rate);
+ 
+   return g_strdup_printf ("%dx%d%s@%s",
+                           monitor_mode_spec->width,
+                           monitor_mode_spec->height,
+                           is_interlaced ? "i" : "",
+                           refresh_rate_str);
+ }
+ 
+ static gboolean
+ meta_monitor_add_mode (MetaMonitor     *monitor,
+                        MetaMonitorMode *monitor_mode,
+                        gboolean         replace)
+ {
+   MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
+   MetaMonitorMode *existing_mode;
+ 
+   existing_mode = g_hash_table_lookup (priv->mode_ids,
+                                        meta_monitor_mode_get_id (monitor_mode));
+   if (existing_mode && !replace)
+     return FALSE;
+ 
+   if (existing_mode)
+     priv->modes = g_list_remove (priv->modes, existing_mode);
+ 
+   priv->modes = g_list_append (priv->modes, monitor_mode);
+   g_hash_table_replace (priv->mode_ids, monitor_mode->id, monitor_mode);
+ 
++  if (existing_mode)
++    meta_monitor_mode_free (existing_mode);
++
+   return TRUE;
+ }
+ 
+ static MetaMonitorModeSpec
+ meta_monitor_create_spec (MetaMonitor  *monitor,
+                           int           width,
+                           int           height,
+                           MetaCrtcMode *crtc_mode)
+ {
+   MetaOutput *output = meta_monitor_get_main_output (monitor);
+ 
+   if (meta_monitor_transform_is_rotated (output->panel_orientation_transform))
+     {
+       int temp = width;
+       width = height;
+       height = temp;
+     }
+ 
+   return (MetaMonitorModeSpec) {
+     .width = width,
+     .height = height,
+     .refresh_rate = crtc_mode->refresh_rate,
+     .flags = crtc_mode->flags & HANDLED_CRTC_MODE_FLAGS
+   };
+ }
+ 
+ static void
+ meta_monitor_normal_generate_modes (MetaMonitorNormal *monitor_normal)
+ {
+   MetaMonitor *monitor = META_MONITOR (monitor_normal);
+-- 
+2.26.2
+
diff --git a/SOURCES/0021-monitor-Use-delete-link-to-free-the-tiled-modes-whil.patch b/SOURCES/0021-monitor-Use-delete-link-to-free-the-tiled-modes-whil.patch
new file mode 100644
index 0000000..e39a759
--- /dev/null
+++ b/SOURCES/0021-monitor-Use-delete-link-to-free-the-tiled-modes-whil.patch
@@ -0,0 +1,86 @@
+From c4c29246f96ff959db7054c60d9aa76fb45b9e91 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Wed, 24 Jul 2019 15:41:14 +0200
+Subject: [PATCH 21/28] monitor: Use delete link to free the tiled modes while
+ iterating
+
+We iterate over a temporary list of tiled modes when adding them, but the list
+isn't free'd during the iteration.
+
+So use GList's delete_link instead of remove_link.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/backends/meta-monitor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c
+index ec583aa13..ff959b3bc 100644
+--- a/src/backends/meta-monitor.c
++++ b/src/backends/meta-monitor.c
+@@ -901,61 +901,61 @@ generate_tiled_monitor_modes (MetaMonitorTiled *monitor_tiled)
+ 
+   main_output = meta_monitor_get_main_output (META_MONITOR (monitor_tiled));
+ 
+   for (i = 0; i < main_output->n_modes; i++)
+     {
+       MetaCrtcMode *reference_crtc_mode = main_output->modes[i];
+       MetaMonitorMode *mode;
+       gboolean is_preferred;
+ 
+       if (!is_crtc_mode_tiled (main_output, reference_crtc_mode))
+         continue;
+ 
+       mode = create_tiled_monitor_mode (monitor_tiled, reference_crtc_mode,
+                                         &is_preferred);
+       if (!mode)
+         continue;
+ 
+       tiled_modes = g_list_append (tiled_modes, mode);
+ 
+       if (is_monitor_mode_assigned (monitor, mode))
+         monitor_priv->current_mode = mode;
+ 
+       if (is_preferred)
+         monitor_priv->preferred_mode = mode;
+     }
+ 
+   while ((l = tiled_modes))
+     {
+       MetaMonitorMode *mode = l->data;
+ 
+-      tiled_modes = g_list_remove_link (tiled_modes, l);
++      tiled_modes = g_list_delete_link (tiled_modes, l);
+ 
+       if (!meta_monitor_add_mode (monitor, mode, FALSE))
+         {
+           meta_monitor_mode_free (mode);
+           continue;
+         }
+ 
+       if (!monitor_priv->preferred_mode)
+         {
+           if (!best_mode ||
+               mode->spec.refresh_rate > best_mode->spec.refresh_rate)
+             best_mode = mode;
+         }
+     }
+ 
+   if (best_mode)
+     monitor_priv->preferred_mode = best_mode;
+ }
+ 
+ static MetaMonitorMode *
+ create_untiled_monitor_mode (MetaMonitorTiled *monitor_tiled,
+                              MetaOutput       *main_output,
+                              MetaCrtcMode     *crtc_mode)
+ {
+   MetaMonitor *monitor = META_MONITOR (monitor_tiled);
+   MetaMonitorPrivate *monitor_priv =
+     meta_monitor_get_instance_private (monitor);
+   MetaMonitorModeTiled *mode;
+   GList *l;
+   int i;
+-- 
+2.26.2
+
diff --git a/SOURCES/0022-monitor-config-store-Check-if-a-config-is-system-one.patch b/SOURCES/0022-monitor-config-store-Check-if-a-config-is-system-one.patch
new file mode 100644
index 0000000..3b7cfe0
--- /dev/null
+++ b/SOURCES/0022-monitor-config-store-Check-if-a-config-is-system-one.patch
@@ -0,0 +1,92 @@
+From 05b226e20e267f1b4368186727e0fbc4b0b43ac6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Wed, 24 Jul 2019 17:22:15 +0200
+Subject: [PATCH 22/28] monitor-config-store: Check if a config is system one
+ before removing it
+
+On meta_monitor_config_store_remove() we save configs if removing a non-system
+config, however we were doing the check after the configuration was removed from
+the has table, and then potentially destroyed. Causing a memory error.
+
+So, do the check before the removal.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/backends/meta-monitor-config-store.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c
+index e24ce707a..7b0b448ea 100644
+--- a/src/backends/meta-monitor-config-store.c
++++ b/src/backends/meta-monitor-config-store.c
+@@ -1425,63 +1425,66 @@ maybe_save_configs (MetaMonitorConfigStore *config_store)
+   /*
+    * If a custom file is used, it means we are run by the test suite. When this
+    * is done, avoid replacing the user configuration file with test data,
+    * except if a custom write file is set as well.
+    */
+   if (!config_store->custom_read_file || config_store->custom_write_file)
+     meta_monitor_config_store_save (config_store);
+ }
+ 
+ static gboolean
+ is_system_config (MetaMonitorsConfig *config)
+ {
+   return !!(config->flags & META_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG);
+ }
+ 
+ void
+ meta_monitor_config_store_add (MetaMonitorConfigStore *config_store,
+                                MetaMonitorsConfig     *config)
+ {
+   g_hash_table_replace (config_store->configs,
+                         config->key, g_object_ref (config));
+ 
+   if (!is_system_config (config))
+     maybe_save_configs (config_store);
+ }
+ 
+ void
+ meta_monitor_config_store_remove (MetaMonitorConfigStore *config_store,
+                                   MetaMonitorsConfig     *config)
+ {
++  gboolean system_config;
++
++  system_config = is_system_config (config);
+   g_hash_table_remove (config_store->configs, config->key);
+ 
+-  if (!is_system_config (config))
++  if (!system_config)
+     maybe_save_configs (config_store);
+ }
+ 
+ gboolean
+ meta_monitor_config_store_set_custom (MetaMonitorConfigStore *config_store,
+                                       const char             *read_path,
+                                       const char             *write_path,
+                                       GError                **error)
+ {
+   g_clear_object (&config_store->custom_read_file);
+   g_clear_object (&config_store->custom_write_file);
+   g_hash_table_remove_all (config_store->configs);
+ 
+   config_store->custom_read_file = g_file_new_for_path (read_path);
+   if (write_path)
+     config_store->custom_write_file = g_file_new_for_path (write_path);
+ 
+   return read_config_file (config_store,
+                            config_store->custom_read_file,
+                            META_MONITORS_CONFIG_FLAG_NONE,
+                            error);
+ }
+ 
+ int
+ meta_monitor_config_store_get_config_count (MetaMonitorConfigStore *config_store)
+ {
+   return (int) g_hash_table_size (config_store->configs);
+ }
+ 
+ MetaMonitorManager *
+-- 
+2.26.2
+
diff --git a/SOURCES/0023-monitor-config-migration-Unref-the-new-config-once-a.patch b/SOURCES/0023-monitor-config-migration-Unref-the-new-config-once-a.patch
new file mode 100644
index 0000000..15c58b2
--- /dev/null
+++ b/SOURCES/0023-monitor-config-migration-Unref-the-new-config-once-a.patch
@@ -0,0 +1,120 @@
+From d585e6d6f15122ca58995603cfc67bfeb111b0d8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Thu, 25 Jul 2019 01:24:01 +0200
+Subject: [PATCH 23/28] monitor-config-migration: Unref the new config once
+ added to the store
+
+When migrating the configurations we've a leak because the config is passed to
+the store that takes its ownership via meta_monitor_config_store_add(), but we
+never relase the reference of the newly created object.
+
+So use an auto-pointer to manage the object lifetime when returning.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/backends/meta-monitor-config-migration.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/src/backends/meta-monitor-config-migration.c b/src/backends/meta-monitor-config-migration.c
+index d619dc433..ed6c80184 100644
+--- a/src/backends/meta-monitor-config-migration.c
++++ b/src/backends/meta-monitor-config-migration.c
+@@ -1067,94 +1067,93 @@ find_disabled_monitor_specs (MetaLegacyMonitorsConfig *legacy_config)
+       MetaOutputKey *output_key = &legacy_config->keys[i];
+       MetaOutputConfig *output_config = &legacy_config->outputs[i];
+       MetaMonitorSpec *monitor_spec;
+ 
+       if (output_config->enabled)
+         continue;
+ 
+       monitor_spec = g_new0 (MetaMonitorSpec, 1);
+       *monitor_spec = (MetaMonitorSpec) {
+         .connector = output_key->connector,
+         .vendor = output_key->vendor,
+         .product = output_key->product,
+         .serial = output_key->serial
+       };
+ 
+       disabled_monitors = g_list_prepend (disabled_monitors, monitor_spec);
+     }
+ 
+   return disabled_monitors;
+ }
+ 
+ static void
+ migrate_config (gpointer key,
+                 gpointer value,
+                 gpointer user_data)
+ {
+   MetaLegacyMonitorsConfig *legacy_config = key;
+   MetaMonitorConfigStore *config_store = user_data;
+   MetaMonitorManager *monitor_manager =
+     meta_monitor_config_store_get_monitor_manager (config_store);
++  g_autoptr (MetaMonitorsConfig) config = NULL;
+   GList *logical_monitor_configs;
+   MetaLogicalMonitorLayoutMode layout_mode;
+   GError *error = NULL;
+   GList *disabled_monitor_specs;
+-  MetaMonitorsConfig *config;
+ 
+   logical_monitor_configs = derive_logical_monitor_configs (legacy_config,
+                                                             config_store,
+                                                             &error);
+   if (!logical_monitor_configs)
+     {
+       g_autofree char *config_name = NULL;
+ 
+       config_name = generate_config_name (legacy_config);
+       g_warning ("Failed to migrate monitor configuration for %s: %s",
+                  config_name, error->message);
+       return;
+     }
+ 
+   disabled_monitor_specs = find_disabled_monitor_specs (legacy_config);
+ 
+   layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
+   config = meta_monitors_config_new_full (logical_monitor_configs,
+                                           disabled_monitor_specs,
+                                           layout_mode,
+                                           META_MONITORS_CONFIG_FLAG_MIGRATED);
+   if (!meta_verify_monitors_config (config, monitor_manager, &error))
+     {
+       g_autofree char *config_name = NULL;
+ 
+       config_name = generate_config_name (legacy_config);
+       g_warning ("Ignoring invalid monitor configuration for %s: %s",
+                  config_name, error->message);
+-      g_object_unref (config);
+       return;
+     }
+ 
+   meta_monitor_config_store_add (config_store, config);
+ }
+ 
+ gboolean
+ meta_migrate_old_monitors_config (MetaMonitorConfigStore *config_store,
+                                   GFile                  *in_file,
+                                   GError                **error)
+ {
+   g_autoptr (GHashTable) configs = NULL;
+ 
+   configs = load_config_file (in_file, error);
+   if (!configs)
+     return FALSE;
+ 
+   g_hash_table_foreach (configs, migrate_config, config_store);
+ 
+   return TRUE;
+ }
+ 
+ gboolean
+ meta_migrate_old_user_monitors_config (MetaMonitorConfigStore *config_store,
+                                        GError                **error)
+ {
+   g_autofree char *backup_path = NULL;
+   g_autoptr (GFile) backup_file = NULL;
+   g_autofree char *user_file_path = NULL;
+   g_autoptr (GFile) user_file = NULL;
+-- 
+2.26.2
+
diff --git a/SOURCES/0024-monitor-config-migration-Free-the-output-key-on-inva.patch b/SOURCES/0024-monitor-config-migration-Free-the-output-key-on-inva.patch
new file mode 100644
index 0000000..7af5917
--- /dev/null
+++ b/SOURCES/0024-monitor-config-migration-Free-the-output-key-on-inva.patch
@@ -0,0 +1,86 @@
+From c07364d65d3e6353076b02c97ce63dfe00aaedc7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Thu, 25 Jul 2019 01:21:28 +0200
+Subject: [PATCH 24/28] monitor-config-migration: Free the output key on
+ invalid spec
+
+In create_monitor_config we assume that we take the ownership of the output_key
+values, however if we have an early return because an invalid spec is set, we
+don't free it.
+
+So cleanup it on failure, as it happens for other cases.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/backends/meta-monitor-config-migration.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/backends/meta-monitor-config-migration.c b/src/backends/meta-monitor-config-migration.c
+index ed6c80184..26393ef02 100644
+--- a/src/backends/meta-monitor-config-migration.c
++++ b/src/backends/meta-monitor-config-migration.c
+@@ -655,60 +655,61 @@ load_config_file (GFile   *file,
+       g_free (parser.output_field);
+       g_hash_table_destroy (parser.configs);
+ 
+       return NULL;
+     }
+ 
+   return parser.configs;
+ }
+ 
+ static MetaMonitorConfig *
+ create_monitor_config (MetaOutputKey    *output_key,
+                        MetaOutputConfig *output_config,
+                        int               mode_width,
+                        int               mode_height,
+                        GError          **error)
+ {
+   MetaMonitorModeSpec *mode_spec;
+   MetaMonitorSpec *monitor_spec;
+   MetaMonitorConfig *monitor_config;
+ 
+   mode_spec = g_new0 (MetaMonitorModeSpec, 1);
+   *mode_spec = (MetaMonitorModeSpec) {
+     .width = mode_width,
+     .height = mode_height,
+     .refresh_rate = output_config->refresh_rate
+   };
+ 
+   if (!meta_verify_monitor_mode_spec (mode_spec, error))
+     {
+       g_free (mode_spec);
++      free_output_key (output_key);
+       return NULL;
+     }
+ 
+   monitor_spec = g_new0 (MetaMonitorSpec, 1);
+   *monitor_spec = (MetaMonitorSpec) {
+     .connector = output_key->connector,
+     .vendor = output_key->vendor,
+     .product = output_key->product,
+     .serial = output_key->serial
+   };
+ 
+   monitor_config = g_new0 (MetaMonitorConfig, 1);
+   *monitor_config = (MetaMonitorConfig) {
+     .monitor_spec = monitor_spec,
+     .mode_spec = mode_spec,
+     .enable_underscanning = output_config->is_underscanning
+   };
+ 
+   if (!meta_verify_monitor_config (monitor_config, error))
+     {
+       meta_monitor_config_free (monitor_config);
+       return NULL;
+     }
+ 
+   return monitor_config;
+ }
+ 
+ typedef struct _MonitorTile
+ {
+   MetaOutputKey *output_key;
+-- 
+2.26.2
+
diff --git a/SOURCES/0025-compositor-Use-meta_window_actor_from_window-to-get-.patch b/SOURCES/0025-compositor-Use-meta_window_actor_from_window-to-get-.patch
new file mode 100644
index 0000000..0186c8d
--- /dev/null
+++ b/SOURCES/0025-compositor-Use-meta_window_actor_from_window-to-get-.patch
@@ -0,0 +1,532 @@
+From a6d6b14306727692bffdadd09bca239aebc867c4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Thu, 25 Jul 2019 02:02:21 +0200
+Subject: [PATCH 25/28] compositor: Use meta_window_actor_from_window to get
+ the actor
+
+Use this utility function instead of repeating the cast all the time.
+
+Also in some case, warn if the returned value isn't valid.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/compositor/compositor.c | 58 +++++++++++++++++++++++++++----------
+ 1 file changed, 42 insertions(+), 16 deletions(-)
+
+diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
+index 799bcddf5..d02926171 100644
+--- a/src/compositor/compositor.c
++++ b/src/compositor/compositor.c
+@@ -116,61 +116,64 @@ meta_finish_workspace_switch (MetaCompositor *compositor)
+ void
+ meta_switch_workspace_completed (MetaCompositor *compositor)
+ {
+   /* FIXME -- must redo stacking order */
+   compositor->switch_workspace_in_progress--;
+   if (compositor->switch_workspace_in_progress < 0)
+     {
+       g_warning ("Error in workspace_switch accounting!");
+       compositor->switch_workspace_in_progress = 0;
+     }
+ 
+   if (!compositor->switch_workspace_in_progress)
+     meta_finish_workspace_switch (compositor);
+ }
+ 
+ void
+ meta_compositor_destroy (MetaCompositor *compositor)
+ {
+   clutter_threads_remove_repaint_func (compositor->pre_paint_func_id);
+   clutter_threads_remove_repaint_func (compositor->post_paint_func_id);
+ 
+   if (compositor->have_x11_sync_object)
+     meta_sync_ring_destroy ();
+ }
+ 
+ static void
+ process_damage (MetaCompositor     *compositor,
+                 XDamageNotifyEvent *event,
+                 MetaWindow         *window)
+ {
+-  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
++  MetaWindowActor *window_actor = meta_window_actor_from_window (window);
++
++  g_return_if_fail (window_actor);
++
+   meta_window_actor_process_x11_damage (window_actor, event);
+ 
+   compositor->frame_has_updated_xsurfaces = TRUE;
+ }
+ 
+ /* compat helper */
+ static MetaCompositor *
+ get_compositor_for_screen (MetaScreen *screen)
+ {
+   return screen->display->compositor;
+ }
+ 
+ /**
+  * meta_get_stage_for_screen:
+  * @screen: a #MetaScreen
+  *
+  * Returns: (transfer none): The #ClutterStage for the screen
+  */
+ ClutterActor *
+ meta_get_stage_for_screen (MetaScreen *screen)
+ {
+   MetaCompositor *compositor = get_compositor_for_screen (screen);
+   return compositor->stage;
+ }
+ 
+ /**
+  * meta_get_window_group_for_screen:
+  * @screen: a #MetaScreen
+  *
+  * Returns: (transfer none): The window group corresponding to @screen
+@@ -707,135 +710,146 @@ meta_shape_cow_for_window (MetaCompositor *compositor,
+       meta_window_get_frame_rect (window, &rect);
+ 
+       window_bounds.x = rect.x;
+       window_bounds.y = rect.y;
+       window_bounds.width = rect.width;
+       window_bounds.height = rect.height;
+ 
+       meta_screen_get_size (display->screen, &width, &height);
+       screen_rect.x = 0;
+       screen_rect.y = 0;
+       screen_rect.width = width;
+       screen_rect.height = height;
+ 
+       output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1);
+ 
+       XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region);
+       XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, output_region);
+       XFixesDestroyRegion (xdisplay, output_region);
+     }
+ }
+ 
+ static void
+ set_unredirected_window (MetaCompositor *compositor,
+                          MetaWindow     *window)
+ {
+   if (compositor->unredirected_window == window)
+     return;
+ 
+   if (compositor->unredirected_window != NULL)
+     {
+-      MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window));
++      MetaWindowActor *window_actor =
++        meta_window_actor_from_window (compositor->unredirected_window);
+       meta_window_actor_set_unredirected (window_actor, FALSE);
+     }
+ 
+   meta_shape_cow_for_window (compositor, window);
+   compositor->unredirected_window = window;
+ 
+   if (compositor->unredirected_window != NULL)
+     {
+-      MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window));
++      MetaWindowActor *window_actor =
++        meta_window_actor_from_window (compositor->unredirected_window);
+       meta_window_actor_set_unredirected (window_actor, TRUE);
+     }
+ }
+ 
+ void
+ meta_compositor_add_window (MetaCompositor    *compositor,
+                             MetaWindow        *window)
+ {
+   MetaDisplay *display = compositor->display;
+ 
+   meta_error_trap_push (display);
+ 
+   meta_window_actor_new (window);
+   sync_actor_stacking (compositor);
+ 
+   meta_error_trap_pop (display);
+ }
+ 
+ void
+ meta_compositor_remove_window (MetaCompositor *compositor,
+                                MetaWindow     *window)
+ {
+-  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
++  MetaWindowActor *window_actor = meta_window_actor_from_window (window);
++
++  if (!window_actor)
++    return;
+ 
+   if (compositor->unredirected_window == window)
+     set_unredirected_window (compositor, NULL);
+ 
+   meta_window_actor_queue_destroy (window_actor);
+ }
+ 
+ void
+ meta_compositor_sync_updates_frozen (MetaCompositor *compositor,
+                                      MetaWindow     *window)
+ {
+-  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
++  MetaWindowActor *window_actor = meta_window_actor_from_window (window);
++
++  g_return_if_fail (window_actor);
++
+   meta_window_actor_sync_updates_frozen (window_actor);
+ }
+ 
+ void
+ meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
+                                    MetaWindow     *window,
+                                    gboolean        no_delay_frame)
+ {
+-  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
++  MetaWindowActor *window_actor = meta_window_actor_from_window (window);
++
++  g_return_if_fail (window_actor);
++
+   meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame);
+ }
+ 
+ void
+ meta_compositor_window_shape_changed (MetaCompositor *compositor,
+                                       MetaWindow     *window)
+ {
+-  MetaWindowActor *window_actor;
+-  window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
++  MetaWindowActor *window_actor = meta_window_actor_from_window (window);
++
+   if (!window_actor)
+     return;
+ 
+   meta_window_actor_update_shape (window_actor);
+ }
+ 
+ void
+ meta_compositor_window_opacity_changed (MetaCompositor *compositor,
+                                         MetaWindow     *window)
+ {
+-  MetaWindowActor *window_actor;
+-  window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
++  MetaWindowActor *window_actor = meta_window_actor_from_window (window);
++
+   if (!window_actor)
+     return;
+ 
+   meta_window_actor_update_opacity (window_actor);
+ }
+ 
+ void
+ meta_compositor_window_surface_changed (MetaCompositor *compositor,
+                                         MetaWindow     *window)
+ {
+   MetaWindowActor *window_actor;
+   window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
+   if (!window_actor)
+     return;
+ 
+   meta_window_actor_update_surface (window_actor);
+ }
+ 
+ /**
+  * meta_compositor_process_event: (skip)
+  * @compositor:
+  * @event:
+  * @window:
+  *
+  */
+ gboolean
+ meta_compositor_process_event (MetaCompositor *compositor,
+                                XEvent         *event,
+                                MetaWindow     *window)
+ {
+@@ -872,81 +886,91 @@ meta_compositor_process_event (MetaCompositor *compositor,
+         }
+     }
+ 
+   if (compositor->have_x11_sync_object)
+     meta_sync_ring_handle_event (event);
+ 
+   /* Clutter needs to know about MapNotify events otherwise it will
+      think the stage is invisible */
+   if (!meta_is_wayland_compositor () && event->type == MapNotify)
+     clutter_x11_handle_event (event);
+ 
+   /* The above handling is basically just "observing" the events, so we return
+    * FALSE to indicate that the event should not be filtered out; if we have
+    * GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example.
+    */
+   return FALSE;
+ }
+ 
+ gboolean
+ meta_compositor_filter_keybinding (MetaCompositor *compositor,
+                                    MetaKeyBinding *binding)
+ {
+   return meta_plugin_manager_filter_keybinding (compositor->plugin_mgr, binding);
+ }
+ 
+ void
+ meta_compositor_show_window (MetaCompositor *compositor,
+ 			     MetaWindow	    *window,
+                              MetaCompEffect  effect)
+ {
+-  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
++  MetaWindowActor *window_actor = meta_window_actor_from_window (window);
++
++  g_return_if_fail (window_actor);
++
+  meta_window_actor_show (window_actor, effect);
+ }
+ 
+ void
+ meta_compositor_hide_window (MetaCompositor *compositor,
+                              MetaWindow     *window,
+                              MetaCompEffect  effect)
+ {
+-  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
++  MetaWindowActor *window_actor = meta_window_actor_from_window (window);
++
++  if (!window_actor)
++    return;
++
+   meta_window_actor_hide (window_actor, effect);
+ }
+ 
+ void
+ meta_compositor_size_change_window (MetaCompositor    *compositor,
+                                     MetaWindow        *window,
+                                     MetaSizeChange     which_change,
+                                     MetaRectangle     *old_frame_rect,
+                                     MetaRectangle     *old_buffer_rect)
+ {
+-  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
++  MetaWindowActor *window_actor = meta_window_actor_from_window (window);
++
++  g_return_if_fail (window_actor);
++
+   meta_window_actor_size_change (window_actor, which_change, old_frame_rect, old_buffer_rect);
+ }
+ 
+ void
+ meta_compositor_switch_workspace (MetaCompositor     *compositor,
+                                   MetaWorkspace      *from,
+                                   MetaWorkspace      *to,
+                                   MetaMotionDirection direction)
+ {
+   gint to_indx, from_indx;
+ 
+   to_indx   = meta_workspace_index (to);
+   from_indx = meta_workspace_index (from);
+ 
+   compositor->switch_workspace_in_progress++;
+ 
+   if (!meta_plugin_manager_switch_workspace (compositor->plugin_mgr,
+                                              from_indx,
+                                              to_indx,
+                                              direction))
+     {
+       compositor->switch_workspace_in_progress--;
+ 
+       /* We have to explicitely call this to fix up stacking order of the
+        * actors; this is because the abs stacking position of actors does not
+        * necessarily change during the window hiding/unhiding, only their
+        * relative position toward the destkop window.
+        */
+       meta_finish_workspace_switch (compositor);
+     }
+@@ -1093,61 +1117,61 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
+   stack = g_list_copy (stack); /* The new stack of MetaWindow */
+   old_stack = g_list_reverse (compositor->windows); /* The old stack of MetaWindowActor */
+   compositor->windows = NULL;
+ 
+   while (TRUE)
+     {
+       MetaWindowActor *old_actor = NULL, *stack_actor = NULL, *actor;
+       MetaWindow *old_window = NULL, *stack_window = NULL, *window;
+ 
+       /* Find the remaining top actor in our existing stack (ignoring
+        * windows that have been hidden and are no longer animating) */
+       while (old_stack)
+         {
+           old_actor = old_stack->data;
+           old_window = meta_window_actor_get_meta_window (old_actor);
+ 
+           if ((old_window->hidden || old_window->unmanaging) &&
+               !meta_window_actor_effect_in_progress (old_actor))
+             {
+               old_stack = g_list_delete_link (old_stack, old_stack);
+               old_actor = NULL;
+             }
+           else
+             break;
+         }
+ 
+       /* And the remaining top actor in the new stack */
+       while (stack)
+         {
+           stack_window = stack->data;
+-          stack_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (stack_window));
++          stack_actor = meta_window_actor_from_window (stack_window);
+           if (!stack_actor)
+             {
+               meta_verbose ("Failed to find corresponding MetaWindowActor "
+                             "for window %s\n", meta_window_get_description (stack_window));
+               stack = g_list_delete_link (stack, stack);
+             }
+           else
+             break;
+         }
+ 
+       if (!old_actor && !stack_actor) /* Nothing more to stack */
+         break;
+ 
+       /* We usually prefer the window in the new stack, but if if we
+        * found a hidden window in the process of being animated out
+        * of existence in the old stack we use that instead. We've
+        * filtered out non-animating hidden windows above.
+        */
+       if (old_actor &&
+           (!stack_actor || old_window->hidden || old_window->unmanaging))
+         {
+           actor = old_actor;
+           window = old_window;
+         }
+       else
+         {
+           actor = stack_actor;
+           window = stack_window;
+         }
+ 
+@@ -1159,63 +1183,65 @@ meta_compositor_sync_stack (MetaCompositor  *compositor,
+       compositor->windows = g_list_prepend (compositor->windows, actor);
+       if (meta_window_actor_is_stereo (actor))
+         stereo_window_count++;
+ 
+       stack = g_list_remove (stack, window);
+       old_stack = g_list_remove (old_stack, actor);
+     }
+ 
+   sync_actor_stacking (compositor);
+ 
+   meta_stereo_set_have_stereo_windows (stereo_window_count > 0);
+ 
+   if (compositor->top_window_actor)
+     g_signal_handlers_disconnect_by_func (compositor->top_window_actor,
+                                           on_top_window_actor_destroyed,
+                                           compositor);
+ 
+   compositor->top_window_actor = get_top_visible_window_actor (compositor);
+ 
+   if (compositor->top_window_actor)
+     g_signal_connect (compositor->top_window_actor, "destroy",
+                       G_CALLBACK (on_top_window_actor_destroyed),
+                       compositor);
+ }
+ 
+ void
+ meta_compositor_sync_window_geometry (MetaCompositor *compositor,
+ 				      MetaWindow *window,
+                                       gboolean did_placement)
+ {
+-  MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
++  MetaWindowActor *window_actor = meta_window_actor_from_window (window);
+   MetaWindowActorChanges changes;
+ 
++  g_return_if_fail (window_actor);
++
+   changes = meta_window_actor_sync_actor_geometry (window_actor, did_placement);
+ 
+   if (changes & META_WINDOW_ACTOR_CHANGE_SIZE)
+     meta_plugin_manager_event_size_changed (compositor->plugin_mgr, window_actor);
+ }
+ 
+ static void
+ on_presented (ClutterStage     *stage,
+               CoglFrameEvent    event,
+               ClutterFrameInfo *frame_info,
+               MetaCompositor   *compositor)
+ {
+   GList *l;
+ 
+   if (event == COGL_FRAME_EVENT_COMPLETE)
+     {
+       gint64 presentation_time_cogl = frame_info->presentation_time;
+       gint64 presentation_time;
+ 
+       if (presentation_time_cogl != 0)
+         {
+           /* Cogl reports presentation in terms of its own clock, which is
+            * guaranteed to be in nanoseconds but with no specified base. The
+            * normal case with the open source GPU drivers on Linux 3.8 and
+            * newer is that the base of cogl_get_clock_time() is that of
+            * clock_gettime(CLOCK_MONOTONIC), so the same as g_get_monotonic_time),
+            * but there's no exposure of that through the API. clock_gettime()
+            * is fairly fast, so calling it twice and subtracting to get a
+            * nearly-zero number is acceptable, if a litle ugly.
+            */
+@@ -1469,61 +1495,61 @@ meta_compositor_flash_screen (MetaCompositor *compositor,
+ 
+   clutter_actor_save_easing_state (flash);
+   clutter_actor_set_easing_mode (flash, CLUTTER_EASE_IN_QUAD);
+   clutter_actor_set_easing_duration (flash, FLASH_TIME_MS);
+   clutter_actor_set_opacity (flash, 192);
+ 
+   transition = clutter_actor_get_transition (flash, "opacity");
+   clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
+   clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
+ 
+   g_signal_connect (transition, "stopped",
+                     G_CALLBACK (flash_out_completed), flash);
+ 
+   clutter_actor_restore_easing_state (flash);
+ }
+ 
+ static void
+ window_flash_out_completed (ClutterTimeline *timeline,
+                             gboolean         is_finished,
+                             gpointer         user_data)
+ {
+   ClutterActor *flash = CLUTTER_ACTOR (user_data);
+   clutter_actor_destroy (flash);
+ }
+ 
+ void
+ meta_compositor_flash_window (MetaCompositor *compositor,
+                               MetaWindow     *window)
+ {
+   ClutterActor *window_actor =
+-    CLUTTER_ACTOR (meta_window_get_compositor_private (window));
++    CLUTTER_ACTOR (meta_window_actor_from_window (window));
+   ClutterActor *flash;
+   ClutterTransition *transition;
+ 
+   flash = clutter_actor_new ();
+   clutter_actor_set_background_color (flash, CLUTTER_COLOR_Black);
+   clutter_actor_set_size (flash, window->rect.width, window->rect.height);
+   clutter_actor_set_position (flash,
+                               window->custom_frame_extents.left,
+                               window->custom_frame_extents.top);
+   clutter_actor_set_opacity (flash, 0);
+   clutter_actor_add_child (window_actor, flash);
+ 
+   clutter_actor_save_easing_state (flash);
+   clutter_actor_set_easing_mode (flash, CLUTTER_EASE_IN_QUAD);
+   clutter_actor_set_easing_duration (flash, FLASH_TIME_MS);
+   clutter_actor_set_opacity (flash, 192);
+ 
+   transition = clutter_actor_get_transition (flash, "opacity");
+   clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
+   clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
+ 
+   g_signal_connect (transition, "stopped",
+                     G_CALLBACK (window_flash_out_completed), flash);
+ 
+   clutter_actor_restore_easing_state (flash);
+ }
+ 
+ /**
+  * meta_compositor_monotonic_time_to_server_time:
+  * @display: a #MetaDisplay
+-- 
+2.26.2
+
diff --git a/SOURCES/0026-compositor-Fix-indentation-on-show-window.patch b/SOURCES/0026-compositor-Fix-indentation-on-show-window.patch
new file mode 100644
index 0000000..810b845
--- /dev/null
+++ b/SOURCES/0026-compositor-Fix-indentation-on-show-window.patch
@@ -0,0 +1,80 @@
+From 15a7f8080788c54cf1ad3df0d969fb61b9dc315d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Thu, 25 Jul 2019 02:02:44 +0200
+Subject: [PATCH 26/28] compositor: Fix indentation on show window
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/compositor/compositor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
+index d02926171..65f5ab1f4 100644
+--- a/src/compositor/compositor.c
++++ b/src/compositor/compositor.c
+@@ -890,61 +890,61 @@ meta_compositor_process_event (MetaCompositor *compositor,
+     meta_sync_ring_handle_event (event);
+ 
+   /* Clutter needs to know about MapNotify events otherwise it will
+      think the stage is invisible */
+   if (!meta_is_wayland_compositor () && event->type == MapNotify)
+     clutter_x11_handle_event (event);
+ 
+   /* The above handling is basically just "observing" the events, so we return
+    * FALSE to indicate that the event should not be filtered out; if we have
+    * GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example.
+    */
+   return FALSE;
+ }
+ 
+ gboolean
+ meta_compositor_filter_keybinding (MetaCompositor *compositor,
+                                    MetaKeyBinding *binding)
+ {
+   return meta_plugin_manager_filter_keybinding (compositor->plugin_mgr, binding);
+ }
+ 
+ void
+ meta_compositor_show_window (MetaCompositor *compositor,
+ 			     MetaWindow	    *window,
+                              MetaCompEffect  effect)
+ {
+   MetaWindowActor *window_actor = meta_window_actor_from_window (window);
+ 
+   g_return_if_fail (window_actor);
+ 
+- meta_window_actor_show (window_actor, effect);
++  meta_window_actor_show (window_actor, effect);
+ }
+ 
+ void
+ meta_compositor_hide_window (MetaCompositor *compositor,
+                              MetaWindow     *window,
+                              MetaCompEffect  effect)
+ {
+   MetaWindowActor *window_actor = meta_window_actor_from_window (window);
+ 
+   if (!window_actor)
+     return;
+ 
+   meta_window_actor_hide (window_actor, effect);
+ }
+ 
+ void
+ meta_compositor_size_change_window (MetaCompositor    *compositor,
+                                     MetaWindow        *window,
+                                     MetaSizeChange     which_change,
+                                     MetaRectangle     *old_frame_rect,
+                                     MetaRectangle     *old_buffer_rect)
+ {
+   MetaWindowActor *window_actor = meta_window_actor_from_window (window);
+ 
+   g_return_if_fail (window_actor);
+ 
+   meta_window_actor_size_change (window_actor, which_change, old_frame_rect, old_buffer_rect);
+ }
+ 
+ void
+-- 
+2.26.2
+
diff --git a/SOURCES/0027-window-actor-Unset-the-window-compositor-private-on-.patch b/SOURCES/0027-window-actor-Unset-the-window-compositor-private-on-.patch
new file mode 100644
index 0000000..b843510
--- /dev/null
+++ b/SOURCES/0027-window-actor-Unset-the-window-compositor-private-on-.patch
@@ -0,0 +1,86 @@
+From 68bdb7ef345a2887ca8570fadbdca81404899b0a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Thu, 25 Jul 2019 02:10:07 +0200
+Subject: [PATCH 27/28] window-actor: Unset the window compositor private on
+ destruction
+
+A window actor could be destroyed before than the related Window (if for
+example, it is explicitly removed from the stage or destroyed), in such case
+we need to unset the compositor private for the window on disposition, or once
+the window is actually destroyed, we will try to access to an invalid pointer,
+and to remove an invalid window actor from the compositor.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ src/compositor/meta-window-actor.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
+index f1f86e14b..39198dbe1 100644
+--- a/src/compositor/meta-window-actor.c
++++ b/src/compositor/meta-window-actor.c
+@@ -480,60 +480,61 @@ meta_window_actor_constructed (GObject *object)
+ }
+ 
+ static void
+ meta_window_actor_dispose (GObject *object)
+ {
+   MetaWindowActor *self = META_WINDOW_ACTOR (object);
+   MetaWindowActorPrivate *priv = self->priv;
+   MetaCompositor *compositor = priv->compositor;
+ 
+   if (priv->disposed)
+     return;
+ 
+   priv->disposed = TRUE;
+ 
+   if (priv->send_frame_messages_timer != 0)
+     {
+       g_source_remove (priv->send_frame_messages_timer);
+       priv->send_frame_messages_timer = 0;
+     }
+ 
+   g_clear_pointer (&priv->shape_region, cairo_region_destroy);
+   g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
+ 
+   g_clear_pointer (&priv->shadow_class, g_free);
+   g_clear_pointer (&priv->focused_shadow, meta_shadow_unref);
+   g_clear_pointer (&priv->unfocused_shadow, meta_shadow_unref);
+   g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref);
+ 
+   compositor->windows = g_list_remove (compositor->windows, (gconstpointer) self);
+ 
++  meta_window_set_compositor_private (priv->window, NULL);
+   g_clear_object (&priv->window);
+ 
+   set_surface (self, NULL);
+ 
+   G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object);
+ }
+ 
+ static void
+ meta_window_actor_finalize (GObject *object)
+ {
+   MetaWindowActor        *self = META_WINDOW_ACTOR (object);
+   MetaWindowActorPrivate *priv = self->priv;
+ 
+   g_list_free_full (priv->frames, (GDestroyNotify) frame_data_free);
+ 
+   G_OBJECT_CLASS (meta_window_actor_parent_class)->finalize (object);
+ }
+ 
+ static void
+ meta_window_actor_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+ {
+   MetaWindowActor        *self   = META_WINDOW_ACTOR (object);
+   MetaWindowActorPrivate *priv = self->priv;
+ 
+   switch (prop_id)
+     {
+     case PROP_META_WINDOW:
+-- 
+2.26.2
+
diff --git a/SOURCES/0028-cleanup-Unref-GSource-s-once-attached.patch b/SOURCES/0028-cleanup-Unref-GSource-s-once-attached.patch
new file mode 100644
index 0000000..6503ab7
--- /dev/null
+++ b/SOURCES/0028-cleanup-Unref-GSource-s-once-attached.patch
@@ -0,0 +1,432 @@
+From c483a57e848aa966eec6dfcb9d31786d83050a33 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
+Date: Wed, 24 Jul 2019 17:10:49 +0200
+Subject: [PATCH 28/28] cleanup: Unref GSource's once attached
+
+When a source is attached the main contaxt takes the ownership of it, so we
+can safely them.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/682
+---
+ clutter/clutter/clutter-backend.c                    | 1 +
+ clutter/clutter/clutter-master-clock-default.c       | 2 +-
+ clutter/clutter/evdev/clutter-device-manager-evdev.c | 2 +-
+ src/backends/meta-screen-cast-stream-src.c           | 1 +
+ src/backends/x11/meta-backend-x11.c                  | 3 ++-
+ src/wayland/meta-wayland.c                           | 2 +-
+ 6 files changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/clutter/clutter/clutter-backend.c b/clutter/clutter/clutter-backend.c
+index 41ea3daed..df51464cc 100644
+--- a/clutter/clutter/clutter-backend.c
++++ b/clutter/clutter/clutter-backend.c
+@@ -381,60 +381,61 @@ clutter_backend_real_create_context (ClutterBackend  *backend,
+               if (clutter_backend_do_real_create_context (backend, all_known_drivers[j].driver_id, &internal_error))
+                 break;
+ 
+               if (internal_error)
+                 {
+                   CLUTTER_NOTE (BACKEND, "Unable to use the %s driver: %s",
+                                 all_known_drivers[j].driver_desc,
+                                 internal_error->message);
+                   g_clear_error (&internal_error);
+                 }
+             }
+         }
+     }
+ 
+   g_strfreev (known_drivers);
+ 
+   if (backend->cogl_context == NULL)
+     {
+       if (internal_error != NULL)
+         g_propagate_error (error, internal_error);
+       else
+         g_set_error_literal (error, CLUTTER_INIT_ERROR,
+                              CLUTTER_INIT_ERROR_BACKEND,
+                             _("Unable to initialize the Clutter backend: no available drivers found."));
+ 
+       return FALSE;
+     }
+ 
+   backend->cogl_source = cogl_glib_source_new (backend->cogl_context, G_PRIORITY_DEFAULT);
+   g_source_attach (backend->cogl_source, NULL);
++  g_source_unref (backend->cogl_source);
+ 
+   return TRUE;
+ }
+ 
+ static ClutterFeatureFlags
+ clutter_backend_real_get_features (ClutterBackend *backend)
+ {
+   ClutterFeatureFlags flags = 0;
+ 
+   if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN))
+     {
+       CLUTTER_NOTE (BACKEND, "Cogl supports multiple onscreen framebuffers");
+       flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
+     }
+   else
+     {
+       CLUTTER_NOTE (BACKEND, "Cogl only supports one onscreen framebuffer");
+       flags |= CLUTTER_FEATURE_STAGE_STATIC;
+     }
+ 
+   if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE))
+     {
+       CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling");
+       flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
+     }
+   else
+     CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling");
+ 
+   if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
+     {
+diff --git a/clutter/clutter/clutter-master-clock-default.c b/clutter/clutter/clutter-master-clock-default.c
+index 7b2df0df3..83b1eadcb 100644
+--- a/clutter/clutter/clutter-master-clock-default.c
++++ b/clutter/clutter/clutter-master-clock-default.c
+@@ -577,61 +577,61 @@ clutter_clock_dispatch (GSource     *source,
+   g_slist_free (stages);
+ 
+   master_clock->prev_tick = master_clock->cur_tick;
+ 
+   _clutter_threads_release_lock ();
+ 
+   return TRUE;
+ }
+ 
+ static void
+ clutter_master_clock_default_finalize (GObject *gobject)
+ {
+   ClutterMasterClockDefault *master_clock = CLUTTER_MASTER_CLOCK_DEFAULT (gobject);
+ 
+   g_slist_free (master_clock->timelines);
+ 
+   G_OBJECT_CLASS (clutter_master_clock_default_parent_class)->finalize (gobject);
+ }
+ 
+ static void
+ clutter_master_clock_default_class_init (ClutterMasterClockDefaultClass *klass)
+ {
+   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ 
+   gobject_class->finalize = clutter_master_clock_default_finalize;
+ }
+ 
+ static void
+ clutter_master_clock_default_init (ClutterMasterClockDefault *self)
+ {
+-  GSource *source;
++  g_autoptr (GSource) source = NULL;
+ 
+   source = clutter_clock_source_new (self);
+   self->source = source;
+ 
+   self->idle = FALSE;
+   self->ensure_next_iteration = FALSE;
+   self->paused = FALSE;
+ 
+ #ifdef CLUTTER_ENABLE_DEBUG
+   self->frame_budget = G_USEC_PER_SEC / 60;
+ #endif
+ 
+   g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW);
+   g_source_set_can_recurse (source, FALSE);
+   g_source_attach (source, NULL);
+ }
+ 
+ static void
+ clutter_master_clock_default_add_timeline (ClutterMasterClock *clock,
+                                            ClutterTimeline    *timeline)
+ {
+   ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock;
+   gboolean is_first;
+ 
+   if (g_slist_find (master_clock->timelines, timeline))
+     return;
+ 
+   is_first = master_clock->timelines == NULL;
+ 
+   master_clock->timelines = g_slist_prepend (master_clock->timelines,
+diff --git a/clutter/clutter/evdev/clutter-device-manager-evdev.c b/clutter/clutter/evdev/clutter-device-manager-evdev.c
+index 11cb4781a..49566c233 100644
+--- a/clutter/clutter/evdev/clutter-device-manager-evdev.c
++++ b/clutter/clutter/evdev/clutter-device-manager-evdev.c
+@@ -706,61 +706,61 @@ clutter_event_dispatch (GSource     *g_source,
+       /* Drop events if we don't have any stage to forward them to */
+       if (!_clutter_input_device_get_stage (input_device))
+         goto out;
+ 
+       /* forward the event into clutter for emission etc. */
+       _clutter_stage_queue_event (event->any.stage, event, FALSE);
+ 
+       /* update the device states *after* the event */
+       event_state = seat->button_state |
+         xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_EFFECTIVE);
+       _clutter_input_device_set_state (seat->core_pointer, event_state);
+       _clutter_input_device_set_state (seat->core_keyboard, event_state);
+     }
+ 
+ out:
+   _clutter_threads_release_lock ();
+ 
+   return TRUE;
+ }
+ static GSourceFuncs event_funcs = {
+   clutter_event_prepare,
+   clutter_event_check,
+   clutter_event_dispatch,
+   NULL
+ };
+ 
+ static ClutterEventSource *
+ clutter_event_source_new (ClutterDeviceManagerEvdev *manager_evdev)
+ {
+   ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv;
+-  GSource *source;
++  g_autoptr (GSource) source = NULL;
+   ClutterEventSource *event_source;
+   gint fd;
+ 
+   source = g_source_new (&event_funcs, sizeof (ClutterEventSource));
+   event_source = (ClutterEventSource *) source;
+ 
+   /* setup the source */
+   event_source->manager_evdev = manager_evdev;
+ 
+   fd = libinput_get_fd (priv->libinput);
+   event_source->event_poll_fd.fd = fd;
+   event_source->event_poll_fd.events = G_IO_IN;
+ 
+   /* and finally configure and attach the GSource */
+   g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
+   g_source_add_poll (source, &event_source->event_poll_fd);
+   g_source_set_can_recurse (source, TRUE);
+   g_source_attach (source, NULL);
+ 
+   return event_source;
+ }
+ 
+ static void
+ clutter_event_source_free (ClutterEventSource *source)
+ {
+   GSource *g_source = (GSource *) source;
+ 
+   CLUTTER_NOTE (EVENT, "Removing GSource for evdev device manager");
+ 
+   /* ignore the return value of close, it's not like we can do something
+diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c
+index 457c0589e..254ef983d 100644
+--- a/src/backends/meta-screen-cast-stream-src.c
++++ b/src/backends/meta-screen-cast-stream-src.c
+@@ -465,60 +465,61 @@ static void
+ init_spa_type (MetaSpaType         *type,
+                struct spa_type_map *map)
+ {
+   spa_type_media_type_map (map, &type->media_type);
+   spa_type_media_subtype_map (map, &type->media_subtype);
+   spa_type_format_video_map (map, &type->format_video);
+   spa_type_video_format_map (map, &type->video_format);
+ }
+ 
+ static MetaPipeWireSource *
+ create_pipewire_source (void)
+ {
+   MetaPipeWireSource *pipewire_source;
+ 
+   pipewire_source =
+     (MetaPipeWireSource *) g_source_new (&pipewire_source_funcs,
+                                          sizeof (MetaPipeWireSource));
+   pipewire_source->pipewire_loop = pw_loop_new (NULL);
+   if (!pipewire_source->pipewire_loop)
+     {
+       g_source_destroy ((GSource *) pipewire_source);
+       return NULL;
+     }
+ 
+   g_source_add_unix_fd (&pipewire_source->base,
+                         pw_loop_get_fd (pipewire_source->pipewire_loop),
+                         G_IO_IN | G_IO_ERR);
+ 
+   pw_loop_enter (pipewire_source->pipewire_loop);
+   g_source_attach (&pipewire_source->base, NULL);
++  g_source_unref (&pipewire_source->base);
+ 
+   return pipewire_source;
+ }
+ 
+ static const struct pw_remote_events remote_events = {
+   PW_VERSION_REMOTE_EVENTS,
+   .state_changed = on_state_changed,
+ };
+ 
+ static gboolean
+ meta_screen_cast_stream_src_initable_init (GInitable     *initable,
+                                            GCancellable  *cancellable,
+                                            GError       **error)
+ {
+   MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (initable);
+   MetaScreenCastStreamSrcPrivate *priv =
+     meta_screen_cast_stream_src_get_instance_private (src);
+ 
+   priv->pipewire_source = create_pipewire_source ();
+   if (!priv->pipewire_source)
+     {
+       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                    "Failed to create PipeWire source");
+       return FALSE;
+     }
+ 
+   priv->pipewire_core = pw_core_new (priv->pipewire_source->pipewire_loop,
+                                      NULL);
+   if (!priv->pipewire_core)
+     {
+diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
+index 3f8645e93..b9acf48c0 100644
+--- a/src/backends/x11/meta-backend-x11.c
++++ b/src/backends/x11/meta-backend-x11.c
+@@ -449,71 +449,72 @@ x_event_source_dispatch (GSource     *source,
+                          gpointer     user_data)
+ {
+   XEventSource *x_source = (XEventSource *) source;
+   MetaBackend *backend = x_source->backend;
+   MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
+   MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
+ 
+   while (XPending (priv->xdisplay))
+     {
+       XEvent event;
+ 
+       XNextEvent (priv->xdisplay, &event);
+ 
+       handle_host_xevent (backend, &event);
+     }
+ 
+   return TRUE;
+ }
+ 
+ static GSourceFuncs x_event_funcs = {
+   x_event_source_prepare,
+   x_event_source_check,
+   x_event_source_dispatch,
+ };
+ 
+ static GSource *
+ x_event_source_new (MetaBackend *backend)
+ {
+   MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
+   MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
+-  GSource *source;
++  g_autoptr (GSource) source = NULL;
+   XEventSource *x_source;
+ 
+   source = g_source_new (&x_event_funcs, sizeof (XEventSource));
+   x_source = (XEventSource *) source;
+   x_source->backend = backend;
+   x_source->event_poll_fd.fd = ConnectionNumber (priv->xdisplay);
+   x_source->event_poll_fd.events = G_IO_IN;
+   g_source_add_poll (source, &x_source->event_poll_fd);
+ 
+   g_source_attach (source, NULL);
++
+   return source;
+ }
+ 
+ static void
+ on_monitors_changed (MetaMonitorManager *manager,
+                      MetaBackend        *backend)
+ {
+   MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
+   MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
+ 
+   priv->cached_current_logical_monitor = NULL;
+ }
+ 
+ static void
+ meta_backend_x11_post_init (MetaBackend *backend)
+ {
+   MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
+   MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
+   MetaMonitorManager *monitor_manager;
+   int major, minor;
+   gboolean has_xi = FALSE;
+ 
+   priv->source = x_event_source_new (backend);
+ 
+   if (!XSyncQueryExtension (priv->xdisplay, &priv->xsync_event_base, &priv->xsync_error_base) ||
+       !XSyncInitialize (priv->xdisplay, &major, &minor))
+     meta_fatal ("Could not initialize XSync");
+ 
+   priv->counter = find_idletime_counter (priv);
+   if (priv->counter == None)
+diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
+index bab6b4ac4..44f48a0ee 100644
+--- a/src/wayland/meta-wayland.c
++++ b/src/wayland/meta-wayland.c
+@@ -325,61 +325,61 @@ meta_wayland_pre_clutter_init (void)
+ }
+ 
+ static bool
+ meta_xwayland_global_filter (const struct wl_client *client,
+                              const struct wl_global *global,
+                              void                   *data)
+ {
+   MetaWaylandCompositor *compositor = (MetaWaylandCompositor *) data;
+   MetaXWaylandManager *xwayland_manager = &compositor->xwayland_manager;
+ 
+   /* Keyboard grabbing protocol is for Xwayland only */
+   if (client != xwayland_manager->client)
+     return (wl_global_get_interface (global) !=
+             &zwp_xwayland_keyboard_grab_manager_v1_interface);
+ 
+   /* All others are visible to all clients */
+   return true;
+ }
+ 
+ void
+ meta_wayland_override_display_name (char *display_name)
+ {
+   g_clear_pointer (&_display_name_override, g_free);
+   _display_name_override = g_strdup (display_name);
+ }
+ 
+ void
+ meta_wayland_init (void)
+ {
+   MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
+-  GSource *wayland_event_source;
++  g_autoptr (GSource) wayland_event_source = NULL;
+ 
+   wayland_event_source = wayland_event_source_new (compositor->wayland_display);
+ 
+   /* XXX: Here we are setting the wayland event source to have a
+    * slightly lower priority than the X event source, because we are
+    * much more likely to get confused being told about surface changes
+    * relating to X clients when we don't know what's happened to them
+    * according to the X protocol.
+    */
+   g_source_set_priority (wayland_event_source, GDK_PRIORITY_EVENTS + 1);
+   g_source_attach (wayland_event_source, NULL);
+ 
+   if (!wl_global_create (compositor->wayland_display,
+ 			 &wl_compositor_interface,
+ 			 META_WL_COMPOSITOR_VERSION,
+ 			 compositor, compositor_bind))
+     g_error ("Failed to register the global wl_compositor");
+ 
+   wl_display_init_shm (compositor->wayland_display);
+ 
+   meta_wayland_outputs_init (compositor);
+   meta_wayland_data_device_manager_init (compositor);
+   meta_wayland_subsurfaces_init (compositor);
+   meta_wayland_shell_init (compositor);
+   meta_wayland_pointer_gestures_init (compositor);
+   meta_wayland_tablet_manager_init (compositor);
+   meta_wayland_seat_init (compositor);
+   meta_wayland_relative_pointer_init (compositor);
+   meta_wayland_pointer_constraints_init (compositor);
+   meta_wayland_xdg_foreign_init (compositor);
+-- 
+2.26.2
+
diff --git a/SPECS/mutter.spec b/SPECS/mutter.spec
index 964b556..a323819 100644
--- a/SPECS/mutter.spec
+++ b/SPECS/mutter.spec
@@ -10,7 +10,7 @@
 
 Name:          mutter
 Version:       3.28.3
-Release:       26%{?dist}
+Release:       28%{?dist}
 Summary:       Window and compositing manager based on Clutter
 
 License:       GPLv2+
@@ -126,6 +126,48 @@ Patch295: fix-extended-osk-characters.patch
 # Only treat WM_PROTOCOLS messages as WM_PROTOCOL messages (#1846242)
 Patch296: 0001-stage-x11-Check-that-message-is-WM_PROTOCOLS-before-.patch
 
+# Turn stacking warning into debug log (#1811029)
+Patch297: 0001-stack-tracker-Fix-coding-style-of-meta_stack_op_appl.patch
+Patch298: 0002-stack-tracker-Don-t-log-warnings-on-race-conditions.patch
+
+# Backport of upstream fixes
+# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/682
+
+Patch401: 0001-cogl-Use-autopointers-to-free-structs-on-return.patch
+Patch402: 0002-cogl-Define-autoptr-cleanup-functions-for-Cogl-types.patch
+Patch403: 0003-cogl-vertex-buffer-Don-t-try-to-use-free-d-data.patch
+Patch404: 0004-cogl-onscreen-template-Unref-the-swap-chain.patch
+Patch405: 0005-cogl-framebuffer-Unref-the-config-swap-chain-if-set.patch
+Patch406: 0006-clutter-backend-Use-an-auto-pointer-to-handle-the-te.patch
+Patch407: 0007-clutter-Keep-a-device-reference-with-events.patch
+Patch408: 0008-clutter-event-Use-all-events-Hash-table-as-a-Set-wit.patch
+Patch409: 0009-clutter-actor-Take-the-marging-boxed-type-if-valid.patch
+Patch410: 0010-clutter-actor-meta-Notify-when-actor-property-change.patch
+Patch411: 0011-clutter-actor-meta-Unset-the-actor-if-disposed-calli.patch
+Patch412: 0012-clutter-stage-manager-Pause-the-master-clock-when-al.patch
+Patch413: 0013-cally-stage-Set-the-keyfocus-to-NULL-if-the-stage-is.patch
+Patch414: 0014-cally-stage-Monitor-key-focus-actor-via-destroyed-si.patch
+Patch415: 0015-group-Free-group-if-returning-early.patch
+Patch416: 0016-surface-actor-Destroy-the-pending-damage-region-on-d.patch
+Patch417: 0017-CrtcMode-Free-the-mode-name-on-finalize.patch
+Patch418: 0018-monitor-config-manager-Always-free-temporary-region-.patch
+Patch419: 0019-monitor-config-store-Use-autopointers-to-cleanup-par.patch
+Patch420: 0020-monitor-Free-the-existing-mode-if-replacing-it.patch
+Patch421: 0021-monitor-Use-delete-link-to-free-the-tiled-modes-whil.patch
+Patch422: 0022-monitor-config-store-Check-if-a-config-is-system-one.patch
+Patch423: 0023-monitor-config-migration-Unref-the-new-config-once-a.patch
+Patch424: 0024-monitor-config-migration-Free-the-output-key-on-inva.patch
+Patch425: 0025-compositor-Use-meta_window_actor_from_window-to-get-.patch
+Patch426: 0026-compositor-Fix-indentation-on-show-window.patch
+Patch427: 0027-window-actor-Unset-the-window-compositor-private-on-.patch
+Patch428: 0028-cleanup-Unref-GSource-s-once-attached.patch
+
+# Leaks fixes
+Patch501: 0001-cally-Fix-state-set-leak.patch
+Patch502: 0002-barriers-Fix-leak-in-meta_barrier_destroy.patch
+Patch503: 0003-barriers-Free-backend-implementation-at-dispose-time.patch
+Patch504: 0004-src-Export-MetaWaylandX11-to-introspection.patch
+
 BuildRequires: chrpath
 BuildRequires: pango-devel
 BuildRequires: startup-notification-devel
@@ -281,6 +323,14 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
 %{_libdir}/pkgconfig/*
 
 %changelog
+* Wed Oct 14 2020 Ray Strode <rstrode@redhat.com> - 3.28.3-28
+- Try to fix leaks
+  Resolves: #1717000
+
+* Mon Jun 22 2020 Jonas Ådahl <jadahl@redhat.com>) - 3.28.3-27
+- Turn stacking warning into debug log
+  Resolves: #1811029
+
 * Mon Jun 22 2020 Jonas Ådahl <jadahl@redhat.com>) - 3.28.3-26
 - Only treat WM_PROTOCOLS messages as WM_PROTOCOL messages
   Resolves: #1846242