diff --git a/SOURCES/0001-clutter-avoid-redundant-_clutter_paint_node_init_typ.patch b/SOURCES/0001-clutter-avoid-redundant-_clutter_paint_node_init_typ.patch
new file mode 100644
index 0000000..7582a55
--- /dev/null
+++ b/SOURCES/0001-clutter-avoid-redundant-_clutter_paint_node_init_typ.patch
@@ -0,0 +1,53 @@
+From a9f9f9b36a03535480b31534547bea7c9f7cf4c1 Mon Sep 17 00:00:00 2001
+From: Christian Hergert <chergert@redhat.com>
+Date: Sun, 23 Feb 2020 17:27:08 -0800
+Subject: [PATCH 1/3] clutter: avoid redundant _clutter_paint_node_init_types()
+
+This only needs to be initialized once but is in the hot path of creating
+new paint nodes (for which we create many). Instead, do this as part of
+the clutter_init() workflow to keep it out of the hot path.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/1087
+---
+ clutter/clutter/clutter-main.c       | 4 ++++
+ clutter/clutter/clutter-paint-node.c | 2 --
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/clutter/clutter/clutter-main.c b/clutter/clutter/clutter-main.c
+index 46537f322..8a465fdc2 100644
+--- a/clutter/clutter/clutter-main.c
++++ b/clutter/clutter/clutter-main.c
+@@ -63,6 +63,7 @@
+ #include "clutter-main.h"
+ #include "clutter-master-clock.h"
+ #include "clutter-mutter.h"
++#include "clutter-paint-node-private.h"
+ #include "clutter-private.h"
+ #include "clutter-settings-private.h"
+ #include "clutter-stage-manager.h"
+@@ -1390,6 +1391,9 @@ clutter_init_real (GError **error)
+   if (clutter_enable_accessibility)
+     cally_accessibility_init ();
+ 
++  /* Initialize types required for paint nodes */
++  _clutter_paint_node_init_types ();
++
+   return CLUTTER_INIT_SUCCESS;
+ }
+ 
+diff --git a/clutter/clutter/clutter-paint-node.c b/clutter/clutter/clutter-paint-node.c
+index 391f48398..db68b7766 100644
+--- a/clutter/clutter/clutter-paint-node.c
++++ b/clutter/clutter/clutter-paint-node.c
+@@ -1113,8 +1113,6 @@ _clutter_paint_node_create (GType gtype)
+ {
+   g_return_val_if_fail (g_type_is_a (gtype, CLUTTER_TYPE_PAINT_NODE), NULL);
+ 
+-  _clutter_paint_node_init_types ();
+-
+   return (gpointer) g_type_create_instance (gtype);
+ }
+ 
+-- 
+2.26.0
+
diff --git a/SOURCES/0001-core-Hide-close-dialog-before-destroying.patch b/SOURCES/0001-core-Hide-close-dialog-before-destroying.patch
new file mode 100644
index 0000000..8d0e542
--- /dev/null
+++ b/SOURCES/0001-core-Hide-close-dialog-before-destroying.patch
@@ -0,0 +1,32 @@
+From b5b252af2580c8dad8097037481963f93babfba7 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Wed, 6 Jun 2018 13:26:55 +0200
+Subject: [PATCH] core: Hide close dialog before destroying
+
+The MetaCloseDialog implementation object may stay artifically alive
+for a longer period. This was usually fine till gnome-shell commit
+b03bcc85aad, as the check_alive() timeout will keep running even
+though the window went unmanaged/destroyed, leading to crashes.
+
+In order to fix this, forcibly hide the dialog if it is visible and
+the window is being unmanaged, so the timeout is stopped in time.
+---
+ src/core/delete.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/core/delete.c b/src/core/delete.c
+index af7cffed9..fd94dc6ca 100644
+--- a/src/core/delete.c
++++ b/src/core/delete.c
+@@ -115,5 +115,8 @@ meta_window_kill (MetaWindow *window)
+ void
+ meta_window_free_delete_dialog (MetaWindow *window)
+ {
++  if (window->close_dialog &&
++      meta_close_dialog_is_visible (window->close_dialog))
++    meta_close_dialog_hide (window->close_dialog);
+   g_clear_object (&window->close_dialog);
+ }
+-- 
+2.25.1
+
diff --git a/SOURCES/0001-display-Make-check-alive-timeout-configureable.patch b/SOURCES/0001-display-Make-check-alive-timeout-configureable.patch
new file mode 100644
index 0000000..18613ba
--- /dev/null
+++ b/SOURCES/0001-display-Make-check-alive-timeout-configureable.patch
@@ -0,0 +1,248 @@
+From 8bdcce5328a451c03e240f40a213e5afb11676ea Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Fri, 21 Feb 2020 21:03:16 +0100
+Subject: [PATCH] display: Make check-alive timeout configureable
+
+The check-alive feature is there for the user to be able to terminate
+frozen applications more easily. However, sometimes applications are
+implemented in a way where they fail to be reply to ping requests in a
+timely manner, resulting in that, to the compositor, they are
+indistinguishable from clients that have frozen indefinitely.
+
+When using an application that has these issues, the GUI showed in
+response to the failure to respond to ping requests can become annoying,
+as it disrupts the visual presentation of the application.
+
+To allow users to work-around these issues, add a setting allowing them
+to configure the timeout waited until an application is considered
+frozen, or disabling the check completely.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/1080
+---
+ data/org.gnome.mutter.gschema.xml.in | 10 ++++
+ src/core/display.c                   | 18 ++++----
+ src/core/prefs.c                     | 68 ++++++++++++++++++++++++++++
+ src/meta/prefs.h                     |  3 ++
+ 4 files changed, 90 insertions(+), 9 deletions(-)
+
+diff --git a/data/org.gnome.mutter.gschema.xml.in b/data/org.gnome.mutter.gschema.xml.in
+index bec5585bd..06f8288c8 100644
+--- a/data/org.gnome.mutter.gschema.xml.in
++++ b/data/org.gnome.mutter.gschema.xml.in
+@@ -127,6 +127,16 @@
+       </description>
+     </key>
+ 
++    <key name="check-alive-timeout" type="u">
++      <default>5000</default>
++      <summary>Timeout for check-alive ping</summary>
++      <description>
++        Number of milliseconds a client has to respond to a ping request in
++        order to not be detected as frozen. Using 0 will disable the alive check
++        completely.
++      </description>
++    </key>
++
+     <child name="keybindings" schema="org.gnome.mutter.keybindings"/>
+ 
+   </schema>
+diff --git a/src/core/display.c b/src/core/display.c
+index d4775cec3..5b843fa51 100644
+--- a/src/core/display.c
++++ b/src/core/display.c
+@@ -2197,12 +2197,6 @@ meta_set_syncing (gboolean setting)
+     }
+ }
+ 
+-/*
+- * How long, in milliseconds, we should wait after pinging a window
+- * before deciding it's not going to get back to us.
+- */
+-#define PING_TIMEOUT_DELAY 5000
+-
+ /**
+  * meta_display_ping_timeout:
+  * @data: All the information about this ping. It is a #MetaPingData
+@@ -2260,6 +2254,11 @@ meta_display_ping_window (MetaWindow *window,
+ {
+   MetaDisplay *display = window->display;
+   MetaPingData *ping_data;
++  unsigned int check_alive_timeout;
++
++  check_alive_timeout = meta_prefs_get_check_alive_timeout ();
++  if (check_alive_timeout == 0)
++    return;
+ 
+   if (serial == 0)
+     {
+@@ -2273,9 +2272,10 @@ meta_display_ping_window (MetaWindow *window,
+   ping_data = g_new (MetaPingData, 1);
+   ping_data->window = window;
+   ping_data->serial = serial;
+-  ping_data->ping_timeout_id = g_timeout_add (PING_TIMEOUT_DELAY,
+-					      meta_display_ping_timeout,
+-					      ping_data);
++  ping_data->ping_timeout_id =
++    g_timeout_add (check_alive_timeout,
++                   meta_display_ping_timeout,
++                   ping_data);
+   g_source_set_name_by_id (ping_data->ping_timeout_id, "[mutter] meta_display_ping_timeout");
+ 
+   display->pending_pings = g_slist_prepend (display->pending_pings, ping_data);
+diff --git a/src/core/prefs.c b/src/core/prefs.c
+index b6a8ab7bf..326db52d2 100644
+--- a/src/core/prefs.c
++++ b/src/core/prefs.c
+@@ -95,6 +95,7 @@ static gboolean bell_is_visible = FALSE;
+ static gboolean bell_is_audible = TRUE;
+ static gboolean gnome_accessibility = FALSE;
+ static gboolean gnome_animations = TRUE;
++static unsigned int check_alive_timeout = 5000;
+ static char *cursor_theme = NULL;
+ /* cursor_size will, when running as an X11 compositing window manager, be the
+  * actual cursor size, multiplied with the global window scaling factor. On
+@@ -225,6 +226,12 @@ typedef struct
+   gint *target;
+ } MetaIntPreference;
+ 
++typedef struct
++{
++  MetaBasePreference base;
++  unsigned int *target;
++} MetaUintPreference;
++
+ 
+ /* All preferences that are not keybindings must be listed here,
+  * plus in the GSettings schemas and the MetaPreference enum.
+@@ -496,6 +503,18 @@ static MetaIntPreference preferences_int[] =
+     { { NULL, 0, 0 }, NULL },
+   };
+ 
++static MetaUintPreference preferences_uint[] =
++  {
++    {
++      { "check-alive-timeout",
++        SCHEMA_MUTTER,
++        META_PREF_CHECK_ALIVE_TIMEOUT,
++      },
++      &check_alive_timeout,
++    },
++    { { NULL, 0, 0 }, NULL },
++  };
++
+ /*
+  * This is used to keep track of override schemas used to
+  * override preferences from the "normal" metacity/mutter
+@@ -633,6 +652,21 @@ handle_preference_init_int (void)
+     }
+ }
+ 
++static void
++handle_preference_init_uint (void)
++{
++  MetaUintPreference *cursor = preferences_uint;
++
++  while (cursor->base.key != NULL)
++    {
++      if (cursor->target)
++        *cursor->target = g_settings_get_uint (SETTINGS (cursor->base.schema),
++                                               cursor->base.key);
++
++      ++cursor;
++    }
++}
++
+ static void
+ handle_preference_update_enum (GSettings *settings,
+                                gchar *key)
+@@ -808,6 +842,28 @@ handle_preference_update_int (GSettings *settings,
+     }
+ }
+ 
++static void
++handle_preference_update_uint (GSettings *settings,
++                               char *key)
++{
++  MetaUintPreference *cursor = preferences_uint;
++  unsigned int new_value;
++
++  while (cursor->base.key && strcmp (key, cursor->base.key) != 0)
++    ++cursor;
++
++  if (!cursor->base.key || !cursor->target)
++    return;
++
++  new_value = g_settings_get_uint (SETTINGS (cursor->base.schema), key);
++
++  if (*cursor->target != new_value)
++    {
++      *cursor->target = new_value;
++      queue_changed (cursor->base.pref);
++    }
++}
++
+ 
+ /****************************************************************************/
+ /* Listeners.                                                               */
+@@ -1003,6 +1059,7 @@ meta_prefs_init (void)
+   handle_preference_init_string ();
+   handle_preference_init_string_array ();
+   handle_preference_init_int ();
++  handle_preference_init_uint ();
+ 
+   update_cursor_size ();
+   shell_shows_app_menu_changed (gtk_settings_get_default (), NULL, NULL);
+@@ -1176,6 +1233,8 @@ settings_changed (GSettings *settings,
+     handle_preference_update_bool (settings, key);
+   else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
+     handle_preference_update_int (settings, key);
++  else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
++    handle_preference_update_uint (settings, key);
+   else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING_ARRAY))
+     handle_preference_update_string_array (settings, key);
+   else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
+@@ -1851,6 +1910,9 @@ meta_preference_to_string (MetaPreference pref)
+ 
+     case META_PREF_AUTO_MAXIMIZE:
+       return "AUTO_MAXIMIZE";
++
++    case META_PREF_CHECK_ALIVE_TIMEOUT:
++      return "CHECK_ALIVE_TIMEOUT";
+     }
+ 
+   return "(unknown)";
+@@ -2177,6 +2239,12 @@ meta_prefs_get_overlay_binding (MetaKeyCombo *combo)
+   *combo = overlay_key_combo;
+ }
+ 
++unsigned int
++meta_prefs_get_check_alive_timeout (void)
++{
++  return check_alive_timeout;
++}
++
+ const char *
+ meta_prefs_get_iso_next_group_option (void)
+ {
+diff --git a/src/meta/prefs.h b/src/meta/prefs.h
+index df3cf6c97..f343925f8 100644
+--- a/src/meta/prefs.h
++++ b/src/meta/prefs.h
+@@ -103,6 +103,7 @@ typedef enum
+   META_PREF_AUTO_MAXIMIZE,
+   META_PREF_CENTER_NEW_WINDOWS,
+   META_PREF_DRAG_THRESHOLD,
++  META_PREF_CHECK_ALIVE_TIMEOUT,
+ } MetaPreference;
+ 
+ typedef void (* MetaPrefsChangedFunc) (MetaPreference pref,
+@@ -406,4 +407,6 @@ gboolean           meta_prefs_get_visual_bell      (void);
+ gboolean           meta_prefs_bell_is_audible      (void);
+ GDesktopVisualBellType meta_prefs_get_visual_bell_type (void);
+ 
++unsigned int meta_prefs_get_check_alive_timeout (void);
++
+ #endif
+-- 
+2.24.1
+
diff --git a/SOURCES/0001-window-free-close-dialog-before-unmanaging-window-fr.patch b/SOURCES/0001-window-free-close-dialog-before-unmanaging-window-fr.patch
new file mode 100644
index 0000000..df3eeae
--- /dev/null
+++ b/SOURCES/0001-window-free-close-dialog-before-unmanaging-window-fr.patch
@@ -0,0 +1,47 @@
+From 376225cea044d050f8fc2923e7149d320150bab7 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode@redhat.com>
+Date: Mon, 29 Apr 2019 13:46:37 -0400
+Subject: [PATCH] window: free close dialog before unmanaging window from
+ compositor
+
+When an application stops responding, the shell darkens its windows.
+
+If a window from a not-responding application gets unmanaged
+then the shell will currently throw an exception trying to retrieve
+the now-dissociated window actor.
+
+That leads to a "stuck window" ghost on screen and a traceback
+in the log.
+
+This commit addresses the problem by making sure the effect is cleaned
+up before the actor is disocciated from its window.
+
+https://gitlab.gnome.org/GNOME/mutter/issues/575
+---
+ src/core/window.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/core/window.c b/src/core/window.c
+index cc0813ac4..aa85806f1 100644
+--- a/src/core/window.c
++++ b/src/core/window.c
+@@ -1388,6 +1388,8 @@ meta_window_unmanage (MetaWindow  *window,
+   meta_verbose ("Unmanaging %s\n", window->desc);
+   window->unmanaging = TRUE;
+ 
++  meta_window_free_delete_dialog (window);
++
+ #ifdef HAVE_WAYLAND
+   /* This needs to happen for both Wayland and XWayland clients,
+    * so it can't be in MetaWindowWayland. */
+@@ -1510,7 +1512,6 @@ meta_window_unmanage (MetaWindow  *window,
+   meta_window_unqueue (window, META_QUEUE_CALC_SHOWING |
+                                META_QUEUE_MOVE_RESIZE |
+                                META_QUEUE_UPDATE_ICON);
+-  meta_window_free_delete_dialog (window);
+ 
+   set_workspace_state (window, FALSE, NULL);
+ 
+-- 
+2.23.0
+
diff --git a/SOURCES/0002-clutter-avoid-g_signal_emit_by_name-from-ClutterActo.patch b/SOURCES/0002-clutter-avoid-g_signal_emit_by_name-from-ClutterActo.patch
new file mode 100644
index 0000000..5746804
--- /dev/null
+++ b/SOURCES/0002-clutter-avoid-g_signal_emit_by_name-from-ClutterActo.patch
@@ -0,0 +1,192 @@
+From 04e5e144ce21c811601e169c13fdef7b8edeae12 Mon Sep 17 00:00:00 2001
+From: Christian Hergert <christian@hergert.me>
+Date: Mon, 24 Feb 2020 22:36:27 +0000
+Subject: [PATCH 2/3] clutter: avoid g_signal_emit_by_name() from ClutterActor
+
+g_signal_emit_by_name() is used to emit signals on ClutterContainer when
+actors are removed or added. It happens to do various interface lookups
+which are a bit unneccessary and can allocate memory.
+
+Simply using emission wrappers makes all of that go away.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/1083
+---
+ clutter/clutter/cally/cally-actor.c         |  5 +--
+ clutter/clutter/clutter-actor.c             | 17 ++++++++--
+ clutter/clutter/clutter-actor.h             |  5 ++-
+ clutter/clutter/clutter-container-private.h | 36 +++++++++++++++++++++
+ clutter/clutter/clutter-container.c         | 21 ++++++++++++
+ 5 files changed, 78 insertions(+), 6 deletions(-)
+ create mode 100644 clutter/clutter/clutter-container-private.h
+
+diff --git a/clutter/clutter/cally/cally-actor.c b/clutter/clutter/cally/cally-actor.c
+index f341d3616..77195c0b0 100644
+--- a/clutter/clutter/cally/cally-actor.c
++++ b/clutter/clutter/cally/cally-actor.c
+@@ -606,10 +606,11 @@ cally_actor_real_remove_actor (ClutterActor *container,
+   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), 0);
+ 
+   atk_parent = ATK_OBJECT (data);
+-  atk_child = clutter_actor_get_accessible (actor);
+ 
+-  if (atk_child)
++  if (clutter_actor_has_accessible (actor))
+     {
++      atk_child = clutter_actor_get_accessible (actor);
++
+       g_value_init (&values.old_value, G_TYPE_POINTER);
+       g_value_set_pointer (&values.old_value, atk_parent);
+ 
+diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c
+index 6954f0396..8da53d3f1 100644
+--- a/clutter/clutter/clutter-actor.c
++++ b/clutter/clutter/clutter-actor.c
+@@ -624,7 +624,7 @@
+ #include "clutter-color-static.h"
+ #include "clutter-color.h"
+ #include "clutter-constraint-private.h"
+-#include "clutter-container.h"
++#include "clutter-container-private.h"
+ #include "clutter-content-private.h"
+ #include "clutter-debug.h"
+ #include "clutter-easing.h"
+@@ -4310,7 +4310,7 @@ clutter_actor_remove_child_internal (ClutterActor                 *self,
+ 
+   /* we need to emit the signal before dropping the reference */
+   if (emit_actor_removed)
+-    g_signal_emit_by_name (self, "actor-removed", child);
++    _clutter_container_emit_actor_removed (CLUTTER_CONTAINER (self), child);
+ 
+   if (notify_first_last)
+     {
+@@ -12980,7 +12980,7 @@ clutter_actor_add_child_internal (ClutterActor              *self,
+     }
+ 
+   if (emit_actor_added)
+-    g_signal_emit_by_name (self, "actor-added", child);
++    _clutter_container_emit_actor_added (CLUTTER_CONTAINER (self), child);
+ 
+   if (notify_first_last)
+     {
+@@ -21150,3 +21150,14 @@ clutter_actor_create_texture_paint_node (ClutterActor *self,
+ 
+   return node;
+ }
++
++gboolean
++clutter_actor_has_accessible (ClutterActor *actor)
++{
++  g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
++
++  if (CLUTTER_ACTOR_GET_CLASS (actor)->has_accessible)
++    return CLUTTER_ACTOR_GET_CLASS (actor)->has_accessible (actor);
++
++  return TRUE;
++}
+diff --git a/clutter/clutter/clutter-actor.h b/clutter/clutter/clutter-actor.h
+index 0c5a08c8c..9b0665c72 100644
+--- a/clutter/clutter/clutter-actor.h
++++ b/clutter/clutter/clutter-actor.h
+@@ -295,10 +295,11 @@ struct _ClutterActorClass
+ 
+   gboolean (* touch_event)          (ClutterActor         *self,
+                                      ClutterTouchEvent    *event);
++  gboolean (* has_accessible)       (ClutterActor         *self);
+ 
+   /*< private >*/
+   /* padding for future expansion */
+-  gpointer _padding_dummy[26];
++  gpointer _padding_dummy[25];
+ };
+ 
+ /**
+@@ -368,6 +369,8 @@ CLUTTER_AVAILABLE_IN_ALL
+ const gchar *                   clutter_actor_get_name                          (ClutterActor                *self);
+ CLUTTER_AVAILABLE_IN_ALL
+ AtkObject *                     clutter_actor_get_accessible                    (ClutterActor                *self);
++CLUTTER_AVAILABLE_IN_ALL
++gboolean                        clutter_actor_has_accessible                    (ClutterActor                *self);
+ 
+ CLUTTER_AVAILABLE_IN_1_24
+ gboolean                        clutter_actor_is_visible                        (ClutterActor                *self);
+diff --git a/clutter/clutter/clutter-container-private.h b/clutter/clutter/clutter-container-private.h
+new file mode 100644
+index 000000000..d619a6531
+--- /dev/null
++++ b/clutter/clutter/clutter-container-private.h
+@@ -0,0 +1,36 @@
++/*
++ * Clutter.
++ *
++ * An OpenGL based 'interactive canvas' library.
++ *
++ * Copyright 2020 Red Hat, Inc.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef __CLUTTER_CONTAINER_PRIVATE_H__
++#define __CLUTTER_CONTAINER_PRIVATE_H__
++
++#include <clutter/clutter-container.h>
++
++G_BEGIN_DECLS
++
++void _clutter_container_emit_actor_added   (ClutterContainer *container,
++                                            ClutterActor     *actor);
++void _clutter_container_emit_actor_removed (ClutterContainer *container,
++                                            ClutterActor     *actor);
++
++G_END_DECLS
++
++#endif /* __CLUTTER_CONTAINER_PRIVATE_H__ */
+diff --git a/clutter/clutter/clutter-container.c b/clutter/clutter/clutter-container.c
+index 81fe4dc2e..52942a246 100644
+--- a/clutter/clutter/clutter-container.c
++++ b/clutter/clutter/clutter-container.c
+@@ -39,6 +39,7 @@
+ 
+ #include "clutter-actor-private.h"
+ #include "clutter-child-meta.h"
++#include "clutter-container-private.h"
+ #include "clutter-debug.h"
+ #include "clutter-main.h"
+ #include "clutter-marshal.h"
+@@ -1448,3 +1449,23 @@ clutter_container_child_notify (ClutterContainer *container,
+                                                          child,
+                                                          pspec);
+ }
++
++void
++_clutter_container_emit_actor_added (ClutterContainer *container,
++                                     ClutterActor     *actor)
++{
++  g_return_if_fail (CLUTTER_IS_CONTAINER (container));
++  g_return_if_fail (CLUTTER_IS_ACTOR (actor));
++
++  g_signal_emit (container, container_signals[ACTOR_ADDED], 0, actor);
++}
++
++void
++_clutter_container_emit_actor_removed (ClutterContainer *container,
++                                       ClutterActor     *actor)
++{
++  g_return_if_fail (CLUTTER_IS_CONTAINER (container));
++  g_return_if_fail (CLUTTER_IS_ACTOR (actor));
++
++  g_signal_emit (container, container_signals[ACTOR_REMOVED], 0, actor);
++}
+-- 
+2.26.0
+
diff --git a/SOURCES/0003-clutter-fix-hole-in-ClutterPaintNode.patch b/SOURCES/0003-clutter-fix-hole-in-ClutterPaintNode.patch
new file mode 100644
index 0000000..0440f51
--- /dev/null
+++ b/SOURCES/0003-clutter-fix-hole-in-ClutterPaintNode.patch
@@ -0,0 +1,167 @@
+From 6d849de8ff486be21ff931bfa63313240b212852 Mon Sep 17 00:00:00 2001
+From: Christian Hergert <christian@hergert.me>
+Date: Fri, 21 Feb 2020 22:36:31 +0000
+Subject: [PATCH 3/3] clutter: fix hole in ClutterPaintNode
+
+Fixing the missalignment takes the structure from 80 bytes down to 72.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/1081
+---
+ clutter/clutter/clutter-actor.c              |  8 +++----
+ clutter/clutter/clutter-canvas.c             |  2 +-
+ clutter/clutter/clutter-image.c              |  2 +-
+ clutter/clutter/clutter-paint-node-private.h |  6 ++---
+ clutter/clutter/clutter-paint-node.c         | 23 +++++++++++++++-----
+ clutter/clutter/clutter-paint-node.h         |  3 +++
+ 6 files changed, 30 insertions(+), 14 deletions(-)
+
+diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c
+index 8da53d3f1..995de8c35 100644
+--- a/clutter/clutter/clutter-actor.c
++++ b/clutter/clutter/clutter-actor.c
+@@ -3692,7 +3692,7 @@ clutter_actor_paint_node (ClutterActor     *actor,
+         clear_flags |= COGL_BUFFER_BIT_COLOR;
+ 
+       node = _clutter_root_node_new (fb, &bg_color, clear_flags);
+-      clutter_paint_node_set_name (node, "stageClear");
++      clutter_paint_node_set_static_name (node, "stageClear");
+       clutter_paint_node_add_rectangle (node, &box);
+       clutter_paint_node_add_child (root, node);
+       clutter_paint_node_unref (node);
+@@ -3707,7 +3707,7 @@ clutter_actor_paint_node (ClutterActor     *actor,
+                      / 255;
+ 
+       node = clutter_color_node_new (&bg_color);
+-      clutter_paint_node_set_name (node, "backgroundColor");
++      clutter_paint_node_set_static_name (node, "backgroundColor");
+       clutter_paint_node_add_rectangle (node, &box);
+       clutter_paint_node_add_child (root, node);
+       clutter_paint_node_unref (node);
+@@ -4014,7 +4014,7 @@ clutter_actor_continue_paint (ClutterActor *self)
+            * virtual function can then be called directly.
+            */
+           dummy = _clutter_dummy_node_new (self);
+-          clutter_paint_node_set_name (dummy, "Root");
++          clutter_paint_node_set_static_name (dummy, "Root");
+ 
+           /* XXX - for 1.12, we use the return value of paint_node() to
+            * decide whether we should emit the ::paint signal.
+@@ -21129,7 +21129,7 @@ clutter_actor_create_texture_paint_node (ClutterActor *self,
+   color.alpha = clutter_actor_get_paint_opacity_internal (self);
+ 
+   node = clutter_texture_node_new (texture, &color, priv->min_filter, priv->mag_filter);
+-  clutter_paint_node_set_name (node, "Texture");
++  clutter_paint_node_set_static_name (node, "Texture");
+ 
+   if (priv->content_repeat == CLUTTER_REPEAT_NONE)
+     clutter_paint_node_add_rectangle (node, &box);
+diff --git a/clutter/clutter/clutter-canvas.c b/clutter/clutter/clutter-canvas.c
+index 42e54ce9d..512e434ed 100644
+--- a/clutter/clutter/clutter-canvas.c
++++ b/clutter/clutter/clutter-canvas.c
+@@ -319,7 +319,7 @@ clutter_canvas_paint_content (ClutterContent   *content,
+     return;
+ 
+   node = clutter_actor_create_texture_paint_node (actor, priv->texture);
+-  clutter_paint_node_set_name (node, "Canvas Content");
++  clutter_paint_node_set_static_name (node, "Canvas Content");
+   clutter_paint_node_add_child (root, node);
+   clutter_paint_node_unref (node);
+ 
+diff --git a/clutter/clutter/clutter-image.c b/clutter/clutter/clutter-image.c
+index 722b0375d..51e610073 100644
+--- a/clutter/clutter/clutter-image.c
++++ b/clutter/clutter/clutter-image.c
+@@ -108,7 +108,7 @@ clutter_image_paint_content (ClutterContent   *content,
+     return;
+ 
+   node = clutter_actor_create_texture_paint_node (actor, priv->texture);
+-  clutter_paint_node_set_name (node, "Image Content");
++  clutter_paint_node_set_static_name (node, "Image Content");
+   clutter_paint_node_add_child (root, node);
+   clutter_paint_node_unref (node);
+ }
+diff --git a/clutter/clutter/clutter-paint-node-private.h b/clutter/clutter/clutter-paint-node-private.h
+index 2945b78a4..ea1665ada 100644
+--- a/clutter/clutter/clutter-paint-node-private.h
++++ b/clutter/clutter/clutter-paint-node-private.h
+@@ -48,11 +48,11 @@ struct _ClutterPaintNode
+   ClutterPaintNode *next_sibling;
+   ClutterPaintNode *last_child;
+ 
+-  guint n_children;
+-
+   GArray *operations;
+ 
+-  gchar *name;
++  const gchar *name;
++
++  guint n_children;
+ 
+   volatile int ref_count;
+ };
+diff --git a/clutter/clutter/clutter-paint-node.c b/clutter/clutter/clutter-paint-node.c
+index db68b7766..5129e00cf 100644
+--- a/clutter/clutter/clutter-paint-node.c
++++ b/clutter/clutter/clutter-paint-node.c
+@@ -173,8 +173,6 @@ clutter_paint_node_real_finalize (ClutterPaintNode *node)
+ {
+   ClutterPaintNode *iter;
+ 
+-  g_free (node->name);
+-
+   if (node->operations != NULL)
+     {
+       guint i;
+@@ -296,7 +294,8 @@ clutter_paint_node_get_type (void)
+  *
+  * The @name will be used for debugging purposes.
+  *
+- * The @node will copy the passed string.
++ * The @node will intern @name using g_intern_string(). If you have access to a
++ * static string, use clutter_paint_node_set_static_name() instead.
+  *
+  * Since: 1.10
+  */
+@@ -306,8 +305,22 @@ clutter_paint_node_set_name (ClutterPaintNode *node,
+ {
+   g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
+ 
+-  g_free (node->name);
+-  node->name = g_strdup (name);
++  node->name = g_intern_string (name);
++}
++
++/**
++ * clutter_paint_node_set_static_name: (skip)
++ *
++ * Like clutter_paint_node_set_name() but uses a static or interned string
++ * containing the name.
++ */
++void
++clutter_paint_node_set_static_name (ClutterPaintNode *node,
++                                    const char       *name)
++{
++  g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
++
++  node->name = name;
+ }
+ 
+ /**
+diff --git a/clutter/clutter/clutter-paint-node.h b/clutter/clutter/clutter-paint-node.h
+index 5f3e962e4..d3e4e7922 100644
+--- a/clutter/clutter/clutter-paint-node.h
++++ b/clutter/clutter/clutter-paint-node.h
+@@ -52,6 +52,9 @@ void                    clutter_paint_node_unref                        (Clutter
+ CLUTTER_AVAILABLE_IN_1_10
+ void                    clutter_paint_node_set_name                     (ClutterPaintNode      *node,
+                                                                          const char            *name);
++CLUTTER_AVAILABLE_IN_ALL
++void                    clutter_paint_node_set_static_name              (ClutterPaintNode      *node,
++                                                                         const char            *name);
+ 
+ CLUTTER_AVAILABLE_IN_1_10
+ void                    clutter_paint_node_add_child                    (ClutterPaintNode      *node,
+-- 
+2.26.0
+
diff --git a/SOURCES/idle-monitor-reset-fix.patch b/SOURCES/idle-monitor-reset-fix.patch
new file mode 100644
index 0000000..411b625
--- /dev/null
+++ b/SOURCES/idle-monitor-reset-fix.patch
@@ -0,0 +1,128 @@
+From 23c81629d775fd902e4bee7ec0a182a916f4252b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Mon, 16 Sep 2019 16:17:48 +0200
+Subject: [PATCH 1/3] idle-monitor: Make helper function static
+
+It wasn't used outside the file, so no reason to not have it static.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/799
+---
+ src/backends/meta-idle-monitor-private.h | 1 -
+ src/backends/meta-idle-monitor.c         | 8 ++++----
+ 2 files changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/src/backends/meta-idle-monitor-private.h b/src/backends/meta-idle-monitor-private.h
+index 82f3f87b7..9ce7e743a 100644
+--- a/src/backends/meta-idle-monitor-private.h
++++ b/src/backends/meta-idle-monitor-private.h
+@@ -54,7 +54,6 @@ struct _MetaIdleMonitorClass
+   GObjectClass parent_class;
+ };
+ 
+-void _meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch);
+ void meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor);
+ 
+ #endif /* META_IDLE_MONITOR_PRIVATE_H */
+diff --git a/src/backends/meta-idle-monitor.c b/src/backends/meta-idle-monitor.c
+index 2c06ee73c..ce1b87bbb 100644
+--- a/src/backends/meta-idle-monitor.c
++++ b/src/backends/meta-idle-monitor.c
+@@ -54,8 +54,8 @@ static GParamSpec *obj_props[PROP_LAST];
+ 
+ G_DEFINE_TYPE (MetaIdleMonitor, meta_idle_monitor, G_TYPE_OBJECT)
+ 
+-void
+-_meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch)
++static void
++meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch)
+ {
+   MetaIdleMonitor *monitor;
+   guint id;
+@@ -319,7 +319,7 @@ idle_monitor_dispatch_timeout (GSource     *source,
+   if (ready_time > now)
+     return G_SOURCE_CONTINUE;
+ 
+-  _meta_idle_monitor_watch_fire (watch);
++  meta_idle_monitor_watch_fire (watch);
+   g_source_set_ready_time (watch->timeout_source, -1);
+ 
+   return G_SOURCE_CONTINUE;
+@@ -506,7 +506,7 @@ meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor)
+ 
+       if (watch->timeout_msec == 0)
+         {
+-          _meta_idle_monitor_watch_fire ((MetaIdleMonitorWatch *) watch);
++          meta_idle_monitor_watch_fire ((MetaIdleMonitorWatch *) watch);
+         }
+       else
+         {
+-- 
+2.23.0
+
+
+From 0d43bbdae0a08c7618e789fa0d5270615c907a36 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Mon, 16 Sep 2019 16:36:05 +0200
+Subject: [PATCH 2/3] idle-monitor: Remove redundant type cast
+
+No need to type cast a `MetaIdleMonitorWatch *` to a
+`MetaIdleMonitorWatch *`.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/799
+---
+ src/backends/meta-idle-monitor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/backends/meta-idle-monitor.c b/src/backends/meta-idle-monitor.c
+index ce1b87bbb..3dbb89944 100644
+--- a/src/backends/meta-idle-monitor.c
++++ b/src/backends/meta-idle-monitor.c
+@@ -506,7 +506,7 @@ meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor)
+ 
+       if (watch->timeout_msec == 0)
+         {
+-          meta_idle_monitor_watch_fire ((MetaIdleMonitorWatch *) watch);
++          meta_idle_monitor_watch_fire (watch);
+         }
+       else
+         {
+-- 
+2.23.0
+
+
+From f6c24dd45c14dd16d6878ebf170f8468ad3d47e1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Mon, 16 Sep 2019 16:36:51 +0200
+Subject: [PATCH 3/3] idle-monitor: Reset timeout before firing watch
+
+The watch might be removed during firing, meaning the source is
+destroyed after returning. Avoid use-after-free by unsetting the timeout
+before firing. Returning G_SOURCE_CONTINUE in that case is harmless, as
+source is destroyed.
+
+Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/796
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/799
+---
+ src/backends/meta-idle-monitor.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/backends/meta-idle-monitor.c b/src/backends/meta-idle-monitor.c
+index 3dbb89944..c6e814468 100644
+--- a/src/backends/meta-idle-monitor.c
++++ b/src/backends/meta-idle-monitor.c
+@@ -319,9 +319,10 @@ idle_monitor_dispatch_timeout (GSource     *source,
+   if (ready_time > now)
+     return G_SOURCE_CONTINUE;
+ 
+-  meta_idle_monitor_watch_fire (watch);
+   g_source_set_ready_time (watch->timeout_source, -1);
+ 
++  meta_idle_monitor_watch_fire (watch);
++
+   return G_SOURCE_CONTINUE;
+ }
+ 
+-- 
+2.23.0
+
diff --git a/SOURCES/input-after-long-idle-fix.patch b/SOURCES/input-after-long-idle-fix.patch
new file mode 100644
index 0000000..d211ff9
--- /dev/null
+++ b/SOURCES/input-after-long-idle-fix.patch
@@ -0,0 +1,378 @@
+From 388ed4984586f96250934a025b1c78915c4cd856 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Thu, 24 Oct 2019 21:19:36 +0200
+Subject: [PATCH 1/2] display: Move finishing of touch sequence to the backend
+
+We need to manipulate an X11 grab when a touch sequence ends; move that
+logic to where it belongs - in the X11 backend.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/886
+---
+ src/backends/meta-backend-private.h     | 16 ++++++++++++
+ src/backends/meta-backend.c             | 14 +++++++++++
+ src/backends/x11/meta-backend-x11.c     | 23 +++++++++++++++++
+ src/core/display.c                      | 33 +++++++++++--------------
+ src/core/meta-gesture-tracker-private.h |  7 +-----
+ src/core/meta-gesture-tracker.c         |  1 +
+ 6 files changed, 70 insertions(+), 24 deletions(-)
+
+diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
+index a25275499..7f4a4ea0f 100644
+--- a/src/backends/meta-backend-private.h
++++ b/src/backends/meta-backend-private.h
+@@ -51,6 +51,14 @@
+ #define META_TYPE_BACKEND (meta_backend_get_type ())
+ G_DECLARE_DERIVABLE_TYPE (MetaBackend, meta_backend, META, BACKEND, GObject)
+ 
++typedef enum _MetaSequenceState
++{
++  META_SEQUENCE_NONE,
++  META_SEQUENCE_ACCEPTED,
++  META_SEQUENCE_REJECTED,
++  META_SEQUENCE_PENDING_END
++} MetaSequenceState;
++
+ struct _MetaBackendClass
+ {
+   GObjectClass parent_class;
+@@ -73,6 +81,10 @@ struct _MetaBackendClass
+                               int          device_id,
+                               uint32_t     timestamp);
+ 
++  void (* finish_touch_sequence) (MetaBackend          *backend,
++                                  ClutterEventSequence *sequence,
++                                  MetaSequenceState     state);
++
+   void (* warp_pointer) (MetaBackend *backend,
+                          int          x,
+                          int          y);
+@@ -134,6 +146,10 @@ gboolean meta_backend_ungrab_device (MetaBackend *backend,
+                                      int          device_id,
+                                      uint32_t     timestamp);
+ 
++void meta_backend_finish_touch_sequence (MetaBackend          *backend,
++                                         ClutterEventSequence *sequence,
++                                         MetaSequenceState     state);
++
+ void meta_backend_warp_pointer (MetaBackend *backend,
+                                 int          x,
+                                 int          y);
+diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
+index ce7e385b9..fb4f69fe6 100644
+--- a/src/backends/meta-backend.c
++++ b/src/backends/meta-backend.c
+@@ -846,6 +846,20 @@ meta_backend_ungrab_device (MetaBackend *backend,
+   return META_BACKEND_GET_CLASS (backend)->ungrab_device (backend, device_id, timestamp);
+ }
+ 
++/**
++ * meta_backend_finish_touch_sequence: (skip)
++ */
++void
++meta_backend_finish_touch_sequence (MetaBackend          *backend,
++                                    ClutterEventSequence *sequence,
++                                    MetaSequenceState     state)
++{
++  if (META_BACKEND_GET_CLASS (backend)->finish_touch_sequence)
++    META_BACKEND_GET_CLASS (backend)->finish_touch_sequence (backend,
++                                                             sequence,
++                                                             state);
++}
++
+ /**
+  * meta_backend_warp_pointer: (skip)
+  */
+diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
+index 2b131d2d0..2835d47d6 100644
+--- a/src/backends/x11/meta-backend-x11.c
++++ b/src/backends/x11/meta-backend-x11.c
+@@ -583,6 +583,28 @@ meta_backend_x11_ungrab_device (MetaBackend *backend,
+   return (ret == Success);
+ }
+ 
++static void
++meta_backend_x11_finish_touch_sequence (MetaBackend          *backend,
++                                        ClutterEventSequence *sequence,
++                                        MetaSequenceState     state)
++{
++  MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
++  MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
++  int event_mode;
++
++  if (state == META_SEQUENCE_ACCEPTED)
++    event_mode = XIAcceptTouch;
++  else if (state == META_SEQUENCE_REJECTED)
++    event_mode = XIRejectTouch;
++  else
++    g_return_if_reached ();
++
++  XIAllowTouchEvents (priv->xdisplay,
++                      META_VIRTUAL_CORE_POINTER_ID,
++                      clutter_x11_event_sequence_get_touch_detail (sequence),
++                      DefaultRootWindow (priv->xdisplay), event_mode);
++}
++
+ static void
+ meta_backend_x11_warp_pointer (MetaBackend *backend,
+                                int          x,
+@@ -768,6 +790,7 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass)
+   backend_class->post_init = meta_backend_x11_post_init;
+   backend_class->grab_device = meta_backend_x11_grab_device;
+   backend_class->ungrab_device = meta_backend_x11_ungrab_device;
++  backend_class->finish_touch_sequence = meta_backend_x11_finish_touch_sequence;
+   backend_class->warp_pointer = meta_backend_x11_warp_pointer;
+   backend_class->get_current_logical_monitor = meta_backend_x11_get_current_logical_monitor;
+   backend_class->get_keymap = meta_backend_x11_get_keymap;
+diff --git a/src/core/display.c b/src/core/display.c
+index e7dd4534b..d4775cec3 100644
+--- a/src/core/display.c
++++ b/src/core/display.c
+@@ -55,6 +55,7 @@
+ #include "backends/x11/meta-backend-x11.h"
+ #include "backends/meta-stage-private.h"
+ #include "backends/meta-input-settings-private.h"
++#include "backends/meta-backend-private.h"
+ #include <clutter/x11/clutter-x11.h>
+ 
+ #ifdef HAVE_RANDR
+@@ -533,27 +534,23 @@ gesture_tracker_state_changed (MetaGestureTracker   *tracker,
+                                MetaSequenceState     state,
+                                MetaDisplay          *display)
+ {
+-  if (meta_is_wayland_compositor ())
++  switch (state)
+     {
+-      if (state == META_SEQUENCE_ACCEPTED)
+-        meta_display_cancel_touch (display);
+-    }
+-  else
+-    {
+-      MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
+-      int event_mode;
++    case META_SEQUENCE_NONE:
++    case META_SEQUENCE_PENDING_END:
++      return;
++    case META_SEQUENCE_ACCEPTED:
++      meta_display_cancel_touch (display);
+ 
+-      if (state == META_SEQUENCE_ACCEPTED)
+-        event_mode = XIAcceptTouch;
+-      else if (state == META_SEQUENCE_REJECTED)
+-        event_mode = XIRejectTouch;
+-      else
+-        return;
++      /* Intentional fall-through */
++    case META_SEQUENCE_REJECTED:
++      {
++        MetaBackend *backend;
+ 
+-      XIAllowTouchEvents (meta_backend_x11_get_xdisplay (backend),
+-                          META_VIRTUAL_CORE_POINTER_ID,
+-                          clutter_x11_event_sequence_get_touch_detail (sequence),
+-                          DefaultRootWindow (display->xdisplay), event_mode);
++        backend = meta_get_backend ();
++        meta_backend_finish_touch_sequence (backend, sequence, state);
++        break;
++      }
+     }
+ }
+ 
+diff --git a/src/core/meta-gesture-tracker-private.h b/src/core/meta-gesture-tracker-private.h
+index 0e39af27f..b4fb02a1e 100644
+--- a/src/core/meta-gesture-tracker-private.h
++++ b/src/core/meta-gesture-tracker-private.h
+@@ -38,12 +38,7 @@
+ typedef struct _MetaGestureTracker MetaGestureTracker;
+ typedef struct _MetaGestureTrackerClass MetaGestureTrackerClass;
+ 
+-typedef enum {
+-  META_SEQUENCE_NONE,
+-  META_SEQUENCE_ACCEPTED,
+-  META_SEQUENCE_REJECTED,
+-  META_SEQUENCE_PENDING_END
+-} MetaSequenceState;
++typedef enum _MetaSequenceState MetaSequenceState;
+ 
+ struct _MetaGestureTracker
+ {
+diff --git a/src/core/meta-gesture-tracker.c b/src/core/meta-gesture-tracker.c
+index e3b702f56..1313aad6d 100644
+--- a/src/core/meta-gesture-tracker.c
++++ b/src/core/meta-gesture-tracker.c
+@@ -31,6 +31,7 @@
+ #include "config.h"
+ #include "meta-gesture-tracker-private.h"
+ #include "meta-surface-actor.h"
++#include "meta-backend-private.h"
+ 
+ #define DISTANCE_THRESHOLD 30
+ 
+-- 
+2.23.0
+
+
+From 75cf52ac533675ecf5d3542e9fba2937a56bfefd Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Fri, 25 Oct 2019 10:06:55 +0200
+Subject: [PATCH 2/2] x11: Limit touch replay pointer events to when replaying
+
+When a touch sequence was rejected, the emulated pointer events would be
+replayed with old timestamps. This caused issues with grabs as they
+would be ignored due to being too old. This was mitigated by making sure
+device event timestamps never travelled back in time by tampering with
+any event that had a timestamp seemingly in the past.
+
+This failed when the most recent timestamp that had been received were
+much older than the timestamp of the new event. This could for example
+happen when a session was left not interacted with for 40+ days or so;
+when interacted with again, as any new timestamp would according to
+XSERVER_TIME_IS_BEFORE() still be in the past compared to the "most
+recent" one. The effect is that we'd always use the `latest_evtime` for
+all new device events without ever updating it.
+
+The end result of this was that passive grabs would become active when
+interacted with, but would then newer be released, as the timestamps to
+XIAllowEvents() would out of date, resulting in the desktop effectively
+freezing, as the Shell would have an active pointer grab.
+
+To avoid the situation where we get stuck with an old `latest_evtime`
+timestamp, limit the tampering with device event timestamp to 1) only
+pointer events, and 2) only during the replay sequence. The second part
+is implemented by sending an asynchronous message via the X server after
+rejecting a touch sequence, only potentially tampering with the device
+event timestamps until the reply. This should avoid the stuck timestamp
+as in those situations, we'll always have a relatively up to date
+`latest_evtime` meaning XSERVER_TIME_IS_BEFORE() will not get confused.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/886
+---
+ src/backends/x11/meta-backend-x11.c | 71 +++++++++++++++++++++++------
+ 1 file changed, 58 insertions(+), 13 deletions(-)
+
+diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
+index 2835d47d6..3f8645e93 100644
+--- a/src/backends/x11/meta-backend-x11.c
++++ b/src/backends/x11/meta-backend-x11.c
+@@ -60,6 +60,10 @@ struct _MetaBackendX11Private
+   XSyncAlarm user_active_alarm;
+   XSyncCounter counter;
+ 
++  int current_touch_replay_sync_serial;
++  int pending_touch_replay_sync_serial;
++  Atom touch_replay_sync_atom;
++
+   int xinput_opcode;
+   int xinput_event_base;
+   int xinput_error_base;
+@@ -168,6 +172,26 @@ meta_backend_x11_translate_device_event (MetaBackendX11 *x11,
+   backend_x11_class->translate_device_event (x11, device_event);
+ }
+ 
++static void
++maybe_translate_touch_replay_pointer_event (MetaBackendX11 *x11,
++                                            XIDeviceEvent  *device_event)
++{
++  MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
++
++  if (!device_event->send_event &&
++      device_event->time != CurrentTime &&
++      priv->current_touch_replay_sync_serial !=
++      priv->pending_touch_replay_sync_serial &&
++      XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime))
++    {
++      /* Emulated pointer events received after XIRejectTouch is received
++       * on a passive touch grab will contain older timestamps, update those
++       * so we dont get InvalidTime at grabs.
++       */
++      device_event->time = priv->latest_evtime;
++    }
++}
++
+ static void
+ translate_device_event (MetaBackendX11 *x11,
+                         XIDeviceEvent  *device_event)
+@@ -177,19 +201,7 @@ translate_device_event (MetaBackendX11 *x11,
+   meta_backend_x11_translate_device_event (x11, device_event);
+ 
+   if (!device_event->send_event && device_event->time != CurrentTime)
+-    {
+-      if (XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime))
+-        {
+-          /* Emulated pointer events received after XIRejectTouch is received
+-           * on a passive touch grab will contain older timestamps, update those
+-           * so we dont get InvalidTime at grabs.
+-           */
+-          device_event->time = priv->latest_evtime;
+-        }
+-
+-      /* Update the internal latest evtime, for any possible later use */
+-      priv->latest_evtime = device_event->time;
+-    }
++    priv->latest_evtime = device_event->time;
+ }
+ 
+ static void
+@@ -254,6 +266,9 @@ maybe_spoof_event_as_stage_event (MetaBackendX11 *x11,
+     case XI_Motion:
+     case XI_ButtonPress:
+     case XI_ButtonRelease:
++      maybe_translate_touch_replay_pointer_event (x11,
++                                                  (XIDeviceEvent *) input_event);
++      /* Intentional fall-through */
+     case XI_KeyPress:
+     case XI_KeyRelease:
+     case XI_TouchBegin:
+@@ -321,6 +336,17 @@ handle_host_xevent (MetaBackend *backend,
+   MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
+   gboolean bypass_clutter = FALSE;
+ 
++  switch (event->type)
++    {
++    case ClientMessage:
++      if (event->xclient.window == meta_backend_x11_get_xwindow (x11) &&
++          event->xclient.message_type == priv->touch_replay_sync_atom)
++        priv->current_touch_replay_sync_serial = event->xclient.data.l[0];
++      break;
++    default:
++      break;
++    }
++
+   XGetEventData (priv->xdisplay, &event->xcookie);
+ 
+   {
+@@ -528,6 +554,10 @@ meta_backend_x11_post_init (MetaBackend *backend)
+   monitor_manager = meta_backend_get_monitor_manager (backend);
+   g_signal_connect (monitor_manager, "monitors-changed-internal",
+                     G_CALLBACK (on_monitors_changed), backend);
++
++  priv->touch_replay_sync_atom = XInternAtom (priv->xdisplay,
++                                              "_MUTTER_TOUCH_SEQUENCE_SYNC",
++                                              False);
+ }
+ 
+ static ClutterBackend *
+@@ -603,6 +633,21 @@ meta_backend_x11_finish_touch_sequence (MetaBackend          *backend,
+                       META_VIRTUAL_CORE_POINTER_ID,
+                       clutter_x11_event_sequence_get_touch_detail (sequence),
+                       DefaultRootWindow (priv->xdisplay), event_mode);
++
++  if (state == META_SEQUENCE_REJECTED)
++    {
++      XClientMessageEvent ev;
++
++      ev = (XClientMessageEvent) {
++          .type = ClientMessage,
++            .window = meta_backend_x11_get_xwindow (x11),
++            .message_type = priv->touch_replay_sync_atom,
++            .format = 32,
++            .data.l[0] = ++priv->pending_touch_replay_sync_serial,
++      };
++      XSendEvent (priv->xdisplay, meta_backend_x11_get_xwindow (x11),
++                  False, 0, (XEvent *) &ev);
++    }
+ }
+ 
+ static void
+-- 
+2.23.0
+
diff --git a/SOURCES/more-performance-backports.patch b/SOURCES/more-performance-backports.patch
new file mode 100644
index 0000000..17db38d
--- /dev/null
+++ b/SOURCES/more-performance-backports.patch
@@ -0,0 +1,186 @@
+From f86e33e1ea32c4208809e8de33bed05ddbce9a4c Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Sun, 7 May 2017 03:00:10 +0200
+Subject: [PATCH 1/3] compositor: Avoid changing pipeline/source if shadow is
+ not being painted
+
+Avoids some context invalidations in cogl.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=782344
+---
+ src/compositor/meta-shadow-factory.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/src/compositor/meta-shadow-factory.c b/src/compositor/meta-shadow-factory.c
+index cd006008b..19147ca9f 100644
+--- a/src/compositor/meta-shadow-factory.c
++++ b/src/compositor/meta-shadow-factory.c
+@@ -220,9 +220,7 @@ meta_shadow_paint (MetaShadow     *shadow,
+   int dest_x[4];
+   int dest_y[4];
+   int n_x, n_y;
+-
+-  cogl_pipeline_set_color4ub (shadow->pipeline,
+-                              opacity, opacity, opacity, opacity);
++  gboolean source_updated = FALSE;
+ 
+   cogl_set_source (shadow->pipeline);
+ 
+@@ -300,6 +298,17 @@ meta_shadow_paint (MetaShadow     *shadow,
+           else
+             overlap = CAIRO_REGION_OVERLAP_IN;
+ 
++          if (overlap == CAIRO_REGION_OVERLAP_OUT)
++            continue;
++
++          if (!source_updated)
++            {
++              cogl_pipeline_set_color4ub (shadow->pipeline,
++                                          opacity, opacity, opacity, opacity);
++              cogl_set_source (shadow->pipeline);
++              source_updated = TRUE;
++            }
++
+           /* There's quite a bit of overhead from allocating a new
+            * region in order to find an exact intersection and
+            * generating more geometry - we make the assumption that
+-- 
+2.23.0
+
+
+From f530bc4c3391cabe2b084cd59def00d81c13286c Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Fri, 5 May 2017 14:15:30 +0200
+Subject: [PATCH 2/3] clutter: Avoid rounding compensation when invalidating 2D
+ actors
+
+This allows the redraw clip to be more constrained, so MetaCullable doesn't
+end up rendering portions of window shadows, frame and background when a
+window invalidates (part of) its contents.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=782344
+---
+ clutter/clutter/clutter-paint-volume.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/clutter/clutter/clutter-paint-volume.c b/clutter/clutter/clutter-paint-volume.c
+index b48f7f9d6..f3405138b 100644
+--- a/clutter/clutter/clutter-paint-volume.c
++++ b/clutter/clutter/clutter-paint-volume.c
+@@ -1166,6 +1166,21 @@ _clutter_paint_volume_get_stage_paint_box (ClutterPaintVolume *pv,
+ 
+   _clutter_paint_volume_get_bounding_box (&projected_pv, box);
+ 
++  if (pv->is_2d && pv->actor &&
++      clutter_actor_get_z_position (pv->actor) == 0)
++    {
++      /* If the volume/actor are perfectly 2D, take the bounding box as
++       * good. We won't need to add any extra room for sub-pixel positioning
++       * in this case.
++       */
++      clutter_paint_volume_free (&projected_pv);
++      box->x1 = CLUTTER_NEARBYINT (box->x1);
++      box->y1 = CLUTTER_NEARBYINT (box->y1);
++      box->x2 = CLUTTER_NEARBYINT (box->x2);
++      box->y2 = CLUTTER_NEARBYINT (box->y2);
++      return;
++    }
++
+   /* The aim here is that for a given rectangle defined with floating point
+    * coordinates we want to determine a stable quantized size in pixels
+    * that doesn't vary due to the original box's sub-pixel position.
+-- 
+2.23.0
+
+
+From 676369000658c6121d0c3b5e1286aa68dc79eb35 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Mon, 8 May 2017 15:10:58 +0200
+Subject: [PATCH 3/3] cogl: Ensure to only clear the depth buffer if depth
+ testing is enabled
+
+The depth buffer is marked as invalid when 1) the framebuffer is just created,
+and 2) whenever GL_DEPTH_TEST is enabled on it. This will ensure the
+framebuffers attached depth buffer (if any) is properly cleared before it's
+actually used, while saving needless clears while depth testing is disabled
+(the default).
+
+https://bugzilla.gnome.org/show_bug.cgi?id=782344
+---
+ cogl/cogl/cogl-framebuffer-private.h       |  5 +++++
+ cogl/cogl/cogl-framebuffer.c               | 11 +++++++++++
+ cogl/cogl/driver/gl/cogl-pipeline-opengl.c |  6 +++++-
+ 3 files changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/cogl/cogl/cogl-framebuffer-private.h b/cogl/cogl/cogl-framebuffer-private.h
+index 99ac2fba9..756e34dfe 100644
+--- a/cogl/cogl/cogl-framebuffer-private.h
++++ b/cogl/cogl/cogl-framebuffer-private.h
+@@ -193,6 +193,11 @@ struct _CoglFramebuffer
+   CoglFramebufferBits bits;
+ 
+   int                 samples_per_pixel;
++
++  /* Whether the depth buffer was enabled for this framebuffer,
++   * usually means it needs to be cleared before being reused next.
++   */
++  CoglBool            depth_buffer_clear_needed;
+ };
+ 
+ typedef enum {
+diff --git a/cogl/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c
+index 55b9e3756..6b105087d 100644
+--- a/cogl/cogl/cogl-framebuffer.c
++++ b/cogl/cogl/cogl-framebuffer.c
+@@ -117,6 +117,7 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
+   framebuffer->viewport_age_for_scissor_workaround = -1;
+   framebuffer->dither_enabled = TRUE;
+   framebuffer->depth_writing_enabled = TRUE;
++  framebuffer->depth_buffer_clear_needed = TRUE;
+ 
+   framebuffer->modelview_stack = cogl_matrix_stack_new (ctx);
+   framebuffer->projection_stack = cogl_matrix_stack_new (ctx);
+@@ -268,6 +269,13 @@ cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
+   int scissor_y1;
+   CoglBool saved_viewport_scissor_workaround;
+ 
++  if (!framebuffer->depth_buffer_clear_needed &&
++      (buffers & COGL_BUFFER_BIT_DEPTH))
++    buffers &= ~(COGL_BUFFER_BIT_DEPTH);
++
++  if (buffers == 0)
++    return;
++
+   _cogl_clip_stack_get_bounds (clip_stack,
+                                &scissor_x0, &scissor_y0,
+                                &scissor_x1, &scissor_y1);
+@@ -415,6 +423,9 @@ cleared:
+   _cogl_framebuffer_mark_mid_scene (framebuffer);
+   _cogl_framebuffer_mark_clear_clip_dirty (framebuffer);
+ 
++  if (buffers & COGL_BUFFER_BIT_DEPTH)
++    framebuffer->depth_buffer_clear_needed = FALSE;
++
+   if (buffers & COGL_BUFFER_BIT_COLOR && buffers & COGL_BUFFER_BIT_DEPTH)
+     {
+       /* For our fast-path for reading back a single pixel of simple
+diff --git a/cogl/cogl/driver/gl/cogl-pipeline-opengl.c b/cogl/cogl/driver/gl/cogl-pipeline-opengl.c
+index 178269646..4f1f69f96 100644
+--- a/cogl/cogl/driver/gl/cogl-pipeline-opengl.c
++++ b/cogl/cogl/driver/gl/cogl-pipeline-opengl.c
+@@ -418,7 +418,11 @@ flush_depth_state (CoglContext *ctx,
+   if (ctx->depth_test_enabled_cache != depth_state->test_enabled)
+     {
+       if (depth_state->test_enabled == TRUE)
+-        GE (ctx, glEnable (GL_DEPTH_TEST));
++        {
++          GE (ctx, glEnable (GL_DEPTH_TEST));
++          if (ctx->current_draw_buffer)
++            ctx->current_draw_buffer->depth_buffer_clear_needed = TRUE;
++        }
+       else
+         GE (ctx, glDisable (GL_DEPTH_TEST));
+       ctx->depth_test_enabled_cache = depth_state->test_enabled;
+-- 
+2.23.0
+
diff --git a/SPECS/mutter.spec b/SPECS/mutter.spec
index cea0b73..085f9fe 100644
--- a/SPECS/mutter.spec
+++ b/SPECS/mutter.spec
@@ -10,7 +10,7 @@
 
 Name:          mutter
 Version:       3.28.3
-Release:       16%{?dist}
+Release:       23%{?dist}
 Summary:       Window and compositing manager based on Clutter
 
 License:       GPLv2+
@@ -99,6 +99,27 @@ Patch278: 0002-xprops-Make-sure-text_property_to_utf8-returns-UTF8.patch
 # Don't loose pointer button grabs (#1657887)
 Patch279: 0001-events-Sync-pending-pointer-events-without-a-window.patch
 
+# Don't freeze if input happens after many days of inactivity (#1728761)
+Patch280: input-after-long-idle-fix.patch
+
+# More performance backports (#1766501)
+Patch281: more-performance-backports.patch
+
+#  Fix invalid read in idle monitor (#1752378)
+Patch282: idle-monitor-reset-fix.patch
+
+# Prevent orphaned animation actors getting stuck on screen (#1753799)
+Patch283: 0001-window-free-close-dialog-before-unmanaging-window-fr.patch
+Patch284: 0001-core-Hide-close-dialog-before-destroying.patch
+
+# Add PING_TIMEOUT_DELAY to mutter MetaPreferences #1809164
+Patch285: 0001-display-Make-check-alive-timeout-configureable.patch
+
+# Improve performance under load (#1824869)
+Patch290: 0001-clutter-avoid-redundant-_clutter_paint_node_init_typ.patch
+Patch291: 0002-clutter-avoid-g_signal_emit_by_name-from-ClutterActo.patch
+Patch292: 0003-clutter-fix-hole-in-ClutterPaintNode.patch
+
 BuildRequires: chrpath
 BuildRequires: pango-devel
 BuildRequires: startup-notification-devel
@@ -254,6 +275,34 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
 %{_libdir}/pkgconfig/*
 
 %changelog
+* Fri Apr 17 2020 Florian Müllner <fmuellner@redhat.com> - 3.28.3-23
+- Improve performance under IO load
+  Resolves: #1824869
+
+* Fri Mar 06 2020 Florian Müllner <fmuellner@redhat.com> - 3.28.3-22
+- Include one more close-dialog backport
+  Related: #1753799
+
+* Thu Mar 05 2020 Jonas Ådahl <jadahl@redhat.com>) - 3.28.3-21
+- Add PING_TIMEOUT_DELAY to mutter MetaPreferences
+  Resolves: #1809164
+
+* Tue Dec 03 2019 Florian Müllner <fmuellner@redhat.com> - 3.28.3-20
+- Free close dialog before unmanaging parent
+  Related: #1753799
+
+* Tue Oct 29 2019 Jonas Ådahl <jadahl@redhat.com>) - 3.28.3-19
+- Fix invalid read in idle monitor
+  Resolves: #1752378
+
+* Tue Oct 29 2019  Jonas Ådahl <jadahl@redhat.com>) - 3.28.3-18
+- More performance backports
+  Resolves: #1766501
+
+* Tue Oct 29 2019  Jonas Ådahl <jadahl@redhat.com>) - 3.28.3-17
+- Don't freeze if input happens after many days of inactivity
+  Resolves: #1728761
+
 * Wed Oct 02 2019 Jonas Ådahl <jadahl@redhat.com>) - 3.28.3-16
 - Don't loose pointer button grabs
   Resolves: #1657887