Blame SOURCES/wayland-frame-callback-rework.patch

4bb951
From 4232f2056cd31811d047104d1223f3e5ced4b107 Mon Sep 17 00:00:00 2001
4bb951
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
4bb951
Date: Thu, 16 Apr 2020 19:42:03 +0200
4bb951
Subject: [PATCH 1/5] clutter/stage: Make clutter_stage_schedule_update()
4bb951
 always schedule
4bb951
4bb951
We could call clutter_stage_schedule_update() and it wouldn't actually
4bb951
schedule anything, as the master frame clock only tries to reschedule if
4bb951
1) there is an active timeline, 2) there are pending relayouts, 3) there
4bb951
are pending redraws, or 4) there are pending events. Thus, a call to
4bb951
clutter_stage_schedule_update() didn't have any effect if it was called
4bb951
at the wrong time.
4bb951
4bb951
Fix this by adding a boolean state "needs_update" to the stage, set on
4bb951
clutter_stage_schedule_update() and cleared on
4bb951
_clutter_stage_do_update(), that will make the master clock reschedule
4bb951
an update if it is TRUE.
4bb951
4bb951
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218
4bb951
(cherry picked from commit b8003807b0772e97354302b5cc2825e0b22c6c83)
4bb951
---
4bb951
 clutter/clutter/clutter-stage.c | 10 +++++++++-
4bb951
 1 file changed, 9 insertions(+), 1 deletion(-)
4bb951
4bb951
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
4bb951
index aaa77d9ede..5a914a3d0b 100644
4bb951
--- a/clutter/clutter/clutter-stage.c
4bb951
+++ b/clutter/clutter/clutter-stage.c
4bb951
@@ -152,6 +152,8 @@ struct _ClutterStagePrivate
4bb951
 
4bb951
   int update_freeze_count;
4bb951
 
4bb951
+  gboolean needs_update;
4bb951
+
4bb951
   guint relayout_pending       : 1;
4bb951
   guint redraw_pending         : 1;
4bb951
   guint is_fullscreen          : 1;
4bb951
@@ -1074,7 +1076,9 @@ _clutter_stage_needs_update (ClutterStage *stage)
4bb951
 
4bb951
   priv = stage->priv;
4bb951
 
4bb951
-  return priv->relayout_pending || priv->redraw_pending;
4bb951
+  return priv->relayout_pending ||
4bb951
+         priv->needs_update ||
4bb951
+         priv->redraw_pending;
4bb951
 }
4bb951
 
4bb951
 void
4bb951
@@ -1232,6 +1236,8 @@ _clutter_stage_do_update (ClutterStage *stage)
4bb951
 
4bb951
   priv->stage_was_relayout = FALSE;
4bb951
 
4bb951
+  priv->needs_update = FALSE;
4bb951
+
4bb951
   /* if the stage is being destroyed, or if the destruction already
4bb951
    * happened and we don't have an StageWindow any more, then we
4bb951
    * should bail out
4bb951
@@ -4080,6 +4086,8 @@ _clutter_stage_schedule_update (ClutterStage *stage)
4bb951
   if (stage_window == NULL)
4bb951
     return;
4bb951
 
4bb951
+  stage->priv->needs_update = TRUE;
4bb951
+
4bb951
   return _clutter_stage_window_schedule_update (stage_window,
4bb951
                                                 stage->priv->sync_delay);
4bb951
 }
4bb951
-- 
4bb951
2.31.1
4bb951
4bb951
4bb951
From 2d4453cfdcaf0c6a9f492d2c2395dbfc8cf833db Mon Sep 17 00:00:00 2001
4bb951
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
4bb951
Date: Thu, 16 Apr 2020 19:11:37 +0200
4bb951
Subject: [PATCH 2/5] clutter/stage: Make clutter_stage_schedule_update()
4bb951
 public API
4bb951
4bb951
It's effectively used by mutter by abusing a ClutterTimeline to scedule
4bb951
updates.  Timelines are not really suited in places that is done, as it
4bb951
is really just about getting a single new update scheduled whenever
4bb951
suitable, so expose the API so we can use it directly.
4bb951
4bb951
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218
4bb951
(cherry picked from commit 99c9a14bc8058830232cd4e07c7bb897e84a8c9c)
4bb951
---
4bb951
 clutter/clutter/clutter-master-clock-default.c |  4 ++--
4bb951
 clutter/clutter/clutter-stage-private.h        |  1 -
4bb951
 clutter/clutter/clutter-stage.c                | 16 ++++++++--------
4bb951
 clutter/clutter/clutter-stage.h                |  3 +++
4bb951
 4 files changed, 13 insertions(+), 11 deletions(-)
4bb951
4bb951
diff --git a/clutter/clutter/clutter-master-clock-default.c b/clutter/clutter/clutter-master-clock-default.c
4bb951
index 0647c3a7fd..de7a1e2f4d 100644
4bb951
--- a/clutter/clutter/clutter-master-clock-default.c
4bb951
+++ b/clutter/clutter/clutter-master-clock-default.c
4bb951
@@ -206,7 +206,7 @@ master_clock_schedule_stage_updates (ClutterMasterClockDefault *master_clock)
4bb951
   stages = clutter_stage_manager_peek_stages (stage_manager);
4bb951
 
4bb951
   for (l = stages; l != NULL; l = l->next)
4bb951
-    _clutter_stage_schedule_update (l->data);
4bb951
+    clutter_stage_schedule_update (l->data);
4bb951
 }
4bb951
 
4bb951
 static GSList *
4bb951
@@ -259,7 +259,7 @@ master_clock_reschedule_stage_updates (ClutterMasterClockDefault *master_clock,
4bb951
       if (master_clock->timelines ||
4bb951
           _clutter_stage_has_queued_events (l->data) ||
4bb951
           _clutter_stage_needs_update (l->data))
4bb951
-        _clutter_stage_schedule_update (l->data);
4bb951
+        clutter_stage_schedule_update (l->data);
4bb951
     }
4bb951
 }
4bb951
 
4bb951
diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h
4bb951
index 42474687ad..ea0ce5ec72 100644
4bb951
--- a/clutter/clutter/clutter-stage-private.h
4bb951
+++ b/clutter/clutter/clutter-stage-private.h
4bb951
@@ -70,7 +70,6 @@ void     _clutter_stage_queue_event                       (ClutterStage *stage,
4bb951
 gboolean _clutter_stage_has_queued_events                 (ClutterStage *stage);
4bb951
 void     _clutter_stage_process_queued_events             (ClutterStage *stage);
4bb951
 void     _clutter_stage_update_input_devices              (ClutterStage *stage);
4bb951
-void     _clutter_stage_schedule_update                   (ClutterStage *stage);
4bb951
 gint64    _clutter_stage_get_update_time                  (ClutterStage *stage);
4bb951
 void     _clutter_stage_clear_update_time                 (ClutterStage *stage);
4bb951
 gboolean _clutter_stage_has_full_redraw_queued            (ClutterStage *stage);
4bb951
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
4bb951
index 5a914a3d0b..74ff8b1337 100644
4bb951
--- a/clutter/clutter/clutter-stage.c
4bb951
+++ b/clutter/clutter/clutter-stage.c
4bb951
@@ -921,7 +921,7 @@ _clutter_stage_queue_event (ClutterStage *stage,
4bb951
     {
4bb951
       ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
4bb951
       _clutter_master_clock_start_running (master_clock);
4bb951
-      _clutter_stage_schedule_update (stage);
4bb951
+      clutter_stage_schedule_update (stage);
4bb951
     }
4bb951
 
4bb951
   /* if needed, update the state of the input device of the event.
4bb951
@@ -1295,7 +1295,7 @@ clutter_stage_real_queue_relayout (ClutterActor *self)
4bb951
 
4bb951
   if (!priv->relayout_pending)
4bb951
     {
4bb951
-      _clutter_stage_schedule_update (stage);
4bb951
+      clutter_stage_schedule_update (stage);
4bb951
       priv->relayout_pending = TRUE;
4bb951
     }
4bb951
 
4bb951
@@ -3788,7 +3788,7 @@ clutter_stage_ensure_redraw (ClutterStage *stage)
4bb951
   priv = stage->priv;
4bb951
 
4bb951
   if (!priv->relayout_pending && !priv->redraw_pending)
4bb951
-    _clutter_stage_schedule_update (stage);
4bb951
+    clutter_stage_schedule_update (stage);
4bb951
 
4bb951
   priv->relayout_pending = TRUE;
4bb951
   priv->redraw_pending = TRUE;
4bb951
@@ -4069,13 +4069,13 @@ clutter_stage_get_minimum_size (ClutterStage *stage,
4bb951
 }
4bb951
 
4bb951
 /**
4bb951
- * _clutter_stage_schedule_update:
4bb951
- * @window: a #ClutterStage actor
4bb951
+ * clutter_stage_schedule_update:
4bb951
+ * @stage: a #ClutterStage actor
4bb951
  *
4bb951
  * Schedules a redraw of the #ClutterStage at the next optimal timestamp.
4bb951
  */
4bb951
 void
4bb951
-_clutter_stage_schedule_update (ClutterStage *stage)
4bb951
+clutter_stage_schedule_update (ClutterStage *stage)
4bb951
 {
4bb951
   ClutterStageWindow *stage_window;
4bb951
 
4bb951
@@ -4097,7 +4097,7 @@ _clutter_stage_schedule_update (ClutterStage *stage)
4bb951
  * @stage: a #ClutterStage actor
4bb951
  *
4bb951
  * Returns the earliest time in which the stage is ready to update. The update
4bb951
- * time is set when _clutter_stage_schedule_update() is called. This can then
4bb951
+ * time is set when clutter_stage_schedule_update() is called. This can then
4bb951
  * be used by e.g. the #ClutterMasterClock to know when the stage needs to be
4bb951
  * redrawn.
4bb951
  *
4bb951
@@ -4267,7 +4267,7 @@ _clutter_stage_queue_actor_redraw (ClutterStage                 *stage,
4bb951
 
4bb951
       CLUTTER_NOTE (PAINT, "First redraw request");
4bb951
 
4bb951
-      _clutter_stage_schedule_update (stage);
4bb951
+      clutter_stage_schedule_update (stage);
4bb951
       priv->redraw_pending = TRUE;
4bb951
 
4bb951
       master_clock = _clutter_master_clock_get_default ();
4bb951
diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h
4bb951
index 9da63d211d..53e37ae3bc 100644
4bb951
--- a/clutter/clutter/clutter-stage.h
4bb951
+++ b/clutter/clutter/clutter-stage.h
4bb951
@@ -265,6 +265,9 @@ CLUTTER_EXPORT
4bb951
 void            clutter_stage_skip_sync_delay                   (ClutterStage          *stage);
4bb951
 #endif
4bb951
 
4bb951
+CLUTTER_EXPORT
4bb951
+void clutter_stage_schedule_update (ClutterStage *stage);
4bb951
+
4bb951
 CLUTTER_EXPORT
4bb951
 gboolean clutter_stage_get_capture_final_size (ClutterStage          *stage,
4bb951
                                                cairo_rectangle_int_t *rect,
4bb951
-- 
4bb951
2.31.1
4bb951
4bb951
4bb951
From 1c4db591b6bb2ae9d649e8157eae24b875e7a22b Mon Sep 17 00:00:00 2001
4bb951
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
4bb951
Date: Mon, 28 Oct 2019 18:20:31 +0100
4bb951
Subject: [PATCH 3/5] wayland/actor-surface: Always store away frame callbacks
4bb951
 on commit
4bb951
4bb951
We're expected by MetaWaylandSurface to always pick the frame callbacks
4bb951
out from the pending state when committing (applying) so that no frame
4bb951
callbacks are unaccounted for. We failed to do this if our actor for
4bb951
some reason (e.g. associated window was unmanaged) was destroyed. To
4bb951
handle this situation better, store away the frame callbacks until we
4bb951
some later point in time need to pass them on forward.
4bb951
4bb951
https://gitlab.gnome.org/GNOME/mutter/merge_requests/893
4bb951
---
4bb951
 src/wayland/meta-wayland-actor-surface.c | 25 +++++++++++++++++++++++-
4bb951
 1 file changed, 24 insertions(+), 1 deletion(-)
4bb951
4bb951
diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c
4bb951
index 2471de0a92..264565c575 100644
4bb951
--- a/src/wayland/meta-wayland-actor-surface.c
4bb951
+++ b/src/wayland/meta-wayland-actor-surface.c
4bb951
@@ -35,6 +35,8 @@ typedef struct _MetaWaylandActorSurfacePrivate MetaWaylandActorSurfacePrivate;
4bb951
 struct _MetaWaylandActorSurfacePrivate
4bb951
 {
4bb951
   MetaSurfaceActor *actor;
4bb951
+
4bb951
+  struct wl_list frame_callback_list;
4bb951
 };
4bb951
 
4bb951
 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaWaylandActorSurface,
4bb951
@@ -56,6 +58,7 @@ meta_wayland_actor_surface_dispose (GObject *object)
4bb951
     meta_wayland_actor_surface_get_instance_private (META_WAYLAND_ACTOR_SURFACE (object));
4bb951
   MetaWaylandSurface *surface =
4bb951
     meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (object));
4bb951
+  MetaWaylandFrameCallback *cb, *next;
4bb951
 
4bb951
   if (priv->actor)
4bb951
     {
4bb951
@@ -66,6 +69,9 @@ meta_wayland_actor_surface_dispose (GObject *object)
4bb951
       g_clear_object (&priv->actor);
4bb951
     }
4bb951
 
4bb951
+  wl_list_for_each_safe (cb, next, &priv->frame_callback_list, link)
4bb951
+    wl_resource_destroy (cb->resource);
4bb951
+
4bb951
   G_OBJECT_CLASS (meta_wayland_actor_surface_parent_class)->dispose (object);
4bb951
 }
4bb951
 
4bb951
@@ -99,6 +105,9 @@ meta_wayland_actor_surface_queue_frame_callbacks (MetaWaylandActorSurface *actor
4bb951
   MetaSurfaceActorWayland *surface_actor_wayland =
4bb951
     META_SURFACE_ACTOR_WAYLAND (priv->actor);
4bb951
 
4bb951
+  meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland,
4bb951
+                                                  &priv->frame_callback_list);
4bb951
+  wl_list_init (&priv->frame_callback_list);
4bb951
   meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland,
4bb951
                                                   &pending->frame_callback_list);
4bb951
   wl_list_init (&pending->frame_callback_list);
4bb951
@@ -253,10 +262,20 @@ meta_wayland_actor_surface_commit (MetaWaylandSurfaceRole  *surface_role,
4bb951
 {
4bb951
   MetaWaylandActorSurface *actor_surface =
4bb951
     META_WAYLAND_ACTOR_SURFACE (surface_role);
4bb951
+  MetaWaylandActorSurfacePrivate *priv =
4bb951
+    meta_wayland_actor_surface_get_instance_private (actor_surface);
4bb951
   MetaWaylandSurface *surface =
4bb951
     meta_wayland_surface_role_get_surface (surface_role);
4bb951
   MetaWaylandSurface *toplevel_surface;
4bb951
 
4bb951
+  if (!priv->actor)
4bb951
+    {
4bb951
+      wl_list_insert_list (&priv->frame_callback_list,
4bb951
+                           &pending->frame_callback_list);
4bb951
+      wl_list_init (&pending->frame_callback_list);
4bb951
+      return;
4bb951
+    }
4bb951
+
4bb951
   meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
4bb951
 
4bb951
   toplevel_surface = meta_wayland_surface_get_toplevel (surface);
4bb951
@@ -307,8 +326,12 @@ meta_wayland_actor_surface_is_on_logical_monitor (MetaWaylandSurfaceRole *surfac
4bb951
 }
4bb951
 
4bb951
 static void
4bb951
-meta_wayland_actor_surface_init (MetaWaylandActorSurface *role)
4bb951
+meta_wayland_actor_surface_init (MetaWaylandActorSurface *actor_surface)
4bb951
 {
4bb951
+  MetaWaylandActorSurfacePrivate *priv =
4bb951
+    meta_wayland_actor_surface_get_instance_private (actor_surface);
4bb951
+
4bb951
+  wl_list_init (&priv->frame_callback_list);
4bb951
 }
4bb951
 
4bb951
 static void
4bb951
-- 
4bb951
2.31.1
4bb951
4bb951
4bb951
From 54e5cee1a8d1a94fb19b438a3c80fe72179a3c80 Mon Sep 17 00:00:00 2001
4bb951
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
4bb951
Date: Fri, 6 Aug 2021 19:09:24 +0200
4bb951
Subject: [PATCH 4/5] wayland/actor-surface: Always store away frame callbacks
4bb951
 on commit
4bb951
4bb951
We're expected by MetaWaylandSurface to always pick the frame callbacks
4bb951
out from the pending state when committing (applying) so that no frame
4bb951
callbacks are unaccounted for. We failed to do this if our actor for
4bb951
some reason (e.g. associated window was unmanaged) was destroyed. To
4bb951
handle this situation better, store away the frame callbacks until we
4bb951
some later point in time need to pass them on forward.
4bb951
4bb951
https://gitlab.gnome.org/GNOME/mutter/merge_requests/893
4bb951
---
4bb951
 src/compositor/meta-surface-actor-wayland.c | 29 ---------
4bb951
 src/wayland/meta-wayland-actor-surface.c    | 65 ++++++++++++++++-----
4bb951
 src/wayland/meta-wayland-actor-surface.h    |  3 +
4bb951
 src/wayland/meta-wayland-cursor-surface.c   |  4 +-
4bb951
 src/wayland/meta-wayland-dnd-surface.c      | 11 +++-
4bb951
 src/wayland/meta-wayland-legacy-xdg-shell.c |  8 +--
4bb951
 src/wayland/meta-wayland-private.h          |  2 +-
4bb951
 src/wayland/meta-wayland-subsurface.c       |  2 -
4bb951
 src/wayland/meta-wayland-surface.c          | 38 +++---------
4bb951
 src/wayland/meta-wayland-surface.h          |  9 +--
4bb951
 src/wayland/meta-wayland-wl-shell.c         |  3 -
4bb951
 src/wayland/meta-wayland-xdg-shell.c        | 15 ++---
4bb951
 src/wayland/meta-wayland.c                  | 56 +++++++++++++-----
4bb951
 src/wayland/meta-wayland.h                  |  8 ++-
4bb951
 src/wayland/meta-xwayland.c                 | 45 --------------
4bb951
 15 files changed, 127 insertions(+), 171 deletions(-)
4bb951
4bb951
diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c
4bb951
index a75c4dd096..480b51c61a 100644
4bb951
--- a/src/compositor/meta-surface-actor-wayland.c
4bb951
+++ b/src/compositor/meta-surface-actor-wayland.c
4bb951
@@ -42,7 +42,6 @@ struct _MetaSurfaceActorWayland
4bb951
   MetaSurfaceActor parent;
4bb951
 
4bb951
   MetaWaylandSurface *surface;
4bb951
-  struct wl_list frame_callback_list;
4bb951
 };
4bb951
 
4bb951
 G_DEFINE_TYPE (MetaSurfaceActorWayland,
4bb951
@@ -91,13 +90,6 @@ meta_surface_actor_wayland_is_unredirected (MetaSurfaceActor *actor)
4bb951
   return FALSE;
4bb951
 }
4bb951
 
4bb951
-void
4bb951
-meta_surface_actor_wayland_add_frame_callbacks (MetaSurfaceActorWayland *self,
4bb951
-                                                struct wl_list *frame_callbacks)
4bb951
-{
4bb951
-  wl_list_insert_list (&self->frame_callback_list, frame_callbacks);
4bb951
-}
4bb951
-
4bb951
 static MetaWindow *
4bb951
 meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor)
4bb951
 {
4bb951
@@ -158,22 +150,6 @@ meta_surface_actor_wayland_get_preferred_height  (ClutterActor *actor,
4bb951
     *natural_height_p *= scale;
4bb951
 }
4bb951
 
4bb951
-static void
4bb951
-meta_surface_actor_wayland_paint (ClutterActor *actor)
4bb951
-{
4bb951
-  MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor);
4bb951
-
4bb951
-  if (self->surface)
4bb951
-    {
4bb951
-      MetaWaylandCompositor *compositor = self->surface->compositor;
4bb951
-
4bb951
-      wl_list_insert_list (&compositor->frame_callbacks, &self->frame_callback_list);
4bb951
-      wl_list_init (&self->frame_callback_list);
4bb951
-    }
4bb951
-
4bb951
-  CLUTTER_ACTOR_CLASS (meta_surface_actor_wayland_parent_class)->paint (actor);
4bb951
-}
4bb951
-
4bb951
 static void
4bb951
 meta_surface_actor_wayland_dispose (GObject *object)
4bb951
 {
4bb951
@@ -190,9 +166,6 @@ meta_surface_actor_wayland_dispose (GObject *object)
4bb951
       self->surface = NULL;
4bb951
     }
4bb951
 
4bb951
-  wl_list_for_each_safe (cb, next, &self->frame_callback_list, link)
4bb951
-    wl_resource_destroy (cb->resource);
4bb951
-
4bb951
   G_OBJECT_CLASS (meta_surface_actor_wayland_parent_class)->dispose (object);
4bb951
 }
4bb951
 
4bb951
@@ -205,7 +178,6 @@ meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass)
4bb951
 
4bb951
   actor_class->get_preferred_width = meta_surface_actor_wayland_get_preferred_width;
4bb951
   actor_class->get_preferred_height = meta_surface_actor_wayland_get_preferred_height;
4bb951
-  actor_class->paint = meta_surface_actor_wayland_paint;
4bb951
 
4bb951
   surface_actor_class->process_damage = meta_surface_actor_wayland_process_damage;
4bb951
   surface_actor_class->pre_paint = meta_surface_actor_wayland_pre_paint;
4bb951
@@ -232,7 +204,6 @@ meta_surface_actor_wayland_new (MetaWaylandSurface *surface)
4bb951
 
4bb951
   g_assert (meta_is_wayland_compositor ());
4bb951
 
4bb951
-  wl_list_init (&self->frame_callback_list);
4bb951
   self->surface = surface;
4bb951
   g_object_add_weak_pointer (G_OBJECT (self->surface),
4bb951
                              (gpointer *) &self->surface);
4bb951
diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c
4bb951
index 264565c575..037dd901ab 100644
4bb951
--- a/src/wayland/meta-wayland-actor-surface.c
4bb951
+++ b/src/wayland/meta-wayland-actor-surface.c
4bb951
@@ -84,16 +84,22 @@ meta_wayland_actor_surface_assigned (MetaWaylandSurfaceRole *surface_role)
4bb951
     meta_wayland_surface_role_get_surface (surface_role);
4bb951
   GList *l;
4bb951
 
4bb951
-  meta_surface_actor_wayland_add_frame_callbacks (META_SURFACE_ACTOR_WAYLAND (priv->actor),
4bb951
-                                                  &surface->pending_frame_callback_list);
4bb951
-  wl_list_init (&surface->pending_frame_callback_list);
4bb951
-
4bb951
   for (l = surface->subsurfaces; l; l = l->next)
4bb951
     {
4bb951
       ClutterActor *subsurface_actor =
4bb951
         CLUTTER_ACTOR (meta_wayland_surface_get_actor (l->data));
4bb951
       clutter_actor_add_child (CLUTTER_ACTOR (priv->actor), subsurface_actor);
4bb951
     }
4bb951
+
4bb951
+  if (wl_list_empty (&surface->unassigned.pending_frame_callback_list))
4bb951
+    return;
4bb951
+
4bb951
+  wl_list_insert_list (priv->frame_callback_list.prev,
4bb951
+                       &surface->unassigned.pending_frame_callback_list);
4bb951
+  wl_list_init (&surface->unassigned.pending_frame_callback_list);
4bb951
+
4bb951
+  meta_wayland_compositor_add_frame_callback_surface (surface->compositor,
4bb951
+                                                      surface);
4bb951
 }
4bb951
 
4bb951
 void
4bb951
@@ -102,15 +108,40 @@ meta_wayland_actor_surface_queue_frame_callbacks (MetaWaylandActorSurface *actor
4bb951
 {
4bb951
   MetaWaylandActorSurfacePrivate *priv =
4bb951
     meta_wayland_actor_surface_get_instance_private (actor_surface);
4bb951
-  MetaSurfaceActorWayland *surface_actor_wayland =
4bb951
-    META_SURFACE_ACTOR_WAYLAND (priv->actor);
4bb951
+  MetaWaylandSurfaceRole *surface_role =
4bb951
+    META_WAYLAND_SURFACE_ROLE (actor_surface);
4bb951
+  MetaWaylandSurface *surface =
4bb951
+    meta_wayland_surface_role_get_surface (surface_role);
4bb951
 
4bb951
-  meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland,
4bb951
-                                                  &priv->frame_callback_list);
4bb951
-  wl_list_init (&priv->frame_callback_list);
4bb951
-  meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland,
4bb951
-                                                  &pending->frame_callback_list);
4bb951
+  if (!priv->actor)
4bb951
+    return;
4bb951
+
4bb951
+  if (wl_list_empty (&pending->frame_callback_list))
4bb951
+    return;
4bb951
+
4bb951
+  wl_list_insert_list (priv->frame_callback_list.prev,
4bb951
+                       &pending->frame_callback_list);
4bb951
   wl_list_init (&pending->frame_callback_list);
4bb951
+
4bb951
+  meta_wayland_compositor_add_frame_callback_surface (surface->compositor,
4bb951
+                                                      surface);
4bb951
+}
4bb951
+
4bb951
+void
4bb951
+meta_wayland_actor_surface_emit_frame_callbacks (MetaWaylandActorSurface *actor_surface,
4bb951
+                                                 uint32_t                 timestamp_ms)
4bb951
+{
4bb951
+  MetaWaylandActorSurfacePrivate *priv =
4bb951
+    meta_wayland_actor_surface_get_instance_private (actor_surface);
4bb951
+
4bb951
+  while (!wl_list_empty (&priv->frame_callback_list))
4bb951
+    {
4bb951
+      MetaWaylandFrameCallback *callback =
4bb951
+        wl_container_of (priv->frame_callback_list.next, callback, link);
4bb951
+
4bb951
+      wl_callback_send_done (callback->resource, timestamp_ms);
4bb951
+      wl_resource_destroy (callback->resource);
4bb951
+    }
4bb951
 }
4bb951
 
4bb951
 static double
4bb951
@@ -268,12 +299,14 @@ meta_wayland_actor_surface_commit (MetaWaylandSurfaceRole  *surface_role,
4bb951
     meta_wayland_surface_role_get_surface (surface_role);
4bb951
   MetaWaylandSurface *toplevel_surface;
4bb951
 
4bb951
-  if (!priv->actor)
4bb951
+  if (!wl_list_empty (&pending->frame_callback_list) &&
4bb951
+      priv->actor &&
4bb951
+      !meta_surface_actor_is_obscured (priv->actor))
4bb951
     {
4bb951
-      wl_list_insert_list (&priv->frame_callback_list,
4bb951
-                           &pending->frame_callback_list);
4bb951
-      wl_list_init (&pending->frame_callback_list);
4bb951
-      return;
4bb951
+      MetaBackend *backend = meta_get_backend ();
4bb951
+      ClutterActor *stage = meta_backend_get_stage (backend);
4bb951
+
4bb951
+      clutter_stage_schedule_update (CLUTTER_STAGE (stage));
4bb951
     }
4bb951
 
4bb951
   meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
4bb951
diff --git a/src/wayland/meta-wayland-actor-surface.h b/src/wayland/meta-wayland-actor-surface.h
4bb951
index 444b3b1785..e79f1caff5 100644
4bb951
--- a/src/wayland/meta-wayland-actor-surface.h
4bb951
+++ b/src/wayland/meta-wayland-actor-surface.h
4bb951
@@ -46,4 +46,7 @@ void meta_wayland_actor_surface_reset_actor (MetaWaylandActorSurface *actor_surf
4bb951
 void meta_wayland_actor_surface_queue_frame_callbacks (MetaWaylandActorSurface *actor_surface,
4bb951
                                                        MetaWaylandPendingState *pending);
4bb951
 
4bb951
+void meta_wayland_actor_surface_emit_frame_callbacks (MetaWaylandActorSurface *actor_surface,
4bb951
+                                                      uint32_t                 timestamp_ms);
4bb951
+
4bb951
 #endif /* META_WAYLAND_ACTOR_SURFACE_H */
4bb951
diff --git a/src/wayland/meta-wayland-cursor-surface.c b/src/wayland/meta-wayland-cursor-surface.c
4bb951
index d46b3511fa..6b791eb378 100644
4bb951
--- a/src/wayland/meta-wayland-cursor-surface.c
4bb951
+++ b/src/wayland/meta-wayland-cursor-surface.c
4bb951
@@ -124,8 +124,8 @@ meta_wayland_cursor_surface_assigned (MetaWaylandSurfaceRole *surface_role)
4bb951
     meta_wayland_cursor_surface_get_instance_private (cursor_surface);
4bb951
 
4bb951
   wl_list_insert_list (&priv->frame_callbacks,
4bb951
-                       &surface->pending_frame_callback_list);
4bb951
-  wl_list_init (&surface->pending_frame_callback_list);
4bb951
+                       &surface->unassigned.pending_frame_callback_list);
4bb951
+  wl_list_init (&surface->unassigned.pending_frame_callback_list);
4bb951
 }
4bb951
 
4bb951
 static void
4bb951
diff --git a/src/wayland/meta-wayland-dnd-surface.c b/src/wayland/meta-wayland-dnd-surface.c
4bb951
index 2aad6dcd5d..8ddeb2a7bd 100644
4bb951
--- a/src/wayland/meta-wayland-dnd-surface.c
4bb951
+++ b/src/wayland/meta-wayland-dnd-surface.c
4bb951
@@ -21,6 +21,8 @@
4bb951
 
4bb951
 #include "wayland/meta-wayland-dnd-surface.h"
4bb951
 
4bb951
+#include "wayland/meta-wayland.h"
4bb951
+
4bb951
 struct _MetaWaylandSurfaceRoleDND
4bb951
 {
4bb951
   MetaWaylandActorSurface parent;
4bb951
@@ -36,7 +38,11 @@ dnd_surface_assigned (MetaWaylandSurfaceRole *surface_role)
4bb951
   MetaWaylandSurface *surface =
4bb951
     meta_wayland_surface_role_get_surface (surface_role);
4bb951
 
4bb951
-  meta_wayland_surface_queue_pending_frame_callbacks (surface);
4bb951
+  if (wl_list_empty (&surface->unassigned.pending_frame_callback_list))
4bb951
+    return;
4bb951
+
4bb951
+  meta_wayland_compositor_add_frame_callback_surface (surface->compositor,
4bb951
+                                                      surface);
4bb951
 }
4bb951
 
4bb951
 static void
4bb951
@@ -46,7 +52,8 @@ dnd_surface_commit (MetaWaylandSurfaceRole  *surface_role,
4bb951
   MetaWaylandSurface *surface =
4bb951
     meta_wayland_surface_role_get_surface (surface_role);
4bb951
 
4bb951
-  meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
4bb951
+  meta_wayland_compositor_add_frame_callback_surface (surface->compositor,
4bb951
+                                                      surface);
4bb951
 }
4bb951
 
4bb951
 static void
4bb951
diff --git a/src/wayland/meta-wayland-legacy-xdg-shell.c b/src/wayland/meta-wayland-legacy-xdg-shell.c
4bb951
index 8230641770..b78552f31b 100644
4bb951
--- a/src/wayland/meta-wayland-legacy-xdg-shell.c
4bb951
+++ b/src/wayland/meta-wayland-legacy-xdg-shell.c
4bb951
@@ -659,6 +659,8 @@ meta_wayland_zxdg_toplevel_v6_commit (MetaWaylandSurfaceRole  *surface_role,
4bb951
     META_WAYLAND_ZXDG_SURFACE_V6 (xdg_toplevel);
4bb951
   MetaWaylandZxdgSurfaceV6Private *xdg_surface_priv =
4bb951
     meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface);
4bb951
+  MetaWaylandActorSurface *actor_surface =
4bb951
+    META_WAYLAND_ACTOR_SURFACE (xdg_surface);
4bb951
   MetaWaylandSurfaceRoleClass *surface_role_class;
4bb951
   MetaWaylandSurface *surface =
4bb951
     meta_wayland_surface_role_get_surface (surface_role);
4bb951
@@ -670,7 +672,7 @@ meta_wayland_zxdg_toplevel_v6_commit (MetaWaylandSurfaceRole  *surface_role,
4bb951
   window = surface->window;
4bb951
   if (!window)
4bb951
     {
4bb951
-      meta_wayland_surface_cache_pending_frame_callbacks (surface, pending);
4bb951
+      meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
4bb951
       return;
4bb951
     }
4bb951
 
4bb951
@@ -1220,14 +1222,10 @@ meta_wayland_zxdg_surface_v6_send_configure (MetaWaylandZxdgSurfaceV6 *xdg_surfa
4bb951
 static void
4bb951
 zxdg_surface_v6_destructor (struct wl_resource *resource)
4bb951
 {
4bb951
-  MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource);
4bb951
   MetaWaylandZxdgSurfaceV6 *xdg_surface = wl_resource_get_user_data (resource);
4bb951
   MetaWaylandZxdgSurfaceV6Private *priv =
4bb951
     meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface);
4bb951
 
4bb951
-  meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
4bb951
-                                                   surface);
4bb951
-
4bb951
   priv->shell_client->surfaces = g_list_remove (priv->shell_client->surfaces,
4bb951
                                                 xdg_surface);
4bb951
 
4bb951
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
4bb951
index 5bcb0ea4f9..215d0967f6 100644
4bb951
--- a/src/wayland/meta-wayland-private.h
4bb951
+++ b/src/wayland/meta-wayland-private.h
4bb951
@@ -67,7 +67,7 @@ struct _MetaWaylandCompositor
4bb951
   struct wl_display *wayland_display;
4bb951
   char *display_name;
4bb951
   GHashTable *outputs;
4bb951
-  struct wl_list frame_callbacks;
4bb951
+  GList *frame_callback_surfaces;
4bb951
 
4bb951
   MetaXWaylandManager xwayland_manager;
4bb951
 
4bb951
diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c
4bb951
index e0fa0a48b2..c7059b99a2 100644
4bb951
--- a/src/wayland/meta-wayland-subsurface.c
4bb951
+++ b/src/wayland/meta-wayland-subsurface.c
4bb951
@@ -239,8 +239,6 @@ wl_subsurface_destructor (struct wl_resource *resource)
4bb951
 {
4bb951
   MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
4bb951
 
4bb951
-  meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
4bb951
-                                                   surface);
4bb951
   if (surface->sub.parent)
4bb951
     {
4bb951
       wl_list_remove (&surface->sub.parent_destroy_listener.link);
4bb951
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
4bb951
index 6ffcd6a7fb..a76ab28c24 100644
4bb951
--- a/src/wayland/meta-wayland-surface.c
4bb951
+++ b/src/wayland/meta-wayland-surface.c
4bb951
@@ -358,15 +358,6 @@ surface_process_damage (MetaWaylandSurface *surface,
4bb951
   cairo_region_destroy (transformed_region);
4bb951
 }
4bb951
 
4bb951
-void
4bb951
-meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface      *surface,
4bb951
-                                                          MetaWaylandPendingState *pending)
4bb951
-{
4bb951
-  wl_list_insert_list (&surface->compositor->frame_callbacks,
4bb951
-                       &pending->frame_callback_list);
4bb951
-  wl_list_init (&pending->frame_callback_list);
4bb951
-}
4bb951
-
4bb951
 void
4bb951
 meta_wayland_surface_destroy_window (MetaWaylandSurface *surface)
4bb951
 {
4bb951
@@ -656,15 +647,6 @@ parent_surface_state_applied (gpointer data,
4bb951
   meta_wayland_subsurface_parent_state_applied (subsurface);
4bb951
 }
4bb951
 
4bb951
-void
4bb951
-meta_wayland_surface_cache_pending_frame_callbacks (MetaWaylandSurface      *surface,
4bb951
-                                                    MetaWaylandPendingState *pending)
4bb951
-{
4bb951
-  wl_list_insert_list (&surface->pending_frame_callback_list,
4bb951
-                       &pending->frame_callback_list);
4bb951
-  wl_list_init (&pending->frame_callback_list);
4bb951
-}
4bb951
-
4bb951
 void
4bb951
 meta_wayland_surface_apply_pending_state (MetaWaylandSurface      *surface,
4bb951
                                           MetaWaylandPendingState *pending)
4bb951
@@ -810,7 +792,9 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface      *surface,
4bb951
     }
4bb951
   else
4bb951
     {
4bb951
-      meta_wayland_surface_cache_pending_frame_callbacks (surface, pending);
4bb951
+      wl_list_insert_list (surface->unassigned.pending_frame_callback_list.prev,
4bb951
+                           &pending->frame_callback_list);
4bb951
+      wl_list_init (&pending->frame_callback_list);
4bb951
 
4bb951
       if (pending->newly_attached)
4bb951
         {
4bb951
@@ -1352,12 +1336,14 @@ wl_surface_destructor (struct wl_resource *resource)
4bb951
   if (surface->input_region)
4bb951
     cairo_region_destroy (surface->input_region);
4bb951
 
4bb951
-  meta_wayland_compositor_destroy_frame_callbacks (compositor, surface);
4bb951
+  meta_wayland_compositor_remove_frame_callback_surface (compositor, surface);
4bb951
 
4bb951
   g_hash_table_foreach (surface->outputs_to_destroy_notify_id, surface_output_disconnect_signal, surface);
4bb951
   g_hash_table_unref (surface->outputs_to_destroy_notify_id);
4bb951
 
4bb951
-  wl_list_for_each_safe (cb, next, &surface->pending_frame_callback_list, link)
4bb951
+  wl_list_for_each_safe (cb, next,
4bb951
+                         &surface->unassigned.pending_frame_callback_list,
4bb951
+                         link)
4bb951
     wl_resource_destroy (cb->resource);
4bb951
 
4bb951
   if (surface->resource)
4bb951
@@ -1401,7 +1387,7 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
4bb951
   surface->resource = wl_resource_create (client, &wl_surface_interface, wl_resource_get_version (compositor_resource), id);
4bb951
   wl_resource_set_implementation (surface->resource, &meta_wayland_wl_surface_interface, surface, wl_surface_destructor);
4bb951
 
4bb951
-  wl_list_init (&surface->pending_frame_callback_list);
4bb951
+  wl_list_init (&surface->unassigned.pending_frame_callback_list);
4bb951
 
4bb951
   sync_drag_dest_funcs (surface);
4bb951
 
4bb951
@@ -1809,14 +1795,6 @@ meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRole *role)
4bb951
   return priv->surface;
4bb951
 }
4bb951
 
4bb951
-void
4bb951
-meta_wayland_surface_queue_pending_frame_callbacks (MetaWaylandSurface *surface)
4bb951
-{
4bb951
-  wl_list_insert_list (&surface->compositor->frame_callbacks,
4bb951
-                       &surface->pending_frame_callback_list);
4bb951
-  wl_list_init (&surface->pending_frame_callback_list);
4bb951
-}
4bb951
-
4bb951
 cairo_region_t *
4bb951
 meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface)
4bb951
 {
4bb951
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
4bb951
index e244a3fdf7..776431fca2 100644
4bb951
--- a/src/wayland/meta-wayland-surface.h
4bb951
+++ b/src/wayland/meta-wayland-surface.h
4bb951
@@ -160,13 +160,9 @@ struct _MetaWaylandSurface
4bb951
   /* Buffer renderer state. */
4bb951
   gboolean buffer_held;
4bb951
 
4bb951
-  /* List of pending frame callbacks that needs to stay queued longer than one
4bb951
-   * commit sequence, such as when it has not yet been assigned a role.
4bb951
-   */
4bb951
-  struct wl_list pending_frame_callback_list;
4bb951
-
4bb951
   /* Intermediate state for when no role has been assigned. */
4bb951
   struct {
4bb951
+    struct wl_list pending_frame_callback_list;
4bb951
     MetaWaylandBuffer *buffer;
4bb951
   } unassigned;
4bb951
 
4bb951
@@ -274,9 +270,6 @@ MetaWaylandSurface *meta_wayland_surface_get_toplevel (MetaWaylandSurface *surfa
4bb951
 
4bb951
 MetaWindow *        meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface);
4bb951
 
4bb951
-void                meta_wayland_surface_cache_pending_frame_callbacks (MetaWaylandSurface      *surface,
4bb951
-                                                                        MetaWaylandPendingState *pending);
4bb951
-
4bb951
 void                meta_wayland_surface_queue_pending_frame_callbacks (MetaWaylandSurface *surface);
4bb951
 
4bb951
 void                meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface      *surface,
4bb951
diff --git a/src/wayland/meta-wayland-wl-shell.c b/src/wayland/meta-wayland-wl-shell.c
4bb951
index 539fb9858e..e80db17e78 100644
4bb951
--- a/src/wayland/meta-wayland-wl-shell.c
4bb951
+++ b/src/wayland/meta-wayland-wl-shell.c
4bb951
@@ -100,9 +100,6 @@ wl_shell_surface_destructor (struct wl_resource *resource)
4bb951
     surface_from_wl_shell_surface_resource (resource);
4bb951
   GList *l;
4bb951
 
4bb951
-  meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
4bb951
-                                                   surface);
4bb951
-
4bb951
   if (wl_shell_surface->popup)
4bb951
     meta_wayland_popup_dismiss (wl_shell_surface->popup);
4bb951
 
4bb951
diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c
4bb951
index fa0207a03c..4a4995c425 100644
4bb951
--- a/src/wayland/meta-wayland-xdg-shell.c
4bb951
+++ b/src/wayland/meta-wayland-xdg-shell.c
4bb951
@@ -684,6 +684,8 @@ meta_wayland_xdg_toplevel_commit (MetaWaylandSurfaceRole  *surface_role,
4bb951
   MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (xdg_toplevel);
4bb951
   MetaWaylandXdgSurfacePrivate *xdg_surface_priv =
4bb951
     meta_wayland_xdg_surface_get_instance_private (xdg_surface);
4bb951
+  MetaWaylandActorSurface *actor_surface =
4bb951
+    META_WAYLAND_ACTOR_SURFACE (xdg_toplevel);
4bb951
   MetaWaylandSurfaceRoleClass *surface_role_class;
4bb951
   MetaWaylandSurface *surface =
4bb951
     meta_wayland_surface_role_get_surface (surface_role);
4bb951
@@ -695,15 +697,12 @@ meta_wayland_xdg_toplevel_commit (MetaWaylandSurfaceRole  *surface_role,
4bb951
   window = surface->window;
4bb951
   if (!window)
4bb951
     {
4bb951
-      meta_wayland_surface_cache_pending_frame_callbacks (surface, pending);
4bb951
+      meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
4bb951
       return;
4bb951
     }
4bb951
 
4bb951
   if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached)
4bb951
     {
4bb951
-      MetaWaylandActorSurface *actor_surface =
4bb951
-        META_WAYLAND_ACTOR_SURFACE (xdg_toplevel);
4bb951
-
4bb951
       meta_wayland_xdg_surface_reset (xdg_surface);
4bb951
       meta_wayland_actor_surface_queue_frame_callbacks (actor_surface,
4bb951
                                                         pending);
4bb951
@@ -1037,6 +1036,8 @@ meta_wayland_xdg_popup_commit (MetaWaylandSurfaceRole  *surface_role,
4bb951
   MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (surface_role);
4bb951
   MetaWaylandXdgSurfacePrivate *xdg_surface_priv =
4bb951
     meta_wayland_xdg_surface_get_instance_private (xdg_surface);
4bb951
+  MetaWaylandActorSurface *actor_surface =
4bb951
+    META_WAYLAND_ACTOR_SURFACE (xdg_popup);
4bb951
   MetaWaylandSurfaceRoleClass *surface_role_class;
4bb951
   MetaWaylandSurface *surface =
4bb951
     meta_wayland_surface_role_get_surface (surface_role);
4bb951
@@ -1048,7 +1049,7 @@ meta_wayland_xdg_popup_commit (MetaWaylandSurfaceRole  *surface_role,
4bb951
   if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached)
4bb951
     {
4bb951
       meta_wayland_xdg_surface_reset (xdg_surface);
4bb951
-      meta_wayland_surface_cache_pending_frame_callbacks (surface, pending);
4bb951
+      meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
4bb951
       return;
4bb951
     }
4bb951
 
4bb951
@@ -1313,14 +1314,10 @@ meta_wayland_xdg_surface_send_configure (MetaWaylandXdgSurface *xdg_surface)
4bb951
 static void
4bb951
 xdg_surface_destructor (struct wl_resource *resource)
4bb951
 {
4bb951
-  MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource);
4bb951
   MetaWaylandXdgSurface *xdg_surface = wl_resource_get_user_data (resource);
4bb951
   MetaWaylandXdgSurfacePrivate *priv =
4bb951
     meta_wayland_xdg_surface_get_instance_private (xdg_surface);
4bb951
 
4bb951
-  meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
4bb951
-                                                   surface);
4bb951
-
4bb951
   priv->shell_client->surfaces = g_list_remove (priv->shell_client->surfaces,
4bb951
                                                 xdg_surface);
4bb951
 
4bb951
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
4bb951
index 129da8e20d..4cb9ca650d 100644
4bb951
--- a/src/wayland/meta-wayland.c
4bb951
+++ b/src/wayland/meta-wayland.c
4bb951
@@ -194,15 +194,35 @@ meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
4bb951
 void
4bb951
 meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor)
4bb951
 {
4bb951
-  gint64 current_time = g_get_monotonic_time ();
4bb951
+  GList *l;
4bb951
+  int64_t now_us;
4bb951
 
4bb951
-  while (!wl_list_empty (&compositor->frame_callbacks))
4bb951
+  now_us = g_get_monotonic_time ();
4bb951
+
4bb951
+  l = compositor->frame_callback_surfaces;
4bb951
+  while (l)
4bb951
     {
4bb951
-      MetaWaylandFrameCallback *callback =
4bb951
-        wl_container_of (compositor->frame_callbacks.next, callback, link);
4bb951
+      GList *l_cur = l;
4bb951
+      MetaWaylandSurface *surface = l->data;
4bb951
+      MetaSurfaceActor *actor;
4bb951
+      MetaWaylandActorSurface *actor_surface;
4bb951
+
4bb951
+      l = l->next;
4bb951
+
4bb951
+      actor = meta_wayland_surface_get_actor (surface);
4bb951
+      if (!actor)
4bb951
+        continue;
4bb951
+
4bb951
+      if (!clutter_actor_has_mapped_clones (CLUTTER_ACTOR (actor)) &&
4bb951
+          meta_surface_actor_is_obscured (actor))
4bb951
+        continue;
4bb951
 
4bb951
-      wl_callback_send_done (callback->resource, current_time / 1000);
4bb951
-      wl_resource_destroy (callback->resource);
4bb951
+      actor_surface = META_WAYLAND_ACTOR_SURFACE (surface->role);
4bb951
+      meta_wayland_actor_surface_emit_frame_callbacks (actor_surface,
4bb951
+                                                       now_us / 1000);
4bb951
+
4bb951
+      compositor->frame_callback_surfaces =
4bb951
+        g_list_delete_link (compositor->frame_callback_surfaces, l_cur);
4bb951
     }
4bb951
 }
4bb951
 
4bb951
@@ -249,16 +269,22 @@ meta_wayland_compositor_update_key_state (MetaWaylandCompositor *compositor,
4bb951
 }
4bb951
 
4bb951
 void
4bb951
-meta_wayland_compositor_destroy_frame_callbacks (MetaWaylandCompositor *compositor,
4bb951
-                                                 MetaWaylandSurface    *surface)
4bb951
+meta_wayland_compositor_add_frame_callback_surface (MetaWaylandCompositor *compositor,
4bb951
+                                                    MetaWaylandSurface    *surface)
4bb951
 {
4bb951
-  MetaWaylandFrameCallback *callback, *next;
4bb951
+  if (g_list_find (compositor->frame_callback_surfaces, surface))
4bb951
+    return;
4bb951
 
4bb951
-  wl_list_for_each_safe (callback, next, &compositor->frame_callbacks, link)
4bb951
-    {
4bb951
-      if (callback->surface == surface)
4bb951
-        wl_resource_destroy (callback->resource);
4bb951
-    }
4bb951
+  compositor->frame_callback_surfaces =
4bb951
+    g_list_prepend (compositor->frame_callback_surfaces, surface);
4bb951
+}
4bb951
+
4bb951
+void
4bb951
+meta_wayland_compositor_remove_frame_callback_surface (MetaWaylandCompositor *compositor,
4bb951
+                                                       MetaWaylandSurface    *surface)
4bb951
+{
4bb951
+  compositor->frame_callback_surfaces =
4bb951
+    g_list_remove (compositor->frame_callback_surfaces, surface);
4bb951
 }
4bb951
 
4bb951
 static void
4bb951
@@ -309,8 +335,6 @@ meta_wayland_log_func (const char *fmt,
4bb951
 static void
4bb951
 meta_wayland_compositor_init (MetaWaylandCompositor *compositor)
4bb951
 {
4bb951
-  wl_list_init (&compositor->frame_callbacks);
4bb951
-
4bb951
   compositor->scheduled_surface_associations = g_hash_table_new (NULL, NULL);
4bb951
 
4bb951
   wl_log_set_handler_server (meta_wayland_log_func);
4bb951
diff --git a/src/wayland/meta-wayland.h b/src/wayland/meta-wayland.h
4bb951
index 2a0aa11400..c5e5924891 100644
4bb951
--- a/src/wayland/meta-wayland.h
4bb951
+++ b/src/wayland/meta-wayland.h
4bb951
@@ -64,9 +64,11 @@ void                    meta_wayland_compositor_set_input_focus (MetaWaylandComp
4bb951
 META_EXPORT_TEST
4bb951
 void                    meta_wayland_compositor_paint_finished  (MetaWaylandCompositor *compositor);
4bb951
 
4bb951
-META_EXPORT_TEST
4bb951
-void                    meta_wayland_compositor_destroy_frame_callbacks (MetaWaylandCompositor *compositor,
4bb951
-                                                                         MetaWaylandSurface    *surface);
4bb951
+void                    meta_wayland_compositor_add_frame_callback_surface (MetaWaylandCompositor *compositor,
4bb951
+                                                                            MetaWaylandSurface    *surface);
4bb951
+
4bb951
+void                    meta_wayland_compositor_remove_frame_callback_surface (MetaWaylandCompositor *compositor,
4bb951
+                                                                               MetaWaylandSurface    *surface);
4bb951
 
4bb951
 META_EXPORT_TEST
4bb951
 const char             *meta_wayland_get_wayland_display_name   (MetaWaylandCompositor *compositor);
4bb951
diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
4bb951
index 275aeb78cb..6e4b9a8ffd 100644
4bb951
--- a/src/wayland/meta-xwayland.c
4bb951
+++ b/src/wayland/meta-xwayland.c
4bb951
@@ -788,49 +788,6 @@ meta_xwayland_stop (MetaXWaylandManager *manager)
4bb951
     }
4bb951
 }
4bb951
 
4bb951
-static void
4bb951
-xwayland_surface_assigned (MetaWaylandSurfaceRole *surface_role)
4bb951
-{
4bb951
-  MetaWaylandSurface *surface =
4bb951
-    meta_wayland_surface_role_get_surface (surface_role);
4bb951
-  MetaWaylandSurfaceRoleClass *surface_role_class =
4bb951
-    META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_xwayland_parent_class);
4bb951
-
4bb951
-  /* See comment in xwayland_surface_commit for why we reply even though the
4bb951
-   * surface may not be drawn the next frame.
4bb951
-   */
4bb951
-  wl_list_insert_list (&surface->compositor->frame_callbacks,
4bb951
-                       &surface->pending_frame_callback_list);
4bb951
-  wl_list_init (&surface->pending_frame_callback_list);
4bb951
-
4bb951
-  surface_role_class->assigned (surface_role);
4bb951
-}
4bb951
-
4bb951
-static void
4bb951
-xwayland_surface_commit (MetaWaylandSurfaceRole  *surface_role,
4bb951
-                         MetaWaylandPendingState *pending)
4bb951
-{
4bb951
-  MetaWaylandSurface *surface =
4bb951
-    meta_wayland_surface_role_get_surface (surface_role);
4bb951
-  MetaWaylandSurfaceRoleClass *surface_role_class =
4bb951
-    META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_xwayland_parent_class);
4bb951
-
4bb951
-  /* For Xwayland windows, throttling frames when the window isn't actually
4bb951
-   * drawn is less useful, because Xwayland still has to do the drawing sent
4bb951
-   * from the application - the throttling would only be of sending us damage
4bb951
-   * messages, so we simplify and send frame callbacks after the next paint of
4bb951
-   * the screen, whether the window was drawn or not.
4bb951
-   *
4bb951
-   * Currently it may take a few frames before we draw the window, for not
4bb951
-   * completely understood reasons, and in that case, not thottling frame
4bb951
-   * callbacks to drawing has the happy side effect that we avoid showing the
4bb951
-   * user the initial black frame from when the window is mapped empty.
4bb951
-   */
4bb951
-  meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
4bb951
-
4bb951
-  surface_role_class->commit (surface_role, pending);
4bb951
-}
4bb951
-
4bb951
 static MetaWaylandSurface *
4bb951
 xwayland_surface_get_toplevel (MetaWaylandSurfaceRole *surface_role)
4bb951
 {
4bb951
@@ -848,8 +805,6 @@ meta_wayland_surface_role_xwayland_class_init (MetaWaylandSurfaceRoleXWaylandCla
4bb951
   MetaWaylandSurfaceRoleClass *surface_role_class =
4bb951
     META_WAYLAND_SURFACE_ROLE_CLASS (klass);
4bb951
 
4bb951
-  surface_role_class->assigned = xwayland_surface_assigned;
4bb951
-  surface_role_class->commit = xwayland_surface_commit;
4bb951
   surface_role_class->get_toplevel = xwayland_surface_get_toplevel;
4bb951
 
4bb951
   xwayland_surface_signals[XWAYLAND_SURFACE_WINDOW_ASSOCIATED] =
4bb951
-- 
4bb951
2.31.1
4bb951
4bb951
4bb951
From 076ac20d34db128aea8ffe0dc3c2791918667c43 Mon Sep 17 00:00:00 2001
4bb951
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
4bb951
Date: Fri, 6 Aug 2021 19:46:06 +0200
4bb951
Subject: [PATCH 5/5] wayland: Respond to frame callbacks even if the paint was
4bb951
 empty
4bb951
4bb951
---
4bb951
 src/compositor/compositor.c | 10 +++++-----
4bb951
 1 file changed, 5 insertions(+), 5 deletions(-)
4bb951
4bb951
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
4bb951
index ce2c1b8a3b..8331737d1a 100644
4bb951
--- a/src/compositor/compositor.c
4bb951
+++ b/src/compositor/compositor.c
4bb951
@@ -467,11 +467,6 @@ after_stage_paint (ClutterStage *stage,
4bb951
 
4bb951
   for (l = compositor->windows; l; l = l->next)
4bb951
     meta_window_actor_post_paint (l->data);
4bb951
-
4bb951
-#ifdef HAVE_WAYLAND
4bb951
-  if (meta_is_wayland_compositor ())
4bb951
-    meta_wayland_compositor_paint_finished (meta_wayland_compositor_get_default ());
4bb951
-#endif
4bb951
 }
4bb951
 
4bb951
 static void
4bb951
@@ -1404,6 +1399,11 @@ meta_post_paint_func (gpointer data)
4bb951
       break;
4bb951
     }
4bb951
 
4bb951
+#ifdef HAVE_WAYLAND
4bb951
+  if (meta_is_wayland_compositor ())
4bb951
+    meta_wayland_compositor_paint_finished (meta_wayland_compositor_get_default ());
4bb951
+#endif
4bb951
+
4bb951
   return TRUE;
4bb951
 }
4bb951
 
4bb951
-- 
4bb951
2.31.1
4bb951