[mutter] wayland: Drive frame callbacks from stage updates



commit 066bc5986d04204788880e372f259d6048cc1ae6
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Mon Apr 27 15:43:19 2020 +0200

    wayland: Drive frame callbacks from stage updates
    
    Don't tie frame callbacks to actor painting, as it may end up in
    situations where we miss sending frame callbacks when we should have. An
    example of this is when a surface is partially off screen, and then
    reports damage that is fully off screen. When this happen, we are likely
    not to repaint anything, thus we won't send any frame callbacks even
    though it's "suitable" for rendering again, as the surface is not on a
    separate workspace or fully obscured.
    
    Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/817
    Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1152
    
    https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218

 src/compositor/meta-surface-actor-wayland.c | 47 --------------------
 src/wayland/meta-wayland-actor-surface.c    | 66 ++++++++++++++++++++---------
 src/wayland/meta-wayland-actor-surface.h    |  3 ++
 src/wayland/meta-wayland-cursor-surface.c   |  4 +-
 src/wayland/meta-wayland-dnd-surface.c      | 10 ++++-
 src/wayland/meta-wayland-legacy-xdg-shell.c |  8 ++--
 src/wayland/meta-wayland-private.h          |  2 +-
 src/wayland/meta-wayland-subsurface.c       |  3 --
 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                  |  7 ++-
 14 files changed, 122 insertions(+), 149 deletions(-)
---
diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c
index a627dd28c6..ce50da1620 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,
@@ -72,23 +71,6 @@ meta_surface_actor_wayland_is_opaque (MetaSurfaceActor *actor)
   return meta_shaped_texture_is_opaque (stex);
 }
 
-static void
-queue_frame_callbacks (MetaSurfaceActorWayland *self)
-{
-  MetaWaylandCompositor *wayland_compositor;
-
-  if (!self->surface)
-    return;
-
-  if (meta_surface_actor_is_obscured (META_SURFACE_ACTOR (self)))
-    return;
-
-  wayland_compositor = self->surface->compositor;
-  wl_list_insert_list (&wayland_compositor->frame_callbacks,
-                       &self->frame_callback_list);
-  wl_list_init (&self->frame_callback_list);
-}
-
 CoglScanout *
 meta_surface_actor_wayland_try_acquire_scanout (MetaSurfaceActorWayland *self,
                                                 CoglOnscreen            *onscreen)
@@ -101,35 +83,13 @@ meta_surface_actor_wayland_try_acquire_scanout (MetaSurfaceActorWayland *self,
   if (!scanout)
     return NULL;
 
-  queue_frame_callbacks (self);
-
   return scanout;
 }
 
-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 void
-meta_surface_actor_wayland_paint (ClutterActor        *actor,
-                                  ClutterPaintContext *paint_context)
-{
-  MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor);
-
-  queue_frame_callbacks (self);
-
-  CLUTTER_ACTOR_CLASS (meta_surface_actor_wayland_parent_class)->paint (actor,
-                                                                        paint_context);
-}
-
 static void
 meta_surface_actor_wayland_dispose (GObject *object)
 {
   MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (object);
-  MetaWaylandFrameCallback *cb, *next;
   MetaShapedTexture *stex;
 
   stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
@@ -143,9 +103,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);
 }
 
@@ -153,11 +110,8 @@ static void
 meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass)
 {
   MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass);
-  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  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;
   surface_actor_class->is_opaque = meta_surface_actor_wayland_is_opaque;
@@ -177,7 +131,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 3d23234d62..47b3c1c3e2 100644
--- a/src/wayland/meta-wayland-actor-surface.c
+++ b/src/wayland/meta-wayland-actor-surface.c
@@ -107,9 +107,15 @@ meta_wayland_actor_surface_assigned (MetaWaylandSurfaceRole *surface_role)
   MetaWaylandSurface *surface =
     meta_wayland_surface_role_get_surface (surface_role);
 
-  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);
+  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
@@ -118,18 +124,37 @@ 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);
 
-  if (!priv->actor)
+  if (wl_list_empty (&pending->frame_callback_list))
     return;
 
-  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_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);
+    }
 }
 
 double
@@ -265,18 +290,17 @@ meta_wayland_actor_surface_apply_state (MetaWaylandSurfaceRole  *surface_role,
   MetaWaylandActorSurfacePrivate *priv =
     meta_wayland_actor_surface_get_instance_private (actor_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;
-    }
+      MetaWaylandSurface *surface =
+        meta_wayland_surface_role_get_surface (surface_role);
+      MetaBackend *backend = surface->compositor->backend;
+      ClutterActor *stage = meta_backend_get_stage (backend);
 
-  if (!wl_list_empty (&pending->frame_callback_list) &&
-      cairo_region_is_empty (pending->surface_damage) &&
-      cairo_region_is_empty (pending->buffer_damage))
-    clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->actor));
+      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 caa3cbe319..bd0cca2753 100644
--- a/src/wayland/meta-wayland-actor-surface.h
+++ b/src/wayland/meta-wayland-actor-surface.h
@@ -48,4 +48,7 @@ void meta_wayland_actor_surface_reset_actor (MetaWaylandActorSurface *actor_surf
 void meta_wayland_actor_surface_queue_frame_callbacks (MetaWaylandActorSurface *actor_surface,
                                                        MetaWaylandSurfaceState *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 d8ac1413ef..95f8186df8 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 b735c13885..c3b0f7557b 100644
--- a/src/wayland/meta-wayland-dnd-surface.c
+++ b/src/wayland/meta-wayland-dnd-surface.c
@@ -23,6 +23,7 @@
 
 #include "backends/meta-logical-monitor.h"
 #include "compositor/meta-feedback-actor-private.h"
+#include "wayland/meta-wayland.h"
 
 struct _MetaWaylandSurfaceRoleDND
 {
@@ -42,7 +43,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
@@ -56,7 +61,8 @@ dnd_surface_apply_state (MetaWaylandSurfaceRole  *surface_role,
   MetaWaylandSurfaceRoleClass *surface_role_class =
     META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_dnd_parent_class);
 
-  meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
+  meta_wayland_compositor_add_frame_callback_surface (surface->compositor,
+                                                      surface);
 
   surface_role_dnd->pending_offset_x = pending->dx;
   surface_role_dnd->pending_offset_y = pending->dy;
diff --git a/src/wayland/meta-wayland-legacy-xdg-shell.c b/src/wayland/meta-wayland-legacy-xdg-shell.c
index 9c5b02e1a4..8395ca39db 100644
--- a/src/wayland/meta-wayland-legacy-xdg-shell.c
+++ b/src/wayland/meta-wayland-legacy-xdg-shell.c
@@ -658,6 +658,8 @@ meta_wayland_zxdg_toplevel_v6_apply_state (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);
@@ -668,7 +670,7 @@ meta_wayland_zxdg_toplevel_v6_apply_state (MetaWaylandSurfaceRole  *surface_role
   window = meta_wayland_surface_get_window (surface);
   if (!window)
     {
-      meta_wayland_surface_cache_pending_frame_callbacks (surface, pending);
+      meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending);
       return;
     }
 
@@ -1218,14 +1220,10 @@ meta_wayland_zxdg_surface_v6_send_configure (MetaWaylandZxdgSurfaceV6       *xdg
 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 a7e5604fcb..727009b07e 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -79,7 +79,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 1ec5b230b3..56e4ca97c6 100644
--- a/src/wayland/meta-wayland-subsurface.c
+++ b/src/wayland/meta-wayland-subsurface.c
@@ -362,9 +362,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);
-
   g_node_unlink (surface->subsurface_branch_node);
   unparent_actor (surface);
 
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index a16ffb92b9..515c679575 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -409,15 +409,6 @@ surface_process_damage (MetaWaylandSurface *surface,
   cairo_region_destroy (transformed_region);
 }
 
-void
-meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface      *surface,
-                                                          MetaWaylandSurfaceState *pending)
-{
-  wl_list_insert_list (&surface->compositor->frame_callbacks,
-                       &pending->frame_callback_list);
-  wl_list_init (&pending->frame_callback_list);
-}
-
 MetaWaylandBuffer *
 meta_wayland_surface_get_buffer (MetaWaylandSurface *surface)
 {
@@ -632,15 +623,6 @@ meta_wayland_surface_state_class_init (MetaWaylandSurfaceStateClass *klass)
                   G_TYPE_NONE, 0);
 }
 
-void
-meta_wayland_surface_cache_pending_frame_callbacks (MetaWaylandSurface      *surface,
-                                                    MetaWaylandSurfaceState *pending)
-{
-  wl_list_insert_list (&surface->pending_frame_callback_list,
-                       &pending->frame_callback_list);
-  wl_list_init (&pending->frame_callback_list);
-}
-
 static void
 meta_wayland_surface_apply_state (MetaWaylandSurface      *surface,
                                   MetaWaylandSurfaceState *state)
@@ -776,7 +758,9 @@ meta_wayland_surface_apply_state (MetaWaylandSurface      *surface,
     }
   else
     {
-      meta_wayland_surface_cache_pending_frame_callbacks (surface, state);
+      wl_list_insert_list (surface->unassigned.pending_frame_callback_list.prev,
+                           &state->frame_callback_list);
+      wl_list_init (&state->frame_callback_list);
 
       if (state->newly_attached)
         {
@@ -1358,14 +1342,16 @@ 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,
                         surface_output_disconnect_signals,
                         surface);
   g_hash_table_destroy (surface->outputs);
 
-  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)
@@ -1412,7 +1398,7 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
                                   surface,
                                   wl_surface_destructor);
 
-  wl_list_init (&surface->pending_frame_callback_list);
+  wl_list_init (&surface->unassigned.pending_frame_callback_list);
 
   surface->outputs = g_hash_table_new (NULL, NULL);
   surface->shortcut_inhibited_seats = g_hash_table_new (NULL, NULL);
@@ -1872,14 +1858,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 1effaa4753..0e66f4b4eb 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -168,13 +168,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;
 
@@ -288,9 +284,6 @@ gboolean            meta_wayland_surface_should_cache_state (MetaWaylandSurface
 
 MetaWindow *        meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface);
 
-void                meta_wayland_surface_cache_pending_frame_callbacks (MetaWaylandSurface      *surface,
-                                                                        MetaWaylandSurfaceState *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 7add5667da..f677347990 100644
--- a/src/wayland/meta-wayland-wl-shell.c
+++ b/src/wayland/meta-wayland-wl-shell.c
@@ -103,9 +103,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 ecad04e120..727f73ccfb 100644
--- a/src/wayland/meta-wayland-xdg-shell.c
+++ b/src/wayland/meta-wayland-xdg-shell.c
@@ -740,6 +740,8 @@ meta_wayland_xdg_toplevel_apply_state (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);
@@ -750,15 +752,12 @@ meta_wayland_xdg_toplevel_apply_state (MetaWaylandSurfaceRole  *surface_role,
   window = meta_wayland_surface_get_window (surface);
   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);
@@ -1089,6 +1088,8 @@ meta_wayland_xdg_popup_apply_state (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);
@@ -1103,7 +1104,7 @@ meta_wayland_xdg_popup_apply_state (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;
     }
 
@@ -1380,14 +1381,10 @@ meta_wayland_xdg_surface_send_configure (MetaWaylandXdgSurface          *xdg_sur
 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 b37d9fdcf1..e4b09cbfc7 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -197,15 +197,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);
     }
 }
 
@@ -252,16 +272,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
@@ -313,8 +339,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 4164563e83..3549fb2d5b 100644
--- a/src/wayland/meta-wayland.h
+++ b/src/wayland/meta-wayland.h
@@ -62,8 +62,11 @@ void                    meta_wayland_compositor_set_input_focus (MetaWaylandComp
 
 void                    meta_wayland_compositor_paint_finished  (MetaWaylandCompositor *compositor);
 
-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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]