diff --git a/SOURCES/0001-wayland-Move-check-for-present-window-out-of-the-act.patch b/SOURCES/0001-wayland-Move-check-for-present-window-out-of-the-act.patch
new file mode 100644
index 0000000..940bc76
--- /dev/null
+++ b/SOURCES/0001-wayland-Move-check-for-present-window-out-of-the-act.patch
@@ -0,0 +1,150 @@
+From 9269b09028ae51c7bb74e9cc9aefafd8eaa882d6 Mon Sep 17 00:00:00 2001
+From: Robert Mader <robert.mader@posteo.de>
+Date: Tue, 16 Apr 2019 23:35:28 +0200
+Subject: [PATCH 1/2] wayland: Move check for present window out of the
+ actor-surface class
+
+All child classes of `MetaWaylandShellSurface` as well as
+`MetaWaylandSurfaceRoleXWayland` should only sync their actor if
+their toplevel surface has a window. Currently this check is done
+in the actor-surface class, but not all surface classes have a
+toplevel window, e.g. dnd-surfaces.
+Move the check to the right places.
+
+For subsurfaces this assumes that the subsurface is not the child of
+a window-less surface (like, as stated above, e.g. a dnd-surface).
+If we want to support subsurfaces of window-less surfaces in the future
+we have to extend the check here.
+But as this is not a regression, ignore this case for now.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/537
+(cherry picked from commit 7e2a0ede16bed5671fe55d3d81ccc9f82eebd94b)
+---
+ src/wayland/meta-wayland-actor-surface.c |  7 -------
+ src/wayland/meta-wayland-shell-surface.c | 20 ++++++++++++++++++++
+ src/wayland/meta-wayland-subsurface.c    |  5 ++++-
+ src/wayland/meta-xwayland.c              | 18 ++++++++++++++++++
+ 4 files changed, 42 insertions(+), 8 deletions(-)
+
+diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c
+index 037dd901ab..e2143e51f1 100644
+--- a/src/wayland/meta-wayland-actor-surface.c
++++ b/src/wayland/meta-wayland-actor-surface.c
+@@ -295,9 +295,6 @@ meta_wayland_actor_surface_commit (MetaWaylandSurfaceRole  *surface_role,
+     META_WAYLAND_ACTOR_SURFACE (surface_role);
+   MetaWaylandActorSurfacePrivate *priv =
+     meta_wayland_actor_surface_get_instance_private (actor_surface);
+-  MetaWaylandSurface *surface =
+-    meta_wayland_surface_role_get_surface (surface_role);
+-  MetaWaylandSurface *toplevel_surface;
+ 
+   if (!wl_list_empty (&pending->frame_callback_list) &&
+       priv->actor &&
+@@ -311,10 +308,6 @@ meta_wayland_actor_surface_commit (MetaWaylandSurfaceRole  *surface_role,
+ 
+   meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
+ 
+-  toplevel_surface = meta_wayland_surface_get_toplevel (surface);
+-  if (!toplevel_surface || !toplevel_surface->window)
+-    return;
+-
+   meta_wayland_actor_surface_sync_actor_state (actor_surface);
+ }
+ 
+diff --git a/src/wayland/meta-wayland-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c
+index 04f2aaeea8..f8354ab7c5 100644
+--- a/src/wayland/meta-wayland-shell-surface.c
++++ b/src/wayland/meta-wayland-shell-surface.c
+@@ -175,6 +175,22 @@ meta_wayland_shell_surface_surface_commit (MetaWaylandSurfaceRole  *surface_role
+   window->buffer_rect.height = cogl_texture_get_height (texture) * scale;
+ }
+ 
++static void
++meta_wayland_shell_surface_sync_actor_state (MetaWaylandActorSurface *actor_surface)
++{
++  MetaWaylandSurfaceRole *surface_role =
++    META_WAYLAND_SURFACE_ROLE (actor_surface);
++  MetaWaylandSurface *surface =
++    meta_wayland_surface_role_get_surface (surface_role);
++  MetaWaylandActorSurfaceClass *actor_surface_class =
++    META_WAYLAND_ACTOR_SURFACE_CLASS (meta_wayland_shell_surface_parent_class);
++  MetaWaylandSurface *toplevel_surface;
++
++  toplevel_surface = meta_wayland_surface_get_toplevel (surface);
++  if (toplevel_surface && toplevel_surface->window)
++    actor_surface_class->sync_actor_state (actor_surface);
++}
++
+ static void
+ meta_wayland_shell_surface_init (MetaWaylandShellSurface *role)
+ {
+@@ -185,6 +201,10 @@ meta_wayland_shell_surface_class_init (MetaWaylandShellSurfaceClass *klass)
+ {
+   MetaWaylandSurfaceRoleClass *surface_role_class =
+     META_WAYLAND_SURFACE_ROLE_CLASS (klass);
++  MetaWaylandActorSurfaceClass *actor_surface_class =
++    META_WAYLAND_ACTOR_SURFACE_CLASS (klass);
+ 
+   surface_role_class->commit = meta_wayland_shell_surface_surface_commit;
++  actor_surface_class->sync_actor_state =
++    meta_wayland_shell_surface_sync_actor_state;
+ }
+diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c
+index c7059b99a2..9a7ff3ec12 100644
+--- a/src/wayland/meta-wayland-subsurface.c
++++ b/src/wayland/meta-wayland-subsurface.c
+@@ -199,8 +199,11 @@ meta_wayland_subsurface_sync_actor_state (MetaWaylandActorSurface *actor_surface
+     meta_wayland_surface_role_get_surface (surface_role);
+   MetaWaylandActorSurfaceClass *actor_surface_class =
+     META_WAYLAND_ACTOR_SURFACE_CLASS (meta_wayland_subsurface_parent_class);
++  MetaWaylandSurface *toplevel_surface;
+ 
+-  actor_surface_class->sync_actor_state (actor_surface);
++  toplevel_surface = meta_wayland_surface_get_toplevel (surface);
++  if (toplevel_surface && toplevel_surface->window)
++    actor_surface_class->sync_actor_state (actor_surface);
+ 
+   sync_actor_subsurface_state (surface);
+ }
+diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
+index 6e4b9a8ffd..b71c638d93 100644
+--- a/src/wayland/meta-xwayland.c
++++ b/src/wayland/meta-xwayland.c
+@@ -794,6 +794,20 @@ xwayland_surface_get_toplevel (MetaWaylandSurfaceRole *surface_role)
+   return meta_wayland_surface_role_get_surface (surface_role);
+ }
+ 
++static void
++xwayland_surface_sync_actor_state (MetaWaylandActorSurface *actor_surface)
++{
++  MetaWaylandSurfaceRole *surface_role =
++    META_WAYLAND_SURFACE_ROLE (actor_surface);
++  MetaWaylandSurface *surface =
++    meta_wayland_surface_role_get_surface (surface_role);
++  MetaWaylandActorSurfaceClass *actor_surface_class =
++    META_WAYLAND_ACTOR_SURFACE_CLASS (meta_wayland_surface_role_xwayland_parent_class);
++
++  if (surface->window)
++    actor_surface_class->sync_actor_state (actor_surface);
++}
++
+ static void
+ meta_wayland_surface_role_xwayland_init (MetaWaylandSurfaceRoleXWayland *role)
+ {
+@@ -804,9 +818,13 @@ meta_wayland_surface_role_xwayland_class_init (MetaWaylandSurfaceRoleXWaylandCla
+ {
+   MetaWaylandSurfaceRoleClass *surface_role_class =
+     META_WAYLAND_SURFACE_ROLE_CLASS (klass);
++  MetaWaylandActorSurfaceClass *actor_surface_class =
++    META_WAYLAND_ACTOR_SURFACE_CLASS (klass);
+ 
+   surface_role_class->get_toplevel = xwayland_surface_get_toplevel;
+ 
++  actor_surface_class->sync_actor_state = xwayland_surface_sync_actor_state;
++
+   xwayland_surface_signals[XWAYLAND_SURFACE_WINDOW_ASSOCIATED] =
+     g_signal_new ("window-associated",
+                   G_TYPE_FROM_CLASS (klass),
+-- 
+2.31.1
+
diff --git a/SOURCES/0002-wayland-dnd-surface-Propagate-commit-to-parent-class.patch b/SOURCES/0002-wayland-dnd-surface-Propagate-commit-to-parent-class.patch
new file mode 100644
index 0000000..2192f91
--- /dev/null
+++ b/SOURCES/0002-wayland-dnd-surface-Propagate-commit-to-parent-class.patch
@@ -0,0 +1,38 @@
+From f37ef55525777f742051cb988341fa1bab403666 Mon Sep 17 00:00:00 2001
+From: Robert Mader <robert.mader@posteo.de>
+Date: Mon, 15 Apr 2019 02:02:10 +0200
+Subject: [PATCH 2/2] wayland/dnd-surface: Propagate commit to parent class
+
+We need to call the underlying actor-surface so the actor
+state is synced, otherwise surface state like the scale factor
+does not get applied.
+
+Fixes https://gitlab.gnome.org/GNOME/mutter/issues/550
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/537
+(cherry picked from commit 01d0316fd703872a2470a351f906ffa4605a647e)
+---
+ src/wayland/meta-wayland-dnd-surface.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/src/wayland/meta-wayland-dnd-surface.c b/src/wayland/meta-wayland-dnd-surface.c
+index 8ddeb2a7bd..7aa7e3be2f 100644
+--- a/src/wayland/meta-wayland-dnd-surface.c
++++ b/src/wayland/meta-wayland-dnd-surface.c
+@@ -51,9 +51,13 @@ dnd_surface_commit (MetaWaylandSurfaceRole  *surface_role,
+ {
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (surface_role);
++  MetaWaylandSurfaceRoleClass *surface_role_class =
++    META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_dnd_parent_class);
+ 
+   meta_wayland_compositor_add_frame_callback_surface (surface->compositor,
+                                                       surface);
++
++  surface_role_class->commit (surface_role, pending);
+ }
+ 
+ static void
+-- 
+2.31.1
+
diff --git a/SOURCES/wayland-frame-callback-rework.patch b/SOURCES/wayland-frame-callback-rework.patch
new file mode 100644
index 0000000..0a6717f
--- /dev/null
+++ b/SOURCES/wayland-frame-callback-rework.patch
@@ -0,0 +1,1045 @@
+From 4232f2056cd31811d047104d1223f3e5ced4b107 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Thu, 16 Apr 2020 19:42:03 +0200
+Subject: [PATCH 1/5] clutter/stage: Make clutter_stage_schedule_update()
+ always schedule
+
+We could call clutter_stage_schedule_update() and it wouldn't actually
+schedule anything, as the master frame clock only tries to reschedule if
+1) there is an active timeline, 2) there are pending relayouts, 3) there
+are pending redraws, or 4) there are pending events. Thus, a call to
+clutter_stage_schedule_update() didn't have any effect if it was called
+at the wrong time.
+
+Fix this by adding a boolean state "needs_update" to the stage, set on
+clutter_stage_schedule_update() and cleared on
+_clutter_stage_do_update(), that will make the master clock reschedule
+an update if it is TRUE.
+
+https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218
+(cherry picked from commit b8003807b0772e97354302b5cc2825e0b22c6c83)
+---
+ clutter/clutter/clutter-stage.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
+index aaa77d9ede..5a914a3d0b 100644
+--- a/clutter/clutter/clutter-stage.c
++++ b/clutter/clutter/clutter-stage.c
+@@ -152,6 +152,8 @@ struct _ClutterStagePrivate
+ 
+   int update_freeze_count;
+ 
++  gboolean needs_update;
++
+   guint relayout_pending       : 1;
+   guint redraw_pending         : 1;
+   guint is_fullscreen          : 1;
+@@ -1074,7 +1076,9 @@ _clutter_stage_needs_update (ClutterStage *stage)
+ 
+   priv = stage->priv;
+ 
+-  return priv->relayout_pending || priv->redraw_pending;
++  return priv->relayout_pending ||
++         priv->needs_update ||
++         priv->redraw_pending;
+ }
+ 
+ void
+@@ -1232,6 +1236,8 @@ _clutter_stage_do_update (ClutterStage *stage)
+ 
+   priv->stage_was_relayout = FALSE;
+ 
++  priv->needs_update = FALSE;
++
+   /* if the stage is being destroyed, or if the destruction already
+    * happened and we don't have an StageWindow any more, then we
+    * should bail out
+@@ -4080,6 +4086,8 @@ _clutter_stage_schedule_update (ClutterStage *stage)
+   if (stage_window == NULL)
+     return;
+ 
++  stage->priv->needs_update = TRUE;
++
+   return _clutter_stage_window_schedule_update (stage_window,
+                                                 stage->priv->sync_delay);
+ }
+-- 
+2.31.1
+
+
+From 2d4453cfdcaf0c6a9f492d2c2395dbfc8cf833db Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Thu, 16 Apr 2020 19:11:37 +0200
+Subject: [PATCH 2/5] clutter/stage: Make clutter_stage_schedule_update()
+ public API
+
+It's effectively used by mutter by abusing a ClutterTimeline to scedule
+updates.  Timelines are not really suited in places that is done, as it
+is really just about getting a single new update scheduled whenever
+suitable, so expose the API so we can use it directly.
+
+https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218
+(cherry picked from commit 99c9a14bc8058830232cd4e07c7bb897e84a8c9c)
+---
+ clutter/clutter/clutter-master-clock-default.c |  4 ++--
+ clutter/clutter/clutter-stage-private.h        |  1 -
+ clutter/clutter/clutter-stage.c                | 16 ++++++++--------
+ clutter/clutter/clutter-stage.h                |  3 +++
+ 4 files changed, 13 insertions(+), 11 deletions(-)
+
+diff --git a/clutter/clutter/clutter-master-clock-default.c b/clutter/clutter/clutter-master-clock-default.c
+index 0647c3a7fd..de7a1e2f4d 100644
+--- a/clutter/clutter/clutter-master-clock-default.c
++++ b/clutter/clutter/clutter-master-clock-default.c
+@@ -206,7 +206,7 @@ master_clock_schedule_stage_updates (ClutterMasterClockDefault *master_clock)
+   stages = clutter_stage_manager_peek_stages (stage_manager);
+ 
+   for (l = stages; l != NULL; l = l->next)
+-    _clutter_stage_schedule_update (l->data);
++    clutter_stage_schedule_update (l->data);
+ }
+ 
+ static GSList *
+@@ -259,7 +259,7 @@ master_clock_reschedule_stage_updates (ClutterMasterClockDefault *master_clock,
+       if (master_clock->timelines ||
+           _clutter_stage_has_queued_events (l->data) ||
+           _clutter_stage_needs_update (l->data))
+-        _clutter_stage_schedule_update (l->data);
++        clutter_stage_schedule_update (l->data);
+     }
+ }
+ 
+diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h
+index 42474687ad..ea0ce5ec72 100644
+--- a/clutter/clutter/clutter-stage-private.h
++++ b/clutter/clutter/clutter-stage-private.h
+@@ -70,7 +70,6 @@ void     _clutter_stage_queue_event                       (ClutterStage *stage,
+ gboolean _clutter_stage_has_queued_events                 (ClutterStage *stage);
+ void     _clutter_stage_process_queued_events             (ClutterStage *stage);
+ void     _clutter_stage_update_input_devices              (ClutterStage *stage);
+-void     _clutter_stage_schedule_update                   (ClutterStage *stage);
+ gint64    _clutter_stage_get_update_time                  (ClutterStage *stage);
+ void     _clutter_stage_clear_update_time                 (ClutterStage *stage);
+ gboolean _clutter_stage_has_full_redraw_queued            (ClutterStage *stage);
+diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
+index 5a914a3d0b..74ff8b1337 100644
+--- a/clutter/clutter/clutter-stage.c
++++ b/clutter/clutter/clutter-stage.c
+@@ -921,7 +921,7 @@ _clutter_stage_queue_event (ClutterStage *stage,
+     {
+       ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
+       _clutter_master_clock_start_running (master_clock);
+-      _clutter_stage_schedule_update (stage);
++      clutter_stage_schedule_update (stage);
+     }
+ 
+   /* if needed, update the state of the input device of the event.
+@@ -1295,7 +1295,7 @@ clutter_stage_real_queue_relayout (ClutterActor *self)
+ 
+   if (!priv->relayout_pending)
+     {
+-      _clutter_stage_schedule_update (stage);
++      clutter_stage_schedule_update (stage);
+       priv->relayout_pending = TRUE;
+     }
+ 
+@@ -3788,7 +3788,7 @@ clutter_stage_ensure_redraw (ClutterStage *stage)
+   priv = stage->priv;
+ 
+   if (!priv->relayout_pending && !priv->redraw_pending)
+-    _clutter_stage_schedule_update (stage);
++    clutter_stage_schedule_update (stage);
+ 
+   priv->relayout_pending = TRUE;
+   priv->redraw_pending = TRUE;
+@@ -4069,13 +4069,13 @@ clutter_stage_get_minimum_size (ClutterStage *stage,
+ }
+ 
+ /**
+- * _clutter_stage_schedule_update:
+- * @window: a #ClutterStage actor
++ * clutter_stage_schedule_update:
++ * @stage: a #ClutterStage actor
+  *
+  * Schedules a redraw of the #ClutterStage at the next optimal timestamp.
+  */
+ void
+-_clutter_stage_schedule_update (ClutterStage *stage)
++clutter_stage_schedule_update (ClutterStage *stage)
+ {
+   ClutterStageWindow *stage_window;
+ 
+@@ -4097,7 +4097,7 @@ _clutter_stage_schedule_update (ClutterStage *stage)
+  * @stage: a #ClutterStage actor
+  *
+  * Returns the earliest time in which the stage is ready to update. The update
+- * time is set when _clutter_stage_schedule_update() is called. This can then
++ * time is set when clutter_stage_schedule_update() is called. This can then
+  * be used by e.g. the #ClutterMasterClock to know when the stage needs to be
+  * redrawn.
+  *
+@@ -4267,7 +4267,7 @@ _clutter_stage_queue_actor_redraw (ClutterStage                 *stage,
+ 
+       CLUTTER_NOTE (PAINT, "First redraw request");
+ 
+-      _clutter_stage_schedule_update (stage);
++      clutter_stage_schedule_update (stage);
+       priv->redraw_pending = TRUE;
+ 
+       master_clock = _clutter_master_clock_get_default ();
+diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h
+index 9da63d211d..53e37ae3bc 100644
+--- a/clutter/clutter/clutter-stage.h
++++ b/clutter/clutter/clutter-stage.h
+@@ -265,6 +265,9 @@ CLUTTER_EXPORT
+ void            clutter_stage_skip_sync_delay                   (ClutterStage          *stage);
+ #endif
+ 
++CLUTTER_EXPORT
++void clutter_stage_schedule_update (ClutterStage *stage);
++
+ CLUTTER_EXPORT
+ gboolean clutter_stage_get_capture_final_size (ClutterStage          *stage,
+                                                cairo_rectangle_int_t *rect,
+-- 
+2.31.1
+
+
+From 1c4db591b6bb2ae9d649e8157eae24b875e7a22b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Mon, 28 Oct 2019 18:20:31 +0100
+Subject: [PATCH 3/5] wayland/actor-surface: Always store away frame callbacks
+ on commit
+
+We're expected by MetaWaylandSurface to always pick the frame callbacks
+out from the pending state when committing (applying) so that no frame
+callbacks are unaccounted for. We failed to do this if our actor for
+some reason (e.g. associated window was unmanaged) was destroyed. To
+handle this situation better, store away the frame callbacks until we
+some later point in time need to pass them on forward.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/893
+---
+ src/wayland/meta-wayland-actor-surface.c | 25 +++++++++++++++++++++++-
+ 1 file changed, 24 insertions(+), 1 deletion(-)
+
+diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c
+index 2471de0a92..264565c575 100644
+--- a/src/wayland/meta-wayland-actor-surface.c
++++ b/src/wayland/meta-wayland-actor-surface.c
+@@ -35,6 +35,8 @@ typedef struct _MetaWaylandActorSurfacePrivate MetaWaylandActorSurfacePrivate;
+ struct _MetaWaylandActorSurfacePrivate
+ {
+   MetaSurfaceActor *actor;
++
++  struct wl_list frame_callback_list;
+ };
+ 
+ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaWaylandActorSurface,
+@@ -56,6 +58,7 @@ meta_wayland_actor_surface_dispose (GObject *object)
+     meta_wayland_actor_surface_get_instance_private (META_WAYLAND_ACTOR_SURFACE (object));
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (object));
++  MetaWaylandFrameCallback *cb, *next;
+ 
+   if (priv->actor)
+     {
+@@ -66,6 +69,9 @@ meta_wayland_actor_surface_dispose (GObject *object)
+       g_clear_object (&priv->actor);
+     }
+ 
++  wl_list_for_each_safe (cb, next, &priv->frame_callback_list, link)
++    wl_resource_destroy (cb->resource);
++
+   G_OBJECT_CLASS (meta_wayland_actor_surface_parent_class)->dispose (object);
+ }
+ 
+@@ -99,6 +105,9 @@ meta_wayland_actor_surface_queue_frame_callbacks (MetaWaylandActorSurface *actor
+   MetaSurfaceActorWayland *surface_actor_wayland =
+     META_SURFACE_ACTOR_WAYLAND (priv->actor);
+ 
++  meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland,
++                                                  &priv->frame_callback_list);
++  wl_list_init (&priv->frame_callback_list);
+   meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland,
+                                                   &pending->frame_callback_list);
+   wl_list_init (&pending->frame_callback_list);
+@@ -253,10 +262,20 @@ meta_wayland_actor_surface_commit (MetaWaylandSurfaceRole  *surface_role,
+ {
+   MetaWaylandActorSurface *actor_surface =
+     META_WAYLAND_ACTOR_SURFACE (surface_role);
++  MetaWaylandActorSurfacePrivate *priv =
++    meta_wayland_actor_surface_get_instance_private (actor_surface);
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (surface_role);
+   MetaWaylandSurface *toplevel_surface;
+ 
++  if (!priv->actor)
++    {
++      wl_list_insert_list (&priv->frame_callback_list,
++                           &pending->frame_callback_list);
++      wl_list_init (&pending->frame_callback_list);
++      return;
++    }
++
+   meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
+ 
+   toplevel_surface = meta_wayland_surface_get_toplevel (surface);
+@@ -307,8 +326,12 @@ meta_wayland_actor_surface_is_on_logical_monitor (MetaWaylandSurfaceRole *surfac
+ }
+ 
+ static void
+-meta_wayland_actor_surface_init (MetaWaylandActorSurface *role)
++meta_wayland_actor_surface_init (MetaWaylandActorSurface *actor_surface)
+ {
++  MetaWaylandActorSurfacePrivate *priv =
++    meta_wayland_actor_surface_get_instance_private (actor_surface);
++
++  wl_list_init (&priv->frame_callback_list);
+ }
+ 
+ static void
+-- 
+2.31.1
+
+
+From 54e5cee1a8d1a94fb19b438a3c80fe72179a3c80 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Fri, 6 Aug 2021 19:09:24 +0200
+Subject: [PATCH 4/5] wayland/actor-surface: Always store away frame callbacks
+ on commit
+
+We're expected by MetaWaylandSurface to always pick the frame callbacks
+out from the pending state when committing (applying) so that no frame
+callbacks are unaccounted for. We failed to do this if our actor for
+some reason (e.g. associated window was unmanaged) was destroyed. To
+handle this situation better, store away the frame callbacks until we
+some later point in time need to pass them on forward.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/893
+---
+ src/compositor/meta-surface-actor-wayland.c | 29 ---------
+ src/wayland/meta-wayland-actor-surface.c    | 65 ++++++++++++++++-----
+ src/wayland/meta-wayland-actor-surface.h    |  3 +
+ src/wayland/meta-wayland-cursor-surface.c   |  4 +-
+ src/wayland/meta-wayland-dnd-surface.c      | 11 +++-
+ src/wayland/meta-wayland-legacy-xdg-shell.c |  8 +--
+ src/wayland/meta-wayland-private.h          |  2 +-
+ src/wayland/meta-wayland-subsurface.c       |  2 -
+ src/wayland/meta-wayland-surface.c          | 38 +++---------
+ src/wayland/meta-wayland-surface.h          |  9 +--
+ src/wayland/meta-wayland-wl-shell.c         |  3 -
+ src/wayland/meta-wayland-xdg-shell.c        | 15 ++---
+ src/wayland/meta-wayland.c                  | 56 +++++++++++++-----
+ src/wayland/meta-wayland.h                  |  8 ++-
+ src/wayland/meta-xwayland.c                 | 45 --------------
+ 15 files changed, 127 insertions(+), 171 deletions(-)
+
+diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c
+index a75c4dd096..480b51c61a 100644
+--- a/src/compositor/meta-surface-actor-wayland.c
++++ b/src/compositor/meta-surface-actor-wayland.c
+@@ -42,7 +42,6 @@ struct _MetaSurfaceActorWayland
+   MetaSurfaceActor parent;
+ 
+   MetaWaylandSurface *surface;
+-  struct wl_list frame_callback_list;
+ };
+ 
+ G_DEFINE_TYPE (MetaSurfaceActorWayland,
+@@ -91,13 +90,6 @@ meta_surface_actor_wayland_is_unredirected (MetaSurfaceActor *actor)
+   return FALSE;
+ }
+ 
+-void
+-meta_surface_actor_wayland_add_frame_callbacks (MetaSurfaceActorWayland *self,
+-                                                struct wl_list *frame_callbacks)
+-{
+-  wl_list_insert_list (&self->frame_callback_list, frame_callbacks);
+-}
+-
+ static MetaWindow *
+ meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor)
+ {
+@@ -158,22 +150,6 @@ meta_surface_actor_wayland_get_preferred_height  (ClutterActor *actor,
+     *natural_height_p *= scale;
+ }
+ 
+-static void
+-meta_surface_actor_wayland_paint (ClutterActor *actor)
+-{
+-  MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor);
+-
+-  if (self->surface)
+-    {
+-      MetaWaylandCompositor *compositor = self->surface->compositor;
+-
+-      wl_list_insert_list (&compositor->frame_callbacks, &self->frame_callback_list);
+-      wl_list_init (&self->frame_callback_list);
+-    }
+-
+-  CLUTTER_ACTOR_CLASS (meta_surface_actor_wayland_parent_class)->paint (actor);
+-}
+-
+ static void
+ meta_surface_actor_wayland_dispose (GObject *object)
+ {
+@@ -190,9 +166,6 @@ meta_surface_actor_wayland_dispose (GObject *object)
+       self->surface = NULL;
+     }
+ 
+-  wl_list_for_each_safe (cb, next, &self->frame_callback_list, link)
+-    wl_resource_destroy (cb->resource);
+-
+   G_OBJECT_CLASS (meta_surface_actor_wayland_parent_class)->dispose (object);
+ }
+ 
+@@ -205,7 +178,6 @@ meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass)
+ 
+   actor_class->get_preferred_width = meta_surface_actor_wayland_get_preferred_width;
+   actor_class->get_preferred_height = meta_surface_actor_wayland_get_preferred_height;
+-  actor_class->paint = meta_surface_actor_wayland_paint;
+ 
+   surface_actor_class->process_damage = meta_surface_actor_wayland_process_damage;
+   surface_actor_class->pre_paint = meta_surface_actor_wayland_pre_paint;
+@@ -232,7 +204,6 @@ meta_surface_actor_wayland_new (MetaWaylandSurface *surface)
+ 
+   g_assert (meta_is_wayland_compositor ());
+ 
+-  wl_list_init (&self->frame_callback_list);
+   self->surface = surface;
+   g_object_add_weak_pointer (G_OBJECT (self->surface),
+                              (gpointer *) &self->surface);
+diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c
+index 264565c575..037dd901ab 100644
+--- a/src/wayland/meta-wayland-actor-surface.c
++++ b/src/wayland/meta-wayland-actor-surface.c
+@@ -84,16 +84,22 @@ meta_wayland_actor_surface_assigned (MetaWaylandSurfaceRole *surface_role)
+     meta_wayland_surface_role_get_surface (surface_role);
+   GList *l;
+ 
+-  meta_surface_actor_wayland_add_frame_callbacks (META_SURFACE_ACTOR_WAYLAND (priv->actor),
+-                                                  &surface->pending_frame_callback_list);
+-  wl_list_init (&surface->pending_frame_callback_list);
+-
+   for (l = surface->subsurfaces; l; l = l->next)
+     {
+       ClutterActor *subsurface_actor =
+         CLUTTER_ACTOR (meta_wayland_surface_get_actor (l->data));
+       clutter_actor_add_child (CLUTTER_ACTOR (priv->actor), subsurface_actor);
+     }
++
++  if (wl_list_empty (&surface->unassigned.pending_frame_callback_list))
++    return;
++
++  wl_list_insert_list (priv->frame_callback_list.prev,
++                       &surface->unassigned.pending_frame_callback_list);
++  wl_list_init (&surface->unassigned.pending_frame_callback_list);
++
++  meta_wayland_compositor_add_frame_callback_surface (surface->compositor,
++                                                      surface);
+ }
+ 
+ void
+@@ -102,15 +108,40 @@ meta_wayland_actor_surface_queue_frame_callbacks (MetaWaylandActorSurface *actor
+ {
+   MetaWaylandActorSurfacePrivate *priv =
+     meta_wayland_actor_surface_get_instance_private (actor_surface);
+-  MetaSurfaceActorWayland *surface_actor_wayland =
+-    META_SURFACE_ACTOR_WAYLAND (priv->actor);
++  MetaWaylandSurfaceRole *surface_role =
++    META_WAYLAND_SURFACE_ROLE (actor_surface);
++  MetaWaylandSurface *surface =
++    meta_wayland_surface_role_get_surface (surface_role);
+ 
+-  meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland,
+-                                                  &priv->frame_callback_list);
+-  wl_list_init (&priv->frame_callback_list);
+-  meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland,
+-                                                  &pending->frame_callback_list);
++  if (!priv->actor)
++    return;
++
++  if (wl_list_empty (&pending->frame_callback_list))
++    return;
++
++  wl_list_insert_list (priv->frame_callback_list.prev,
++                       &pending->frame_callback_list);
+   wl_list_init (&pending->frame_callback_list);
++
++  meta_wayland_compositor_add_frame_callback_surface (surface->compositor,
++                                                      surface);
++}
++
++void
++meta_wayland_actor_surface_emit_frame_callbacks (MetaWaylandActorSurface *actor_surface,
++                                                 uint32_t                 timestamp_ms)
++{
++  MetaWaylandActorSurfacePrivate *priv =
++    meta_wayland_actor_surface_get_instance_private (actor_surface);
++
++  while (!wl_list_empty (&priv->frame_callback_list))
++    {
++      MetaWaylandFrameCallback *callback =
++        wl_container_of (priv->frame_callback_list.next, callback, link);
++
++      wl_callback_send_done (callback->resource, timestamp_ms);
++      wl_resource_destroy (callback->resource);
++    }
+ }
+ 
+ static double
+@@ -268,12 +299,14 @@ meta_wayland_actor_surface_commit (MetaWaylandSurfaceRole  *surface_role,
+     meta_wayland_surface_role_get_surface (surface_role);
+   MetaWaylandSurface *toplevel_surface;
+ 
+-  if (!priv->actor)
++  if (!wl_list_empty (&pending->frame_callback_list) &&
++      priv->actor &&
++      !meta_surface_actor_is_obscured (priv->actor))
+     {
+-      wl_list_insert_list (&priv->frame_callback_list,
+-                           &pending->frame_callback_list);
+-      wl_list_init (&pending->frame_callback_list);
+-      return;
++      MetaBackend *backend = meta_get_backend ();
++      ClutterActor *stage = meta_backend_get_stage (backend);
++
++      clutter_stage_schedule_update (CLUTTER_STAGE (stage));
+     }
+ 
+   meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
+diff --git a/src/wayland/meta-wayland-actor-surface.h b/src/wayland/meta-wayland-actor-surface.h
+index 444b3b1785..e79f1caff5 100644
+--- a/src/wayland/meta-wayland-actor-surface.h
++++ b/src/wayland/meta-wayland-actor-surface.h
+@@ -46,4 +46,7 @@ void meta_wayland_actor_surface_reset_actor (MetaWaylandActorSurface *actor_surf
+ void meta_wayland_actor_surface_queue_frame_callbacks (MetaWaylandActorSurface *actor_surface,
+                                                        MetaWaylandPendingState *pending);
+ 
++void meta_wayland_actor_surface_emit_frame_callbacks (MetaWaylandActorSurface *actor_surface,
++                                                      uint32_t                 timestamp_ms);
++
+ #endif /* META_WAYLAND_ACTOR_SURFACE_H */
+diff --git a/src/wayland/meta-wayland-cursor-surface.c b/src/wayland/meta-wayland-cursor-surface.c
+index d46b3511fa..6b791eb378 100644
+--- a/src/wayland/meta-wayland-cursor-surface.c
++++ b/src/wayland/meta-wayland-cursor-surface.c
+@@ -124,8 +124,8 @@ meta_wayland_cursor_surface_assigned (MetaWaylandSurfaceRole *surface_role)
+     meta_wayland_cursor_surface_get_instance_private (cursor_surface);
+ 
+   wl_list_insert_list (&priv->frame_callbacks,
+-                       &surface->pending_frame_callback_list);
+-  wl_list_init (&surface->pending_frame_callback_list);
++                       &surface->unassigned.pending_frame_callback_list);
++  wl_list_init (&surface->unassigned.pending_frame_callback_list);
+ }
+ 
+ static void
+diff --git a/src/wayland/meta-wayland-dnd-surface.c b/src/wayland/meta-wayland-dnd-surface.c
+index 2aad6dcd5d..8ddeb2a7bd 100644
+--- a/src/wayland/meta-wayland-dnd-surface.c
++++ b/src/wayland/meta-wayland-dnd-surface.c
+@@ -21,6 +21,8 @@
+ 
+ #include "wayland/meta-wayland-dnd-surface.h"
+ 
++#include "wayland/meta-wayland.h"
++
+ struct _MetaWaylandSurfaceRoleDND
+ {
+   MetaWaylandActorSurface parent;
+@@ -36,7 +38,11 @@ dnd_surface_assigned (MetaWaylandSurfaceRole *surface_role)
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (surface_role);
+ 
+-  meta_wayland_surface_queue_pending_frame_callbacks (surface);
++  if (wl_list_empty (&surface->unassigned.pending_frame_callback_list))
++    return;
++
++  meta_wayland_compositor_add_frame_callback_surface (surface->compositor,
++                                                      surface);
+ }
+ 
+ static void
+@@ -46,7 +52,8 @@ dnd_surface_commit (MetaWaylandSurfaceRole  *surface_role,
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (surface_role);
+ 
+-  meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
++  meta_wayland_compositor_add_frame_callback_surface (surface->compositor,
++                                                      surface);
+ }
+ 
+ static void
+diff --git a/src/wayland/meta-wayland-legacy-xdg-shell.c b/src/wayland/meta-wayland-legacy-xdg-shell.c
+index 8230641770..b78552f31b 100644
+--- a/src/wayland/meta-wayland-legacy-xdg-shell.c
++++ b/src/wayland/meta-wayland-legacy-xdg-shell.c
+@@ -659,6 +659,8 @@ meta_wayland_zxdg_toplevel_v6_commit (MetaWaylandSurfaceRole  *surface_role,
+     META_WAYLAND_ZXDG_SURFACE_V6 (xdg_toplevel);
+   MetaWaylandZxdgSurfaceV6Private *xdg_surface_priv =
+     meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface);
++  MetaWaylandActorSurface *actor_surface =
++    META_WAYLAND_ACTOR_SURFACE (xdg_surface);
+   MetaWaylandSurfaceRoleClass *surface_role_class;
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (surface_role);
+@@ -670,7 +672,7 @@ meta_wayland_zxdg_toplevel_v6_commit (MetaWaylandSurfaceRole  *surface_role,
+   window = surface->window;
+   if (!window)
+     {
+-      meta_wayland_surface_cache_pending_frame_callbacks (surface, pending);
++      meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
+       return;
+     }
+ 
+@@ -1220,14 +1222,10 @@ meta_wayland_zxdg_surface_v6_send_configure (MetaWaylandZxdgSurfaceV6 *xdg_surfa
+ static void
+ zxdg_surface_v6_destructor (struct wl_resource *resource)
+ {
+-  MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource);
+   MetaWaylandZxdgSurfaceV6 *xdg_surface = wl_resource_get_user_data (resource);
+   MetaWaylandZxdgSurfaceV6Private *priv =
+     meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface);
+ 
+-  meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
+-                                                   surface);
+-
+   priv->shell_client->surfaces = g_list_remove (priv->shell_client->surfaces,
+                                                 xdg_surface);
+ 
+diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
+index 5bcb0ea4f9..215d0967f6 100644
+--- a/src/wayland/meta-wayland-private.h
++++ b/src/wayland/meta-wayland-private.h
+@@ -67,7 +67,7 @@ struct _MetaWaylandCompositor
+   struct wl_display *wayland_display;
+   char *display_name;
+   GHashTable *outputs;
+-  struct wl_list frame_callbacks;
++  GList *frame_callback_surfaces;
+ 
+   MetaXWaylandManager xwayland_manager;
+ 
+diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c
+index e0fa0a48b2..c7059b99a2 100644
+--- a/src/wayland/meta-wayland-subsurface.c
++++ b/src/wayland/meta-wayland-subsurface.c
+@@ -239,8 +239,6 @@ wl_subsurface_destructor (struct wl_resource *resource)
+ {
+   MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
+ 
+-  meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
+-                                                   surface);
+   if (surface->sub.parent)
+     {
+       wl_list_remove (&surface->sub.parent_destroy_listener.link);
+diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
+index 6ffcd6a7fb..a76ab28c24 100644
+--- a/src/wayland/meta-wayland-surface.c
++++ b/src/wayland/meta-wayland-surface.c
+@@ -358,15 +358,6 @@ surface_process_damage (MetaWaylandSurface *surface,
+   cairo_region_destroy (transformed_region);
+ }
+ 
+-void
+-meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface      *surface,
+-                                                          MetaWaylandPendingState *pending)
+-{
+-  wl_list_insert_list (&surface->compositor->frame_callbacks,
+-                       &pending->frame_callback_list);
+-  wl_list_init (&pending->frame_callback_list);
+-}
+-
+ void
+ meta_wayland_surface_destroy_window (MetaWaylandSurface *surface)
+ {
+@@ -656,15 +647,6 @@ parent_surface_state_applied (gpointer data,
+   meta_wayland_subsurface_parent_state_applied (subsurface);
+ }
+ 
+-void
+-meta_wayland_surface_cache_pending_frame_callbacks (MetaWaylandSurface      *surface,
+-                                                    MetaWaylandPendingState *pending)
+-{
+-  wl_list_insert_list (&surface->pending_frame_callback_list,
+-                       &pending->frame_callback_list);
+-  wl_list_init (&pending->frame_callback_list);
+-}
+-
+ void
+ meta_wayland_surface_apply_pending_state (MetaWaylandSurface      *surface,
+                                           MetaWaylandPendingState *pending)
+@@ -810,7 +792,9 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface      *surface,
+     }
+   else
+     {
+-      meta_wayland_surface_cache_pending_frame_callbacks (surface, pending);
++      wl_list_insert_list (surface->unassigned.pending_frame_callback_list.prev,
++                           &pending->frame_callback_list);
++      wl_list_init (&pending->frame_callback_list);
+ 
+       if (pending->newly_attached)
+         {
+@@ -1352,12 +1336,14 @@ wl_surface_destructor (struct wl_resource *resource)
+   if (surface->input_region)
+     cairo_region_destroy (surface->input_region);
+ 
+-  meta_wayland_compositor_destroy_frame_callbacks (compositor, surface);
++  meta_wayland_compositor_remove_frame_callback_surface (compositor, surface);
+ 
+   g_hash_table_foreach (surface->outputs_to_destroy_notify_id, surface_output_disconnect_signal, surface);
+   g_hash_table_unref (surface->outputs_to_destroy_notify_id);
+ 
+-  wl_list_for_each_safe (cb, next, &surface->pending_frame_callback_list, link)
++  wl_list_for_each_safe (cb, next,
++                         &surface->unassigned.pending_frame_callback_list,
++                         link)
+     wl_resource_destroy (cb->resource);
+ 
+   if (surface->resource)
+@@ -1401,7 +1387,7 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
+   surface->resource = wl_resource_create (client, &wl_surface_interface, wl_resource_get_version (compositor_resource), id);
+   wl_resource_set_implementation (surface->resource, &meta_wayland_wl_surface_interface, surface, wl_surface_destructor);
+ 
+-  wl_list_init (&surface->pending_frame_callback_list);
++  wl_list_init (&surface->unassigned.pending_frame_callback_list);
+ 
+   sync_drag_dest_funcs (surface);
+ 
+@@ -1809,14 +1795,6 @@ meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRole *role)
+   return priv->surface;
+ }
+ 
+-void
+-meta_wayland_surface_queue_pending_frame_callbacks (MetaWaylandSurface *surface)
+-{
+-  wl_list_insert_list (&surface->compositor->frame_callbacks,
+-                       &surface->pending_frame_callback_list);
+-  wl_list_init (&surface->pending_frame_callback_list);
+-}
+-
+ cairo_region_t *
+ meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface)
+ {
+diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
+index e244a3fdf7..776431fca2 100644
+--- a/src/wayland/meta-wayland-surface.h
++++ b/src/wayland/meta-wayland-surface.h
+@@ -160,13 +160,9 @@ struct _MetaWaylandSurface
+   /* Buffer renderer state. */
+   gboolean buffer_held;
+ 
+-  /* List of pending frame callbacks that needs to stay queued longer than one
+-   * commit sequence, such as when it has not yet been assigned a role.
+-   */
+-  struct wl_list pending_frame_callback_list;
+-
+   /* Intermediate state for when no role has been assigned. */
+   struct {
++    struct wl_list pending_frame_callback_list;
+     MetaWaylandBuffer *buffer;
+   } unassigned;
+ 
+@@ -274,9 +270,6 @@ MetaWaylandSurface *meta_wayland_surface_get_toplevel (MetaWaylandSurface *surfa
+ 
+ MetaWindow *        meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface);
+ 
+-void                meta_wayland_surface_cache_pending_frame_callbacks (MetaWaylandSurface      *surface,
+-                                                                        MetaWaylandPendingState *pending);
+-
+ void                meta_wayland_surface_queue_pending_frame_callbacks (MetaWaylandSurface *surface);
+ 
+ void                meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface      *surface,
+diff --git a/src/wayland/meta-wayland-wl-shell.c b/src/wayland/meta-wayland-wl-shell.c
+index 539fb9858e..e80db17e78 100644
+--- a/src/wayland/meta-wayland-wl-shell.c
++++ b/src/wayland/meta-wayland-wl-shell.c
+@@ -100,9 +100,6 @@ wl_shell_surface_destructor (struct wl_resource *resource)
+     surface_from_wl_shell_surface_resource (resource);
+   GList *l;
+ 
+-  meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
+-                                                   surface);
+-
+   if (wl_shell_surface->popup)
+     meta_wayland_popup_dismiss (wl_shell_surface->popup);
+ 
+diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c
+index fa0207a03c..4a4995c425 100644
+--- a/src/wayland/meta-wayland-xdg-shell.c
++++ b/src/wayland/meta-wayland-xdg-shell.c
+@@ -684,6 +684,8 @@ meta_wayland_xdg_toplevel_commit (MetaWaylandSurfaceRole  *surface_role,
+   MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (xdg_toplevel);
+   MetaWaylandXdgSurfacePrivate *xdg_surface_priv =
+     meta_wayland_xdg_surface_get_instance_private (xdg_surface);
++  MetaWaylandActorSurface *actor_surface =
++    META_WAYLAND_ACTOR_SURFACE (xdg_toplevel);
+   MetaWaylandSurfaceRoleClass *surface_role_class;
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (surface_role);
+@@ -695,15 +697,12 @@ meta_wayland_xdg_toplevel_commit (MetaWaylandSurfaceRole  *surface_role,
+   window = surface->window;
+   if (!window)
+     {
+-      meta_wayland_surface_cache_pending_frame_callbacks (surface, pending);
++      meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
+       return;
+     }
+ 
+   if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached)
+     {
+-      MetaWaylandActorSurface *actor_surface =
+-        META_WAYLAND_ACTOR_SURFACE (xdg_toplevel);
+-
+       meta_wayland_xdg_surface_reset (xdg_surface);
+       meta_wayland_actor_surface_queue_frame_callbacks (actor_surface,
+                                                         pending);
+@@ -1037,6 +1036,8 @@ meta_wayland_xdg_popup_commit (MetaWaylandSurfaceRole  *surface_role,
+   MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (surface_role);
+   MetaWaylandXdgSurfacePrivate *xdg_surface_priv =
+     meta_wayland_xdg_surface_get_instance_private (xdg_surface);
++  MetaWaylandActorSurface *actor_surface =
++    META_WAYLAND_ACTOR_SURFACE (xdg_popup);
+   MetaWaylandSurfaceRoleClass *surface_role_class;
+   MetaWaylandSurface *surface =
+     meta_wayland_surface_role_get_surface (surface_role);
+@@ -1048,7 +1049,7 @@ meta_wayland_xdg_popup_commit (MetaWaylandSurfaceRole  *surface_role,
+   if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached)
+     {
+       meta_wayland_xdg_surface_reset (xdg_surface);
+-      meta_wayland_surface_cache_pending_frame_callbacks (surface, pending);
++      meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
+       return;
+     }
+ 
+@@ -1313,14 +1314,10 @@ meta_wayland_xdg_surface_send_configure (MetaWaylandXdgSurface *xdg_surface)
+ static void
+ xdg_surface_destructor (struct wl_resource *resource)
+ {
+-  MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource);
+   MetaWaylandXdgSurface *xdg_surface = wl_resource_get_user_data (resource);
+   MetaWaylandXdgSurfacePrivate *priv =
+     meta_wayland_xdg_surface_get_instance_private (xdg_surface);
+ 
+-  meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
+-                                                   surface);
+-
+   priv->shell_client->surfaces = g_list_remove (priv->shell_client->surfaces,
+                                                 xdg_surface);
+ 
+diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
+index 129da8e20d..4cb9ca650d 100644
+--- a/src/wayland/meta-wayland.c
++++ b/src/wayland/meta-wayland.c
+@@ -194,15 +194,35 @@ meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
+ void
+ meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor)
+ {
+-  gint64 current_time = g_get_monotonic_time ();
++  GList *l;
++  int64_t now_us;
+ 
+-  while (!wl_list_empty (&compositor->frame_callbacks))
++  now_us = g_get_monotonic_time ();
++
++  l = compositor->frame_callback_surfaces;
++  while (l)
+     {
+-      MetaWaylandFrameCallback *callback =
+-        wl_container_of (compositor->frame_callbacks.next, callback, link);
++      GList *l_cur = l;
++      MetaWaylandSurface *surface = l->data;
++      MetaSurfaceActor *actor;
++      MetaWaylandActorSurface *actor_surface;
++
++      l = l->next;
++
++      actor = meta_wayland_surface_get_actor (surface);
++      if (!actor)
++        continue;
++
++      if (!clutter_actor_has_mapped_clones (CLUTTER_ACTOR (actor)) &&
++          meta_surface_actor_is_obscured (actor))
++        continue;
+ 
+-      wl_callback_send_done (callback->resource, current_time / 1000);
+-      wl_resource_destroy (callback->resource);
++      actor_surface = META_WAYLAND_ACTOR_SURFACE (surface->role);
++      meta_wayland_actor_surface_emit_frame_callbacks (actor_surface,
++                                                       now_us / 1000);
++
++      compositor->frame_callback_surfaces =
++        g_list_delete_link (compositor->frame_callback_surfaces, l_cur);
+     }
+ }
+ 
+@@ -249,16 +269,22 @@ meta_wayland_compositor_update_key_state (MetaWaylandCompositor *compositor,
+ }
+ 
+ void
+-meta_wayland_compositor_destroy_frame_callbacks (MetaWaylandCompositor *compositor,
+-                                                 MetaWaylandSurface    *surface)
++meta_wayland_compositor_add_frame_callback_surface (MetaWaylandCompositor *compositor,
++                                                    MetaWaylandSurface    *surface)
+ {
+-  MetaWaylandFrameCallback *callback, *next;
++  if (g_list_find (compositor->frame_callback_surfaces, surface))
++    return;
+ 
+-  wl_list_for_each_safe (callback, next, &compositor->frame_callbacks, link)
+-    {
+-      if (callback->surface == surface)
+-        wl_resource_destroy (callback->resource);
+-    }
++  compositor->frame_callback_surfaces =
++    g_list_prepend (compositor->frame_callback_surfaces, surface);
++}
++
++void
++meta_wayland_compositor_remove_frame_callback_surface (MetaWaylandCompositor *compositor,
++                                                       MetaWaylandSurface    *surface)
++{
++  compositor->frame_callback_surfaces =
++    g_list_remove (compositor->frame_callback_surfaces, surface);
+ }
+ 
+ static void
+@@ -309,8 +335,6 @@ meta_wayland_log_func (const char *fmt,
+ static void
+ meta_wayland_compositor_init (MetaWaylandCompositor *compositor)
+ {
+-  wl_list_init (&compositor->frame_callbacks);
+-
+   compositor->scheduled_surface_associations = g_hash_table_new (NULL, NULL);
+ 
+   wl_log_set_handler_server (meta_wayland_log_func);
+diff --git a/src/wayland/meta-wayland.h b/src/wayland/meta-wayland.h
+index 2a0aa11400..c5e5924891 100644
+--- a/src/wayland/meta-wayland.h
++++ b/src/wayland/meta-wayland.h
+@@ -64,9 +64,11 @@ void                    meta_wayland_compositor_set_input_focus (MetaWaylandComp
+ META_EXPORT_TEST
+ void                    meta_wayland_compositor_paint_finished  (MetaWaylandCompositor *compositor);
+ 
+-META_EXPORT_TEST
+-void                    meta_wayland_compositor_destroy_frame_callbacks (MetaWaylandCompositor *compositor,
+-                                                                         MetaWaylandSurface    *surface);
++void                    meta_wayland_compositor_add_frame_callback_surface (MetaWaylandCompositor *compositor,
++                                                                            MetaWaylandSurface    *surface);
++
++void                    meta_wayland_compositor_remove_frame_callback_surface (MetaWaylandCompositor *compositor,
++                                                                               MetaWaylandSurface    *surface);
+ 
+ META_EXPORT_TEST
+ const char             *meta_wayland_get_wayland_display_name   (MetaWaylandCompositor *compositor);
+diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
+index 275aeb78cb..6e4b9a8ffd 100644
+--- a/src/wayland/meta-xwayland.c
++++ b/src/wayland/meta-xwayland.c
+@@ -788,49 +788,6 @@ meta_xwayland_stop (MetaXWaylandManager *manager)
+     }
+ }
+ 
+-static void
+-xwayland_surface_assigned (MetaWaylandSurfaceRole *surface_role)
+-{
+-  MetaWaylandSurface *surface =
+-    meta_wayland_surface_role_get_surface (surface_role);
+-  MetaWaylandSurfaceRoleClass *surface_role_class =
+-    META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_xwayland_parent_class);
+-
+-  /* See comment in xwayland_surface_commit for why we reply even though the
+-   * surface may not be drawn the next frame.
+-   */
+-  wl_list_insert_list (&surface->compositor->frame_callbacks,
+-                       &surface->pending_frame_callback_list);
+-  wl_list_init (&surface->pending_frame_callback_list);
+-
+-  surface_role_class->assigned (surface_role);
+-}
+-
+-static void
+-xwayland_surface_commit (MetaWaylandSurfaceRole  *surface_role,
+-                         MetaWaylandPendingState *pending)
+-{
+-  MetaWaylandSurface *surface =
+-    meta_wayland_surface_role_get_surface (surface_role);
+-  MetaWaylandSurfaceRoleClass *surface_role_class =
+-    META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_xwayland_parent_class);
+-
+-  /* For Xwayland windows, throttling frames when the window isn't actually
+-   * drawn is less useful, because Xwayland still has to do the drawing sent
+-   * from the application - the throttling would only be of sending us damage
+-   * messages, so we simplify and send frame callbacks after the next paint of
+-   * the screen, whether the window was drawn or not.
+-   *
+-   * Currently it may take a few frames before we draw the window, for not
+-   * completely understood reasons, and in that case, not thottling frame
+-   * callbacks to drawing has the happy side effect that we avoid showing the
+-   * user the initial black frame from when the window is mapped empty.
+-   */
+-  meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
+-
+-  surface_role_class->commit (surface_role, pending);
+-}
+-
+ static MetaWaylandSurface *
+ xwayland_surface_get_toplevel (MetaWaylandSurfaceRole *surface_role)
+ {
+@@ -848,8 +805,6 @@ meta_wayland_surface_role_xwayland_class_init (MetaWaylandSurfaceRoleXWaylandCla
+   MetaWaylandSurfaceRoleClass *surface_role_class =
+     META_WAYLAND_SURFACE_ROLE_CLASS (klass);
+ 
+-  surface_role_class->assigned = xwayland_surface_assigned;
+-  surface_role_class->commit = xwayland_surface_commit;
+   surface_role_class->get_toplevel = xwayland_surface_get_toplevel;
+ 
+   xwayland_surface_signals[XWAYLAND_SURFACE_WINDOW_ASSOCIATED] =
+-- 
+2.31.1
+
+
+From 076ac20d34db128aea8ffe0dc3c2791918667c43 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
+Date: Fri, 6 Aug 2021 19:46:06 +0200
+Subject: [PATCH 5/5] wayland: Respond to frame callbacks even if the paint was
+ empty
+
+---
+ src/compositor/compositor.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
+index ce2c1b8a3b..8331737d1a 100644
+--- a/src/compositor/compositor.c
++++ b/src/compositor/compositor.c
+@@ -467,11 +467,6 @@ after_stage_paint (ClutterStage *stage,
+ 
+   for (l = compositor->windows; l; l = l->next)
+     meta_window_actor_post_paint (l->data);
+-
+-#ifdef HAVE_WAYLAND
+-  if (meta_is_wayland_compositor ())
+-    meta_wayland_compositor_paint_finished (meta_wayland_compositor_get_default ());
+-#endif
+ }
+ 
+ static void
+@@ -1404,6 +1399,11 @@ meta_post_paint_func (gpointer data)
+       break;
+     }
+ 
++#ifdef HAVE_WAYLAND
++  if (meta_is_wayland_compositor ())
++    meta_wayland_compositor_paint_finished (meta_wayland_compositor_get_default ());
++#endif
++
+   return TRUE;
+ }
+ 
+-- 
+2.31.1
+
diff --git a/SOURCES/xwayland-xauth-xhost-user.patch b/SOURCES/xwayland-xauth-xhost-user.patch
new file mode 100644
index 0000000..519bb3b
--- /dev/null
+++ b/SOURCES/xwayland-xauth-xhost-user.patch
@@ -0,0 +1,479 @@
+From 8e756d48ed31bcacf12b99cbd82fb2052503f51e Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 18 Jun 2019 16:12:46 +0200
+Subject: [PATCH 1/4] xwayland: Generate a Xauth file and pass this to Xwayland
+ when starting it
+
+Before this commit, sudo x11-app, e.g. sudo gvim /etc/some-file, fails
+when running a Wayland session. Where as doing this under a "GNOME on Xorg"
+session works fine. For a user switching from the Xorg session to the
+Wayland session, this is regression, which we want to avoid.
+
+This commit fixes this by creating and passing an xauth file to Xwayland when
+mutter starts it. Just like gdm or startx pass a xauth file to Xorg when they
+start Xorg.
+
+Fixes #643
+
+https://gitlab.gnome.org/GNOME/mutter/issues/643
+---
+ meson.build                        |  1 +
+ src/meson.build                    |  1 +
+ src/wayland/meta-wayland-private.h |  1 +
+ src/wayland/meta-wayland.c         | 11 +++-
+ src/wayland/meta-xwayland.c        | 81 ++++++++++++++++++++++++++++++
+ 5 files changed, 94 insertions(+), 1 deletion(-)
+
+diff --git a/meson.build b/meson.build
+index 8ef592bc58..2a404857ce 100644
+--- a/meson.build
++++ b/meson.build
+@@ -117,6 +117,7 @@ xrandr_dep = dependency('xrandr', version: xrandr_req)
+ xcb_randr_dep = dependency('xcb-randr')
+ xcb_res_dep = dependency('xcb-res')
+ xinerama_dep = dependency('xinerama')
++xau_dep = dependency('xau')
+ ice_dep = dependency('ice')
+ atk_dep = dependency('atk', version: atk_req)
+ libcanberra_dep = dependency('libcanberra', version: libcanberra_req)
+diff --git a/src/meson.build b/src/meson.build
+index 7cced8f534..91fe74b99a 100644
+--- a/src/meson.build
++++ b/src/meson.build
+@@ -101,6 +101,7 @@ if have_x11
+     x11_xcb_dep,
+     xcb_randr_dep,
+     xcb_res_dep,
++    xau_dep,
+   ]
+ 
+   if have_sm
+diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
+index 07a71f82b1..5bcb0ea4f9 100644
+--- a/src/wayland/meta-wayland-private.h
++++ b/src/wayland/meta-wayland-private.h
+@@ -51,6 +51,7 @@ typedef struct
+   struct wl_client *client;
+   struct wl_resource *xserver_resource;
+   char *display_name;
++  char *auth_file;
+ 
+   GCancellable *xserver_died_cancellable;
+   GSubprocess *proc;
+diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
+index a593f0a7b7..129da8e20d 100644
+--- a/src/wayland/meta-wayland.c
++++ b/src/wayland/meta-wayland.c
+@@ -362,6 +362,12 @@ meta_wayland_override_display_name (const char *display_name)
+   _display_name_override = g_strdup (display_name);
+ }
+ 
++static const char *
++meta_wayland_get_xwayland_auth_file (MetaWaylandCompositor *compositor)
++{
++  return compositor->xwayland_manager.auth_file;
++}
++
+ void
+ meta_wayland_init (void)
+ {
+@@ -439,7 +445,10 @@ meta_wayland_init (void)
+     }
+ 
+   if (meta_should_autostart_x11_display ())
+-    set_gnome_env ("DISPLAY", meta_wayland_get_xwayland_display_name (compositor));
++    {
++      set_gnome_env ("DISPLAY", meta_wayland_get_xwayland_display_name (compositor));
++      set_gnome_env ("XAUTHORITY", meta_wayland_get_xwayland_auth_file (compositor));
++    }
+ 
+   set_gnome_env ("WAYLAND_DISPLAY", meta_wayland_get_wayland_display_name (compositor));
+ }
+diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
+index f3df9766ee..c883eb3d6f 100644
+--- a/src/wayland/meta-xwayland.c
++++ b/src/wayland/meta-xwayland.c
+@@ -32,6 +32,9 @@
+ #include <sys/socket.h>
+ #include <sys/stat.h>
+ #include <sys/un.h>
++#include <sys/random.h>
++#include <unistd.h>
++#include <X11/Xauth.h>
+ 
+ #include "compositor/meta-surface-actor-wayland.h"
+ #include "meta/main.h"
+@@ -525,6 +528,75 @@ choose_xdisplay (MetaXWaylandManager *manager)
+   return TRUE;
+ }
+ 
++G_DEFINE_AUTOPTR_CLEANUP_FUNC (FILE, fclose)
++
++static gboolean
++prepare_auth_file (MetaXWaylandManager *manager)
++{
++  Xauth auth_entry = { 0 };
++  g_autoptr (FILE) fp = NULL;
++  char hostname[HOST_NAME_MAX + 1];
++  char auth_data[16];
++  int fd;
++
++  manager->auth_file = g_build_filename (g_get_user_runtime_dir (),
++                                         ".mutter-Xwaylandauth.XXXXXX",
++                                         NULL);
++
++  if (gethostname (hostname, HOST_NAME_MAX) < 0)
++    g_strlcpy (hostname, "localhost", HOST_NAME_MAX);
++
++  if (getrandom (auth_data, sizeof (auth_data), 0) != sizeof (auth_data))
++    {
++      g_warning ("Failed to get random data: %s", g_strerror (errno));
++      return FALSE;
++    }
++
++  auth_entry.family = FamilyLocal;
++  auth_entry.address = hostname;
++  auth_entry.address_length = strlen (auth_entry.address);
++  auth_entry.name = (char *) "MIT-MAGIC-COOKIE-1";
++  auth_entry.name_length = strlen (auth_entry.name);
++  auth_entry.data = auth_data;
++  auth_entry.data_length = sizeof (auth_data);
++
++  fd = g_mkstemp (manager->auth_file);
++  if (fd < 0)
++    {
++      g_warning ("Failed to open Xauthority file: %s", g_strerror (errno));
++      return FALSE;
++    }
++
++  fp = fdopen (fd, "w+");
++  if (!fp)
++    {
++      g_warning ("Failed to open Xauthority stream: %s", g_strerror (errno));
++      close (fd);
++      return FALSE;
++    }
++
++  if (!XauWriteAuth (fp, &auth_entry))
++    {
++      g_warning ("Error writing to Xauthority file: %s", g_strerror (errno));
++      return FALSE;
++    }
++
++  auth_entry.family = FamilyWild;
++  if (!XauWriteAuth (fp, &auth_entry))
++    {
++      g_warning ("Error writing to Xauthority file: %s", g_strerror (errno));
++      return FALSE;
++    }
++
++  if (fflush (fp) == EOF)
++    {
++      g_warning ("Error writing to Xauthority file: %s", g_strerror (errno));
++      return FALSE;
++    }
++
++  return TRUE;
++}
++
+ static void
+ xserver_finished_init (MetaXWaylandManager *manager)
+ {
+@@ -566,6 +638,9 @@ meta_xwayland_start (MetaXWaylandManager *manager,
+   if (!choose_xdisplay (manager))
+     goto out;
+ 
++  if (!prepare_auth_file (manager))
++    goto out;
++
+   /* We want xwayland to be a wayland client so we make a socketpair to setup a
+    * wayland protocol connection. */
+   if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, xwayland_client_fd) < 0)
+@@ -610,6 +685,7 @@ meta_xwayland_start (MetaXWaylandManager *manager,
+                                                "-terminate",
+                                                "-accessx",
+                                                "-core",
++                                               "-auth", manager->auth_file,
+                                                "-listen", "4",
+                                                "-listen", "5",
+                                                "-displayfd", "6",
+@@ -678,6 +754,11 @@ meta_xwayland_stop (MetaXWaylandManager *manager)
+   unlink (path);
+ 
+   g_clear_pointer (&manager->display_name, g_free);
++  if (manager->auth_file)
++    {
++      unlink (manager->auth_file);
++      g_clear_pointer (&manager->auth_file, g_free);
++    }
+   if (manager->lock_file)
+     {
+       unlink (manager->lock_file);
+-- 
+2.31.1
+
+
+From fdf6969cf89dc9127fc9f4d03d9408e54ccd1b40 Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <ofourdan@redhat.com>
+Date: Mon, 19 Aug 2019 15:36:32 +0200
+Subject: [PATCH 2/4] xwayland: pass the X11 display
+
+Pass the X11 display to `meta_xwayland_complete_init()` so that it can
+be used without poking into GDK.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/735
+---
+ src/wayland/meta-xwayland-private.h | 3 ++-
+ src/wayland/meta-xwayland.c         | 3 ++-
+ src/x11/meta-x11-display.c          | 5 ++---
+ 3 files changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/src/wayland/meta-xwayland-private.h b/src/wayland/meta-xwayland-private.h
+index 38874eda3f..abcb09e49b 100644
+--- a/src/wayland/meta-xwayland-private.h
++++ b/src/wayland/meta-xwayland-private.h
+@@ -29,7 +29,8 @@ meta_xwayland_start (MetaXWaylandManager *manager,
+                      struct wl_display   *display);
+ 
+ void
+-meta_xwayland_complete_init (MetaDisplay *display);
++meta_xwayland_complete_init (MetaDisplay *display,
++                             Display     *xdisplay);
+ 
+ void
+ meta_xwayland_stop (MetaXWaylandManager *manager);
+diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
+index c883eb3d6f..350626dfdb 100644
+--- a/src/wayland/meta-xwayland.c
++++ b/src/wayland/meta-xwayland.c
+@@ -727,7 +727,8 @@ on_x11_display_closing (MetaDisplay *display)
+ 
+ /* To be called right after connecting */
+ void
+-meta_xwayland_complete_init (MetaDisplay *display)
++meta_xwayland_complete_init (MetaDisplay *display,
++                             Display     *xdisplay)
+ {
+   /* We install an X IO error handler in addition to the child watch,
+      because after Xlib connects our child watch may not be called soon
+diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c
+index 065ffcdda5..d40dcfa3f8 100644
+--- a/src/x11/meta-x11-display.c
++++ b/src/x11/meta-x11-display.c
+@@ -1066,14 +1066,13 @@ meta_x11_display_new (MetaDisplay *display, GError **error)
+ 
+   g_assert (prepared_gdk_display);
+   gdk_display = g_steal_pointer (&prepared_gdk_display);
++  xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display);
+ 
+ #ifdef HAVE_WAYLAND
+   if (meta_is_wayland_compositor ())
+-    meta_xwayland_complete_init (display);
++    meta_xwayland_complete_init (display, xdisplay);
+ #endif
+ 
+-  xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display);
+-
+   if (meta_is_syncing ())
+     XSynchronize (xdisplay, True);
+ 
+-- 
+2.31.1
+
+
+From 25a0945aa69c479d6356a970b39e6ae42e43c877 Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <ofourdan@redhat.com>
+Date: Mon, 19 Aug 2019 15:48:17 +0200
+Subject: [PATCH 3/4] xwayland: Use given X11 display for DnD setup
+
+Use the provided X11 display instead of poking into GDK to get the X11
+display.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/735
+---
+ src/wayland/meta-xwayland-private.h   |  4 ++--
+ src/wayland/meta-xwayland-selection.c | 18 +++++++++---------
+ src/wayland/meta-xwayland.c           |  7 +++++--
+ 3 files changed, 16 insertions(+), 13 deletions(-)
+
+diff --git a/src/wayland/meta-xwayland-private.h b/src/wayland/meta-xwayland-private.h
+index abcb09e49b..f562d7c96d 100644
+--- a/src/wayland/meta-xwayland-private.h
++++ b/src/wayland/meta-xwayland-private.h
+@@ -36,8 +36,8 @@ void
+ meta_xwayland_stop (MetaXWaylandManager *manager);
+ 
+ /* wl_data_device/X11 selection interoperation */
+-void     meta_xwayland_init_selection         (void);
+-void     meta_xwayland_shutdown_selection     (void);
++void     meta_xwayland_init_selection         (Display *xdisplay);
++void     meta_xwayland_shutdown_selection     (Display *xdisplay);
+ gboolean meta_xwayland_selection_handle_event (XEvent *xevent);
+ 
+ const MetaWaylandDragDestFuncs * meta_xwayland_selection_get_drag_dest_funcs (void);
+diff --git a/src/wayland/meta-xwayland-selection.c b/src/wayland/meta-xwayland-selection.c
+index 808f913339..122bb76e1c 100644
+--- a/src/wayland/meta-xwayland-selection.c
++++ b/src/wayland/meta-xwayland-selection.c
+@@ -353,9 +353,9 @@ xdnd_send_status (MetaXWaylandSelection *selection_data,
+ }
+ 
+ static void
+-meta_xwayland_init_dnd (MetaXWaylandManager *manager)
++meta_xwayland_init_dnd (MetaXWaylandManager *manager,
++                        Display             *xdisplay)
+ {
+-  Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+   MetaDndBridge *dnd = &manager->selection_data->dnd;
+   XSetWindowAttributes attributes;
+   guint32 i, version = XDND_VERSION;
+@@ -382,12 +382,12 @@ meta_xwayland_init_dnd (MetaXWaylandManager *manager)
+ }
+ 
+ static void
+-meta_xwayland_shutdown_dnd (MetaXWaylandManager *manager)
++meta_xwayland_shutdown_dnd (MetaXWaylandManager *manager,
++                            Display             *xdisplay)
+ {
+   MetaDndBridge *dnd = &manager->selection_data->dnd;
+ 
+-  XDestroyWindow (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
+-                  dnd->dnd_window);
++  XDestroyWindow (xdisplay, dnd->dnd_window);
+   dnd->dnd_window = None;
+ }
+ 
+@@ -1755,7 +1755,7 @@ shutdown_selection_bridge (MetaSelectionBridge *selection)
+ }
+ 
+ void
+-meta_xwayland_init_selection (void)
++meta_xwayland_init_selection (Display *xdisplay)
+ {
+   MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
+   MetaXWaylandManager *manager = &compositor->xwayland_manager;
+@@ -1764,7 +1764,7 @@ meta_xwayland_init_selection (void)
+ 
+   manager->selection_data = g_slice_new0 (MetaXWaylandSelection);
+ 
+-  meta_xwayland_init_dnd (manager);
++  meta_xwayland_init_dnd (manager, xdisplay);
+   init_selection_bridge (&manager->selection_data->clipboard,
+                          gdk_x11_get_xatom_by_name ("CLIPBOARD"),
+                          &compositor->seat->data_device.selection_ownership_signal);
+@@ -1777,7 +1777,7 @@ meta_xwayland_init_selection (void)
+ }
+ 
+ void
+-meta_xwayland_shutdown_selection (void)
++meta_xwayland_shutdown_selection (Display *xdisplay)
+ {
+   MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
+   MetaXWaylandManager *manager = &compositor->xwayland_manager;
+@@ -1787,7 +1787,7 @@ meta_xwayland_shutdown_selection (void)
+ 
+   g_clear_object (&selection->clipboard.source);
+ 
+-  meta_xwayland_shutdown_dnd (manager);
++  meta_xwayland_shutdown_dnd (manager, xdisplay);
+   shutdown_selection_bridge (&selection->clipboard);
+   shutdown_selection_bridge (&selection->primary);
+   shutdown_selection_bridge (&selection->dnd.selection);
+diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
+index 350626dfdb..3236711482 100644
+--- a/src/wayland/meta-xwayland.c
++++ b/src/wayland/meta-xwayland.c
+@@ -38,6 +38,7 @@
+ 
+ #include "compositor/meta-surface-actor-wayland.h"
+ #include "meta/main.h"
++#include "meta/meta-x11-display.h"
+ #include "wayland/meta-wayland-actor-surface.h"
+ 
+ enum
+@@ -722,7 +723,9 @@ out:
+ static void
+ on_x11_display_closing (MetaDisplay *display)
+ {
+-  meta_xwayland_shutdown_selection ();
++  Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
++
++  meta_xwayland_shutdown_selection (xdisplay);
+ }
+ 
+ /* To be called right after connecting */
+@@ -739,7 +742,7 @@ meta_xwayland_complete_init (MetaDisplay *display,
+ 
+   g_signal_connect (display, "x11-display-closing",
+                     G_CALLBACK (on_x11_display_closing), NULL);
+-  meta_xwayland_init_selection ();
++  meta_xwayland_init_selection (xdisplay);
+ }
+ 
+ void
+-- 
+2.31.1
+
+
+From a398699a53b9cc6efda4aa8abe0e3176bab80e92 Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <ofourdan@redhat.com>
+Date: Mon, 19 Aug 2019 15:50:54 +0200
+Subject: [PATCH 4/4] xwayland: Add local user to xhost
+
+With the addition of xauth support (commit a8984a81c), Xwayland would
+rely only on the provided cookies for authentication.
+
+As a result, running an Xclient from another VT (hence without the
+XAUTHORITY environment variable set) would result in an access denied.
+
+The same on X11 is granted because the local user is automatically
+granted access to Xserver by the startup scripts.
+
+Add the local user to xhost at startup on Xwayland so that the user can
+still run a client by setting the DISPLAY as long as it's the same user
+on the same host.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/735
+---
+ src/wayland/meta-xwayland.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
+index 3236711482..275aeb78cb 100644
+--- a/src/wayland/meta-xwayland.c
++++ b/src/wayland/meta-xwayland.c
+@@ -598,6 +598,23 @@ prepare_auth_file (MetaXWaylandManager *manager)
+   return TRUE;
+ }
+ 
++static void
++add_local_user_to_xhost (Display *xdisplay)
++{
++  XHostAddress host_entry;
++  XServerInterpretedAddress siaddr;
++
++  siaddr.type = (char *) "localuser";
++  siaddr.typelength = strlen (siaddr.type);
++  siaddr.value = (char *) g_get_user_name();
++  siaddr.valuelength = strlen (siaddr.value);
++
++  host_entry.family = FamilyServerInterpreted;
++  host_entry.address = (char *) &siaddr;
++
++  XAddHost (xdisplay, &host_entry);
++}
++
+ static void
+ xserver_finished_init (MetaXWaylandManager *manager)
+ {
+@@ -743,6 +760,7 @@ meta_xwayland_complete_init (MetaDisplay *display,
+   g_signal_connect (display, "x11-display-closing",
+                     G_CALLBACK (on_x11_display_closing), NULL);
+   meta_xwayland_init_selection (xdisplay);
++  add_local_user_to_xhost (xdisplay);
+ }
+ 
+ void
+-- 
+2.31.1
+
diff --git a/SPECS/mutter.spec b/SPECS/mutter.spec
index 940675a..38da087 100644
--- a/SPECS/mutter.spec
+++ b/SPECS/mutter.spec
@@ -8,7 +8,7 @@
 
 Name:          mutter
 Version:       3.32.2
-Release:       57%{?dist}
+Release:       60%{?dist}
 Summary:       Window and compositing manager based on Clutter
 
 License:       GPLv2+
@@ -183,6 +183,15 @@ Patch511: geometric-picking.patch
 
 Patch520: 0001-clutter-Backport-of-touch-mode.patch
 
+# Backport passing -xauth and adding local user to xhost (#1949176)
+Patch521: xwayland-xauth-xhost-user.patch
+
+# Backport fixes avoiding frozen partly off-screen clients (#1989035)
+Patch522: wayland-frame-callback-rework.patch
+# Backport fix avoiding regression due to the above changes (#1999120)
+Patch523: 0001-wayland-Move-check-for-present-window-out-of-the-act.patch
+Patch524: 0002-wayland-dnd-surface-Propagate-commit-to-parent-class.patch
+
 BuildRequires: chrpath
 BuildRequires: pango-devel
 BuildRequires: startup-notification-devel
@@ -324,6 +333,18 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/%{name}.desktop
 %{_datadir}/mutter-%{mutter_api_version}/tests
 
 %changelog
+* Mon Aug 30 2021 Jonas Ådahl <jadahl@redhat.com> - 3.32.2-60
+- Backport fix avoiding DND regression
+  Resolves: #1999120
+
+* Fri Aug 06 2021 Jonas Ådahl <jadahl@redhat.com> - 3.32.2-59
+- Backport fixes avoiding frozen partly off-screen clients
+  Resolves: #1989035
+
+* Mon Jul 05 2021 Jonas Ådahl <jadahl@redhat.com> - 3.32.2-58
+- Backport xauth and xhost patches
+  Resolves: #1949176
+
 * Mon Feb 22 2021 Carlos Garnacho <cgarnach@redhat.com> - 3.32.2-57
 - Backport touch-mode
   Resolves: #1833787